/* ---------------------------------------------------------------------------- */ /* Atmel Microcontroller Software Support */ /* SAM Software Package License */ /* ---------------------------------------------------------------------------- */ /* Copyright (c) 2015, Atmel Corporation */ /* */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following condition is 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: * * * 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 #include /* 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_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_IF1 | 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; assert(pXdmad == &XDMAD_Instance); 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;; }