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 xdmad_module
\r
32 * \section Xdma xDma Configuration Usage
\r
34 * To configure a XDMA channel, the user has to follow these few steps :
\r
36 * <li> Initialize a XDMA driver instance by XDMAD_Initialize().</li>
\r
37 * <li> choose an available (disabled) channel using XDMAD_AllocateChannel().</li>
\r
38 * <li> After the XDMAC selected channel has been programmed, XDMAD_PrepareChannel() is to enable
\r
39 * clock and dma peripheral of the DMA, and set Configuration register to set up the transfer type
\r
40 * (memory or non-memory peripheral for source and destination) and flow control device.</li>
\r
41 * <li> Invoke XDMAD_StartTransfer() to start DMA transfer or XDMAD_StopTransfer() to force stop DMA transfer.</li>
\r
42 * <li> Once the buffer of data is transferred, XDMAD_IsTransferDone() checks if DMA transfer is finished.</li>
\r
43 * <li> XDMAD_Handler() handles XDMA interrupt, and invoking XDMAD_SetCallback() if provided.</li>
\r
53 /** \addtogroup dmad_functions
\r
56 /*----------------------------------------------------------------------------
\r
58 *----------------------------------------------------------------------------*/
\r
63 /*----------------------------------------------------------------------------
\r
65 *----------------------------------------------------------------------------*/
\r
67 * \brief Try to allocate a DMA channel for on given controller.
\r
68 * \param pDmad Pointer to DMA driver instance.
\r
69 * \param bXdmac xDMA controller ID (0 ~ 1).
\r
70 * \param bSrcID Source peripheral ID, 0xFF for memory.
\r
71 * \param bDstID Destination peripheral ID, 0xFF for memory.
\r
72 * \return Channel number if allocation sucessful, return
\r
73 * DMAD_ALLOC_FAILED if allocation failed.
\r
75 static uint32_t XDMAD_AllocateXdmacChannel( sXdmad *pXdmad,
\r
81 /* Can't support peripheral to peripheral */
\r
82 if ((( bSrcID != XDMAD_TRANSFER_MEMORY ) && ( bDstID != XDMAD_TRANSFER_MEMORY )))
\r
84 return XDMAD_ALLOC_FAILED;
\r
86 /* dma transfer from peripheral to memory */
\r
87 if ( bDstID == XDMAD_TRANSFER_MEMORY)
\r
89 if( (!XDMAIF_IsValidatedPeripherOnDma(bXdmac, bSrcID)) )
\r
91 return XDMAD_ALLOC_FAILED;
\r
94 /* dma transfer from memory to peripheral */
\r
95 if ( bSrcID == XDMAD_TRANSFER_MEMORY )
\r
97 if( (!XDMAIF_IsValidatedPeripherOnDma(bXdmac, bDstID)) )
\r
99 return XDMAD_ALLOC_FAILED;
\r
103 for (i = 0; i < pXdmad->numChannels; i ++)
\r
105 if ( pXdmad->XdmaChannels[bXdmac][i].state == XDMAD_STATE_FREE )
\r
107 /* Allocate the channel */
\r
108 pXdmad->XdmaChannels[bXdmac][i].state = XDMAD_STATE_ALLOCATED;
\r
109 /* Get general informations */
\r
110 pXdmad->XdmaChannels[bXdmac][i].bSrcPeriphID = bSrcID;
\r
111 pXdmad->XdmaChannels[bXdmac][i].bDstPeriphID = bDstID;
\r
112 pXdmad->XdmaChannels[bXdmac][i].bSrcTxIfID =
\r
113 XDMAIF_Get_ChannelNumber(bXdmac, bSrcID, 0);
\r
114 pXdmad->XdmaChannels[bXdmac][i].bSrcRxIfID =
\r
115 XDMAIF_Get_ChannelNumber(bXdmac, bSrcID, 1);
\r
116 pXdmad->XdmaChannels[bXdmac][i].bDstTxIfID =
\r
117 XDMAIF_Get_ChannelNumber(bXdmac, bDstID, 0);
\r
118 pXdmad->XdmaChannels[bXdmac][i].bDstTxIfID =
\r
119 XDMAIF_Get_ChannelNumber(bXdmac, bDstID, 1);
\r
120 return ((bXdmac << 8)) | ((i) & 0xFF);
\r
123 return XDMAD_ALLOC_FAILED;
\r
126 /*----------------------------------------------------------------------------
\r
127 * Exported functions
\r
128 *----------------------------------------------------------------------------*/
\r
131 * \brief Initialize xDMA driver instance.
\r
132 * \param pXdmad Pointer to xDMA driver instance.
\r
133 * \param bPollingMode Polling DMA transfer:
\r
134 * 1. Via XDMAD_IsTransferDone(); or
\r
135 * 2. Via XDMAD_Handler().
\r
137 void XDMAD_Initialize( sXdmad *pXdmad, uint8_t bPollingMode )
\r
141 assert( pXdmad != NULL ) ;
\r
143 pXdmad->pXdmacs[0] = XDMAC0;
\r
144 pXdmad->pXdmacs[1] = XDMAC1;
\r
145 pXdmad->pollingMode = bPollingMode;
\r
146 pXdmad->numControllers = XDMAC_CONTROLLER_NUM;
\r
147 pXdmad->numChannels = XDMAC_CHANNEL_NUM;
\r
149 for (i = 0; i < pXdmad->numControllers; i ++)
\r
151 for (j = 0; j < pXdmad->numChannels; j ++)
\r
153 pXdmad->XdmaChannels[i][j].fCallback = 0;
\r
154 pXdmad->XdmaChannels[i][j].pArg = 0;
\r
155 pXdmad->XdmaChannels[i][j].bIrqOwner = 0;
\r
156 pXdmad->XdmaChannels[i][j].bSrcPeriphID = 0;
\r
157 pXdmad->XdmaChannels[i][j].bDstPeriphID = 0;
\r
158 pXdmad->XdmaChannels[i][j].bSrcTxIfID = 0;
\r
159 pXdmad->XdmaChannels[i][j].bSrcRxIfID = 0;
\r
160 pXdmad->XdmaChannels[i][j].bDstTxIfID = 0;
\r
161 pXdmad->XdmaChannels[i][j].bDstRxIfID = 0;
\r
162 pXdmad->XdmaChannels[i][j].state = XDMAD_STATE_FREE;
\r
169 * \brief Allocate a XDMA channel for upper layer.
\r
170 * \param pXdmad Pointer to xDMA driver instance.
\r
171 * \param bSrcID Source peripheral ID, 0xFF for memory.
\r
172 * \param bDstID Destination peripheral ID, 0xFF for memory.
\r
173 * \return Channel number if allocation sucessful, return
\r
174 * XDMAD_ALLOC_FAILED if allocation failed.
\r
176 uint32_t XDMAD_AllocateChannel( sXdmad *pXdmad,
\r
180 uint32_t _iController;
\r
181 uint32_t dwChannel = XDMAD_ALLOC_FAILED;
\r
182 for ( _iController = 0; _iController < pXdmad->numControllers; _iController ++)
\r
184 dwChannel = XDMAD_AllocateXdmacChannel( pXdmad, _iController, bSrcID, bDstID );
\r
185 if (dwChannel != XDMAD_ALLOC_FAILED)
\r
192 * \brief Free the specified xDMA channel.
\r
193 * \param pXdmad Pointer to xDMA driver instance.
\r
194 * \param dwChannel ControllerNumber << 8 | ChannelNumber.
\r
196 eXdmadRC XDMAD_FreeChannel( sXdmad *pXdmad,
\r
197 uint32_t dwChannel )
\r
199 uint8_t _iController = (dwChannel >> 8);
\r
200 uint8_t iChannel = (dwChannel) & 0xFF;
\r
202 assert( pXdmad != NULL ) ;
\r
203 switch ( pXdmad->XdmaChannels[_iController][iChannel].state )
\r
205 case XDMAD_STATE_START:
\r
207 case XDMAD_STATE_ALLOCATED: case XDMAD_STATE_DONE:
\r
208 pXdmad->XdmaChannels[_iController][iChannel].state = XDMAD_STATE_FREE;
\r
216 * \brief Set the callback function for xDMA channel transfer.
\r
217 * \param pXdmad Pointer to xDMA driver instance.
\r
218 * \param dwChannel ControllerNumber << 8 | ChannelNumber.
\r
219 * \param fCallback Pointer to callback function.
\r
220 * \param pArg Pointer to optional argument for callback.
\r
222 eXdmadRC XDMAD_SetCallback( sXdmad *pXdmad,
\r
223 uint32_t dwChannel,
\r
224 XdmadTransferCallback fCallback,
\r
227 uint8_t _iController = (dwChannel >> 8);
\r
228 uint8_t iChannel = (dwChannel) & 0xFF;
\r
229 assert( pXdmad != NULL ) ;
\r
230 if ( pXdmad->XdmaChannels[_iController][iChannel].state == XDMAD_STATE_FREE )
\r
231 return XDMAD_ERROR;
\r
232 else if ( pXdmad->XdmaChannels[_iController][iChannel].state == XDMAD_STATE_START )
\r
235 pXdmad->XdmaChannels[_iController][iChannel].fCallback = fCallback;
\r
236 pXdmad->XdmaChannels[_iController][iChannel].pArg = pArg;
\r
243 * \brief Enable clock of the xDMA peripheral, Enable the dma peripheral,
\r
244 * configure configuration register for xDMA transfer.
\r
245 * \param pXdmad Pointer to xDMA driver instance.
\r
246 * \param dwChannel ControllerNumber << 8 | ChannelNumber.
\r
247 * \param dwCfg Configuration value.
\r
249 eXdmadRC XDMAD_PrepareChannel( sXdmad *pXdmad, uint32_t dwChannel)
\r
251 uint8_t _iController = (dwChannel >> 8);
\r
252 uint8_t iChannel = (dwChannel) & 0xFF;
\r
255 assert( pXdmad != NULL ) ;
\r
256 Xdmac *pXdmac = pXdmad->pXdmacs[_iController];
\r
258 if ( pXdmad->XdmaChannels[_iController][iChannel].state == XDMAD_STATE_FREE )
\r
259 return XDMAD_ERROR;
\r
260 else if ( pXdmad->XdmaChannels[_iController][iChannel].state == XDMAD_STATE_START )
\r
262 /* Clear dummy status */
\r
263 XDMAC_GetGlobalChStatus( pXdmac );
\r
264 XDMAC_GetGIsr (pXdmac);
\r
265 _dwdmaId = (_iController == 0) ? ID_XDMAC0 : ID_XDMAC1;
\r
266 /* Enable clock of the DMA peripheral */
\r
267 if (!PMC_IsPeriphEnabled( _dwdmaId ))
\r
269 PMC_EnablePeripheral( _dwdmaId );
\r
271 /* Clear dummy status */
\r
272 XDMAC_GetChannelIsr( pXdmac,iChannel );
\r
273 /* Disables XDMAC interrupt for the given channel. */
\r
274 XDMAC_DisableGIt (pXdmac, -1);
\r
275 XDMAC_DisableChannelIt (pXdmac, iChannel, -1);
\r
276 /* Disable the given dma channel. */
\r
277 XDMAC_DisableChannel( pXdmac, iChannel );
\r
278 XDMAC_SetSourceAddr(pXdmac, iChannel, 0);
\r
279 XDMAC_SetDestinationAddr(pXdmac, iChannel, 0);
\r
280 XDMAC_SetBlockControl(pXdmac, iChannel, 0);
\r
281 XDMAC_SetChannelConfig( pXdmac, iChannel, 0x20);
\r
282 XDMAC_SetDescriptorAddr(pXdmac, iChannel, 0, 0);
\r
283 XDMAC_SetDescriptorControl(pXdmac, iChannel, 0);
\r
288 * \brief xDMA interrupt handler
\r
289 * \param pxDmad Pointer to DMA driver instance.
\r
291 void XDMAD_Handler( sXdmad *pDmad)
\r
294 sXdmadChannel *pCh;
\r
295 uint32_t xdmaChannelIntStatus, xdmaGlobaIntStatus,xdmaGlobalChStatus;
\r
297 uint8_t _iController, _iChannel;
\r
298 assert( pDmad != NULL ) ;
\r
300 for (_iController = 0; _iController < pDmad->numControllers; _iController ++)
\r
302 pXdmac = pDmad->pXdmacs[_iController];
\r
303 xdmaGlobaIntStatus = XDMAC_GetGIsr(pXdmac);
\r
304 if ((xdmaGlobaIntStatus & 0xFFFF) == 0) continue;
\r
305 xdmaGlobalChStatus = XDMAC_GetGlobalChStatus(pXdmac);
\r
306 for (_iChannel = 0; _iChannel < pDmad->numChannels; _iChannel ++)
\r
308 if (!(xdmaGlobaIntStatus & (1<<_iChannel))) continue;
\r
309 pCh = &pDmad->XdmaChannels[_iController][_iChannel];
\r
310 if ( pCh->state == XDMAD_STATE_FREE) return ;
\r
311 if ((xdmaGlobalChStatus & ( XDMAC_GS_ST0 << _iChannel)) == 0)
\r
314 xdmaChannelIntStatus = XDMAC_GetChannelIsr( pXdmac, _iChannel);
\r
315 if (xdmaChannelIntStatus & XDMAC_CIS_BIS) {
\r
316 if((XDMAC_GetChannelItMask(pXdmac, _iChannel) & XDMAC_CIM_LIM) == 0 ) {
\r
317 pCh->state = XDMAD_STATE_DONE ;
\r
320 //printf("XDMAC_CIS_BIS\n\r");
\r
322 if (xdmaChannelIntStatus & XDMAC_CIS_FIS) {
\r
323 // printf("XDMAC_CIS_FIS\n\r");
\r
325 if (xdmaChannelIntStatus & XDMAC_CIS_RBEIS) {
\r
326 //printf("XDMAC_CIS_RBEIS\n\r");
\r
328 if (xdmaChannelIntStatus & XDMAC_CIS_WBEIS) {
\r
329 // printf("XDMAC_CIS_WBEIS\n\r");
\r
331 if (xdmaChannelIntStatus & XDMAC_CIS_ROIS) {
\r
332 // printf("XDMAC_CIS_ROIS\n\r");
\r
334 if (xdmaChannelIntStatus & XDMAC_CIS_LIS) {
\r
335 //printf("XDMAC_CIS_LIS\n\r");
\r
337 pCh->state = XDMAD_STATE_DONE ;
\r
340 if (xdmaChannelIntStatus & XDMAC_CIS_DIS )
\r
342 pCh->state = XDMAD_STATE_DONE ;
\r
346 // printf("bExec =%d, _iChannel=%d \n\r",bExec,_iChannel);
\r
347 /* Execute callback */
\r
348 if (bExec && pCh->fCallback) {
\r
349 //XDMAC_DisableGIt( pXdmac,1 << _iChannel);
\r
350 pCh->fCallback(_iChannel, pCh->pArg);
\r
357 * \brief Check if DMA transfer is finished.
\r
358 * In polling mode XDMAD_Handler() is polled.
\r
359 * \param pDmad Pointer to DMA driver instance.
\r
360 * \param dwChannel ControllerNumber << 8 | ChannelNumber.
\r
362 eXdmadRC XDMAD_IsTransferDone( sXdmad *pXdmad, uint32_t dwChannel )
\r
364 uint8_t _iController = (dwChannel >> 8);
\r
365 uint8_t iChannel = (dwChannel) & 0xFF;
\r
367 state = pXdmad->XdmaChannels[_iController][iChannel].state;
\r
368 assert( pXdmad != NULL ) ;
\r
369 if ( state == XDMAD_STATE_ALLOCATED ) return XDMAD_OK;
\r
370 if ( state == XDMAD_STATE_FREE )
\r
371 return XDMAD_ERROR;
\r
372 else if ( state != XDMAD_STATE_DONE )
\r
374 if(pXdmad->pollingMode) XDMAD_Handler( pXdmad);
\r
382 * \brief Configure DMA for a single transfer.
\r
383 * \param pXdmad Pointer to xDMA driver instance.
\r
384 * \param dwChannel ControllerNumber << 8 | ChannelNumber.
\r
386 eXdmadRC XDMAD_ConfigureTransfer( sXdmad *pXdmad,
\r
387 uint32_t dwChannel,
\r
388 sXdmadCfg *pXdmaParam,
\r
389 uint32_t dwXdmaDescCfg,
\r
390 uint32_t dwXdmaDescAddr)
\r
392 uint8_t _iController = (dwChannel >> 8);
\r
393 uint8_t iChannel = (dwChannel) & 0xFF;
\r
394 Xdmac *pXdmac = pXdmad->pXdmacs[_iController];
\r
395 XDMAC_GetGIsr(pXdmac);
\r
396 XDMAC_GetChannelIsr( pXdmac, iChannel);
\r
397 if ( pXdmad->XdmaChannels[_iController][iChannel].state == XDMAD_STATE_FREE )
\r
398 return XDMAD_ERROR;
\r
399 if ( pXdmad->XdmaChannels[_iController][iChannel].state == XDMAD_STATE_START )
\r
401 /* Linked List is enabled */
\r
402 if ((dwXdmaDescCfg & XDMAC_CNDC_NDE) == XDMAC_CNDC_NDE_DSCR_FETCH_EN)
\r
404 if ((dwXdmaDescCfg & XDMAC_CNDC_NDVIEW_Msk) == XDMAC_CNDC_NDVIEW_NDV0) {
\r
405 XDMAC_SetChannelConfig( pXdmac, iChannel, pXdmaParam->mbr_cfg );
\r
406 XDMAC_SetSourceAddr(pXdmac, iChannel, pXdmaParam->mbr_sa);
\r
407 XDMAC_SetDestinationAddr(pXdmac, iChannel, pXdmaParam->mbr_da);
\r
409 if ((dwXdmaDescCfg & XDMAC_CNDC_NDVIEW_Msk) == XDMAC_CNDC_NDVIEW_NDV1) {
\r
410 XDMAC_SetChannelConfig( pXdmac, iChannel, pXdmaParam->mbr_cfg );
\r
412 XDMAC_SetDescriptorAddr(pXdmac, iChannel, dwXdmaDescAddr, 0);
\r
413 XDMAC_SetDescriptorControl(pXdmac, iChannel, dwXdmaDescCfg);
\r
414 XDMAC_DisableChannelIt (pXdmac, iChannel, -1);
\r
415 XDMAC_EnableChannelIt (pXdmac,iChannel, XDMAC_CIE_LIE );
\r
417 /* LLI is disabled. */
\r
420 XDMAC_SetSourceAddr(pXdmac, iChannel, pXdmaParam->mbr_sa);
\r
421 XDMAC_SetDestinationAddr(pXdmac, iChannel, pXdmaParam->mbr_da);
\r
422 XDMAC_SetMicroblockControl(pXdmac, iChannel, pXdmaParam->mbr_ubc);
\r
423 XDMAC_SetBlockControl(pXdmac, iChannel, pXdmaParam->mbr_bc);
\r
424 XDMAC_SetDataStride_MemPattern(pXdmac, iChannel, pXdmaParam->mbr_ds);
\r
425 XDMAC_SetSourceMicroBlockStride(pXdmac, iChannel, pXdmaParam->mbr_sus);
\r
426 XDMAC_SetDestinationMicroBlockStride(pXdmac, iChannel, pXdmaParam->mbr_dus);
\r
427 XDMAC_SetChannelConfig( pXdmac, iChannel, pXdmaParam->mbr_cfg );
\r
428 XDMAC_SetDescriptorAddr(pXdmac, iChannel, 0, 0);
\r
429 XDMAC_SetDescriptorControl(pXdmac, iChannel, 0);
\r
430 XDMAC_EnableChannelIt (pXdmac,
\r
443 * \brief Start xDMA transfer.
\r
444 * \param pXdmad Pointer to XDMA driver instance.
\r
445 * \param dwChannel ControllerNumber << 8 | ChannelNumber.
\r
447 eXdmadRC XDMAD_StartTransfer( sXdmad *pXdmad, uint32_t dwChannel )
\r
449 uint8_t _iController = (dwChannel >> 8);
\r
450 uint8_t iChannel = (dwChannel) & 0xFF;
\r
451 Xdmac *pXdmac = pXdmad->pXdmacs[_iController];
\r
452 if ( pXdmad->XdmaChannels[_iController][iChannel].state == XDMAD_STATE_FREE )
\r
454 printf("-E- XDMAD_STATE_FREE \n\r");
\r
455 return XDMAD_ERROR;
\r
457 else if ( pXdmad->XdmaChannels[_iController][iChannel].state == XDMAD_STATE_START )
\r
459 printf("-E- XDMAD_STATE_START \n\r");
\r
462 /* Change state to transferring */
\r
463 pXdmad->XdmaChannels[_iController][iChannel].state = XDMAD_STATE_START;
\r
464 XDMAC_EnableChannel(pXdmac, iChannel);
\r
465 if ( pXdmad->pollingMode == 0 )
\r
467 XDMAC_EnableGIt( pXdmac,1 << iChannel);
\r
474 * \brief Stop DMA transfer.
\r
475 * \param pDmad Pointer to DMA driver instance.
\r
476 * \param dwChannel ControllerNumber << 8 | ChannelNumber.
\r
478 eXdmadRC XDMAD_StopTransfer( sXdmad *pXdmad, uint32_t dwChannel )
\r
480 uint8_t _iController = (dwChannel >> 8);
\r
481 uint8_t _iChannel = (dwChannel) & 0xFF;
\r
482 Xdmac *pXdmac = pXdmad->pXdmacs[_iController];
\r
484 pXdmad->XdmaChannels[_iController][_iChannel].state = XDMAD_STATE_ALLOCATED;
\r
485 /* Disable channel */
\r
486 XDMAC_DisableChannel(pXdmac, _iChannel);
\r
487 /* Disable interrupts */
\r
488 XDMAC_DisableChannelIt(pXdmac, _iChannel, -1);
\r
489 /* Clear pending status */
\r
490 XDMAC_GetChannelIsr( pXdmac, _iChannel);
\r
491 XDMAC_GetGlobalChStatus(pXdmac);
\r