/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2009, 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 adc_module Working with ADC
* The ADC driver provides the interface to configure and use the ADC peripheral.
* \n
*
* It converts the analog input to digital format. The converted result could be
* 12bit or 10bit. The ADC supports up to 16 analog lines.
*
* To Enable a ADC conversion,the user has to follow these few steps:
*
* - Select an appropriate reference voltage on ADVREF
* - Configure the ADC according to its requirements and special needs,which
* could be broken down into several parts:
* -# Select the resolution by setting or clearing ADC_MR_LOWRES bit in
* ADC_MR (Mode Register)
* -# Set ADC clock by setting ADC_MR_PRESCAL bits in ADC_MR, the clock is
* calculated with ADCClock = MCK / ( (PRESCAL+1) * 2 )
* -# Set Startup Time,Tracking Clock cycles and Transfer Clock respectively
* in ADC_MR.
* - Start conversion by setting ADC_CR_START in ADC_CR.
*
*
* For more accurate information, please look at the ADC section of the
* Datasheet.
*
* Related files :\n
* \ref adc.c\n
* \ref adc.h\n
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include
#include
#include
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Initialize the ADC controller
* \param pAdc Pointer to an Adc instance.
* \param trgEn trigger mode, software or Hardware
* \param trgSel hardware trigger selection
* \param sleepMode sleep mode selection
* \param resolution resolution selection 10 bits or 12 bits
* \param mckClock value of MCK in Hz
* \param adcClock value of the ADC clock in Hz
* \param startupTime value of the start up time (in ADCClock) (see datasheet)
* \param trackingt Tracking Time (in ADCClock cycle)
*/
void ADC_Initialize(Adc *pAdc, uint8_t idAdc, uint8_t trgEn, uint8_t trgSel,
uint8_t sleepMode, uint8_t resolution, uint32_t mckClock,
uint32_t adcClock, uint32_t startup, uint32_t tracking) {
uint32_t prescal;
prescal = (mckClock / (2*adcClock)) - 1;
ASSERT( (prescal<0x3F), "ADC Bad PRESCAL\n\r");
TRACE_DEBUG("adcClock:%lu MasterClock:%lu\n\r", (mckClock/((prescal+1)*2)),
mckClock);
if( adcClock != (mckClock/((prescal+1)*2)) ) {
TRACE_WARNING("User and calculated adcClocks are different : "
"user=%lu calc=%lu\n\r",
adcClock, (mckClock/((prescal+1)*2)));
}
/* Enable peripheral clock*/
PMC->PMC_PCER0 = 1 << idAdc;
/* Reset the controller */
ADC_SoftReset(pAdc);
/* Write to the MR register */
ADC_CfgModeReg( pAdc,
( trgEn & ADC_MR_TRGEN)
| ( trgSel & ADC_MR_TRGSEL)
| ( resolution & ADC_MR_LOWRES)
| ( sleepMode & ADC_MR_SLEEP)
| ( (prescal<<8) & ADC_MR_PRESCAL)
| ( (startup<<16) & ADC_MR_STARTUP)
| ( (tracking<<24) & ADC_MR_TRACKTIM) );
}
/**
* Return the Channel Converted Data
* \param pAdc Pointer to an Adc instance.
* \param channel channel to get converted value
*/
uint32_t ADC_GetConvertedData(Adc *pAdc, uint32_t channel) {
uint32_t data=0;
if (15 >= channel) {
data = *((RoReg *)((uint32_t)&(pAdc->ADC_CDR0)+ channel*4));
}
return data;
}
/**
* Set compare channel
* \param pAdc Pointer to an Adc instance.
* \param channel channel number to be set,16 for all channels
*/
void ADC_SetCompareChannel(Adc *pAdc, uint8_t channel) {
ASSERT(channel<=16, "Invalid channel number");
if (channel < 16) {
pAdc->ADC_EMR &= ~(ADC_EMR_CMPALL);
pAdc->ADC_EMR &= ~(ADC_EMR_CMPSEL);
pAdc->ADC_EMR |= (channel << 4);
} else {
pAdc->ADC_EMR |= ADC_EMR_CMPALL;
}
}
/**
* Set compare mode
* \param pAdc Pointer to an Adc instance.
* \param mode compare mode
*/
void ADC_SetCompareMode(Adc *pAdc, uint8_t mode) {
pAdc->ADC_EMR &= ~(ADC_EMR_CMPMODE);
pAdc->ADC_EMR |= mode;
}
/**
* Set comparsion window,one thereshold each time
* \param pAdc Pointer to an Adc instance.
* \param hi_lo Comparison Window
*/
void ADC_SetComparisonWindow(Adc *pAdc, uint32_t hi_lo) {
pAdc->ADC_CWR = hi_lo;
}
/**----------------------------------------------------------------------------
* Test if ADC Interrupt is Masked
* \param pAdc Pointer to an Adc instance.
* \param flag flag to be tested
* \return 1 if interrupt is masked, otherwise 0
*/
uint32_t ADC_IsInterruptMasked(Adc *pAdc, uint32_t flag) {
return (ADC_GetInterruptMaskStatus(pAdc) & flag);
}
/**----------------------------------------------------------------------------
* Test if ADC Status is Set
* \param pAdc Pointer to an Adc instance.
* \param flag flag to be tested
* \return 1 if the staus is set; 0 otherwise
*/
uint32_t ADC_IsStatusSet(Adc *pAdc, uint32_t flag) {
return (ADC_GetStatus(pAdc) & flag);
}
/**----------------------------------------------------------------------------
* Test if ADC channel interrupt Status is Set
* \param adc_sr Value of SR register
* \param channel Channel to be tested
* \return 1 if interrupt status is set, otherwise 0
*/
uint8_t ADC_IsChannelInterruptStatusSet(uint32_t adc_sr, uint32_t channel) {
uint8_t status;
if((adc_sr & (1<ADC_RCR == 0) && (pADC->ADC_RNCR == 0)) {
pADC->ADC_RPR = (uint32_t) pBuffer;
pADC->ADC_RCR = size;
pADC->ADC_PTCR = ADC_PTCR_RXTEN;
return 1;
}
/* Check if the second PDC bank is free*/
else if (pADC->ADC_RNCR == 0) {
pADC->ADC_RNPR = (uint32_t) pBuffer;
pADC->ADC_RNCR = size;
return 1;
} else {
return 0;
}
}