Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

uartdma.c

Go to the documentation of this file.
00001 /*! \file uartdma.c \brief UART driver for AT91SAM7S with DMA. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'uartdma.c'
00005 // Title        : UART driver for AT91SAM7S with DMA
00006 // Author       : Pascal Stang - Copyright (C) 2004-2006
00007 // Created      : 4/3/2004
00008 // Revised      : 10/24/2006
00009 // Version      : 0.1
00010 // Target MCU   : Atmel ARM AT91SAM7S Series
00011 // Editor Tabs  : 4
00012 //
00013 // This code is distributed under the GNU Public License
00014 //      which can be found at http://www.gnu.org/licenses/gpl.txt
00015 //
00016 //*****************************************************************************
00017 
00018 // AT91SAM7S definitions
00019 #include "at91sam7s64.h"
00020 
00021 #include "global.h"
00022 #include "processor.h"
00023 #include "buffer.h"
00024 #include "uartdma.h"
00025 
00026 // receive and transmit buffers
00027 cBuffer UartRxBuffer[3];            ///< uart receive buffers
00028 static unsigned char Uart0RxData[UART0_RX_BUFFER_SIZE];
00029 static unsigned char Uart1RxData[UART1_RX_BUFFER_SIZE];
00030 static unsigned char Uart2RxData[UART2_RX_BUFFER_SIZE];
00031 cBuffer UartTxBuffer[3];            ///< uart transmit buffers
00032 static unsigned char Uart0TxData[UART0_TX_BUFFER_SIZE];
00033 static unsigned char Uart1TxData[UART1_TX_BUFFER_SIZE];
00034 static unsigned char Uart2TxData[UART2_TX_BUFFER_SIZE];
00035 
00036 // Global Pointer to USARTs
00037 AT91S_USART* const pUSART[3] = { AT91C_BASE_US0, AT91C_BASE_US0, AT91C_BASE_DBGU };
00038 #define pUSART0     ((AT91S_USART*)AT91C_BASE_US0)
00039 #define pUSART1     ((AT91S_USART*)AT91C_BASE_US1)
00040 #define pUSART2     ((AT91S_USART*)AT91C_BASE_DBGU)
00041 #define pPDC(dev)   ((AT91S_PDC*)((unsigned char*)(dev)+0x100))
00042 
00043 
00044 //! enable and initialize the uart
00045 void uart0Init(uint16_t bauddiv, uint32_t mode)
00046 {
00047     // enable the clock of UART0
00048     AT91C_BASE_PMC->PMC_PCER = (1<<AT91C_ID_US0);
00049     // enable uart pins on PIO
00050     *AT91C_PIOA_PDR = AT91C_PA5_RXD0 | AT91C_PA6_TXD0;
00051     // select peripheral connection
00052     *AT91C_PIOA_ASR = AT91C_PA5_RXD0 | AT91C_PA6_TXD0;
00053     // enable I/O pullup to avoid spurious receive if RXD pin left unconnected
00054     *AT91C_PIOA_PPUER = AT91C_PA5_RXD0;
00055     // reset the UART
00056     pUSART[0]->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RXDIS |AT91C_US_TXDIS;
00057     // set serial line mode
00058     pUSART[0]->US_MR =  AT91C_US_USMODE_NORMAL |// Normal Mode
00059                         AT91C_US_CLKS_CLOCK |   // Clock = MCK
00060                         mode;                   // user-defined data parameters
00061     // set the baud rate
00062     pUSART[0]->US_BRGR = bauddiv;
00063     // enable the uart
00064     pUSART[0]->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
00065     
00066     // initialize buffers
00067     uart0InitBuffers();
00068     // setup DMA controller for transmit
00069     uartInitDmaTx(0);
00070     // setup DMA controller for receive
00071     //uartInitDmaRx(0);
00072 
00073     // attach interrupt handler
00074     processorAicAttach(AT91C_ID_US0, (UART0_INTERRUPT_LEVEL|AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL), uart0Service);
00075     // enable receive interrupt
00076     pUSART[0]->US_IER = AT91C_US_RXRDY;
00077 }
00078 
00079 void uart1Init(uint16_t bauddiv, uint32_t mode)
00080 {
00081     // enable the clock of UART1
00082     AT91C_BASE_PMC->PMC_PCER = (1<<AT91C_ID_US1);
00083     // enable uart pins on PIO
00084     *AT91C_PIOA_PDR = AT91C_PA21_RXD1 | AT91C_PA22_TXD1;
00085     // select peripheral connection
00086     *AT91C_PIOA_ASR = AT91C_PA21_RXD1 | AT91C_PA22_TXD1;
00087     // enable I/O pullup to avoid spurious receive if RXD pin left unconnected
00088     *AT91C_PIOA_PPUER = AT91C_PA21_RXD1;
00089     // reset the UART
00090     pUSART[1]->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RXDIS |AT91C_US_TXDIS;
00091     // set serial line mode
00092     pUSART[1]->US_MR =  AT91C_US_USMODE_NORMAL |// Normal Mode
00093                         AT91C_US_CLKS_CLOCK |   // Clock = MCK
00094                         mode;                   // user-defined data parameters
00095     // set the baud rate
00096     pUSART[1]->US_BRGR = bauddiv;
00097     // enable the uart
00098     pUSART[1]->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
00099     
00100     // initialize buffers
00101     uart1InitBuffers();
00102     // setup DMA controller for transmit
00103     uartInitDmaTx(1);
00104     // setup DMA controller for receive
00105     //uartInitDmaRx(0);
00106 
00107     // attach interrupt handler
00108     processorAicAttach(AT91C_ID_US1, (UART1_INTERRUPT_LEVEL|AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL), uart1Service);
00109     // enable receive interrupt
00110     pUSART[1]->US_IER = AT91C_US_RXRDY;
00111 }
00112 
00113 void uart2Init(uint16_t bauddiv, uint32_t mode)
00114 {
00115     // enable the clock of DBGU
00116     AT91C_BASE_PMC->PMC_PCER = (1<<AT91C_ID_SYS);
00117     // enable uart pins on PIO
00118     *AT91C_PIOA_PDR = AT91C_PA9_DRXD | AT91C_PA10_DTXD;
00119     // enable I/O pullup to avoid spurious receive if RXD pin left unconnected
00120     *AT91C_PIOA_PPUER = AT91C_PA9_DRXD;
00121     // reset the UART
00122     pUSART[2]->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RXDIS |AT91C_US_TXDIS;
00123     // set serial line mode
00124     pUSART[2]->US_MR =  AT91C_US_USMODE_NORMAL |    // Normal Mode
00125                         AT91C_US_CLKS_CLOCK |       // Clock = MCK
00126                         AT91C_US_CHRL_8_BITS |      // 8-bit Data (no effect on DBGU)
00127                         AT91C_US_PAR_NONE |         // No Parity
00128                         AT91C_US_NBSTOP_1_BIT;      // 1 Stop Bit (no effect on DBGU)
00129     // set the baud rate
00130     pUSART[2]->US_BRGR = bauddiv;
00131     // enable the uart
00132     pUSART[2]->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
00133     
00134     // initialize buffers
00135     uart2InitBuffers();
00136     // setup DMA controller for transmit
00137     uartInitDmaTx(2);
00138     // setup DMA controller for receive
00139     //uartInitDmaRx(2);
00140 
00141     // attach interrupt handler
00142     processorAicAttachSys(SYSPID_DBGU, uart2Service);
00143     // enable receive interrupt
00144     pUSART[2]->US_IER = AT91C_US_RXRDY;
00145 }
00146 
00147 void uart0InitBuffers(void)
00148 {
00149     // initialize the UART0 buffers
00150     bufferInit(&UartRxBuffer[0], Uart0RxData, UART0_RX_BUFFER_SIZE);
00151     bufferInit(&UartTxBuffer[0], Uart0TxData, UART0_TX_BUFFER_SIZE);
00152 }
00153 
00154 void uart1InitBuffers(void)
00155 {
00156     // initialize the UART0 buffers
00157     bufferInit(&UartRxBuffer[1], Uart1RxData, UART1_RX_BUFFER_SIZE);
00158     bufferInit(&UartTxBuffer[1], Uart1TxData, UART1_TX_BUFFER_SIZE);
00159 }
00160 
00161 void uart2InitBuffers(void)
00162 {
00163     // initialize the UART0 buffers
00164     bufferInit(&UartRxBuffer[2], Uart2RxData, UART2_RX_BUFFER_SIZE);
00165     bufferInit(&UartTxBuffer[2], Uart2TxData, UART2_TX_BUFFER_SIZE);
00166 }
00167 
00168 void uartInitDmaTx(int dev)
00169 {
00170     // clear buffer
00171     UartTxBuffer[dev].dataindex = 0;
00172     UartTxBuffer[dev].datalength = 0;
00173     // setup DMA controller for transmit
00174     pPDC(pUSART[dev])->PDC_PTCR = AT91C_PDC_TXTDIS; // disable Tx DMA
00175     pPDC(pUSART[dev])->PDC_TPR = (unsigned int)UartTxBuffer[dev].dataptr;
00176     pPDC(pUSART[dev])->PDC_TCR = 0;
00177     pPDC(pUSART[dev])->PDC_TNPR = (unsigned int)UartTxBuffer[dev].dataptr;
00178     pPDC(pUSART[dev])->PDC_TNCR = 0;
00179     pPDC(pUSART[dev])->PDC_PTCR = AT91C_PDC_TXTEN;  // enable Tx DMA    
00180 }
00181 
00182 void uartInitDmaRx(int dev)
00183 {
00184     // clear buffer
00185     UartRxBuffer[dev].dataindex = 0;
00186     UartRxBuffer[dev].datalength = 0;
00187     // setup DMA controller for receive
00188     pPDC(pUSART[dev])->PDC_PTCR = AT91C_PDC_RXTDIS; // disable Rx DMA
00189     pPDC(pUSART[dev])->PDC_RPR = (unsigned int)UartTxBuffer[dev].dataptr;
00190     pPDC(pUSART[dev])->PDC_RCR = UartTxBuffer[dev].size;
00191     pPDC(pUSART[dev])->PDC_RNPR = (unsigned int)UartTxBuffer[dev].dataptr;
00192     pPDC(pUSART[dev])->PDC_RNCR = 0;
00193     pPDC(pUSART[dev])->PDC_PTCR = AT91C_PDC_RXTEN;  // enable Rx DMA
00194 }
00195 
00196 cBuffer* uartGetRxBuffer(int dev)
00197 {
00198     // return rx buffer pointer
00199     return &UartRxBuffer[dev];
00200 }
00201 
00202 int uartSendByte(int dev, int data)
00203 {
00204     #if defined(UART_DMA_BLOCK_IF_BUSY)
00205         // block if DMA buffer has no room
00206         while( (pPDC(pUSART[dev])->PDC_TCR + pPDC(pUSART[dev])->PDC_TNCR) >= UartTxBuffer[dev].size);
00207     #else
00208         // return failure if DMA buffer has no room
00209         if( (pPDC(pUSART[dev])->PDC_TCR + pPDC(pUSART[dev])->PDC_TNCR) >= UartTxBuffer[dev].size)
00210             return -1;
00211     #endif
00212     // is a circular buffer wrap necessary?
00213     if(UartTxBuffer[dev].dataindex == UartTxBuffer[dev].size)
00214     {
00215         //rprintf("Wrapping\n");
00216         // do write pointer wrap
00217         UartTxBuffer[dev].dataindex = 0;
00218         // add byte to dma buffer
00219         //rprintf("DMA WrPtr=%d\n", TxBufferWr);
00220         UartTxBuffer[dev].dataptr[UartTxBuffer[dev].dataindex] = data;
00221         UartTxBuffer[dev].dataindex++;
00222         // switch to "next" DMA
00223         pPDC(pUSART[dev])->PDC_TNPR = (unsigned int)UartTxBuffer[dev].dataptr;
00224         // increment byte count on "next" DMA
00225         pPDC(pUSART[dev])->PDC_TNCR++;
00226     }
00227     else
00228     {
00229         // no write pointer wrap
00230         // add byte to dma buffer
00231         //rprintf("DMA WrPtr=%d\n", TxBufferWr);
00232         UartTxBuffer[dev].dataptr[UartTxBuffer[dev].dataindex] = data;
00233         UartTxBuffer[dev].dataindex++;
00234         // if "next" DMA is already busy...
00235         if(pPDC(pUSART[dev])->PDC_TNCR)
00236             pPDC(pUSART[dev])->PDC_TNCR++;  // increment byte count on "next" DMA
00237         else
00238             pPDC(pUSART[dev])->PDC_TCR++;   // else, increment byte count on "this" DMA
00239     }
00240 
00241     return data;
00242 }
00243 
00244 int uartGetByte(int dev)
00245 {
00246     if(UartRxBuffer[dev].datalength)        // check if character is available
00247         return bufferGetFromFront(&UartRxBuffer[dev]);  // return character
00248     return -1;
00249 
00250 /*  
00251     int data;
00252 
00253     // are any bytes available?
00254     if( (pPDC(pUSART[dev])->PDC_RCR + pPDC(pUSART[dev])->PDC_RNCR) >= UartRxBuffer[dev].size)
00255         return -1;
00256 
00257     // is a wrap necessary?
00258     if(UartRxBuffer[dev].dataindex == UartRxBuffer[dev].size)
00259     {
00260         //rprintf("Wrapping\n");
00261         // do pointer wrap
00262         UartRxBuffer[dev].dataindex = 0;
00263         // read byte from dma buffer
00264         //rprintf("DMA RdPtr=%d  ", UartRxBuffer[dev].dataindex);
00265         data = UartRxBuffer[dev].dataptr[UartTxBuffer[dev].dataindex];
00266         UartRxBuffer[dev].dataindex++;
00267         // switch to "next" DMA
00268         //pUSART_PDC->PDC_RNPR = (unsigned int)RxBuffer;
00269         // increment byte count on "next" DMA
00270         pPDC(pUSART[dev])->PDC_RCR++;
00271     }
00272     else
00273     {
00274         // no pointer wrap
00275         // read byte from dma buffer
00276         //rprintf("DMA RdPtr=%d  ", UartRxBuffer[dev].dataindex);
00277         data = UartRxBuffer[dev].dataptr[UartTxBuffer[dev].dataindex];
00278         UartRxBuffer[dev].dataindex++;
00279         // if "next" DMA is already busy...
00280         pPDC(pUSART[dev])->PDC_RNPR = (unsigned int)UartRxBuffer[dev].dataptr;
00281         if( ((pPDC(pUSART[dev])->PDC_RPR-(unsigned int)UartRxBuffer[dev].dataptr) + pPDC(pUSART[dev])->PDC_RCR) < UartRxBuffer[dev].size)
00282             pPDC(pUSART[dev])->PDC_RCR++;   // increment byte count on "this" DMA
00283         else
00284             pPDC(pUSART[dev])->PDC_RNCR++;  // else, increment byte count on "next" DMA
00285     }
00286 
00287     //rprintf("RPR =0x%x  ", pPDC(pUSART[dev])->PDC_RPR-(int)UartRxBuffer[dev].dataptr);
00288     //rprintf("RCR =0x%x  ", pPDC(pUSART[dev])->PDC_RCR);
00289     //rprintf("RNPR=0x%x  ", pPDC(pUSART[dev])->PDC_RNPR-(int)UartRxBuffer[dev].dataptr);
00290     //rprintf("RNCR=0x%x\n", pPDC(pUSART[dev])->PDC_RNCR);
00291 
00292     return data;
00293 */
00294 }
00295 
00296 int uartSendBlock(int dev, unsigned char* data, unsigned int len)
00297 {
00298     #if defined(UART_DMA_BLOCK_IF_BUSY)
00299         // block if DMA is not ready
00300         while( (pPDC(pUSART[dev])->PDC_TCR + pPDC(pUSART[dev])->PDC_TNCR) > 0);
00301     #else
00302         // return failure if DMA is not ready
00303         if( (pPDC(pUSART[dev])->PDC_TCR + pPDC(pUSART[dev])->PDC_TNCR) > 0)
00304             return -1;
00305     #endif
00306 
00307     // setup DMA block transfer
00308     pPDC(pUSART[dev])->PDC_PTCR = AT91C_PDC_TXTDIS; // disable Tx DMA
00309     pPDC(pUSART[dev])->PDC_TPR = (unsigned int)data;// set pointer to data buffer
00310     pPDC(pUSART[dev])->PDC_TCR = len;               // set number of bytes to transfer
00311     pPDC(pUSART[dev])->PDC_PTCR = AT91C_PDC_TXTEN;  // enable Tx DMA (starts DMA output)
00312     // return success
00313     return 0;
00314 }
00315 
00316 int uartGetBlock(int dev, unsigned char* data, unsigned int len)
00317 {
00318     #if defined(UART_DMA_BLOCK_IF_BUSY)
00319         // block if DMA is not ready
00320         while( (pPDC(pUSART[dev])->PDC_RCR + pPDC(pUSART[dev])->PDC_RNCR) > 0);
00321     #else
00322         // return failure if DMA is not ready
00323         if( (pPDC(pUSART[dev])->PDC_RCR + pPDC(pUSART[dev])->PDC_RNCR) > 0)
00324             return -1;
00325     #endif
00326 
00327     if(len)
00328     {
00329         // setup new DMA block transfer
00330         pPDC(pUSART[dev])->PDC_PTCR = AT91C_PDC_TXTDIS; // disable Rx DMA
00331         pPDC(pUSART[dev])->PDC_RPR = (unsigned int)data;// set pointer to data buffer
00332         pPDC(pUSART[dev])->PDC_RCR = len;               // set number of bytes to transfer
00333         pPDC(pUSART[dev])->PDC_PTCR = AT91C_PDC_TXTEN;  // enable Rx DMA (starts DMA input)
00334         // return success
00335         return len;
00336     }
00337     else
00338     {
00339         // return remaining byte count on current DMA transfer
00340         return pPDC(pUSART[dev])->PDC_TCR;
00341     }
00342 }
00343 
00344 void uart0Service(void)
00345 {
00346     unsigned int status;
00347 
00348     // read the channel status register
00349     status  = pUSART0->US_CSR;
00350     status &= pUSART0->US_IMR;
00351 
00352     if(status & AT91C_US_RXRDY)
00353     {
00354         bufferAddToEnd(&UartRxBuffer[0], pUSART0->US_RHR);
00355     }
00356 
00357     if(status & AT91C_US_TXRDY)
00358     {
00359     }
00360 
00361     // reset error status bits
00362     pUSART0->US_CR = AT91C_US_RSTSTA;
00363     // clear AIC
00364     AT91C_BASE_AIC->AIC_EOICR = 0;
00365 }
00366 
00367 void uart1Service(void)
00368 {
00369     unsigned int status;
00370 
00371     // read the channel status register
00372     status  = pUSART1->US_CSR;
00373     status &= pUSART1->US_IMR;
00374 
00375     if(status & AT91C_US_RXRDY)
00376     {
00377         bufferAddToEnd(&UartRxBuffer[1], pUSART1->US_RHR);
00378     }
00379 
00380     if(status & AT91C_US_TXRDY)
00381     {
00382     }
00383 
00384     // reset error status bits
00385     pUSART1->US_CR = AT91C_US_RSTSTA;
00386     // clear AIC
00387     AT91C_BASE_AIC->AIC_EOICR = 0;
00388 }
00389 
00390 void uart2Service(void)
00391 {
00392     unsigned int status;
00393 
00394     // read the channel status register
00395     status  = pUSART2->US_CSR;
00396     status &= pUSART2->US_IMR;
00397 
00398     if(status & AT91C_US_RXRDY)
00399     {
00400         bufferAddToEnd(&UartRxBuffer[2], pUSART2->US_RHR);
00401     }
00402 
00403     if(status & AT91C_US_TXRDY)
00404     {
00405     }
00406 
00407     // reset error status bits
00408     pUSART2->US_CR = AT91C_US_RSTSTA;
00409     // clear AIC
00410     AT91C_BASE_AIC->AIC_EOICR = 0;
00411 }

Generated on Mon Nov 6 23:36:58 2006 for Procyon ARMlib by  doxygen 1.4.2