2011-02-17 11:33:15 +08:00
|
|
|
/***************************************************************************//**
|
|
|
|
* @file
|
2011-06-20 09:56:28 +08:00
|
|
|
* @brief Analog to Digital Converter (ADC) Peripheral API for EFM32
|
2011-02-17 11:33:15 +08:00
|
|
|
* @author Energy Micro AS
|
2011-12-27 15:44:29 +08:00
|
|
|
* @version 2.3.2
|
2011-02-17 11:33:15 +08:00
|
|
|
*******************************************************************************
|
|
|
|
* @section License
|
|
|
|
* <b>(C) Copyright 2010 Energy Micro AS, http://www.energymicro.com</b>
|
|
|
|
*******************************************************************************
|
|
|
|
*
|
|
|
|
* This source code is the property of Energy Micro AS. The source and compiled
|
|
|
|
* code may only be used on Energy Micro "EFM32" microcontrollers.
|
|
|
|
*
|
|
|
|
* This copyright notice may not be removed from the source code nor changed.
|
|
|
|
*
|
|
|
|
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
|
|
|
* obligation to support this Software. Energy Micro AS is providing the
|
|
|
|
* Software "AS IS", with no express or implied warranties of any kind,
|
|
|
|
* including, but not limited to, any implied warranties of merchantability
|
|
|
|
* or fitness for any particular purpose or warranties against infringement
|
|
|
|
* of any proprietary rights of a third party.
|
|
|
|
*
|
|
|
|
* Energy Micro AS will not be liable for any consequential, incidental, or
|
|
|
|
* special damages, or any other relief, or for any claim by any third party,
|
|
|
|
* arising from your use of this Software.
|
|
|
|
*
|
|
|
|
******************************************************************************/
|
|
|
|
#include "efm32_adc.h"
|
|
|
|
#include "efm32_cmu.h"
|
|
|
|
#include "efm32_assert.h"
|
|
|
|
|
|
|
|
/***************************************************************************//**
|
|
|
|
* @addtogroup EFM32_Library
|
|
|
|
* @{
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************//**
|
|
|
|
* @addtogroup ADC
|
2011-06-20 09:56:28 +08:00
|
|
|
* @brief Analog to Digital Converter (ADC) Peripheral API for EFM32
|
2011-02-17 11:33:15 +08:00
|
|
|
* @{
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
******************************* DEFINES ***********************************
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
|
|
|
|
|
|
|
/** Validation of ADC register block pointer reference for assert statements. */
|
|
|
|
#define ADC_REF_VALID(ref) ((ref) == ADC0)
|
|
|
|
|
|
|
|
/** Max ADC clock */
|
|
|
|
#define ADC_MAX_CLOCK 13000000
|
|
|
|
|
|
|
|
/** Min ADC clock */
|
|
|
|
#define ADC_MIN_CLOCK 32000
|
|
|
|
|
2011-06-20 09:56:28 +08:00
|
|
|
/** @endcond */
|
2011-02-17 11:33:15 +08:00
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
*************************** LOCAL FUNCTIONS *******************************
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
|
|
|
|
|
|
|
/***************************************************************************//**
|
|
|
|
* @brief
|
|
|
|
* Load SCAN calibrate register with predefined values for a certain
|
|
|
|
* reference.
|
|
|
|
*
|
|
|
|
* @details
|
|
|
|
* During production, calibration values are made and stored in the device
|
|
|
|
* information page for known references. Notice that for external references,
|
|
|
|
* calibration values must be determined explicitly, and this function
|
|
|
|
* will not modify the calibration register.
|
|
|
|
*
|
|
|
|
* @param[in] adc
|
|
|
|
* Pointer to ADC peripheral register block.
|
|
|
|
*
|
|
|
|
* @param[in] ref
|
|
|
|
* Reference to load calibrated values for. No values are loaded for
|
|
|
|
* external references.
|
|
|
|
******************************************************************************/
|
|
|
|
static void ADC_CalibrateLoadScan(ADC_TypeDef *adc, ADC_Ref_TypeDef ref)
|
|
|
|
{
|
|
|
|
uint32_t cal;
|
|
|
|
|
|
|
|
/* Load proper calibration data depending on selected reference */
|
|
|
|
/* NOTE: We use ...SCAN... defines below, they are the same as */
|
|
|
|
/* similar ...SINGLE... defines. */
|
|
|
|
switch (ref)
|
|
|
|
{
|
|
|
|
case adcRef1V25:
|
|
|
|
cal = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
|
|
|
|
cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_GAIN_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
|
|
|
|
cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
|
|
|
|
adc->CAL = cal;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case adcRef2V5:
|
|
|
|
cal = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
|
|
|
|
cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_GAIN_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
|
|
|
|
cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_OFFSET_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
|
|
|
|
adc->CAL = cal;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case adcRefVDD:
|
|
|
|
cal = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
|
|
|
|
cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_GAIN_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
|
|
|
|
cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_OFFSET_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
|
|
|
|
adc->CAL = cal;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case adcRef5VDIFF:
|
|
|
|
cal = adc->CAL & ~(_ADC_CAL_SCANOFFSET_MASK | _ADC_CAL_SCANGAIN_MASK);
|
|
|
|
cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT) << _ADC_CAL_SCANGAIN_SHIFT;
|
|
|
|
cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
|
|
|
|
adc->CAL = cal;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case adcRef2xVDD:
|
|
|
|
/* Gain value not of relevance for this reference, leave as is */
|
|
|
|
cal = adc->CAL & ~_ADC_CAL_SCANOFFSET_MASK;
|
|
|
|
cal |= ((DEVINFO->ADC0CAL2 & _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT) << _ADC_CAL_SCANOFFSET_SHIFT;
|
|
|
|
adc->CAL = cal;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* For external references, the calibration must be determined for the */
|
|
|
|
/* specific application and set explicitly. */
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************//**
|
|
|
|
* @brief
|
|
|
|
* Load SINGLE calibrate register with predefined values for a certain
|
|
|
|
* reference.
|
|
|
|
*
|
|
|
|
* @details
|
|
|
|
* During production, calibration values are made and stored in the device
|
|
|
|
* information page for known references. Notice that for external references,
|
|
|
|
* calibration values must be determined explicitly, and this function
|
|
|
|
* will not modify the calibration register.
|
|
|
|
*
|
|
|
|
* @param[in] adc
|
|
|
|
* Pointer to ADC peripheral register block.
|
|
|
|
*
|
|
|
|
* @param[in] ref
|
|
|
|
* Reference to load calibrated values for. No values are loaded for
|
|
|
|
* external references.
|
|
|
|
******************************************************************************/
|
|
|
|
static void ADC_CalibrateLoadSingle(ADC_TypeDef *adc, ADC_Ref_TypeDef ref)
|
|
|
|
{
|
|
|
|
uint32_t cal;
|
|
|
|
|
|
|
|
/* Load proper calibration data depending on selected reference */
|
|
|
|
/* NOTE: We use ...SCAN... defines below, they are the same as */
|
|
|
|
/* similar ...SINGLE... defines. */
|
|
|
|
switch (ref)
|
|
|
|
{
|
|
|
|
case adcRef1V25:
|
|
|
|
cal = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
|
|
|
|
cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_GAIN_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
|
|
|
|
cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
|
|
|
|
adc->CAL = cal;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case adcRef2V5:
|
|
|
|
cal = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
|
|
|
|
cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_GAIN_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
|
|
|
|
cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_2V5_OFFSET_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
|
|
|
|
adc->CAL = cal;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case adcRefVDD:
|
|
|
|
cal = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
|
|
|
|
cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_GAIN_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
|
|
|
|
cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_VDD_OFFSET_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
|
|
|
|
adc->CAL = cal;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case adcRef5VDIFF:
|
|
|
|
cal = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
|
|
|
|
cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
|
|
|
|
cal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
|
|
|
|
adc->CAL = cal;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case adcRef2xVDD:
|
|
|
|
/* Gain value not of relevance for this reference, leave as is */
|
|
|
|
cal = adc->CAL & ~_ADC_CAL_SINGLEOFFSET_MASK;
|
|
|
|
cal |= ((DEVINFO->ADC0CAL2 & _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
|
|
|
|
adc->CAL = cal;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* For external references, the calibration must be determined for the */
|
|
|
|
/* specific application and set explicitly. */
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-20 09:56:28 +08:00
|
|
|
/** @endcond */
|
2011-02-17 11:33:15 +08:00
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
************************** GLOBAL FUNCTIONS *******************************
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************//**
|
|
|
|
* @brief
|
|
|
|
* Initialize ADC.
|
|
|
|
*
|
|
|
|
* @details
|
|
|
|
* Initializes common parts for both single conversion and scan sequence.
|
|
|
|
* In addition, single and/or scan control configuration must be done, please
|
|
|
|
* refer to ADC_InitSingle() and ADC_InitScan() respectively.
|
|
|
|
*
|
|
|
|
* @note
|
|
|
|
* This function will stop any ongoing conversion.
|
|
|
|
*
|
|
|
|
* @param[in] adc
|
|
|
|
* Pointer to ADC peripheral register block.
|
|
|
|
*
|
|
|
|
* @param[in] init
|
|
|
|
* Pointer to ADC initialization structure.
|
|
|
|
******************************************************************************/
|
|
|
|
void ADC_Init(ADC_TypeDef *adc, const ADC_Init_TypeDef *init)
|
|
|
|
{
|
|
|
|
uint32_t tmp;
|
|
|
|
|
|
|
|
EFM_ASSERT(ADC_REF_VALID(adc));
|
|
|
|
|
|
|
|
/* Make sure conversion is not in progress */
|
|
|
|
adc->CMD = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP;
|
|
|
|
|
|
|
|
tmp = ((uint32_t)(init->ovsRateSel) << _ADC_CTRL_OVSRSEL_SHIFT) |
|
|
|
|
(((uint32_t)(init->timebase) << _ADC_CTRL_TIMEBASE_SHIFT) & _ADC_CTRL_TIMEBASE_MASK) |
|
|
|
|
(((uint32_t)(init->prescale) << _ADC_CTRL_PRESC_SHIFT) & _ADC_CTRL_PRESC_MASK) |
|
|
|
|
((uint32_t)(init->lpfMode) << _ADC_CTRL_LPFMODE_SHIFT) |
|
|
|
|
((uint32_t)(init->warmUpMode) << _ADC_CTRL_WARMUPMODE_SHIFT);
|
|
|
|
|
|
|
|
if (init->tailgate)
|
|
|
|
{
|
|
|
|
tmp |= ADC_CTRL_TAILGATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
adc->CTRL = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************//**
|
|
|
|
* @brief
|
|
|
|
* Initialize ADC scan sequence.
|
|
|
|
*
|
|
|
|
* @details
|
|
|
|
* Please refer to ADC_StartScan() for starting scan sequence.
|
|
|
|
*
|
|
|
|
* When selecting an external reference, the gain and offset calibration
|
|
|
|
* must be set explicitly (CAL register). For other references, the
|
|
|
|
* calibration is updated with values defined during manufacturing.
|
|
|
|
*
|
|
|
|
* @note
|
|
|
|
* This function will stop any ongoing scan sequence.
|
|
|
|
*
|
|
|
|
* @param[in] adc
|
|
|
|
* Pointer to ADC peripheral register block.
|
|
|
|
*
|
|
|
|
* @param[in] init
|
|
|
|
* Pointer to ADC initialization structure.
|
|
|
|
******************************************************************************/
|
|
|
|
void ADC_InitScan(ADC_TypeDef *adc, const ADC_InitScan_TypeDef *init)
|
|
|
|
{
|
|
|
|
uint32_t tmp;
|
|
|
|
|
|
|
|
EFM_ASSERT(ADC_REF_VALID(adc));
|
|
|
|
|
|
|
|
/* Make sure scan sequence is not in progress */
|
|
|
|
adc->CMD = ADC_CMD_SCANSTOP;
|
|
|
|
|
|
|
|
/* Load proper calibration data depending on selected reference */
|
|
|
|
ADC_CalibrateLoadScan(adc, init->reference);
|
|
|
|
|
2011-06-20 09:56:28 +08:00
|
|
|
tmp = ((uint32_t)(init->prsSel) << _ADC_SCANCTRL_PRSSEL_SHIFT) |
|
2011-02-17 11:33:15 +08:00
|
|
|
((uint32_t)(init->acqTime) << _ADC_SCANCTRL_AT_SHIFT) |
|
|
|
|
((uint32_t)(init->reference) << _ADC_SCANCTRL_REF_SHIFT) |
|
|
|
|
init->input |
|
|
|
|
((uint32_t)(init->resolution) << _ADC_SCANCTRL_RES_SHIFT);
|
|
|
|
|
|
|
|
if (init->prsEnable)
|
|
|
|
{
|
|
|
|
tmp |= ADC_SCANCTRL_PRSEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (init->leftAdjust)
|
|
|
|
{
|
|
|
|
tmp |= ADC_SCANCTRL_ADJ_LEFT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (init->diff)
|
|
|
|
{
|
|
|
|
tmp |= ADC_SCANCTRL_DIFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (init->rep)
|
|
|
|
{
|
|
|
|
tmp |= ADC_SCANCTRL_REP;
|
|
|
|
}
|
|
|
|
|
|
|
|
adc->SCANCTRL = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************//**
|
|
|
|
* @brief
|
|
|
|
* Initialize single ADC sample conversion.
|
|
|
|
*
|
|
|
|
* @details
|
|
|
|
* Please refer to ADC_StartSingle() for starting single conversion.
|
|
|
|
*
|
|
|
|
* When selecting an external reference, the gain and offset calibration
|
|
|
|
* must be set explicitly (CAL register). For other references, the
|
|
|
|
* calibration is updated with values defined during manufacturing.
|
|
|
|
*
|
|
|
|
* @note
|
|
|
|
* This function will stop any ongoing single conversion.
|
|
|
|
*
|
|
|
|
* @param[in] adc
|
|
|
|
* Pointer to ADC peripheral register block.
|
|
|
|
*
|
|
|
|
* @param[in] init
|
|
|
|
* Pointer to ADC initialization structure.
|
|
|
|
******************************************************************************/
|
|
|
|
void ADC_InitSingle(ADC_TypeDef *adc, const ADC_InitSingle_TypeDef *init)
|
|
|
|
{
|
|
|
|
uint32_t tmp;
|
|
|
|
|
|
|
|
EFM_ASSERT(ADC_REF_VALID(adc));
|
|
|
|
|
|
|
|
/* Make sure single conversion is not in progress */
|
|
|
|
adc->CMD = ADC_CMD_SINGLESTOP;
|
|
|
|
|
|
|
|
/* Load proper calibration data depending on selected reference */
|
|
|
|
ADC_CalibrateLoadSingle(adc, init->reference);
|
|
|
|
|
|
|
|
tmp = ((uint32_t)(init->prsSel) << _ADC_SINGLECTRL_PRSSEL_SHIFT) |
|
|
|
|
((uint32_t)(init->acqTime) << _ADC_SINGLECTRL_AT_SHIFT) |
|
|
|
|
((uint32_t)(init->reference) << _ADC_SINGLECTRL_REF_SHIFT) |
|
|
|
|
((uint32_t)(init->input) << _ADC_SINGLECTRL_INPUTSEL_SHIFT) |
|
|
|
|
((uint32_t)(init->resolution) << _ADC_SINGLECTRL_RES_SHIFT);
|
|
|
|
|
|
|
|
if (init->prsEnable)
|
|
|
|
{
|
|
|
|
tmp |= ADC_SINGLECTRL_PRSEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (init->leftAdjust)
|
|
|
|
{
|
|
|
|
tmp |= ADC_SINGLECTRL_ADJ_LEFT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (init->diff)
|
|
|
|
{
|
|
|
|
tmp |= ADC_SINGLECTRL_DIFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (init->rep)
|
|
|
|
{
|
|
|
|
tmp |= ADC_SINGLECTRL_REP;
|
|
|
|
}
|
|
|
|
|
|
|
|
adc->SINGLECTRL = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************//**
|
|
|
|
* @brief
|
|
|
|
* Calculate prescaler value used to determine ADC clock.
|
|
|
|
*
|
|
|
|
* @details
|
|
|
|
* The ADC clock is given by: HFPERCLK / (prescale + 1).
|
|
|
|
*
|
|
|
|
* @param[in] adcFreq ADC frequency wanted. The frequency will automatically
|
|
|
|
* be adjusted to be within valid range according to reference manual.
|
|
|
|
*
|
|
|
|
* @param[in] hfperFreq Frequency in Hz of reference HFPER clock. Set to 0 to
|
|
|
|
* use currently defined HFPER clock setting.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* Prescaler value to use for ADC in order to achieve a clock value
|
|
|
|
* <= @p adcFreq.
|
|
|
|
******************************************************************************/
|
|
|
|
uint8_t ADC_PrescaleCalc(uint32_t adcFreq, uint32_t hfperFreq)
|
|
|
|
{
|
|
|
|
uint32_t ret;
|
|
|
|
|
|
|
|
/* Make sure selected ADC clock is within valid range */
|
|
|
|
if (adcFreq > ADC_MAX_CLOCK)
|
|
|
|
{
|
|
|
|
adcFreq = ADC_MAX_CLOCK;
|
|
|
|
}
|
|
|
|
else if (adcFreq < ADC_MIN_CLOCK)
|
|
|
|
{
|
|
|
|
adcFreq = ADC_MIN_CLOCK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use current HFPER frequency? */
|
|
|
|
if (!hfperFreq)
|
|
|
|
{
|
|
|
|
hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = (hfperFreq + adcFreq - 1) / adcFreq;
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
ret--;
|
|
|
|
}
|
|
|
|
|
2011-06-20 09:56:28 +08:00
|
|
|
return (uint8_t)ret;
|
2011-02-17 11:33:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************//**
|
|
|
|
* @brief
|
|
|
|
* Reset ADC to same state as after a HW reset.
|
|
|
|
*
|
|
|
|
* @note
|
|
|
|
* The ROUTE register is NOT reset by this function, in order to allow for
|
|
|
|
* centralized setup of this feature.
|
|
|
|
*
|
|
|
|
* @param[in] adc
|
|
|
|
* Pointer to ADC peripheral register block.
|
|
|
|
******************************************************************************/
|
|
|
|
void ADC_Reset(ADC_TypeDef *adc)
|
|
|
|
{
|
|
|
|
uint32_t cal;
|
|
|
|
|
|
|
|
/* Stop conversions, before resetting other registers. */
|
|
|
|
adc->CMD = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP;
|
|
|
|
adc->SINGLECTRL = _ADC_SINGLECTRL_RESETVALUE;
|
|
|
|
adc->SCANCTRL = _ADC_SCANCTRL_RESETVALUE;
|
|
|
|
adc->CTRL = _ADC_CTRL_RESETVALUE;
|
|
|
|
adc->IEN = _ADC_IEN_RESETVALUE;
|
|
|
|
adc->IFC = _ADC_IFC_MASK;
|
|
|
|
adc->BIASPROG = _ADC_BIASPROG_RESETVALUE;
|
|
|
|
|
|
|
|
cal = adc->CAL & ~(_ADC_CAL_SINGLEOFFSET_MASK | _ADC_CAL_SINGLEGAIN_MASK);
|
|
|
|
cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_GAIN_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT) << _ADC_CAL_SINGLEGAIN_SHIFT;
|
|
|
|
cal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK) >>
|
|
|
|
_DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT) << _ADC_CAL_SINGLEOFFSET_SHIFT;
|
|
|
|
adc->CAL = cal;
|
|
|
|
|
|
|
|
/* Do not reset route register, setting should be done independently */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************//**
|
|
|
|
* @brief
|
|
|
|
* Calculate timebase value in order to get a timebase providing at least 1us.
|
|
|
|
*
|
|
|
|
* @param[in] hfperFreq Frequency in Hz of reference HFPER clock. Set to 0 to
|
|
|
|
* use currently defined HFPER clock setting.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* Timebase value to use for ADC in order to achieve at least 1 us.
|
|
|
|
******************************************************************************/
|
|
|
|
uint8_t ADC_TimebaseCalc(uint32_t hfperFreq)
|
|
|
|
{
|
|
|
|
if (!hfperFreq)
|
|
|
|
{
|
|
|
|
hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
|
|
|
|
|
|
|
|
/* Just in case, make sure we get non-zero freq for below calculation */
|
|
|
|
if (!hfperFreq)
|
|
|
|
{
|
|
|
|
hfperFreq = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine number of HFPERCLK cycle >= 1us */
|
|
|
|
hfperFreq += 999999;
|
|
|
|
hfperFreq /= 1000000;
|
|
|
|
|
|
|
|
/* Return timebase value (N+1 format) */
|
|
|
|
return (uint8_t)(hfperFreq - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** @} (end addtogroup ADC) */
|
|
|
|
/** @} (end addtogroup EFM32_Library) */
|