Index: ecos/packages/devs/serial/arm/at91/current/ChangeLog =================================================================== RCS file: /cvs/ecos/ecos/packages/devs/serial/arm/at91/current/ChangeLog,v retrieving revision 1.8 diff -u -r1.8 ChangeLog --- ecos/packages/devs/serial/arm/at91/current/ChangeLog 16 Oct 2003 18:02:54 -0000 1.8 +++ ecos/packages/devs/serial/arm/at91/current/ChangeLog 23 Oct 2003 14:45:27 -0000 @@ -1,3 +1,8 @@ +2003-10-23 Laurent Gonzalez + + * cdl/ser_arm_at91.cdl: now implements CYGINT_IO_SERIAL_BLOCK_TRANSFER + * src/at91_serial.c: Add PDC support for both Rx and Tx. + 2003-10-16 Nick Garnett * src/at91_serial.c (at91_serial_config_port): Added update of Index: ecos/packages/devs/serial/arm/at91/current/cdl/ser_arm_at91.cdl =================================================================== RCS file: /cvs/ecos/ecos/packages/devs/serial/arm/at91/current/cdl/ser_arm_at91.cdl,v retrieving revision 1.5 diff -u -r1.5 ser_arm_at91.cdl --- ecos/packages/devs/serial/arm/at91/current/cdl/ser_arm_at91.cdl 24 Feb 2003 14:12:18 -0000 1.5 +++ ecos/packages/devs/serial/arm/at91/current/cdl/ser_arm_at91.cdl 23 Oct 2003 14:45:27 -0000 @@ -59,6 +59,7 @@ requires CYGPKG_ERROR include_dir cyg/io include_files ; # none _exported_ whatsoever + implements CYGINT_IO_SERIAL_BLOCK_TRANSFER description " This option enables the serial device drivers for the Atmel AT91 (EB40)." Index: ecos/packages/devs/serial/arm/at91/current/src/at91_serial.c =================================================================== RCS file: /cvs/ecos/ecos/packages/devs/serial/arm/at91/current/src/at91_serial.c,v retrieving revision 1.6 diff -u -r1.6 at91_serial.c --- ecos/packages/devs/serial/arm/at91/current/src/at91_serial.c 16 Oct 2003 18:02:55 -0000 1.6 +++ ecos/packages/devs/serial/arm/at91/current/src/at91_serial.c 23 Oct 2003 14:45:27 -0000 @@ -2,7 +2,7 @@ // // io/serial/arm/at91/at91_serial.c // -// Atmel AT91/EB40 Serial I/O Interface Module (interrupt driven) +// Atmel AT91 Serial I/O Interface Module (interrupt driven) // //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### @@ -41,7 +41,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas -// Contributors: gthomas +// Contributors: gthomas, lgonzale@ri.silicomp.fr // Date: 2001-07-24 // Purpose: Atmel AT91/EB40 Serial I/O module (interrupt driven version) // Description: @@ -69,6 +69,13 @@ typedef struct at91_serial_info { CYG_ADDRWORD base; CYG_WORD int_num; + unsigned char *buf_a; + unsigned char *buf_b; + unsigned char *current_buf; + unsigned char *second_buf; + int bytes_avail; + unsigned char *tx_buf; + int tx_remain; cyg_interrupt serial_interrupt; cyg_handle_t serial_interrupt_handle; } at91_serial_info; @@ -95,9 +102,16 @@ at91_serial_stop_xmit ); +#define AT91_PDC_IN_BUFFER_SIZE 32 +#define AT91_PDC_OUT_BUFFER_SIZE 65535 /* this size is not allocated ! */ + #ifdef CYGPKG_IO_SERIAL_ARM_AT91_SERIAL0 +static unsigned char at91_serial0_Rx_PDC_buf0[AT91_PDC_IN_BUFFER_SIZE+1]; +static unsigned char at91_serial0_Rx_PDC_buf1[AT91_PDC_IN_BUFFER_SIZE+1]; static at91_serial_info at91_serial_info0 = {(CYG_ADDRWORD)AT91_USART0, - CYGNUM_HAL_INTERRUPT_USART0}; + CYGNUM_HAL_INTERRUPT_USART0, + at91_serial0_Rx_PDC_buf0, + at91_serial0_Rx_PDC_buf1}; #if CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE > 0 static unsigned char at91_serial_out_buf0[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE]; static unsigned char at91_serial_in_buf0[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE]; @@ -136,8 +150,12 @@ #endif // CYGPKG_IO_SERIAL_ARM_AT91_SERIAL1 #ifdef CYGPKG_IO_SERIAL_ARM_AT91_SERIAL1 +static unsigned char at91_serial1_Rx_PDC_buf0[AT91_PDC_IN_BUFFER_SIZE+1]; +static unsigned char at91_serial1_Rx_PDC_buf1[AT91_PDC_IN_BUFFER_SIZE+1]; static at91_serial_info at91_serial_info1 = {(CYG_ADDRWORD)AT91_USART1, - CYGNUM_HAL_INTERRUPT_USART1}; + CYGNUM_HAL_INTERRUPT_USART1, + at91_serial1_Rx_PDC_buf0, + at91_serial1_Rx_PDC_buf1}; #if CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE > 0 static unsigned char at91_serial_out_buf1[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE]; static unsigned char at91_serial_in_buf1[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE]; @@ -192,7 +210,9 @@ } // Reset device - HAL_WRITE_UINT32(base+AT91_US_CR, AT91_US_CR_RxRESET | AT91_US_CR_TxRESET); + HAL_WRITE_UINT32(base+AT91_US_CR, AT91_US_CR_RxRESET | AT91_US_CR_TxRESET | + AT91_US_CR_RxDISAB | AT91_US_CR_TxDISAB | + AT91_US_CR_RSTATUS); // Configuration HAL_WRITE_UINT32(base+AT91_US_MR, parity | word_length | stop_bits); @@ -200,14 +220,23 @@ // Baud rate HAL_WRITE_UINT32(base+AT91_US_BRG, AT91_US_BAUD(select_baud[new_config->baud])); + // data controller configuration + at91_chan->current_buf=at91_chan->buf_a; + at91_chan->second_buf =at91_chan->buf_b; + HAL_WRITE_UINT32(base+AT91_US_TCR,0); + HAL_WRITE_UINT32(base+AT91_US_RPR,(CYG_ADDRWORD)at91_chan->current_buf); + HAL_WRITE_UINT32(base+AT91_US_RCR,AT91_PDC_IN_BUFFER_SIZE); + at91_chan->bytes_avail= at91_chan->tx_remain= 0; + // Disable all interrupts HAL_WRITE_UINT32(base+AT91_US_IDR, 0xFFFFFFFF); // Enable Rx interrupts - HAL_WRITE_UINT32(base+AT91_US_IER, AT91_US_IER_RxRDY); + HAL_WRITE_UINT32(base+AT91_US_IER,AT91_US_IER_ENDRX|AT91_US_IER_TIMEOUT); - // Enable RX and TX + // Enable RX (+TIMEOUT) and TX HAL_WRITE_UINT32(base+AT91_US_CR, AT91_US_CR_RxENAB | AT91_US_CR_TxENAB); + HAL_WRITE_UINT32(base+AT91_US_RTO,4*10); // Time out after ca. 4 char idle line if (new_config != &chan->config) { chan->config = *new_config; @@ -227,7 +256,7 @@ #ifdef CYGDBG_IO_INIT diag_printf("AT91 SERIAL init - dev: %x.%d\n", at91_chan->base, at91_chan->int_num); #endif - (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices + if (chan->out_cbuf.len != 0) { cyg_drv_interrupt_create(at91_chan->int_num, 4, // Priority @@ -239,7 +268,7 @@ cyg_drv_interrupt_attach(at91_chan->serial_interrupt_handle); cyg_drv_interrupt_unmask(at91_chan->int_num); } - res = at91_serial_config_port(chan, &chan->config, true); + res = 0; return res; } @@ -251,7 +280,8 @@ { serial_channel *chan = (serial_channel *)(*tab)->priv; - (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices + (chan->callbacks->serial_init)(chan); + at91_serial_config_port(chan, &chan->config, true); return ENOERR; } @@ -318,9 +348,35 @@ { at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv; CYG_ADDRWORD base = at91_chan->base; + int avail_space,res; + unsigned char *avail_buf; - (chan->callbacks->xmt_char)(chan); // Kick transmitter (if necessary) - HAL_WRITE_UINT32(base+AT91_US_IER, AT91_US_IER_TxRDY); + // first test if transmit is idle + if (at91_chan->tx_remain==0) { + res=(chan->callbacks->data_xmt_req)(chan,AT91_PDC_OUT_BUFFER_SIZE, + &avail_space,&avail_buf); + switch (res) { + case CYG_XMT_OK: + at91_chan->tx_buf=avail_buf; + at91_chan->tx_remain=avail_space; + HAL_WRITE_UINT32(base+AT91_US_TPR,(CYG_ADDRWORD)at91_chan->tx_buf); + HAL_WRITE_UINT32(base+AT91_US_TCR,at91_chan->tx_remain); + HAL_WRITE_UINT32(base+AT91_US_IER, AT91_US_IER_ENDTX); + break; + case CYG_XMT_DISABLED: + (chan->callbacks->xmt_char)(chan); + HAL_WRITE_UINT32(base+AT91_US_IER, AT91_US_IER_TxRDY); + case CYG_XMT_EMPTY:// Nothing to transmit + default: ; + } + return; + } + // then if transmit is suspended + HAL_WRITE_UINT32(base+AT91_US_IER, AT91_US_IER_ENDTX); + HAL_READ_UINT32(base+AT91_US_TPR,(CYG_ADDRWORD)avail_buf); + if (avail_buf==at91_chan->tx_buf) + HAL_WRITE_UINT32(base+AT91_US_TCR,at91_chan->tx_remain); + // else do nothing because it is already running } // Disable the transmitter on the device @@ -329,16 +385,68 @@ { at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv; CYG_ADDRWORD base = at91_chan->base; + int len; + unsigned char *remain_buf; - HAL_WRITE_UINT32(base+AT91_US_IDR, AT91_US_IER_TxRDY); + // Stop Tx + HAL_WRITE_UINT32(base+AT91_US_TCR, 0); + HAL_WRITE_UINT32(base+AT91_US_IDR, AT91_US_IER_ENDTX|AT91_US_IER_TxRDY); + // look if transmit is suspending + if (at91_chan->tx_remain==0) return; //no + // yes, then find where we are stopped + //diag_printf("Stop_xmit while running\n"); + HAL_READ_UINT32 (base+AT91_US_TPR, (CYG_ADDRWORD)remain_buf); + len = (int)(remain_buf-at91_chan->tx_buf); + // acknowledge what is already transmitted + (chan->callbacks->data_xmt_done)(chan,len); + // update info to restart Tx later + at91_chan->tx_remain -= len; + at91_chan->tx_buf = remain_buf; } // Serial I/O - low level interrupt handler (ISR) static cyg_uint32 at91_serial_ISR(cyg_vector_t vector, cyg_addrword_t data) { + serial_channel *chan = (serial_channel *)data; + at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv; + CYG_ADDRWORD base = at91_chan->base; + int stat; + cyg_drv_interrupt_mask(vector); cyg_drv_interrupt_acknowledge(vector); + + HAL_READ_UINT32 (base+AT91_US_CSR, stat); + if ( stat&(AT91_US_CSR_ENDRX|AT91_US_CSR_TIMEOUT) ) { + cyg_uint8 *ptr; + cyg_uint32 status; + // swap Rx buffer with care and restart reception + HAL_WRITE_UINT32(base+AT91_US_RCR, 0); + HAL_READ_UINT32(base+AT91_US_RPR,(cyg_uint32)ptr); + // At most one new character might have been received during PDC stop + HAL_READ_UINT32(base+AT91_US_CSR, status); + if ((status & AT91_US_CSR_RxRDY) == 0) { + // All characters have been handled by the PDC + // => Read back the PDC position + HAL_READ_UINT32(base+AT91_US_RPR,(cyg_uint32)ptr); + } else { + // A new character has been received => Force it to be in the PDC buffer + cyg_uint32 c; + HAL_READ_UINT32(base+AT91_US_RHR, c); + *ptr++ = (cyg_uint8)(c & 0xFF); + } + at91_chan->current_buf = ptr; + HAL_WRITE_UINT32(base+AT91_US_RPR, (CYG_ADDRWORD)at91_chan->second_buf); + HAL_WRITE_UINT32(base+AT91_US_RCR, AT91_PDC_IN_BUFFER_SIZE); + HAL_WRITE_UINT32(base+AT91_US_CR, AT91_US_CR_STTTO); + // remember Rx event + at91_chan->bytes_avail = 1; + // look for a possibly incoming char during this time + HAL_READ_UINT32 (base+AT91_US_CSR, stat); + if ( stat & AT91_US_CSR_RxRDY ) // yes + HAL_READ_UINT8 (base+AT91_US_RHR, *(at91_chan->current_buf++)); + } + return (CYG_ISR_CALL_DSR|CYG_ISR_HANDLED); // Cause DSR to be run } @@ -349,24 +457,66 @@ serial_channel *chan = (serial_channel *)data; at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv; CYG_ADDRWORD base = at91_chan->base; - cyg_uint32 stat, c; + cyg_uint32 stat, mask; // Check status - HAL_READ_UINT32(base+AT91_US_IMR, stat); + HAL_READ_UINT32(base+AT91_US_CSR, stat); + HAL_READ_UINT32(base+AT91_US_IMR, mask); + stat &= mask; - if (stat & (AT91_US_IER_TxRDY)) { + // Packet transmition + if (stat & AT91_US_CSR_ENDTX) { + int avail_space,nb_send; + xmt_req_reply_t res; + unsigned char *avail_buf; + nb_send=at91_chan->tx_remain; + at91_chan->tx_remain=0; + (chan->callbacks->data_xmt_done)(chan,nb_send); + res=(chan->callbacks->data_xmt_req)(chan,AT91_PDC_OUT_BUFFER_SIZE, + &avail_space,&avail_buf); + switch (res) { + case CYG_XMT_OK: + at91_chan->tx_buf=avail_buf; + at91_chan->tx_remain=avail_space; + HAL_WRITE_UINT32(base+AT91_US_TPR, (CYG_ADDRWORD)at91_chan->tx_buf); + HAL_WRITE_UINT32(base+AT91_US_TCR, at91_chan->tx_remain); + break; + case CYG_XMT_DISABLED: + (chan->callbacks->xmt_char)(chan); + case CYG_XMT_EMPTY:// Nothing to transmit + default:; + } + } + // Char transmition + if (stat & (AT91_US_CSR_TxRDY)) { (chan->callbacks->xmt_char)(chan); } - if (stat & (AT91_US_IER_RxRDY)) { - while (true) { - HAL_READ_UINT32(base+AT91_US_CSR, stat); - if ((stat & AT91_US_CSR_RxRDY) == 0) { - break; - } - HAL_READ_UINT32(base+AT91_US_RHR, c); - (chan->callbacks->rcv_char)(chan, c); - } + // Packet reception + if (at91_chan->bytes_avail) { + int len,avail_space,cnt; + unsigned char *avail_buf,*rx_buf; + at91_chan->bytes_avail=0; + // find the base of the buffer to be processed + rx_buf=at91_chan->second_buf = + (at91_chan->second_buf==at91_chan->buf_a)? + at91_chan->buf_b:at91_chan->buf_a; + len = at91_chan->current_buf - at91_chan->second_buf; + while (len!=0) { + switch ((chan->callbacks->data_rcv_req)(chan,len,&avail_space,&avail_buf)) { + case CYG_RCV_OK: + len -= (cnt = avail_space); + while (cnt--) *avail_buf++=*rx_buf++; + (chan->callbacks->data_rcv_done)(chan,avail_space); + break; + case CYG_RCV_DISABLED: + while (len--) + (chan->callbacks->rcv_char)(chan,*rx_buf++); + case CYG_RCV_FULL: // then received char will be lost + default: + len=0; + } + } } cyg_drv_interrupt_unmask(vector); } -#endif +#endif // CYGPKG_IO_SERIAL_ARM_AT91 Index: ecos/packages/hal/arm/at91/var/current/ChangeLog =================================================================== RCS file: /cvs/ecos/ecos/packages/hal/arm/at91/var/current/ChangeLog,v retrieving revision 1.11 diff -u -r1.11 ChangeLog --- ecos/packages/hal/arm/at91/var/current/ChangeLog 21 Aug 2003 15:29:53 -0000 1.11 +++ ecos/packages/hal/arm/at91/var/current/ChangeLog 23 Oct 2003 14:45:29 -0000 @@ -1,3 +1,9 @@ +2003-10-23 Laurent Gonzalez + + * include/var_io.h: Added definition to support the PDC + management in the interrupt driven serial driver. Fix baud + formula to get a more accurate value. + 2003-08-21 Thomas Koeller * include/var_io.h: Index: ecos/packages/hal/arm/at91/var/current/include/var_io.h =================================================================== RCS file: /cvs/ecos/ecos/packages/hal/arm/at91/var/current/include/var_io.h,v retrieving revision 1.5 diff -u -r1.5 var_io.h --- ecos/packages/hal/arm/at91/var/current/include/var_io.h 21 Aug 2003 15:29:53 -0000 1.5 +++ ecos/packages/hal/arm/at91/var/current/include/var_io.h 23 Oct 2003 14:45:29 -0000 @@ -123,8 +123,11 @@ #define AT91_US_CSR 0x14 // Channel status register #define AT91_US_CSR_RxRDY 0x01 // Receive data ready #define AT91_US_CSR_TxRDY 0x02 // Transmit ready +#define AT91_US_CSR_ENDRX 0x08 // PDC Rx end +#define AT91_US_CSR_ENDTX 0x10 // PDC Tx end #define AT91_US_CSR_OVRE 0x20 // Overrun error #define AT91_US_CSR_FRAME 0x40 // Framing error +#define AT91_US_CSR_TIMEOUT 0x100 // Rx timeout #define AT91_US_RHR 0x18 // Receive holding register #define AT91_US_THR 0x1C // Transmit holding register #define AT91_US_BRG 0x20 // Baud rate generator @@ -135,7 +138,7 @@ #define AT91_US_TPR 0x38 // Transmit pointer register #define AT91_US_TCR 0x3c // Transmit counter register -#define AT91_US_BAUD(baud) (CYGNUM_HAL_ARM_AT91_CLOCK_SPEED/(16*(baud))) +#define AT91_US_BAUD(baud) ((CYGNUM_HAL_ARM_AT91_CLOCK_SPEED/8/(baud)+1)/2) //============================================================================= // PIO