00001 /* ---------------------------------------------------------------------------- */ 00002 /* Atmel Microcontroller Software Support */ 00003 /* SAM Software Package License */ 00004 /* ---------------------------------------------------------------------------- */ 00005 /* Copyright (c) 2015, Atmel Corporation */ 00006 /* */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without */ 00010 /* modification, are permitted provided that the following condition is met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, */ 00013 /* this list of conditions and the disclaimer below. */ 00014 /* */ 00015 /* Atmel's name may not be used to endorse or promote products derived from */ 00016 /* this software without specific prior written permission. */ 00017 /* */ 00018 /* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR */ 00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ 00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE */ 00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, */ 00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ 00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */ 00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ 00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ 00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ 00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 00028 /* ---------------------------------------------------------------------------- */ 00029 00030 /** \addtogroup dacc_module Working with DACC 00031 * \ingroup peripherals_module 00032 * The DACC driver provides the interface to configure and use the DACC 00033 * peripheral.\n 00034 * 00035 * The DACC(Digital-to-Analog Converter Controller) converts digital code to 00036 * analog output. 00037 * The data to be converted are sent in a common register for all channels. 00038 * It offers up to 2 analog outputs.The output voltage ranges from (1/6)ADVREF 00039 * to (5/6)ADVREF. 00040 * 00041 * To Enable a DACC conversion,the user has to follow these few steps: 00042 * <ul> 00043 * <li> Select an appropriate reference voltage on ADVREF </li> 00044 * <li> Configure the DACC according to its requirements and special needs, 00045 * which could be broken down into several parts: 00046 * -# Enable DACC in free running mode by clearing TRGEN in DACC_MR; 00047 * -# Configure Refresh Period through setting REFRESH fields 00048 * in DACC_MR; The refresh mechanism is used to protect the output analog 00049 * value from 00050 * decreasing. 00051 * -# Enable channels and write digital code to DACC_CDR,in free running mode, 00052 * the conversion is started right after at least one channel is enabled and 00053 * data is written . 00054 </li> 00055 * </ul> 00056 * 00057 * For more accurate information, please look at the DACC section of the 00058 * Datasheet. 00059 * 00060 * Related files :\n 00061 * \ref dac_dma.c\n 00062 * \ref dac_dma.h\n 00063 */ 00064 /*@{*/ 00065 /*@}*/ 00066 /** 00067 * \file 00068 * 00069 * Implementation of Digital-to-Analog Converter Controller (DACC). 00070 * 00071 */ 00072 00073 /*---------------------------------------------------------------------------- 00074 * Headers 00075 *----------------------------------------------------------------------------*/ 00076 00077 #include "chip.h" 00078 00079 #include <stdint.h> 00080 #include <assert.h> 00081 00082 /* DMA driver instance */ 00083 static uint32_t dacDmaTxChannel; 00084 static LinkedListDescriporView1 dmaWriteLinkList[256]; 00085 /*---------------------------------------------------------------------------- 00086 * Local functions 00087 *----------------------------------------------------------------------------*/ 00088 00089 /** 00090 * \brief Configure the DMA Channels: 0 RX. 00091 * Channels are disabled after configure. 00092 * \returns 0 if the dma channel configuration successfully; otherwise returns 00093 * DAC_ERROR_XXX. 00094 */ 00095 static uint8_t _DacConfigureDmaChannels(DacDma *pDacd) 00096 { 00097 00098 /* Driver initialize */ 00099 XDMAD_Initialize(pDacd->pXdmad, 0); 00100 00101 XDMAD_FreeChannel(pDacd->pXdmad, dacDmaTxChannel); 00102 00103 /* Allocate a DMA channel for DAC0/1 TX. */ 00104 dacDmaTxChannel = 00105 XDMAD_AllocateChannel(pDacd->pXdmad, XDMAD_TRANSFER_MEMORY, ID_DACC); 00106 00107 if (dacDmaTxChannel == XDMAD_ALLOC_FAILED) 00108 return DAC_ERROR; 00109 00110 if (XDMAD_PrepareChannel(pDacd->pXdmad, dacDmaTxChannel)) 00111 return DAC_ERROR; 00112 00113 return DAC_OK; 00114 } 00115 00116 00117 /** 00118 * \brief Configure the DMA source and destination with Linker List mode. 00119 * 00120 * \param pBuffer Pointer to dac buffer 00121 * \param size length of buffer 00122 */ 00123 00124 static uint8_t _Dac_configureLinkList(Dacc *pDacHw, void *pXdmad, 00125 DacCmd *pCommand) 00126 { 00127 uint32_t xdmaCndc; 00128 sXdmadCfg xdmadCfg; 00129 uint32_t *pBuffer; 00130 /* Setup TX Link List */ 00131 uint8_t i; 00132 pBuffer = (uint32_t *)pCommand->pTxBuff; 00133 00134 for (i = 0; i < pCommand->TxSize; i++) { 00135 dmaWriteLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1 00136 | XDMA_UBC_NDE_FETCH_EN 00137 | XDMA_UBC_NSEN_UPDATED 00138 | XDMAC_CUBC_UBLEN(4); 00139 dmaWriteLinkList[i].mbr_sa = (uint32_t)pBuffer; 00140 dmaWriteLinkList[i].mbr_da = 00141 (uint32_t) & (pDacHw->DACC_CDR[pCommand->dacChannel]); 00142 00143 if (i == (pCommand->TxSize - 1)) { 00144 if (pCommand->loopback) 00145 dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[0]; 00146 else 00147 dmaWriteLinkList[i].mbr_nda = 0; 00148 } else 00149 dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[i + 1]; 00150 00151 pBuffer++; 00152 } 00153 00154 xdmadCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN 00155 | XDMAC_CC_MBSIZE_SINGLE 00156 | XDMAC_CC_DSYNC_MEM2PER 00157 | XDMAC_CC_CSIZE_CHK_1 00158 | XDMAC_CC_DWIDTH_WORD 00159 | XDMAC_CC_SIF_AHB_IF1 00160 | XDMAC_CC_DIF_AHB_IF1 00161 | XDMAC_CC_SAM_INCREMENTED_AM 00162 | XDMAC_CC_DAM_FIXED_AM 00163 | XDMAC_CC_PERID( 00164 XDMAIF_Get_ChannelNumber(ID_DACC, XDMAD_TRANSFER_TX)); 00165 xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1 00166 | XDMAC_CNDC_NDE_DSCR_FETCH_EN 00167 | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED 00168 | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED; 00169 XDMAD_ConfigureTransfer(pXdmad, dacDmaTxChannel, &xdmadCfg, xdmaCndc, 00170 (uint32_t)&dmaWriteLinkList[0], XDMAC_CIE_LIE); 00171 return DAC_OK; 00172 } 00173 00174 /*---------------------------------------------------------------------------- 00175 * Exported functions 00176 *----------------------------------------------------------------------------*/ 00177 /** 00178 * \brief Initializes the DacDma structure and the corresponding DAC & DMA . 00179 * hardware select value. 00180 * The driver will uses DMA channel 0 for RX . 00181 * The DMA channels are freed automatically when no DMA command processing. 00182 * 00183 * \param pDacd Pointer to a DacDma instance. 00184 * \param pDacHw Associated Dac peripheral. 00185 * \param DacId Dac peripheral identifier. 00186 * \param pDmad Pointer to a Dmad instance. 00187 */ 00188 uint32_t Dac_ConfigureDma(DacDma *pDacd , 00189 Dacc *pDacHw , 00190 uint8_t DacId, 00191 sXdmad *pXdmad) 00192 { 00193 /* Initialize the Dac structure */ 00194 pDacd->pDacHw = pDacHw; 00195 pDacd->dacId = DacId; 00196 pDacd->semaphore = 1; 00197 pDacd->pCurrentCommand = 0; 00198 pDacd->pXdmad = pXdmad; 00199 return 0; 00200 } 00201 00202 /** 00203 * \brief Starts a DAC transfer. This is a non blocking function. It will 00204 * return as soon as the transfer is started. 00205 * 00206 * \param pDacd Pointer to a DacDma instance. 00207 * \param pCommand Pointer to the Dac command to execute. 00208 * \returns 0 if the transfer has been started successfully; otherwise returns 00209 * DAC_ERROR_LOCK is the driver is in use, or DAC_ERROR if the command is not 00210 * valid. 00211 */ 00212 uint32_t Dac_SendData(DacDma *pDacd, DacCmd *pCommand) 00213 { 00214 Dacc *pDacHw = pDacd->pDacHw; 00215 00216 /* Try to get the dataflash semaphore */ 00217 if (pDacd->semaphore == 0) 00218 return DAC_ERROR_LOCK; 00219 00220 pDacd->semaphore--; 00221 00222 // Initialize the callback 00223 pDacd->pCurrentCommand = pCommand; 00224 00225 /* Initialize DMA controller using channel 0 for RX. */ 00226 if (_DacConfigureDmaChannels(pDacd)) 00227 return DAC_ERROR_LOCK; 00228 00229 if (_Dac_configureLinkList(pDacHw, pDacd->pXdmad, pCommand)) 00230 return DAC_ERROR_LOCK; 00231 00232 SCB_CleanDCache(); 00233 00234 /* Start DMA TX */ 00235 if (XDMAD_StartTransfer(pDacd->pXdmad, dacDmaTxChannel)) 00236 return DAC_ERROR_LOCK; 00237 00238 return DAC_OK;; 00239 }