00001 /* ---------------------------------------------------------------------------- 00002 * SAM Software Package License 00003 * ---------------------------------------------------------------------------- 00004 * Copyright (c) 2014, Atmel Corporation 00005 * 00006 * All rights reserved. 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions are met: 00010 * 00011 * - Redistributions of source code must retain the above copyright notice, 00012 * this list of conditions and the disclaimer below. 00013 * 00014 * Atmel's name may not be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR 00018 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00019 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 00020 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, 00021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00022 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 00023 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00024 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00025 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 00026 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 * ---------------------------------------------------------------------------- 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 if ( dacDmaTxChannel == XDMAD_ALLOC_FAILED ) { 00107 return DAC_ERROR; 00108 } 00109 00110 if ( XDMAD_PrepareChannel( pDacd->pXdmad, dacDmaTxChannel )) 00111 return DAC_ERROR; 00112 return DAC_OK; 00113 } 00114 00115 00116 /** 00117 * \brief Configure the DMA source and destination with Linker List mode. 00118 * 00119 * \param pBuffer Pointer to dac buffer 00120 * \param size length of buffer 00121 */ 00122 00123 static uint8_t _Dac_configureLinkList(Dacc *pDacHw, void *pXdmad, DacCmd *pCommand) 00124 { 00125 uint32_t xdmaCndc; 00126 sXdmadCfg xdmadCfg; 00127 uint32_t * pBuffer; 00128 /* Setup TX Link List */ 00129 uint8_t i; 00130 pBuffer = (uint32_t *)pCommand->pTxBuff; 00131 for(i = 0; i < pCommand->TxSize; i++){ 00132 dmaWriteLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1 00133 | XDMA_UBC_NDE_FETCH_EN 00134 | XDMA_UBC_NSEN_UPDATED 00135 | XDMAC_CUBC_UBLEN(4); 00136 dmaWriteLinkList[i].mbr_sa = (uint32_t)pBuffer; 00137 dmaWriteLinkList[i].mbr_da = 00138 (uint32_t)&(pDacHw->DACC_CDR[pCommand->dacChannel]); 00139 if ( i == (pCommand->TxSize - 1 )) { 00140 if (pCommand->loopback) { 00141 dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[0]; 00142 } else { 00143 dmaWriteLinkList[i].mbr_nda = 0; 00144 } 00145 } else { 00146 dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[i+1]; 00147 } 00148 pBuffer++; 00149 } 00150 xdmadCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN 00151 | XDMAC_CC_MBSIZE_SINGLE 00152 | XDMAC_CC_DSYNC_MEM2PER 00153 | XDMAC_CC_CSIZE_CHK_1 00154 | XDMAC_CC_DWIDTH_WORD 00155 | XDMAC_CC_SIF_AHB_IF0 00156 | XDMAC_CC_DIF_AHB_IF1 00157 | XDMAC_CC_SAM_INCREMENTED_AM 00158 | XDMAC_CC_DAM_FIXED_AM 00159 | XDMAC_CC_PERID( 00160 XDMAIF_Get_ChannelNumber(ID_DACC, XDMAD_TRANSFER_TX )); 00161 xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1 00162 | XDMAC_CNDC_NDE_DSCR_FETCH_EN 00163 | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED 00164 | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED ; 00165 XDMAD_ConfigureTransfer( pXdmad, dacDmaTxChannel, &xdmadCfg, xdmaCndc, 00166 (uint32_t)&dmaWriteLinkList[0], XDMAC_CIE_LIE); 00167 return DAC_OK; 00168 } 00169 00170 /*---------------------------------------------------------------------------- 00171 * Exported functions 00172 *----------------------------------------------------------------------------*/ 00173 /** 00174 * \brief Initializes the DacDma structure and the corresponding DAC & DMA . 00175 * hardware select value. 00176 * The driver will uses DMA channel 0 for RX . 00177 * The DMA channels are freed automatically when no DMA command processing. 00178 * 00179 * \param pDacd Pointer to a DacDma instance. 00180 * \param pDacHw Associated Dac peripheral. 00181 * \param DacId Dac peripheral identifier. 00182 * \param pDmad Pointer to a Dmad instance. 00183 */ 00184 uint32_t Dac_ConfigureDma( DacDma *pDacd , 00185 Dacc *pDacHw , 00186 uint8_t DacId, 00187 sXdmad *pXdmad ) 00188 { 00189 /* Initialize the Dac structure */ 00190 pDacd->pDacHw = pDacHw; 00191 pDacd->dacId = DacId; 00192 pDacd->semaphore = 1; 00193 pDacd->pCurrentCommand = 0; 00194 pDacd->pXdmad = pXdmad; 00195 return 0; 00196 } 00197 00198 /** 00199 * \brief Starts a DAC transfer. This is a non blocking function. It will 00200 * return as soon as the transfer is started. 00201 * 00202 * \param pDacd Pointer to a DacDma instance. 00203 * \param pCommand Pointer to the Dac command to execute. 00204 * \returns 0 if the transfer has been started successfully; otherwise returns 00205 * DAC_ERROR_LOCK is the driver is in use, or DAC_ERROR if the command is not 00206 * valid. 00207 */ 00208 uint32_t Dac_SendData( DacDma *pDacd, DacCmd *pCommand) 00209 { 00210 Dacc *pDacHw = pDacd->pDacHw; 00211 00212 /* Try to get the dataflash semaphore */ 00213 if (pDacd->semaphore == 0) { 00214 return DAC_ERROR_LOCK; 00215 } 00216 pDacd->semaphore--; 00217 00218 // Initialize the callback 00219 pDacd->pCurrentCommand = pCommand; 00220 00221 /* Initialize DMA controller using channel 0 for RX. */ 00222 if (_DacConfigureDmaChannels(pDacd) ) 00223 return DAC_ERROR_LOCK; 00224 00225 if (_Dac_configureLinkList(pDacHw, pDacd->pXdmad, pCommand)) 00226 return DAC_ERROR_LOCK; 00227 00228 SCB_CleanDCache(); 00229 00230 /* Start DMA TX */ 00231 if (XDMAD_StartTransfer( pDacd->pXdmad, dacDmaTxChannel )) 00232 return DAC_ERROR_LOCK; 00233 return DAC_OK;; 00234 }