]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained_IAR_Keil/libchip_samv7/source/dac_dma.c
Final V8.2.1 release ready for tagging:
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained_IAR_Keil / libchip_samv7 / source / dac_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 /** \addtogroup dacc_module Working with DACC\r
31  *  \ingroup peripherals_module\r
32  * The DACC driver provides the interface to configure and use the DACC peripheral.\n\r
33  *\r
34  * The DACC(Digital-to-Analog Converter Controller) converts digital code to analog output.\r
35  * The data to be converted are sent in a common register for all channels. It offers up to 2\r
36  * analog outputs.The output voltage ranges from (1/6)ADVREF to (5/6)ADVREF.\r
37  *\r
38  * To Enable a DACC conversion,the user has to follow these few steps:\r
39  * <ul>\r
40  * <li> Select an appropriate reference voltage on ADVREF   </li>\r
41  * <li> Configure the DACC according to its requirements and special needs,which could be\r
42  broken down into several parts:\r
43  * -#   Enable DACC in free running mode by clearing TRGEN in DACC_MR;\r
44  * -#   Configure Refresh Period through setting REFRESH fields\r
45  *      in DACC_MR; The refresh mechanism is used to protect the output analog value from\r
46  *      decreasing.\r
47  * -#   Enable channels and write digital code to DACC_CDR,in free running mode, the conversion\r
48  *      is started right after at least one channel is enabled and data is written .\r
49  </li>\r
50  * </ul>\r
51  *\r
52  * For more accurate information, please look at the DACC section of the\r
53  * Datasheet.\r
54  *\r
55  * Related files :\n\r
56  * \ref DACC.c\n\r
57  * \ref DACC.h\n\r
58  */\r
59 /*@{*/\r
60 /*@}*/\r
61 /**\r
62  * \file\r
63  *\r
64  * Implementation of Digital-to-Analog Converter Controller (DACC).\r
65  *\r
66  */\r
67 \r
68 /*----------------------------------------------------------------------------\r
69  *        Headers\r
70  *----------------------------------------------------------------------------*/\r
71 \r
72 #include "chip.h"\r
73 \r
74 #include <stdint.h>\r
75 #include <assert.h>\r
76 \r
77 /*  DMA driver instance */\r
78 static uint32_t dacDmaTxChannel;\r
79 static LinkedListDescriporView1 dmaWriteLinkList[256];\r
80 /*----------------------------------------------------------------------------\r
81  *        Local functions\r
82  *----------------------------------------------------------------------------*/\r
83 \r
84 /**\r
85  * \brief Configure the DMA Channels: 0 RX.\r
86  * Channels are disabled after configure.\r
87  * \returns 0 if the dma channel configuration successfully; otherwise returns\r
88  * DAC_ERROR_XXX.\r
89  */\r
90 static uint8_t _DacConfigureDmaChannels( DacDma* pDacd )\r
91 {\r
92 \r
93     /* Driver initialize */\r
94     XDMAD_Initialize( pDacd->pXdmad, 0 );\r
95 \r
96     XDMAD_FreeChannel( pDacd->pXdmad, dacDmaTxChannel);\r
97 \r
98     /* Allocate a DMA channel for DAC0/1 TX. */\r
99     dacDmaTxChannel = XDMAD_AllocateChannel( pDacd->pXdmad, XDMAD_TRANSFER_MEMORY, ID_DACC);\r
100     {\r
101         if ( dacDmaTxChannel == XDMAD_ALLOC_FAILED ) \r
102         {\r
103             return DAC_ERROR;\r
104         }\r
105     }\r
106     if ( XDMAD_PrepareChannel( pDacd->pXdmad, dacDmaTxChannel )) \r
107         return DAC_ERROR;\r
108     return DAC_OK;\r
109 }\r
110 \r
111 \r
112 /**\r
113  * \brief Configure the DMA source and destination with Linker List mode.\r
114  *\r
115  * \param pBuffer Pointer to dac buffer\r
116  * \param size length of buffer\r
117  */\r
118 \r
119 static uint8_t _Dac_configureLinkList(Dacc *pDacHw, void *pXdmad, DacCmd *pCommand)\r
120 {\r
121     uint32_t xdmaCndc;\r
122     sXdmadCfg xdmadCfg;\r
123     uint32_t * pBuffer;\r
124     /* Setup TX Link List */\r
125     uint8_t i;\r
126     pBuffer = (uint32_t *)pCommand->pTxBuff;\r
127     for(i = 0; i < pCommand->TxSize; i++){\r
128         dmaWriteLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1 \r
129             | XDMA_UBC_NDE_FETCH_EN\r
130             | XDMA_UBC_NSEN_UPDATED\r
131             | XDMAC_CUBC_UBLEN(4);\r
132         dmaWriteLinkList[i].mbr_sa = (uint32_t)pBuffer;\r
133         dmaWriteLinkList[i].mbr_da = (uint32_t)&(pDacHw->DACC_CDR[pCommand->dacChannel]);\r
134         if ( i == (pCommand->TxSize - 1 )) {\r
135             if (pCommand->loopback) {\r
136                 dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[0];\r
137             }\r
138             else {\r
139                 dmaWriteLinkList[i].mbr_nda = 0;\r
140             }\r
141         } else {\r
142             dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[i+1];\r
143         }\r
144         pBuffer++;\r
145     }\r
146     xdmadCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN \r
147         | XDMAC_CC_MBSIZE_SINGLE \r
148         | XDMAC_CC_DSYNC_MEM2PER \r
149         | XDMAC_CC_CSIZE_CHK_1 \r
150         | XDMAC_CC_DWIDTH_WORD\r
151         | XDMAC_CC_SIF_AHB_IF0 \r
152         | XDMAC_CC_DIF_AHB_IF1 \r
153         | XDMAC_CC_SAM_INCREMENTED_AM \r
154         | XDMAC_CC_DAM_FIXED_AM \r
155         | XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(ID_DACC, XDMAD_TRANSFER_TX ));\r
156     xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1 \r
157         | XDMAC_CNDC_NDE_DSCR_FETCH_EN \r
158         | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED\r
159         | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED ;\r
160     XDMAD_ConfigureTransfer( pXdmad, dacDmaTxChannel, &xdmadCfg, xdmaCndc, (uint32_t)&dmaWriteLinkList[0]);\r
161     return DAC_OK;\r
162 }\r
163 \r
164 /*----------------------------------------------------------------------------\r
165  *        Exported functions\r
166  *----------------------------------------------------------------------------*/\r
167 \r
168 \r
169 /**\r
170  * \brief Initializes the DacDma structure and the corresponding DAC & DMA hardware.\r
171  * select value.\r
172  * The driver will uses DMA channel 0 for RX .\r
173  * The DMA channels are freed automatically when no DMA command processing.\r
174  *\r
175  * \param pDacd  Pointer to a DacDma instance.\r
176  * \param pDacHw Associated Dac peripheral.\r
177  * \param DacId  Dac peripheral identifier.\r
178  * \param pDmad  Pointer to a Dmad instance. \r
179  */\r
180 uint32_t Dac_ConfigureDma( DacDma *pDacd ,\r
181         Dacc *pDacHw ,\r
182         uint8_t DacId,\r
183         sXdmad *pXdmad )\r
184 {\r
185     /* Initialize the Dac structure */\r
186     pDacd->pDacHw = pDacHw;\r
187     pDacd->dacId  = DacId;\r
188     pDacd->semaphore = 1;\r
189     pDacd->pCurrentCommand = 0;\r
190     pDacd->pXdmad = pXdmad;\r
191     return 0;\r
192 }\r
193 \r
194 /**\r
195  * \brief Starts a DAC transfer. This is a non blocking function. It will\r
196  *  return as soon as the transfer is started.\r
197  *\r
198  * \param pDacd  Pointer to a DacDma instance.\r
199  * \param pCommand Pointer to the Dac command to execute.\r
200  * \returns 0 if the transfer has been started successfully; otherwise returns\r
201  * DAC_ERROR_LOCK is the driver is in use, or DAC_ERROR if the command is not\r
202  * valid.\r
203  */\r
204 uint32_t Dac_SendData( DacDma *pDacd, DacCmd *pCommand)\r
205 {\r
206     Dacc *pDacHw = pDacd->pDacHw;\r
207 \r
208     /* Try to get the dataflash semaphore */\r
209     if (pDacd->semaphore == 0) {\r
210 \r
211         return DAC_ERROR_LOCK;\r
212     }\r
213     pDacd->semaphore--;\r
214 \r
215     // Initialize the callback\r
216     pDacd->pCurrentCommand = pCommand;\r
217 \r
218     /* Initialize DMA controller using channel 0 for RX. */\r
219     if (_DacConfigureDmaChannels(pDacd) )\r
220         return DAC_ERROR_LOCK;\r
221 \r
222     if (_Dac_configureLinkList(pDacHw, pDacd->pXdmad, pCommand))\r
223         return DAC_ERROR_LOCK;\r
224 \r
225 \r
226     /* Start DMA TX */\r
227     if (XDMAD_StartTransfer( pDacd->pXdmad, dacDmaTxChannel )) \r
228         return DAC_ERROR_LOCK;\r
229     return DAC_OK;;\r
230 }\r
231 \r
232 \r
233 \r
234 #if 0\r
235 \r
236 /*  DMA driver instance */\r
237 static uint32_t dacDmaTxChannel;\r
238 \r
239 /** Global DMA driver for all transfer */\r
240 static sXdmad dacDma;\r
241 \r
242 #define MAX_LINKER_LIST      256\r
243 /** DMA Linker list descriptors */\r
244 static LinkedListDescriporView1 dmaWriteLinkList[MAX_LINKER_LIST];\r
245 \r
246 /*----------------------------------------------------------------------------\r
247  *        Exported functions\r
248  *----------------------------------------------------------------------------*/\r
249 /**\r
250  * Set the Conversion Data\r
251  * \param pDACC Pointer to an Dacc instance.\r
252  * \param dwData  date to be converted.\r
253  * \param channel Channel number\r
254  */\r
255 extern void DACC_SetConversionData( Dacc* pDACC, uint32_t dwData, uint32_t channel)\r
256 {\r
257     pDACC->DACC_CDR[channel] = dwData ;\r
258 }\r
259 \r
260 /**\r
261  * \brief Configure the DMA TX Channel .\r
262  * Channels are disabled after configure.\r
263  * \returns 0 if the dma channel configuration successfully; otherwise returns\r
264  * UARTD_ERROR_XXX.\r
265  */\r
266 uint8_t dacConfigureDmaChannel(void)\r
267 {\r
268 \r
269     /* Driver initialize */\r
270     XDMAD_Initialize( &dacDma, 0 );\r
271 \r
272     /* Allocate a DMA channel for DAC TX. */\r
273     dacDmaTxChannel = XDMAD_AllocateChannel( &dacDma, XDMAD_TRANSFER_MEMORY, ID_DACC);\r
274     {\r
275         if ( dacDmaTxChannel == XDMAD_ALLOC_FAILED ) \r
276         {\r
277             return UARTD_ERROR;\r
278         }\r
279     }\r
280     if ( XDMAD_PrepareChannel( &dacDma, dacDmaTxChannel ))\r
281         return UARTD_ERROR;\r
282     return 0;\r
283 }\r
284 \r
285 /**\r
286  * \brief Configure the DMA source and destination with Linker List mode.\r
287  *\r
288  * \param pBuffer Pointer to DAC buffer\r
289  * \param len length of buffer\r
290  * \param loopback 1: loopback, 0: fixed length of LLI\r
291  * \param channel Channel number\r
292  */\r
293 uint8_t dacConfigureLinkList(Dacc *pDACC, uint32_t *pBuffer, uint32_t len, uint32_t loopback, uint32_t channel)\r
294 {\r
295     uint8_t i;\r
296     uint32_t xdmaCndc;\r
297     sXdmadCfg xdmadCfg;\r
298     assert (len < MAX_LINKER_LIST);\r
299     for(i = 0; i < len; i++){\r
300         dmaWriteLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1 \r
301             | XDMA_UBC_NDE_FETCH_EN\r
302             | XDMA_UBC_NSEN_UPDATED\r
303             | XDMAC_CUBC_UBLEN(4);\r
304         dmaWriteLinkList[i].mbr_sa = (uint32_t)(pBuffer);\r
305         dmaWriteLinkList[i].mbr_da = (uint32_t)&(pDACC->DACC_CDR[channel]);\r
306         if ( i == (len - 1 )) {\r
307             if (loopback) {\r
308                 dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[0];\r
309             }\r
310             else {\r
311                 dmaWriteLinkList[i].mbr_nda = 0;\r
312             }\r
313         } else {\r
314             dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[i+1];\r
315         }\r
316         pBuffer++;\r
317     }\r
318     xdmadCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN \r
319         | XDMAC_CC_MBSIZE_SINGLE \r
320         | XDMAC_CC_DSYNC_MEM2PER \r
321         | XDMAC_CC_CSIZE_CHK_1 \r
322         | XDMAC_CC_DWIDTH_WORD\r
323         | XDMAC_CC_SIF_AHB_IF0 \r
324         | XDMAC_CC_DIF_AHB_IF1 \r
325         | XDMAC_CC_SAM_INCREMENTED_AM \r
326         | XDMAC_CC_DAM_FIXED_AM \r
327         | XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(ID_DACC, XDMAD_TRANSFER_TX ));\r
328     xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1 \r
329         | XDMAC_CNDC_NDE_DSCR_FETCH_EN \r
330         | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED\r
331         | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED ;\r
332     XDMAD_ConfigureTransfer( &dacDma, dacDmaTxChannel, &xdmadCfg, xdmaCndc, (uint32_t)&dmaWriteLinkList[0]);\r
333     return 0;\r
334 }\r
335 \r
336 /**\r
337  * \brief Start DMA transfer.\r
338  *\r
339  * \param channel Channel number\r
340  */\r
341 void dacStartConvert(Dacc *pDACC, uint32_t channel)\r
342 {\r
343     XDMAD_StartTransfer( &dacDma, dacDmaTxChannel);\r
344 \r
345 }\r
346 \r
347 #endif\r