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 }