]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained_IAR_Keil/libchip_samv7/source/usart_dma.c
Final V8.2.1 release ready for tagging:
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained_IAR_Keil / libchip_samv7 / source / usart_dma.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License \r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2014, 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 usart_dma_module USART xDMA driver\r
32  * \section Usage\r
33  *\r
34  * <ul>\r
35  * <li> USARTD_Configure() initializes and configures the USART peripheral and xDMA for data transfer.</li>\r
36  * <li> Configures the parameters for the device corresponding to the cs value by USARTD_ConfigureCS(). </li>\r
37  * </ul>\r
38  *\r
39  */\r
40 \r
41 /**\r
42  * \file\r
43  *\r
44  * Implementation for the USART with xDMA driver.\r
45  *\r
46  */\r
47 \r
48 \r
49 /*----------------------------------------------------------------------------\r
50  *        Headers\r
51  *----------------------------------------------------------------------------*/\r
52 \r
53 #include "chip.h"\r
54 \r
55 /*----------------------------------------------------------------------------\r
56  *        Definitions\r
57  *----------------------------------------------------------------------------*/\r
58 \r
59 \r
60 /** xDMA Link List size for usart transmition*/\r
61 #define DMA_USART_LLI     2\r
62 \r
63 /*----------------------------------------------------------------------------\r
64  *        Macros\r
65  *----------------------------------------------------------------------------*/\r
66 \r
67 /*----------------------------------------------------------------------------\r
68  *        Local Variables\r
69  *----------------------------------------------------------------------------*/\r
70 \r
71 /*----------------------------------------------------------------------------\r
72  *        Local functions\r
73  *----------------------------------------------------------------------------*/\r
74 \r
75 \r
76 /**\r
77  * \brief USART xDMA Rx callback\r
78  * Invoked on USART DMA reception done.\r
79  * \param channel DMA channel.\r
80  * \param pArg Pointer to callback argument - Pointer to USARTDma instance.   \r
81  */ \r
82 static void USARTD_Rx_Cb(uint32_t channel, UsartDma* pArg)\r
83 {\r
84 \r
85     UsartChannel *pUsartdCh = pArg->pRxChannel;\r
86     if (channel != pUsartdCh->ChNum)\r
87         return;\r
88 \r
89     //    NVIC_ClearPendingIRQ(XDMAC_IRQn);\r
90 \r
91     /* Release the DMA channels */\r
92     XDMAD_FreeChannel(pArg->pXdmad, pUsartdCh->ChNum);\r
93 \r
94     /* Invoke the callback associated with the current command */\r
95     if (pUsartdCh && pUsartdCh->callback) {\r
96         pUsartdCh->callback(0, pUsartdCh->pArgument);\r
97     }    \r
98     pUsartdCh->Done = 1;\r
99     memory_barrier();\r
100 }\r
101 \r
102 /**\r
103  * \brief USART xDMA Rx callback\r
104  * Invoked on USART DMA reception done.\r
105  * \param channel DMA channel.\r
106  * \param pArg Pointer to callback argument - Pointer to USARTDma instance.   \r
107  */ \r
108 static void USARTD_Tx_Cb(uint32_t channel, UsartDma* pArg)\r
109 {\r
110     UsartChannel *pUsartdCh = pArg->pTxChannel;\r
111     if (channel != pUsartdCh->ChNum)\r
112         return;\r
113 \r
114     //    NVIC_ClearPendingIRQ(XDMAC_IRQn);\r
115 \r
116     /* Release the DMA channels */\r
117     XDMAD_FreeChannel(pArg->pXdmad, pUsartdCh->ChNum);\r
118 \r
119     /* Invoke the callback associated with the current command */\r
120     if (pUsartdCh && pUsartdCh->callback) {\r
121         pUsartdCh->callback(0, pUsartdCh->pArgument);\r
122     }\r
123     pUsartdCh->Done = 1;\r
124     memory_barrier();\r
125 }\r
126 \r
127 /**\r
128  * \brief Configure the USART Rx DMA Destination with Linker List mode.\r
129  *\r
130  * \param UsartChannel Pointer to USART dma channel\r
131  * \returns 0 if the dma multibuffer configuration successfully; otherwise returns\r
132  * USARTD_ERROR_XXX.\r
133  */\r
134 static uint8_t _configureRxLinkList(Usart *pUsartHw, void *pXdmad, UsartChannel *pUsartRx)\r
135 {\r
136     sXdmadCfg xdmadRxCfg;\r
137     uint32_t xdmaCndc;\r
138     uint32_t usartId;\r
139     if ((unsigned int)pUsartHw == (unsigned int)USART0 ) usartId = ID_USART0;\r
140     if ((unsigned int)pUsartHw == (unsigned int)USART1 ) usartId = ID_USART1;\r
141     if ((unsigned int)pUsartHw == (unsigned int)USART2 ) usartId = ID_USART2;\r
142 \r
143     /* Setup RX Link List */\r
144     xdmadRxCfg.mbr_ubc = XDMA_UBC_NVIEW_NDV0 |\r
145         XDMA_UBC_NDE_FETCH_DIS|\r
146         XDMA_UBC_NDEN_UPDATED |\r
147         pUsartRx->BuffSize;\r
148     xdmadRxCfg.mbr_da = (uint32_t)pUsartRx->pBuff;\r
149 \r
150     xdmadRxCfg.mbr_sa = (uint32_t)&pUsartHw->US_RHR;\r
151     xdmadRxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |\r
152         XDMAC_CC_MBSIZE_SINGLE |\r
153         XDMAC_CC_DSYNC_PER2MEM |\r
154         XDMAC_CC_CSIZE_CHK_1 |\r
155         XDMAC_CC_DWIDTH_BYTE |\r
156         XDMAC_CC_SIF_AHB_IF1 |\r
157         XDMAC_CC_DIF_AHB_IF0 |\r
158         XDMAC_CC_SAM_FIXED_AM |\r
159         XDMAC_CC_DAM_INCREMENTED_AM |\r
160         XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(  usartId, XDMAD_TRANSFER_RX ));\r
161 \r
162     xdmadRxCfg.mbr_bc = 0;\r
163     xdmadRxCfg.mbr_sus = 0;\r
164     xdmadRxCfg.mbr_dus =0;\r
165     xdmaCndc = 0;\r
166     if (XDMAD_ConfigureTransfer( pXdmad, pUsartRx->ChNum, &xdmadRxCfg, xdmaCndc, 0))\r
167         return USARTD_ERROR;\r
168 \r
169     return 0;\r
170 }\r
171 \r
172 \r
173 /**\r
174  * \brief Configure the USART tx DMA source with Linker List mode.\r
175  *\r
176  * \param UsartChannel Pointer to USART dma channel\r
177  * \returns 0 if the dma multibuffer configuration successfully; otherwise returns\r
178  * USARTD_ERROR_XXX.\r
179  */\r
180 static uint8_t _configureTxLinkList(Usart *pUsartHw, void *pXdmad, UsartChannel *pUsartTx)\r
181 {\r
182     sXdmadCfg xdmadTxCfg;\r
183     uint32_t xdmaCndc;\r
184     uint32_t usartId;\r
185     if ((unsigned int)pUsartHw == (unsigned int)USART0 ) usartId = ID_USART0;\r
186     if ((unsigned int)pUsartHw == (unsigned int)USART1 ) usartId = ID_USART1;\r
187     if ((unsigned int)pUsartHw == (unsigned int)USART2 ) usartId = ID_USART2;\r
188     /* Setup TX Link List */ \r
189     xdmadTxCfg.mbr_ubc =   XDMA_UBC_NVIEW_NDV0 |\r
190         XDMA_UBC_NDE_FETCH_DIS|\r
191         XDMA_UBC_NSEN_UPDATED |  pUsartTx->BuffSize;\r
192 \r
193     xdmadTxCfg.mbr_sa = (uint32_t)pUsartTx->pBuff;\r
194     xdmadTxCfg.mbr_da = (uint32_t)&pUsartHw->US_THR;\r
195     xdmadTxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |\r
196         XDMAC_CC_MBSIZE_SINGLE |\r
197         XDMAC_CC_DSYNC_MEM2PER |\r
198         XDMAC_CC_CSIZE_CHK_1 |\r
199         XDMAC_CC_DWIDTH_BYTE|\r
200         XDMAC_CC_SIF_AHB_IF0 |\r
201         XDMAC_CC_DIF_AHB_IF1 |\r
202         XDMAC_CC_SAM_INCREMENTED_AM |\r
203         XDMAC_CC_DAM_FIXED_AM |\r
204         XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(  usartId, XDMAD_TRANSFER_TX ));\r
205 \r
206     xdmadTxCfg.mbr_bc = 0;\r
207     xdmadTxCfg.mbr_sus = 0;\r
208     xdmadTxCfg.mbr_dus =0;\r
209     xdmaCndc = 0;\r
210 \r
211     if (XDMAD_ConfigureTransfer( pXdmad, pUsartTx->ChNum, &xdmadTxCfg, xdmaCndc, 0))\r
212         return USARTD_ERROR;\r
213     return 0;\r
214 }\r
215 \r
216 \r
217 /*----------------------------------------------------------------------------\r
218  *        Exported functions\r
219  *----------------------------------------------------------------------------*/\r
220 /**\r
221  * \brief Initializes the USARTDma structure and the corresponding USART & DMA hardware.\r
222  * select value.\r
223  * The driver will uses DMA channel 0 for RX and DMA channel 1 for TX.\r
224  * The DMA channels are freed automatically when no USART command processing.\r
225  *\r
226  * \param pUSARTd  Pointer to a UsartDma instance.\r
227  * \param pUsartHw Associated USART peripheral.\r
228  * \param usartId  USART peripheral identifier.\r
229  * \param UsartClk USART clock.\r
230  * \param pXdmad  Pointer to a Dmad instance. \r
231  */\r
232 uint32_t USARTD_Configure( UsartDma *pUsartd ,\r
233         Usart *pUsartHw ,\r
234         uint8_t usartId,\r
235         uint32_t UsartMode,\r
236         uint32_t UsartClk,\r
237         sXdmad *pXdmad )\r
238 {\r
239     /* Initialize the USART structure */\r
240     pUsartd->pUsartHw = pUsartHw;\r
241     pUsartd->usartId  = usartId;\r
242     pUsartd->pRxChannel = 0;\r
243     pUsartd->pTxChannel = 0;\r
244     pUsartd->pXdmad = pXdmad;\r
245 \r
246     /* Enable the USART Peripheral ,Execute a software reset of the USART, Configure USART in Master Mode*/\r
247     USART_Configure ( pUsartHw, UsartMode, UsartClk, BOARD_MCK);\r
248 \r
249     /* Driver initialize */\r
250     XDMAD_Initialize(  pUsartd->pXdmad, 0 );\r
251     /* Configure and enable interrupt on RC compare */ \r
252     NVIC_ClearPendingIRQ(XDMAC_IRQn);\r
253     NVIC_SetPriority( XDMAC_IRQn ,1);\r
254     return 0;\r
255 }\r
256 \r
257 /**\r
258  * \brief Enables USART Rx DMA channel\r
259  * select value.\r
260  * The driver will uses DMA channel 0 for RX and DMA channel 1 for TX.\r
261  * The DMA channels are freed automatically when no USART command processing.\r
262  *\r
263  * \param pUSARTd  Pointer to a UsartDma instance.\r
264  * \param pUsartHw Associated USART peripheral.\r
265  * \param usartId  USART peripheral identifier.\r
266  * \param UsartClk USART clock.\r
267  * \param pDmad  Pointer to a Dmad instance. \r
268  */\r
269 \r
270 uint32_t USARTD_EnableRxChannels( UsartDma *pUsartd, UsartChannel *pRxCh)\r
271 {\r
272     Usart *pUsartHw = pUsartd->pUsartHw;\r
273 \r
274     // Initialize the callback\r
275     pUsartd->pRxChannel = pRxCh;\r
276 \r
277     /* Enables the USART to receive data. */\r
278     USART_SetReceiverEnabled ( pUsartHw , 1);\r
279 \r
280     XDMAD_FreeChannel( pUsartd->pXdmad, pRxCh->ChNum);\r
281 \r
282     /* Allocate a DMA channel for USART0/1 RX. */\r
283     pRxCh->ChNum =  XDMAD_AllocateChannel( pUsartd->pXdmad, pUsartd->usartId, XDMAD_TRANSFER_MEMORY);\r
284     if ( pRxCh->ChNum == XDMAD_ALLOC_FAILED ) \r
285     {\r
286         return USARTD_ERROR;\r
287     }\r
288 \r
289     /* Setup callbacks for USART0/1 RX */\r
290     XDMAD_SetCallback(pUsartd->pXdmad, pRxCh->ChNum, (XdmadTransferCallback)USARTD_Rx_Cb, pUsartd);\r
291     if (XDMAD_PrepareChannel( pUsartd->pXdmad, pRxCh->ChNum ))\r
292         return USARTD_ERROR;\r
293 \r
294     /* Enable interrupt  */ \r
295     NVIC_EnableIRQ(XDMAC_IRQn);\r
296 \r
297     if (_configureRxLinkList(pUsartHw, pUsartd->pXdmad, pRxCh))\r
298         return USARTD_ERROR_LOCK;\r
299 \r
300     return 0;\r
301 }\r
302 \r
303 \r
304 \r
305 uint32_t USARTD_EnableTxChannels( UsartDma *pUsartd, UsartChannel *pTxCh)\r
306 {\r
307     Usart *pUsartHw = pUsartd->pUsartHw;\r
308 \r
309     // Initialize the callback\r
310     pUsartd->pTxChannel = pTxCh;\r
311 \r
312     /* Enables the USART to transfer data. */\r
313     USART_SetTransmitterEnabled ( pUsartHw , 1);    \r
314 \r
315     XDMAD_FreeChannel( pUsartd->pXdmad, pTxCh->ChNum);\r
316 \r
317     /* Allocate a DMA channel for USART0/1 TX. */\r
318     pTxCh->ChNum =  XDMAD_AllocateChannel( pUsartd->pXdmad, XDMAD_TRANSFER_MEMORY, pUsartd->usartId);\r
319     if ( pTxCh->ChNum == XDMAD_ALLOC_FAILED ) \r
320     {\r
321         return USARTD_ERROR;\r
322     }\r
323 \r
324     /* Setup callbacks for USART0/1 TX */\r
325     XDMAD_SetCallback(pUsartd->pXdmad, pTxCh->ChNum, (XdmadTransferCallback)USARTD_Tx_Cb, pUsartd);\r
326     if ( XDMAD_PrepareChannel( pUsartd->pXdmad, pTxCh->ChNum ))\r
327         return USARTD_ERROR;\r
328 \r
329     /* Enable interrupt  */ \r
330     NVIC_EnableIRQ(XDMAC_IRQn);\r
331 \r
332     if (_configureTxLinkList(pUsartHw, pUsartd->pXdmad, pTxCh))\r
333         return USARTD_ERROR_LOCK;\r
334 \r
335     return 0;\r
336 }\r
337 \r
338 /**\r
339  * \brief Starts a USART master transfer. This is a non blocking function. It will\r
340  *  return as soon as the transfer is started.\r
341  *\r
342  * \param pUSARTd  Pointer to a USARTDma instance.\r
343  * \param pCommand Pointer to the USART command to execute.\r
344  * \returns 0 if the transfer has been started successfully; otherwise returns\r
345  * USARTD_ERROR_LOCK is the driver is in use, or USARTD_ERROR if the command is not\r
346  * valid.\r
347  */\r
348 uint32_t USARTD_SendData( UsartDma *pUsartd)\r
349 {\r
350 \r
351     /* Start DMA 0(RX) && 1(TX) */\r
352     while(!pUsartd->pTxChannel->Done);\r
353     if (XDMAD_StartTransfer( pUsartd->pXdmad, pUsartd->pTxChannel->ChNum )) \r
354         return USARTD_ERROR_LOCK;\r
355     pUsartd->pTxChannel->Done=0;\r
356     memory_barrier();\r
357     return 0;\r
358 }\r
359 \r
360 /**\r
361  * \brief Starts a USART master transfer. This is a non blocking function. It will\r
362  *  return as soon as the transfer is started.\r
363  *\r
364  * \param pUSARTd  Pointer to a USARTDma instance.\r
365  * \param pCommand Pointer to the USART command to execute.\r
366  * \returns 0 if the transfer has been started successfully; otherwise returns\r
367  * USARTD_ERROR_LOCK is the driver is in use, or USARTD_ERROR if the command is not\r
368  * valid.\r
369  */\r
370 uint32_t USARTD_RcvData( UsartDma *pUsartd)\r
371 {    \r
372 \r
373     while(!pUsartd->pRxChannel->Done);\r
374     /* Start DMA 0(RX) && 1(TX) */\r
375     if (XDMAD_StartTransfer( pUsartd->pXdmad, pUsartd->pRxChannel->ChNum )) \r
376         return USARTD_ERROR_LOCK;\r
377     pUsartd->pRxChannel->Done=0;\r
378     memory_barrier();\r
379     return 0;\r
380 }\r
381 \r