1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2014, Atmel Corporation
\r
6 * All rights reserved.
\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
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\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
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
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
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
38 * To Enable a DACC conversion,the user has to follow these few steps:
\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
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
52 * For more accurate information, please look at the DACC section of the
\r
64 * Implementation of Digital-to-Analog Converter Controller (DACC).
\r
68 /*----------------------------------------------------------------------------
\r
70 *----------------------------------------------------------------------------*/
\r
77 /* DMA driver instance */
\r
78 static uint32_t dacDmaTxChannel;
\r
79 static LinkedListDescriporView1 dmaWriteLinkList[256];
\r
80 /*----------------------------------------------------------------------------
\r
82 *----------------------------------------------------------------------------*/
\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
90 static uint8_t _DacConfigureDmaChannels( DacDma* pDacd )
\r
93 /* Driver initialize */
\r
94 XDMAD_Initialize( pDacd->pXdmad, 0 );
\r
96 XDMAD_FreeChannel( pDacd->pXdmad, dacDmaTxChannel);
\r
98 /* Allocate a DMA channel for DAC0/1 TX. */
\r
99 dacDmaTxChannel = XDMAD_AllocateChannel( pDacd->pXdmad, XDMAD_TRANSFER_MEMORY, ID_DACC);
\r
101 if ( dacDmaTxChannel == XDMAD_ALLOC_FAILED )
\r
106 if ( XDMAD_PrepareChannel( pDacd->pXdmad, dacDmaTxChannel ))
\r
113 * \brief Configure the DMA source and destination with Linker List mode.
\r
115 * \param pBuffer Pointer to dac buffer
\r
116 * \param size length of buffer
\r
119 static uint8_t _Dac_configureLinkList(Dacc *pDacHw, void *pXdmad, DacCmd *pCommand)
\r
122 sXdmadCfg xdmadCfg;
\r
123 uint32_t * pBuffer;
\r
124 /* Setup TX Link List */
\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
139 dmaWriteLinkList[i].mbr_nda = 0;
\r
142 dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[i+1];
\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
164 /*----------------------------------------------------------------------------
\r
165 * Exported functions
\r
166 *----------------------------------------------------------------------------*/
\r
170 * \brief Initializes the DacDma structure and the corresponding DAC & DMA hardware.
\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
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
180 uint32_t Dac_ConfigureDma( DacDma *pDacd ,
\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
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
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
204 uint32_t Dac_SendData( DacDma *pDacd, DacCmd *pCommand)
\r
206 Dacc *pDacHw = pDacd->pDacHw;
\r
208 /* Try to get the dataflash semaphore */
\r
209 if (pDacd->semaphore == 0) {
\r
211 return DAC_ERROR_LOCK;
\r
213 pDacd->semaphore--;
\r
215 // Initialize the callback
\r
216 pDacd->pCurrentCommand = pCommand;
\r
218 /* Initialize DMA controller using channel 0 for RX. */
\r
219 if (_DacConfigureDmaChannels(pDacd) )
\r
220 return DAC_ERROR_LOCK;
\r
222 if (_Dac_configureLinkList(pDacHw, pDacd->pXdmad, pCommand))
\r
223 return DAC_ERROR_LOCK;
\r
227 if (XDMAD_StartTransfer( pDacd->pXdmad, dacDmaTxChannel ))
\r
228 return DAC_ERROR_LOCK;
\r
236 /* DMA driver instance */
\r
237 static uint32_t dacDmaTxChannel;
\r
239 /** Global DMA driver for all transfer */
\r
240 static sXdmad dacDma;
\r
242 #define MAX_LINKER_LIST 256
\r
243 /** DMA Linker list descriptors */
\r
244 static LinkedListDescriporView1 dmaWriteLinkList[MAX_LINKER_LIST];
\r
246 /*----------------------------------------------------------------------------
\r
247 * Exported functions
\r
248 *----------------------------------------------------------------------------*/
\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
255 extern void DACC_SetConversionData( Dacc* pDACC, uint32_t dwData, uint32_t channel)
\r
257 pDACC->DACC_CDR[channel] = dwData ;
\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
266 uint8_t dacConfigureDmaChannel(void)
\r
269 /* Driver initialize */
\r
270 XDMAD_Initialize( &dacDma, 0 );
\r
272 /* Allocate a DMA channel for DAC TX. */
\r
273 dacDmaTxChannel = XDMAD_AllocateChannel( &dacDma, XDMAD_TRANSFER_MEMORY, ID_DACC);
\r
275 if ( dacDmaTxChannel == XDMAD_ALLOC_FAILED )
\r
277 return UARTD_ERROR;
\r
280 if ( XDMAD_PrepareChannel( &dacDma, dacDmaTxChannel ))
\r
281 return UARTD_ERROR;
\r
286 * \brief Configure the DMA source and destination with Linker List mode.
\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
293 uint8_t dacConfigureLinkList(Dacc *pDACC, uint32_t *pBuffer, uint32_t len, uint32_t loopback, uint32_t channel)
\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
308 dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[0];
\r
311 dmaWriteLinkList[i].mbr_nda = 0;
\r
314 dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[i+1];
\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
337 * \brief Start DMA transfer.
\r
339 * \param channel Channel number
\r
341 void dacStartConvert(Dacc *pDACC, uint32_t channel)
\r
343 XDMAD_StartTransfer( &dacDma, dacDmaTxChannel);
\r