/* ---------------------------------------------------------------------------- | |
* SAM Software Package License | |
* ---------------------------------------------------------------------------- | |
* Copyright (c) 2014, Atmel Corporation | |
* | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* - Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the disclaimer below. | |
* | |
* Atmel's name may not be used to endorse or promote products derived from | |
* this software without specific prior written permission. | |
* | |
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | |
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
* ---------------------------------------------------------------------------- | |
*/ | |
/** \addtogroup dacc_module Working with DACC | |
* \ingroup peripherals_module | |
* The DACC driver provides the interface to configure and use the DACC | |
* peripheral.\n | |
* | |
* The DACC(Digital-to-Analog Converter Controller) converts digital code to | |
* analog output. | |
* The data to be converted are sent in a common register for all channels. | |
* It offers up to 2 analog outputs.The output voltage ranges from (1/6)ADVREF | |
* to (5/6)ADVREF. | |
* | |
* To Enable a DACC conversion,the user has to follow these few steps: | |
* <ul> | |
* <li> Select an appropriate reference voltage on ADVREF </li> | |
* <li> Configure the DACC according to its requirements and special needs, | |
* which could be broken down into several parts: | |
* -# Enable DACC in free running mode by clearing TRGEN in DACC_MR; | |
* -# Configure Refresh Period through setting REFRESH fields | |
* in DACC_MR; The refresh mechanism is used to protect the output analog | |
* value from | |
* decreasing. | |
* -# Enable channels and write digital code to DACC_CDR,in free running mode, | |
* the conversion is started right after at least one channel is enabled and | |
* data is written . | |
</li> | |
* </ul> | |
* | |
* For more accurate information, please look at the DACC section of the | |
* Datasheet. | |
* | |
* Related files :\n | |
* \ref dac_dma.c\n | |
* \ref dac_dma.h\n | |
*/ | |
/*@{*/ | |
/*@}*/ | |
/** | |
* \file | |
* | |
* Implementation of Digital-to-Analog Converter Controller (DACC). | |
* | |
*/ | |
/*---------------------------------------------------------------------------- | |
* Headers | |
*----------------------------------------------------------------------------*/ | |
#include "chip.h" | |
#include <stdint.h> | |
#include <assert.h> | |
/* DMA driver instance */ | |
static uint32_t dacDmaTxChannel; | |
static LinkedListDescriporView1 dmaWriteLinkList[256]; | |
/*---------------------------------------------------------------------------- | |
* Local functions | |
*----------------------------------------------------------------------------*/ | |
/** | |
* \brief Configure the DMA Channels: 0 RX. | |
* Channels are disabled after configure. | |
* \returns 0 if the dma channel configuration successfully; otherwise returns | |
* DAC_ERROR_XXX. | |
*/ | |
static uint8_t _DacConfigureDmaChannels( DacDma* pDacd ) | |
{ | |
/* Driver initialize */ | |
XDMAD_Initialize( pDacd->pXdmad, 0 ); | |
XDMAD_FreeChannel( pDacd->pXdmad, dacDmaTxChannel); | |
/* Allocate a DMA channel for DAC0/1 TX. */ | |
dacDmaTxChannel = | |
XDMAD_AllocateChannel( pDacd->pXdmad, XDMAD_TRANSFER_MEMORY, ID_DACC); | |
if ( dacDmaTxChannel == XDMAD_ALLOC_FAILED ) { | |
return DAC_ERROR; | |
} | |
if ( XDMAD_PrepareChannel( pDacd->pXdmad, dacDmaTxChannel )) | |
return DAC_ERROR; | |
return DAC_OK; | |
} | |
/** | |
* \brief Configure the DMA source and destination with Linker List mode. | |
* | |
* \param pBuffer Pointer to dac buffer | |
* \param size length of buffer | |
*/ | |
static uint8_t _Dac_configureLinkList(Dacc *pDacHw, void *pXdmad, DacCmd *pCommand) | |
{ | |
uint32_t xdmaCndc; | |
sXdmadCfg xdmadCfg; | |
uint32_t * pBuffer; | |
/* Setup TX Link List */ | |
uint8_t i; | |
pBuffer = (uint32_t *)pCommand->pTxBuff; | |
for(i = 0; i < pCommand->TxSize; i++){ | |
dmaWriteLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1 | |
| XDMA_UBC_NDE_FETCH_EN | |
| XDMA_UBC_NSEN_UPDATED | |
| XDMAC_CUBC_UBLEN(4); | |
dmaWriteLinkList[i].mbr_sa = (uint32_t)pBuffer; | |
dmaWriteLinkList[i].mbr_da = | |
(uint32_t)&(pDacHw->DACC_CDR[pCommand->dacChannel]); | |
if ( i == (pCommand->TxSize - 1 )) { | |
if (pCommand->loopback) { | |
dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[0]; | |
} else { | |
dmaWriteLinkList[i].mbr_nda = 0; | |
} | |
} else { | |
dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[i+1]; | |
} | |
pBuffer++; | |
} | |
xdmadCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN | |
| XDMAC_CC_MBSIZE_SINGLE | |
| XDMAC_CC_DSYNC_MEM2PER | |
| XDMAC_CC_CSIZE_CHK_1 | |
| XDMAC_CC_DWIDTH_WORD | |
| XDMAC_CC_SIF_AHB_IF0 | |
| XDMAC_CC_DIF_AHB_IF1 | |
| XDMAC_CC_SAM_INCREMENTED_AM | |
| XDMAC_CC_DAM_FIXED_AM | |
| XDMAC_CC_PERID( | |
XDMAIF_Get_ChannelNumber(ID_DACC, XDMAD_TRANSFER_TX )); | |
xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1 | |
| XDMAC_CNDC_NDE_DSCR_FETCH_EN | |
| XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED | |
| XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED ; | |
XDMAD_ConfigureTransfer( pXdmad, dacDmaTxChannel, &xdmadCfg, xdmaCndc, | |
(uint32_t)&dmaWriteLinkList[0], XDMAC_CIE_LIE); | |
return DAC_OK; | |
} | |
/*---------------------------------------------------------------------------- | |
* Exported functions | |
*----------------------------------------------------------------------------*/ | |
/** | |
* \brief Initializes the DacDma structure and the corresponding DAC & DMA . | |
* hardware select value. | |
* The driver will uses DMA channel 0 for RX . | |
* The DMA channels are freed automatically when no DMA command processing. | |
* | |
* \param pDacd Pointer to a DacDma instance. | |
* \param pDacHw Associated Dac peripheral. | |
* \param DacId Dac peripheral identifier. | |
* \param pDmad Pointer to a Dmad instance. | |
*/ | |
uint32_t Dac_ConfigureDma( DacDma *pDacd , | |
Dacc *pDacHw , | |
uint8_t DacId, | |
sXdmad *pXdmad ) | |
{ | |
/* Initialize the Dac structure */ | |
pDacd->pDacHw = pDacHw; | |
pDacd->dacId = DacId; | |
pDacd->semaphore = 1; | |
pDacd->pCurrentCommand = 0; | |
pDacd->pXdmad = pXdmad; | |
return 0; | |
} | |
/** | |
* \brief Starts a DAC transfer. This is a non blocking function. It will | |
* return as soon as the transfer is started. | |
* | |
* \param pDacd Pointer to a DacDma instance. | |
* \param pCommand Pointer to the Dac command to execute. | |
* \returns 0 if the transfer has been started successfully; otherwise returns | |
* DAC_ERROR_LOCK is the driver is in use, or DAC_ERROR if the command is not | |
* valid. | |
*/ | |
uint32_t Dac_SendData( DacDma *pDacd, DacCmd *pCommand) | |
{ | |
Dacc *pDacHw = pDacd->pDacHw; | |
/* Try to get the dataflash semaphore */ | |
if (pDacd->semaphore == 0) { | |
return DAC_ERROR_LOCK; | |
} | |
pDacd->semaphore--; | |
// Initialize the callback | |
pDacd->pCurrentCommand = pCommand; | |
/* Initialize DMA controller using channel 0 for RX. */ | |
if (_DacConfigureDmaChannels(pDacd) ) | |
return DAC_ERROR_LOCK; | |
if (_Dac_configureLinkList(pDacHw, pDacd->pXdmad, pCommand)) | |
return DAC_ERROR_LOCK; | |
SCB_CleanDCache(); | |
/* Start DMA TX */ | |
if (XDMAD_StartTransfer( pDacd->pXdmad, dacDmaTxChannel )) | |
return DAC_ERROR_LOCK; | |
return DAC_OK;; | |
} |