]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained/libchip_samv7/source/uart_dma.c
Update version number ready for V8.2.1 release.
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained / libchip_samv7 / source / uart_dma.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License \r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2013, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 /**\r
31  * \addtogroup uart_dma_module UART xDMA driver\r
32  * \ingroup lib_uartflash\r
33  * \section Usage\r
34  *\r
35  * <ul>\r
36  * <li> UARTD_Configure() initializes and configures the UART peripheral and xDMA for data transfer.</li>\r
37  * <li> Configures the parameters for the device corresponding to the cs value by UARTD_ConfigureCS(). </li>\r
38  * <li> Starts a UART master transfer. This is a non blocking function UARTD_SendCommand(). It will\r
39  * return as soon as the transfer is started..</li>\r
40  * </ul>\r
41  *\r
42  */\r
43 \r
44 /**\r
45  * \file\r
46  *\r
47  * Implementation for the UART Flash with xDMA driver.\r
48  *\r
49  */\r
50 \r
51 \r
52 /*----------------------------------------------------------------------------\r
53  *        Headers\r
54  *----------------------------------------------------------------------------*/\r
55 \r
56 #include "chip.h"\r
57 \r
58 /*----------------------------------------------------------------------------\r
59  *        Definitions\r
60  *----------------------------------------------------------------------------*/\r
61 \r
62 \r
63 /** xDMA Link List size for uart transation*/\r
64 #define DMA_UART_LLI     2\r
65 \r
66 /*----------------------------------------------------------------------------\r
67  *        Macros\r
68  *----------------------------------------------------------------------------*/\r
69 \r
70 /*----------------------------------------------------------------------------\r
71  *        Local Variables\r
72  *----------------------------------------------------------------------------*/\r
73 \r
74 \r
75 /*----------------------------------------------------------------------------\r
76  *        Local functions\r
77  *----------------------------------------------------------------------------*/\r
78 \r
79 \r
80 /**\r
81  * \brief UART xDMA Rx callback\r
82  * Invoked on UART DMA reception done.\r
83  * \param channel DMA channel.\r
84  * \param pArg Pointer to callback argument - Pointer to UARTDma instance.   \r
85  */ \r
86 static void UARTD_Rx_Cb(uint32_t channel, UartDma* pArg)\r
87 {\r
88 \r
89     UartChannel *pUartdCh = pArg->pRxChannel;\r
90     if (channel != pUartdCh->ChNum)\r
91         return;\r
92 \r
93     //    NVIC_ClearPendingIRQ(XDMAC_IRQn);\r
94 \r
95     /* Release the DMA channels */\r
96     XDMAD_FreeChannel(pArg->pXdmad, pUartdCh->ChNum);\r
97 \r
98     /* Invoke the callback associated with the current command */\r
99     if (pUartdCh && pUartdCh->callback) {\r
100         pUartdCh->callback(0, pUartdCh->pArgument);\r
101     }   \r
102     pUartdCh->sempaphore = 1;\r
103 }\r
104 \r
105 /**\r
106  * \brief USART xDMA Rx callback\r
107  * Invoked on USART DMA reception done.\r
108  * \param channel DMA channel.\r
109  * \param pArg Pointer to callback argument - Pointer to USARTDma instance.   \r
110  */ \r
111 static void UARTD_Tx_Cb(uint32_t channel, UartDma* pArg)\r
112 {\r
113     UartChannel *pUartdCh = pArg->pTxChannel;\r
114     if (channel != pUartdCh->ChNum)\r
115         return;\r
116 \r
117     //    NVIC_ClearPendingIRQ(XDMAC_IRQn);\r
118 \r
119     /* Release the DMA channels */\r
120     XDMAD_FreeChannel(pArg->pXdmad, pUartdCh->ChNum);\r
121 \r
122     /* Invoke the callback associated with the current command */\r
123     if (pUartdCh && pUartdCh->callback) {\r
124         pUartdCh->callback(0, pUartdCh->pArgument);\r
125     }\r
126     pUartdCh->sempaphore = 1;\r
127 }\r
128 \r
129 \r
130 /**\r
131  * \brief Configure the UART Rx DMA Destination with Linker List mode.\r
132  *\r
133  * \param UartChannel Pointer to UART dma channel\r
134  * \returns 0 if the dma multibuffer configuration successfully; otherwise returns\r
135  * USARTD_ERROR_XXX.\r
136  */\r
137 static uint8_t _configureRxLinkList(Uart *pUartHw, void *pXdmad, UartChannel *pUartRx)\r
138 {\r
139     sXdmadCfg xdmadRxCfg;\r
140     uint32_t xdmaCndc;\r
141     uint32_t uartId;\r
142     if ((unsigned int)pUartHw == (unsigned int)UART0 ) uartId = ID_UART0;\r
143     if ((unsigned int)pUartHw == (unsigned int)UART1 ) uartId = ID_UART1;\r
144     if ((unsigned int)pUartHw == (unsigned int)UART2 ) uartId = ID_UART2;\r
145     if ((unsigned int)pUartHw == (unsigned int)UART3 ) uartId = ID_UART3;\r
146     if ((unsigned int)pUartHw == (unsigned int)UART4 ) uartId = ID_UART4;\r
147 \r
148     /* Setup RX Link List */\r
149     xdmadRxCfg.mbr_ubc = XDMA_UBC_NVIEW_NDV0 |\r
150         XDMA_UBC_NDE_FETCH_DIS|\r
151         XDMA_UBC_NDEN_UPDATED |\r
152         pUartRx->BuffSize;\r
153     xdmadRxCfg.mbr_da = (uint32_t)pUartRx->pBuff;\r
154 \r
155     xdmadRxCfg.mbr_sa = (uint32_t)&pUartHw->UART_RHR;\r
156     xdmadRxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |\r
157         XDMAC_CC_MBSIZE_SINGLE |\r
158         XDMAC_CC_DSYNC_PER2MEM |\r
159         XDMAC_CC_CSIZE_CHK_1 |\r
160         XDMAC_CC_DWIDTH_BYTE |\r
161         XDMAC_CC_SIF_AHB_IF1 |\r
162         XDMAC_CC_DIF_AHB_IF0 |\r
163         XDMAC_CC_SAM_FIXED_AM |\r
164         XDMAC_CC_DAM_INCREMENTED_AM |\r
165         XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(  uartId, XDMAD_TRANSFER_RX ));\r
166 \r
167     xdmadRxCfg.mbr_bc = 0;\r
168     xdmadRxCfg.mbr_sus = 0;\r
169     xdmadRxCfg.mbr_dus =0;\r
170     xdmaCndc = 0;\r
171     if (XDMAD_ConfigureTransfer( pXdmad, pUartRx->ChNum, &xdmadRxCfg, xdmaCndc, 0))\r
172         return USARTD_ERROR;\r
173 \r
174     return 0;\r
175 }\r
176 \r
177 \r
178 /**\r
179  * \brief Configure the UART tx DMA source with Linker List mode.\r
180  *\r
181  * \param UartChannel Pointer to UART dma channel\r
182  * \returns 0 if the dma multibuffer configuration successfully; otherwise returns\r
183  * USARTD_ERROR_XXX.\r
184  */\r
185 static uint8_t _configureTxLinkList(Uart *pUartHw, void *pXdmad, UartChannel *pUartTx)\r
186 {\r
187     sXdmadCfg xdmadTxCfg;\r
188     uint32_t xdmaCndc;\r
189     uint32_t uartId;\r
190     if ((unsigned int)pUartHw == (unsigned int)UART0 ) uartId = ID_UART0;\r
191     if ((unsigned int)pUartHw == (unsigned int)UART1 ) uartId = ID_UART1;\r
192     if ((unsigned int)pUartHw == (unsigned int)UART2 ) uartId = ID_UART2;\r
193     if ((unsigned int)pUartHw == (unsigned int)UART3 ) uartId = ID_UART3;\r
194     if ((unsigned int)pUartHw == (unsigned int)UART4 ) uartId = ID_UART4;\r
195 \r
196     /* Setup TX Link List */ \r
197     xdmadTxCfg.mbr_ubc =   XDMA_UBC_NVIEW_NDV0 |\r
198         XDMA_UBC_NDE_FETCH_DIS|\r
199         XDMA_UBC_NSEN_UPDATED |  pUartTx->BuffSize;\r
200 \r
201     xdmadTxCfg.mbr_sa = (uint32_t)pUartTx->pBuff;\r
202     xdmadTxCfg.mbr_da = (uint32_t)&pUartHw->UART_THR;\r
203     xdmadTxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |\r
204         XDMAC_CC_MBSIZE_SINGLE |\r
205         XDMAC_CC_DSYNC_MEM2PER |\r
206         XDMAC_CC_CSIZE_CHK_1 |\r
207         XDMAC_CC_DWIDTH_BYTE|\r
208         XDMAC_CC_SIF_AHB_IF0 |\r
209         XDMAC_CC_DIF_AHB_IF1 |\r
210         XDMAC_CC_SAM_INCREMENTED_AM |\r
211         XDMAC_CC_DAM_FIXED_AM |\r
212         XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(  uartId, XDMAD_TRANSFER_TX ));\r
213 \r
214     xdmadTxCfg.mbr_bc = 0;\r
215     xdmadTxCfg.mbr_sus = 0;\r
216     xdmadTxCfg.mbr_dus =0;\r
217     xdmaCndc = 0;\r
218 \r
219     if (XDMAD_ConfigureTransfer( pXdmad, pUartTx->ChNum, &xdmadTxCfg, xdmaCndc, 0))\r
220         return USARTD_ERROR;\r
221     return 0;\r
222 }\r
223 \r
224 /*----------------------------------------------------------------------------\r
225  *        Exported functions\r
226  *----------------------------------------------------------------------------*/\r
227 /**\r
228  * \brief Initializes the UartDma structure and the corresponding UART & DMA hardware.\r
229  * select value.\r
230  * The driver will uses DMA channel 0 for RX and DMA channel 1 for TX.\r
231  * The DMA channels are freed automatically when no UART command processing.\r
232  *\r
233  * \param pUartd  Pointer to a UartDma instance.\r
234  * \param pUartHw Associated UART peripheral.\r
235  * \param uartId  UART peripheral identifier.\r
236  * \param pXdmad  Pointer to a Dmad instance. \r
237  */\r
238 uint32_t UARTD_Configure( UartDma *pUartd ,\r
239         Uart *pUartHw ,\r
240         uint8_t uartId,\r
241         uint32_t UartMode,\r
242         sXdmad *pXdmad )\r
243 {\r
244     /* Initialize the UART structure */\r
245     pUartd->pUartHw = pUartHw;\r
246     pUartd->uartId  = uartId;\r
247     pUartd->pTxChannel = 0;\r
248     pUartd->pRxChannel = 0;\r
249     pUartd->pXdmad = pXdmad;\r
250 \r
251     /* Enable the UART Peripheral ,Execute a software reset of the UART, Configure UART in Master Mode*/\r
252     UART_Configure ( pUartHw, UartMode, 115200, BOARD_MCK);\r
253 \r
254     /* Driver initialize */\r
255     XDMAD_Initialize(  pUartd->pXdmad, 0 );\r
256     /* Configure and enable interrupt on RC compare */ \r
257     NVIC_ClearPendingIRQ(XDMAC_IRQn);\r
258     NVIC_SetPriority( XDMAC_IRQn ,1);\r
259     return 0;\r
260 }\r
261 \r
262 \r
263 /**\r
264  * \brief Enables USART Rx DMA channel\r
265  * select value.\r
266  * The driver will uses DMA channel 0 for RX and DMA channel 1 for TX.\r
267  * The DMA channels are freed automatically when no USART command processing.\r
268  *\r
269  * \param pUSARTd  Pointer to a UartDma instance.\r
270  * \param pUartHw Associated USART peripheral.\r
271  * \param uartId  USART peripheral identifier.\r
272  * \param UartClk USART clock.\r
273  * \param pDmad  Pointer to a Dmad instance. \r
274  */\r
275 \r
276 uint32_t UARTD_EnableRxChannels( UartDma *pUartd, UartChannel *pRxCh)\r
277 {\r
278     Uart *pUartHw = pUartd->pUartHw;\r
279     uint32_t Channel;\r
280 \r
281     // Initialize the callback\r
282     pUartd->pRxChannel = pRxCh;\r
283 \r
284     /* Enables the USART to receive data. */\r
285     UART_SetReceiverEnabled ( pUartHw , 1);\r
286 \r
287     XDMAD_FreeChannel( pUartd->pXdmad, pRxCh->ChNum);\r
288 \r
289     /* Allocate a DMA channel for UART0/1 RX. */\r
290     Channel =  XDMAD_AllocateChannel( pUartd->pXdmad, pUartd->uartId, XDMAD_TRANSFER_MEMORY);\r
291     if ( Channel == XDMAD_ALLOC_FAILED ) \r
292     {\r
293         return USARTD_ERROR;\r
294     }\r
295 \r
296     pRxCh->ChNum = Channel ;\r
297 \r
298     /* Setup callbacks for UART0/1 RX */\r
299     XDMAD_SetCallback(pUartd->pXdmad, pRxCh->ChNum, (XdmadTransferCallback)UARTD_Rx_Cb, pUartd);\r
300     if (XDMAD_PrepareChannel( pUartd->pXdmad, pRxCh->ChNum ))\r
301         return USARTD_ERROR;\r
302 \r
303     /* Enable interrupt  */ \r
304     NVIC_EnableIRQ(XDMAC_IRQn);\r
305 \r
306     if (_configureRxLinkList(pUartHw, pUartd->pXdmad, pRxCh))\r
307         return USARTD_ERROR_LOCK;\r
308 \r
309     return 0;\r
310 }\r
311 \r
312 \r
313 \r
314 uint32_t UARTD_EnableTxChannels( UartDma *pUartd, UartChannel *pTxCh)\r
315 {\r
316     Uart *pUartHw = pUartd->pUartHw;\r
317     uint32_t Channel;\r
318 \r
319     // Initialize the callback\r
320     pUartd->pTxChannel = pTxCh;\r
321 \r
322     /* Enables the USART to transfer data. */\r
323     UART_SetTransmitterEnabled ( pUartHw , 1);\r
324 \r
325     XDMAD_FreeChannel( pUartd->pXdmad, pTxCh->ChNum);\r
326 \r
327     /* Allocate a DMA channel for USART0/1 TX. */\r
328     Channel =  XDMAD_AllocateChannel( pUartd->pXdmad, XDMAD_TRANSFER_MEMORY, pUartd->uartId);\r
329     if ( pTxCh->ChNum == XDMAD_ALLOC_FAILED ) \r
330     {\r
331         return USARTD_ERROR;\r
332     }\r
333 \r
334     pTxCh->ChNum = Channel ;\r
335 \r
336     /* Setup callbacks for USART0/1 TX */\r
337     XDMAD_SetCallback(pUartd->pXdmad, pTxCh->ChNum, (XdmadTransferCallback)UARTD_Tx_Cb, pUartd);\r
338     if ( XDMAD_PrepareChannel( pUartd->pXdmad, pTxCh->ChNum ))\r
339         return USARTD_ERROR;\r
340 \r
341     /* Enable interrupt  */ \r
342     NVIC_EnableIRQ(XDMAC_IRQn);\r
343 \r
344     if (_configureTxLinkList(pUartHw, pUartd->pXdmad, pTxCh))\r
345         return USARTD_ERROR_LOCK;\r
346 \r
347     return 0;\r
348 }\r
349 \r
350 /**\r
351  * \brief Starts a USART master transfer. This is a non blocking function. It will\r
352  *  return as soon as the transfer is started.\r
353  *\r
354  * \param pUSARTd  Pointer to a USARTDma instance.\r
355  * \param pCommand Pointer to the USART command to execute.\r
356  * \returns 0 if the transfer has been started successfully; otherwise returns\r
357  * USARTD_ERROR_LOCK is the driver is in use, or USARTD_ERROR if the command is not\r
358  * valid.\r
359  */\r
360 uint32_t UARTD_SendData( UartDma *pUartd)\r
361 {\r
362 \r
363     /* Start DMA 0(RX) && 1(TX) */\r
364     while(!pUartd->pTxChannel->sempaphore);\r
365     if (XDMAD_StartTransfer( pUartd->pXdmad, pUartd->pTxChannel->ChNum )) \r
366         return USARTD_ERROR_LOCK;\r
367     pUartd->pTxChannel->sempaphore=0;\r
368     return 0;\r
369 }\r
370 \r
371 /**\r
372  * \brief Starts a USART master transfer. This is a non blocking function. It will\r
373  *  return as soon as the transfer is started.\r
374  *\r
375  * \param pUSARTd  Pointer to a USARTDma instance.\r
376  * \param pCommand Pointer to the USART command to execute.\r
377  * \returns 0 if the transfer has been started successfully; otherwise returns\r
378  * USARTD_ERROR_LOCK is the driver is in use, or USARTD_ERROR if the command is not\r
379  * valid.\r
380  */\r
381 uint32_t UARTD_RcvData( UartDma *pUartd)\r
382 {    \r
383 \r
384     while(!pUartd->pRxChannel->sempaphore);\r
385     /* Start DMA 0(RX) && 1(TX) */\r
386     if (XDMAD_StartTransfer( pUartd->pXdmad, pUartd->pRxChannel->ChNum )) \r
387         return USARTD_ERROR_LOCK;\r
388     pUartd->pRxChannel->sempaphore=0;\r
389     return 0;\r
390 }\r
391 \r