This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
There are several problems with the current Atmel derial driver. I have fixed most of them with this almost entirely rewritten driver. Lets first explain the problems: 1 - the serial driver does no hardware buffering even though Atmel PDC is cabable of it. So it drops characters OFTEN. 2 - even with hardware buffering you need to cope with an ENDRX interupt on a buffer full. But eCos cannot call the ISR function fast enough so it drops a couple of characters at the end of each buffer. The solution is to use the PDC in both directions, disable RXRDY/TXRDY interrupts entirely, and insert some REALLY fast flip buffer routine inside eCos's main interrupt handler. Note that the code below assumes our board. Simply replace SETH with AT91 and seth with at91 to get a at91 driver. Our first order of business is to optimise the eCos irq handler. Below is an optmised version with a flip buffer handler. The rest of the sources are attached. I have made the buffer really large: SETH_UART_BUF_SIZE = 1024 Probably a buffer of 128 is more than sufficient. I have only tested uart0. but uart1 is symmetrically coded, so it should work fine. here is the new irq routine: ---------------- FLIP_BUFFER_DEF(SETH_UART_BUF_SIZE); static struct flip_buffer *uart0, *uart1; void flip_set_uart0 (struct flip_buffer *u) { uart0 = u; } void flip_set_uart1 (struct flip_buffer *u) { uart1 = u; } // // This routine is called to respond to a hardware interrupt (IRQ). It // should interrogate the hardware and return the IRQ vector number. int hal_IRQ_handler (void) { cyg_uint32 irq_num = 0; cyg_uint32 ipr, imr, count, p; HAL_READ_UINT32 (SETH_AIC + SETH_AIC_IPR, ipr); HAL_READ_UINT32 (SETH_AIC + SETH_AIC_IMR, imr); ipr &= imr; if (ipr & (1 << 0)) goto done; irq_num = 1; if (ipr & (1 << 1)) goto done; irq_num = CYGNUM_HAL_INTERRUPT_USART0; if ((ipr & (1 << CYGNUM_HAL_INTERRUPT_USART0))) { HAL_READ_UINT32 (SETH_USART0 + SETH_US_CSR, ipr); HAL_READ_UINT32 (SETH_USART0 + SETH_US_IMR, imr); if ((ipr & imr & (SETH_US_IER_ENDRX | SETH_US_IER_TIMEOUT)) && uart0) { HAL_READ_UINT32 (SETH_USART0 + SETH_US_RPR, p); count = p - (cyg_uint32) uart0->buf[uart0->buf_which]; if (count > 0) { // PDC has done work /* record the location of the bytes read while we were away */ uart0->buf_p = uart0->buf[uart0->buf_which]; uart0->buf_count = count; /* flip the buffer */ uart0->buf_which = 1 - uart0->buf_which; HAL_WRITE_UINT32 (SETH_USART0 + SETH_US_RPR, (cyg_uint32) uart0->buf[uart0->buf_which]); HAL_WRITE_UINT32 (SETH_USART0 + SETH_US_RCR, (cyg_uint32) SETH_UART_BUF_SIZE); } HAL_WRITE_UINT32 (SETH_USART0 + SETH_US_RTOR, RECV_UART_CHAR_TIMEOUT); HAL_WRITE_UINT32 (SETH_USART0 + SETH_US_CR, SETH_US_CR_STTTO); } goto done; } irq_num = CYGNUM_HAL_INTERRUPT_USART1; if ((ipr & (1 << CYGNUM_HAL_INTERRUPT_USART1))) { HAL_READ_UINT32 (SETH_USART1 + SETH_US_CSR, ipr); HAL_READ_UINT32 (SETH_USART1 + SETH_US_IMR, imr); if ((ipr & imr & (SETH_US_IER_ENDRX | SETH_US_IER_TIMEOUT)) && uart1) { HAL_READ_UINT32 (SETH_USART1 + SETH_US_RPR, p); count = p - (cyg_uint32) uart1->buf[uart1->buf_which]; if (count > 0) { // PDC has done work /* record the location of the bytes read while we were away */ uart1->buf_p = uart1->buf[uart1->buf_which]; uart1->buf_count = count; /* flip the buffer */ uart1->buf_which = 1 - uart1->buf_which; HAL_WRITE_UINT32 (SETH_USART1 + SETH_US_RPR, (cyg_uint32) uart1->buf[uart1->buf_which]); HAL_WRITE_UINT32 (SETH_USART1 + SETH_US_RCR, (cyg_uint32) SETH_UART_BUF_SIZE); } HAL_WRITE_UINT32 (SETH_USART1 + SETH_US_RTOR, RECV_UART_CHAR_TIMEOUT); HAL_WRITE_UINT32 (SETH_USART1 + SETH_US_CR, SETH_US_CR_STTTO); } goto done; } irq_num = CYGNUM_HAL_INTERRUPT_TIMER0; if (ipr & (1 << CYGNUM_HAL_INTERRUPT_TIMER0)) goto done; irq_num = CYGNUM_HAL_INTERRUPT_TIMER1; if (ipr & (1 << CYGNUM_HAL_INTERRUPT_TIMER1)) goto done; irq_num = CYGNUM_HAL_INTERRUPT_TIMER2; if (ipr & (1 << CYGNUM_HAL_INTERRUPT_TIMER2)) goto done; irq_num = CYGNUM_HAL_INTERRUPT_WATCHDOG; if (ipr & (1 << CYGNUM_HAL_INTERRUPT_WATCHDOG)) goto done; irq_num = CYGNUM_HAL_INTERRUPT_PIO; if (ipr & (1 << CYGNUM_HAL_INTERRUPT_PIO)) goto done; irq_num = CYGNUM_HAL_INTERRUPT_EXT0; if (ipr & (1 << CYGNUM_HAL_INTERRUPT_EXT0)) goto done; irq_num = CYGNUM_HAL_INTERRUPT_EXT1; if (ipr & (1 << CYGNUM_HAL_INTERRUPT_EXT1)) goto done; irq_num = CYGNUM_HAL_INTERRUPT_EXT2; if (ipr & (1 << CYGNUM_HAL_INTERRUPT_EXT2)) goto done; irq_num = CYGNUM_HAL_ISR_MAX + 1; done: return irq_num; } --------------------------------------------- This message was sent using World Mail. http://www.worldonline.co.za
Attachment:
serial.tar.gz
Description: Binary data
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |