added prescaler for 16 bit pwm in LPC1347 target
Fork of mbed-dev by
Diff: targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_adc.c
- Revision:
- 50:a417edff4437
- Parent:
- 0:9b334a45a8ff
- Child:
- 144:ef7eb2e8f9f7
--- a/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_adc.c Wed Jan 13 12:45:11 2016 +0000 +++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_adc.c Fri Jan 15 07:45:16 2016 +0000 @@ -1,10 +1,10 @@ /***************************************************************************//** * @file em_adc.c * @brief Analog to Digital Converter (ADC) Peripheral API - * @version 3.20.12 + * @version 4.2.1 ******************************************************************************* * @section License - * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b> + * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b> ******************************************************************************* * * Permission is granted to anyone to use this software for any purpose, @@ -30,12 +30,12 @@ * ******************************************************************************/ - #include "em_adc.h" -#if defined(ADC_COUNT) && (ADC_COUNT > 0) +#if defined( ADC_COUNT ) && ( ADC_COUNT > 0 ) #include "em_cmu.h" #include "em_assert.h" +#include <stddef.h> /***************************************************************************//** * @addtogroup EM_Library @@ -58,11 +58,124 @@ #define ADC_REF_VALID(ref) ((ref) == ADC0) /** Max ADC clock */ +#if defined( _SILICON_LABS_32B_PLATFORM_1 ) #define ADC_MAX_CLOCK 13000000 +#else +#define ADC_MAX_CLOCK 16000000 +#endif /** Min ADC clock */ #define ADC_MIN_CLOCK 32000 +/** Helper defines for selecting ADC calibration and DEVINFO register fields. */ +#if defined( _DEVINFO_ADC0CAL0_1V25_GAIN_MASK ) +#define DEVINFO_ADC0_GAIN1V25_MASK _DEVINFO_ADC0CAL0_1V25_GAIN_MASK +#elif defined( _DEVINFO_ADC0CAL0_GAIN1V25_MASK ) +#define DEVINFO_ADC0_GAIN1V25_MASK _DEVINFO_ADC0CAL0_GAIN1V25_MASK +#endif + +#if defined( _DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT ) +#define DEVINFO_ADC0_GAIN1V25_SHIFT _DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT +#elif defined( _DEVINFO_ADC0CAL0_GAIN1V25_SHIFT ) +#define DEVINFO_ADC0_GAIN1V25_SHIFT _DEVINFO_ADC0CAL0_GAIN1V25_SHIFT +#endif + +#if defined( _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK ) +#define DEVINFO_ADC0_OFFSET1V25_MASK _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK +#elif defined( _DEVINFO_ADC0CAL0_OFFSET1V25_MASK ) +#define DEVINFO_ADC0_OFFSET1V25_MASK _DEVINFO_ADC0CAL0_OFFSET1V25_MASK +#endif + +#if defined( _DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT ) +#define DEVINFO_ADC0_OFFSET1V25_SHIFT _DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT +#elif defined( _DEVINFO_ADC0CAL0_OFFSET1V25_SHIFT ) +#define DEVINFO_ADC0_OFFSET1V25_SHIFT _DEVINFO_ADC0CAL0_OFFSET1V25_SHIFT +#endif + +#if defined( _DEVINFO_ADC0CAL0_2V5_GAIN_MASK ) +#define DEVINFO_ADC0_GAIN2V5_MASK _DEVINFO_ADC0CAL0_2V5_GAIN_MASK +#elif defined( _DEVINFO_ADC0CAL0_GAIN2V5_MASK ) +#define DEVINFO_ADC0_GAIN2V5_MASK _DEVINFO_ADC0CAL0_GAIN2V5_MASK +#endif + +#if defined( _DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT ) +#define DEVINFO_ADC0_GAIN2V5_SHIFT _DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT +#elif defined( _DEVINFO_ADC0CAL0_GAIN2V5_SHIFT ) +#define DEVINFO_ADC0_GAIN2V5_SHIFT _DEVINFO_ADC0CAL0_GAIN2V5_SHIFT +#endif + +#if defined( _DEVINFO_ADC0CAL0_2V5_OFFSET_MASK ) +#define DEVINFO_ADC0_OFFSET2V5_MASK _DEVINFO_ADC0CAL0_2V5_OFFSET_MASK +#elif defined( _DEVINFO_ADC0CAL0_OFFSET2V5_MASK ) +#define DEVINFO_ADC0_OFFSET2V5_MASK _DEVINFO_ADC0CAL0_OFFSET2V5_MASK +#endif + +#if defined( _DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT ) +#define DEVINFO_ADC0_OFFSET2V5_SHIFT _DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT +#elif defined( _DEVINFO_ADC0CAL0_OFFSET2V5_SHIFT ) +#define DEVINFO_ADC0_OFFSET2V5_SHIFT _DEVINFO_ADC0CAL0_OFFSET2V5_SHIFT +#endif + +#if defined( _DEVINFO_ADC0CAL1_VDD_GAIN_MASK ) +#define DEVINFO_ADC0_GAINVDD_MASK _DEVINFO_ADC0CAL1_VDD_GAIN_MASK +#elif defined( _DEVINFO_ADC0CAL1_GAINVDD_MASK ) +#define DEVINFO_ADC0_GAINVDD_MASK _DEVINFO_ADC0CAL1_GAINVDD_MASK +#endif + +#if defined( _DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT ) +#define DEVINFO_ADC0_GAINVDD_SHIFT _DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT +#elif defined( _DEVINFO_ADC0CAL1_GAINVDD_SHIFT ) +#define DEVINFO_ADC0_GAINVDD_SHIFT _DEVINFO_ADC0CAL1_GAINVDD_SHIFT +#endif + +#if defined( _DEVINFO_ADC0CAL1_VDD_OFFSET_MASK ) +#define DEVINFO_ADC0_OFFSETVDD_MASK _DEVINFO_ADC0CAL1_VDD_OFFSET_MASK +#elif defined( _DEVINFO_ADC0CAL1_OFFSETVDD_MASK ) +#define DEVINFO_ADC0_OFFSETVDD_MASK _DEVINFO_ADC0CAL1_OFFSETVDD_MASK +#endif + +#if defined( _DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT ) +#define DEVINFO_ADC0_OFFSETVDD_SHIFT _DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT +#elif defined( _DEVINFO_ADC0CAL1_OFFSETVDD_SHIFT ) +#define DEVINFO_ADC0_OFFSETVDD_SHIFT _DEVINFO_ADC0CAL1_OFFSETVDD_SHIFT +#endif + +#if defined( _DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK ) +#define DEVINFO_ADC0_GAIN5VDIFF_MASK _DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK +#elif defined( _DEVINFO_ADC0CAL1_GAIN5VDIFF_MASK ) +#define DEVINFO_ADC0_GAIN5VDIFF_MASK _DEVINFO_ADC0CAL1_GAIN5VDIFF_MASK +#endif + +#if defined( _DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT ) +#define DEVINFO_ADC0_GAIN5VDIFF_SHIFT _DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT +#elif defined( _DEVINFO_ADC0CAL1_GAIN5VDIFF_SHIFT ) +#define DEVINFO_ADC0_GAIN5VDIFF_SHIFT _DEVINFO_ADC0CAL1_GAIN5VDIFF_SHIFT +#endif + +#if defined( _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK ) +#define DEVINFO_ADC0_OFFSET5VDIFF_MASK _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK +#elif defined( _DEVINFO_ADC0CAL1_OFFSET5VDIFF_MASK ) +#define DEVINFO_ADC0_OFFSET5VDIFF_MASK _DEVINFO_ADC0CAL1_OFFSET5VDIFF_MASK +#endif + +#if defined( _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT ) +#define DEVINFO_ADC0_OFFSET5VDIFF_SHIFT _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT +#elif defined( _DEVINFO_ADC0CAL1_OFFSET5VDIFF_SHIFT ) +#define DEVINFO_ADC0_OFFSET5VDIFF_SHIFT _DEVINFO_ADC0CAL1_OFFSET5VDIFF_SHIFT +#endif + +#if defined( _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK ) +#define DEVINFO_ADC0_OFFSET2XVDD_MASK _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK +#elif defined( _DEVINFO_ADC0CAL2_OFFSET2XVDD_MASK ) +#define DEVINFO_ADC0_OFFSET2XVDD_MASK _DEVINFO_ADC0CAL2_OFFSET2XVDD_MASK +#endif + +#if defined( _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT ) +#define DEVINFO_ADC0_OFFSET2XVDD_SHIFT _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT +#elif defined( _DEVINFO_ADC0CAL2_OFFSET2XVDD_SHIFT ) +#define DEVINFO_ADC0_OFFSET2XVDD_SHIFT _DEVINFO_ADC0CAL2_OFFSET2XVDD_SHIFT +#endif + /** @endcond */ @@ -74,14 +187,13 @@ /***************************************************************************//** * @brief - * Load SCAN calibrate register with predefined values for a certain - * reference. + * Load ADC calibration register for a selected reference and conversion mode. * * @details - * During production, calibration values are made and stored in the device - * information page for known references. Notice that for external references, + * During production, calibration values are stored in the device + * information page for internal references. Notice that for external references, * calibration values must be determined explicitly, and this function - * will not modify the calibration register. + * will not modify the calibration register for external references. * * @param[in] adc * Pointer to ADC peripheral register block. @@ -89,143 +201,135 @@ * @param[in] ref * Reference to load calibrated values for. No values are loaded for * external references. + * + * @param[in] setScanCal + * Select scan mode (true) or single mode (false) calibration load. ******************************************************************************/ -static void ADC_CalibrateLoadScan(ADC_TypeDef *adc, ADC_Ref_TypeDef ref) +static void ADC_LoadDevinfoCal(ADC_TypeDef *adc, + ADC_Ref_TypeDef ref, + bool setScanCal) { - uint32_t cal; + uint32_t calReg; + uint32_t newCal; + uint32_t mask; + uint32_t shift; - /* Load proper calibration data depending on selected reference */ - /* NOTE: We use ...SCAN... defines below, they are the same as */ - /* similar ...SINGLE... defines. */ + if (setScanCal) + { + shift = _ADC_CAL_SCANOFFSET_SHIFT; + mask = ~(_ADC_CAL_SCANOFFSET_MASK +#if defined( _ADC_CAL_SCANOFFSETINV_MASK ) + | _ADC_CAL_SCANOFFSETINV_MASK +#endif + | _ADC_CAL_SCANGAIN_MASK); + } + else + { + shift = _ADC_CAL_SINGLEOFFSET_SHIFT; + mask = ~(_ADC_CAL_SINGLEOFFSET_MASK +#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK ) + | _ADC_CAL_SINGLEOFFSETINV_MASK +#endif + | _ADC_CAL_SINGLEGAIN_MASK); + } + + calReg = adc->CAL & mask; + newCal = 0; + 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 adcRef1V25: + newCal |= ((DEVINFO->ADC0CAL0 & DEVINFO_ADC0_GAIN1V25_MASK) + >> DEVINFO_ADC0_GAIN1V25_SHIFT) + << _ADC_CAL_SINGLEGAIN_SHIFT; + newCal |= ((DEVINFO->ADC0CAL0 & DEVINFO_ADC0_OFFSET1V25_MASK) + >> DEVINFO_ADC0_OFFSET1V25_SHIFT) + << _ADC_CAL_SINGLEOFFSET_SHIFT; +#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK ) + newCal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_NEGSEOFFSET1V25_MASK) + >> _DEVINFO_ADC0CAL0_NEGSEOFFSET1V25_SHIFT) + << _ADC_CAL_SINGLEOFFSETINV_SHIFT; +#endif + 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 adcRef2V5: + newCal |= ((DEVINFO->ADC0CAL0 & DEVINFO_ADC0_GAIN2V5_MASK) + >> DEVINFO_ADC0_GAIN2V5_SHIFT) + << _ADC_CAL_SINGLEGAIN_SHIFT; + newCal |= ((DEVINFO->ADC0CAL0 & DEVINFO_ADC0_OFFSET2V5_MASK) + >> DEVINFO_ADC0_OFFSET2V5_SHIFT) + << _ADC_CAL_SINGLEOFFSET_SHIFT; +#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK ) + newCal |= ((DEVINFO->ADC0CAL0 & _DEVINFO_ADC0CAL0_NEGSEOFFSET2V5_MASK) + >> _DEVINFO_ADC0CAL0_NEGSEOFFSET2V5_SHIFT) + << _ADC_CAL_SINGLEOFFSETINV_SHIFT; +#endif + 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; - } -} + case adcRefVDD: + newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_GAINVDD_MASK) + >> DEVINFO_ADC0_GAINVDD_SHIFT) + << _ADC_CAL_SINGLEGAIN_SHIFT; + newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_OFFSETVDD_MASK) + >> DEVINFO_ADC0_OFFSETVDD_SHIFT) + << _ADC_CAL_SINGLEOFFSET_SHIFT; +#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK ) + newCal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_MASK) + >> _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_SHIFT) + << _ADC_CAL_SINGLEOFFSETINV_SHIFT; +#endif + 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 adcRef5VDIFF: + newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_GAIN5VDIFF_MASK) + >> DEVINFO_ADC0_GAIN5VDIFF_SHIFT) + << _ADC_CAL_SINGLEGAIN_SHIFT; + newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_OFFSET5VDIFF_MASK) + >> DEVINFO_ADC0_OFFSET5VDIFF_SHIFT) + << _ADC_CAL_SINGLEOFFSET_SHIFT; +#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK ) + newCal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_NEGSEOFFSET5VDIFF_MASK) + >> _DEVINFO_ADC0CAL1_NEGSEOFFSET5VDIFF_SHIFT) + << _ADC_CAL_SINGLEOFFSETINV_SHIFT; +#endif + 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 adcRef2xVDD: + /* There is no gain calibration for this reference */ + newCal |= ((DEVINFO->ADC0CAL2 & DEVINFO_ADC0_OFFSET2XVDD_MASK) + >> DEVINFO_ADC0_OFFSET2XVDD_SHIFT) + << _ADC_CAL_SINGLEOFFSET_SHIFT; +#if defined( _ADC_CAL_SINGLEOFFSETINV_MASK ) + newCal |= ((DEVINFO->ADC0CAL2 & _DEVINFO_ADC0CAL2_NEGSEOFFSET2XVDD_MASK) + >> _DEVINFO_ADC0CAL2_NEGSEOFFSET2XVDD_SHIFT) + << _ADC_CAL_SINGLEOFFSETINV_SHIFT; +#endif + 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; +#if defined( _ADC_SINGLECTRLX_VREFSEL_VDDXWATT ) + case adcRefVddxAtt: + newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_GAINVDD_MASK) + >> DEVINFO_ADC0_GAINVDD_SHIFT) + << _ADC_CAL_SINGLEGAIN_SHIFT; + newCal |= ((DEVINFO->ADC0CAL1 & DEVINFO_ADC0_OFFSETVDD_MASK) + >> DEVINFO_ADC0_OFFSETVDD_SHIFT) + << _ADC_CAL_SINGLEOFFSET_SHIFT; + newCal |= ((DEVINFO->ADC0CAL1 & _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_MASK) + >> _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_SHIFT) + << _ADC_CAL_SINGLEOFFSETINV_SHIFT; + break; +#endif - 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 by the user. Calibration data is also not + available for the internal references adcRefVBGR, adcRefVEntropy and + adcRefVBGRlow. */ + default: + newCal = 0; + break; + } - /* For external references, the calibration must be determined for the */ - /* specific application and set explicitly. */ - default: - break; - } + adc->CAL = calReg | (newCal << shift); } /** @endcond */ @@ -243,6 +347,10 @@ * In addition, single and/or scan control configuration must be done, please * refer to ADC_InitSingle() and ADC_InitScan() respectively. * + * On ADC architectures with the ADCn->SCANCHCONF register, + * ADC_ScanSingleEndedInit() and ADC_ScanDifferentialInit() can be used to + * assist scan conversion input setup. + * * @note * This function will stop any ongoing conversion. * @@ -261,23 +369,295 @@ /* 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); + 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) +#if defined ( _ADC_CTRL_LPFMODE_MASK ) + | ((uint32_t)(init->lpfMode) << _ADC_CTRL_LPFMODE_SHIFT) +#endif + | ((uint32_t)(init->warmUpMode) << _ADC_CTRL_WARMUPMODE_SHIFT); if (init->tailgate) { tmp |= ADC_CTRL_TAILGATE; } + adc->CTRL = tmp; - adc->CTRL = tmp; + /* Set ADC EM2 clock configuration */ +#if defined( _ADC_CTRL_ADCCLKMODE_MASK ) + BUS_RegMaskedWrite(&ADC0->CTRL, + _ADC_CTRL_ADCCLKMODE_MASK | _ADC_CTRL_ASYNCCLKEN_MASK, + init->em2ClockConfig << _ADC_CTRL_ASYNCCLKEN_SHIFT); +#endif + +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) + /* Fix for errata ADC_EXXX */ + ADC_IntClear(adc, ADC_IFC_SCANUF); +#endif +} + + +#if defined( _ADC_SCANINPUTSEL_MASK ) +/***************************************************************************//** + * @brief + * Clear ADC scan input configuration. + * + * @param[in] scanInit + * Struct to hold the scan configuration, input configuration. + ******************************************************************************/ +void ADC_ScanInputClear(ADC_InitScan_TypeDef *scanInit) +{ + /* Clear input configuration */ + + /* Select none */ + scanInit->scanInputConfig.scanInputSel = 0xFFFFFFFF; + scanInit->scanInputConfig.scanInputEn = 0; + + /* Default alternative negative inputs */ + scanInit->scanInputConfig.scanNegSel = _ADC_SCANNEGSEL_RESETVALUE; +} + + +/***************************************************************************//** + * @brief + * Initialize ADC scan single-ended input configuration. + * + * @details + * Set configuration for ADC scan conversion with single-ended inputs. The + * ADC_InitScan_TypeDef struct updated from this function should be passed to + * ADC_InitScan(). + * + * @param[in] inputGroup + * ADC scan input group. See section 25.3.4 in the reference manual for + * more information. + * + * @param[in] singleEndedSel + * APORT select. + * + * @return + * Scan ID of selected ADC input. ee section 25.3.4 in the reference manual for + * more information. Note that the returned integer represents the bit position + * in ADCn_SCANMASK set by this function. The accumulated mask is stored in + * scanInit->scanInputConfig->scanInputEn. + ******************************************************************************/ +uint32_t ADC_ScanSingleEndedInputAdd(ADC_InitScan_TypeDef *scanInit, + ADC_ScanInputGroup_TypeDef inputGroup, + ADC_PosSel_TypeDef singleEndedSel) +{ + uint32_t currentSel; + uint32_t newSel; + uint32_t scanId; + + scanInit->diff = false; + + /* Check for unsupported APORTs */ + EFM_ASSERT((singleEndedSel <= adcPosSelAPORT0YCH0) || (singleEndedSel >= adcPosSelAPORT0YCH15)); + + /* Decode the input group select by shifting right by 3 */ + newSel = singleEndedSel >> 3; + + currentSel = (scanInit->scanInputConfig.scanInputSel >> (inputGroup * 8)) & 0xFF; + + /* If none selected */ + if (currentSel == 0xFF) + { + scanInit->scanInputConfig.scanInputSel &= ~(0xFF << (inputGroup * 8)); + scanInit->scanInputConfig.scanInputSel |= (newSel << (inputGroup * 8)); + } + else if (currentSel == newSel) + { + /* Ok, but do nothing. */ + } + else + { + /* Invalid channel range. A range is already selected for this group. */ + EFM_ASSERT(false); + } + + /* Update and return scan input enable mask (SCANMASK) */ + scanId = (inputGroup * 8) + (singleEndedSel & 0x7); + EFM_ASSERT(scanId < 32); + scanInit->scanInputConfig.scanInputEn |= 0x1 << scanId; + return scanId; } /***************************************************************************//** * @brief + * Initialize ADC scan differential input configuration. + * + * @details + * Set configuration for ADC scan conversion with differential inputs. The + * ADC_InitScan_TypeDef struct updated by this function should be passed to + * ADC_InitScan(). + * + * @param[in] scanInit + * Struct to hold the scan and input configuration. + * + * @param[in] inputGroup + * ADC scan input group. See section 25.3.4 in the reference manual for + * more information. + * + * @param[in] posSel + * APORT bus pair select. The negative terminal is implicitly selected by + * the positive terminal. + * + * @param[in] negInput + * ADC scan alternative negative input. Set to adcScanNegInputDefault to select + * default negative input (implicit from posSel). + * + * @return + * Scan ID of selected ADC input. ee section 25.3.4 in the reference manual for + * more information. Note that the returned integer represents the bit position + * in ADCn_SCANMASK set by this function. The accumulated mask is stored in + * scanInit->scanInputConfig->scanInputEn. + ******************************************************************************/ +uint32_t ADC_ScanDifferentialInputAdd(ADC_InitScan_TypeDef *scanInit, + ADC_ScanInputGroup_TypeDef inputGroup, + ADC_PosSel_TypeDef posSel, + ADC_ScanNegInput_TypeDef negInput) +{ + uint32_t negInputRegMask = 0; + uint32_t negInputRegShift = 0; + uint32_t negInputRegVal = 0; + uint32_t scanId = 0; + + /* Do a single ended init, then update for differential scan. */ + scanId = ADC_ScanSingleEndedInputAdd(scanInit, inputGroup, posSel); + + /* Reset to differential mode */ + scanInit->diff = true; + + /* Set negative ADC input, unless the default is selected. */ + if (negInput != adcScanNegInputDefault) + { + if (scanId == 0) + { + negInputRegMask = _ADC_SCANNEGSEL_INPUT0NEGSEL_MASK; + negInputRegShift = _ADC_SCANNEGSEL_INPUT0NEGSEL_SHIFT; + EFM_ASSERT(inputGroup == 0); + } + else if (scanId == 2) + { + negInputRegMask = _ADC_SCANNEGSEL_INPUT2NEGSEL_MASK; + negInputRegShift = _ADC_SCANNEGSEL_INPUT2NEGSEL_SHIFT; + EFM_ASSERT(inputGroup == 0); + } + else if (scanId == 4) + { + negInputRegMask = _ADC_SCANNEGSEL_INPUT4NEGSEL_MASK; + negInputRegShift = _ADC_SCANNEGSEL_INPUT4NEGSEL_SHIFT; + EFM_ASSERT(inputGroup == 0); + } + else if (scanId == 6) + { + negInputRegMask = _ADC_SCANNEGSEL_INPUT6NEGSEL_MASK; + negInputRegShift = _ADC_SCANNEGSEL_INPUT6NEGSEL_SHIFT; + EFM_ASSERT(inputGroup == 0); + } + else if (scanId == 9) + { + negInputRegMask = _ADC_SCANNEGSEL_INPUT9NEGSEL_MASK; + negInputRegShift = _ADC_SCANNEGSEL_INPUT9NEGSEL_SHIFT; + EFM_ASSERT(inputGroup == 1); + } + else if (scanId == 11) + { + negInputRegMask = _ADC_SCANNEGSEL_INPUT11NEGSEL_MASK; + negInputRegShift = _ADC_SCANNEGSEL_INPUT11NEGSEL_SHIFT; + EFM_ASSERT(inputGroup == 1); + } + else if (scanId == 13) + { + negInputRegMask = _ADC_SCANNEGSEL_INPUT13NEGSEL_MASK; + negInputRegShift = _ADC_SCANNEGSEL_INPUT13NEGSEL_SHIFT; + EFM_ASSERT(inputGroup == 1); + } + else if (scanId == 15) + { + negInputRegMask = _ADC_SCANNEGSEL_INPUT15NEGSEL_MASK; + negInputRegShift = _ADC_SCANNEGSEL_INPUT15NEGSEL_SHIFT; + EFM_ASSERT(inputGroup == 1); + } + else + { + /* There is not negative input option for this positive input (negInput is posInput + 1). */ + EFM_ASSERT(false); + } + + /* Find ADC_SCANNEGSEL_CHxNSEL value for positive input 0, 2, 4 and 6 */ + if (inputGroup == 0) + { + switch (negInput) + { + case adcScanNegInput1: + negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT1; + break; + + case adcScanNegInput3: + negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT3; + break; + + case adcScanNegInput5: + negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT5; + break; + + case adcScanNegInput7: + negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT7; + break; + + default: + /* Invalid selection. Options are input 1, 3, 5 and 7. */ + EFM_ASSERT(false); + break; + } + } + else if (inputGroup == 1) + { + /* Find ADC_SCANNEGSEL_CHxNSEL value for positive input 9, 11, 13 and 15 */ + switch (negInput) + { + case adcScanNegInput8: + negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT8; + break; + + case adcScanNegInput10: + negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT10; + break; + + case adcScanNegInput12: + negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT12; + break; + + case adcScanNegInput14: + negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT14; + break; + + default: + /* Invalid selection. Options are input 8, 10, 12 and 14. */ + EFM_ASSERT(false); + break; + } + } + else + { + /* No alternative negative input for input group > 1 */ + EFM_ASSERT(false); + } + + /* Update config */ + scanInit->scanInputConfig.scanNegSel &= ~negInputRegMask; + scanInit->scanInputConfig.scanNegSel |= negInputRegVal << negInputRegShift; + } + return scanId; +} +#endif + + +/***************************************************************************//** + * @brief * Initialize ADC scan sequence. * * @details @@ -305,14 +685,18 @@ /* 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); + /* Load calibration data for selected reference */ + ADC_LoadDevinfoCal(adc, init->reference, true); - tmp = ((uint32_t)(init->prsSel) << _ADC_SCANCTRL_PRSSEL_SHIFT) | - ((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); + tmp = 0 +#if defined ( _ADC_SCANCTRL_PRSSEL_MASK ) + | (init->prsSel << _ADC_SCANCTRL_PRSSEL_SHIFT) +#endif + | (init->acqTime << _ADC_SCANCTRL_AT_SHIFT) +#if defined ( _ADC_SCANCTRL_INPUTMASK_MASK ) + | init->input +#endif + | (init->resolution << _ADC_SCANCTRL_RES_SHIFT); if (init->prsEnable) { @@ -324,17 +708,82 @@ tmp |= ADC_SCANCTRL_ADJ_LEFT; } +#if defined( _ADC_SCANCTRL_INPUTMASK_MASK ) if (init->diff) +#elif defined( _ADC_SCANINPUTSEL_MASK ) + if (init->diff) +#endif { tmp |= ADC_SCANCTRL_DIFF; } if (init->rep) { +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) + /* Scan repeat mode does not work on platform 2 as described in errata ADC_EXXX. */ + EFM_ASSERT(false); +#endif tmp |= ADC_SCANCTRL_REP; } + /* Set scan reference. Check if reference configuraion is extended to SCANCTRLX. */ +#if defined ( _ADC_SCANCTRLX_VREFSEL_MASK ) + if (init->reference & ADC_CTRLX_VREFSEL_REG) + { + /* Select extension register */ + tmp |= ADC_SCANCTRL_REF_CONF; + } + else + { + tmp |= init->reference << _ADC_SCANCTRL_REF_SHIFT; + } +#else + tmp |= init->reference << _ADC_SCANCTRL_REF_SHIFT; +#endif + +#if defined( _ADC_SCANCTRL_INPUTMASK_MASK ) + tmp |= init->input; +#endif + adc->SCANCTRL = tmp; + + /* Update SINGLECTRLX for reference select and PRS select */ +#if defined ( _ADC_SCANCTRLX_MASK ) + tmp = adc->SCANCTRLX & ~(_ADC_SCANCTRLX_VREFSEL_MASK + | _ADC_SCANCTRLX_PRSSEL_MASK + | _ADC_SCANCTRLX_FIFOOFACT_MASK); + if (init->reference & ADC_CTRLX_VREFSEL_REG) + { + tmp |= (init->reference & ~ADC_CTRLX_VREFSEL_REG) << _ADC_SCANCTRLX_VREFSEL_SHIFT; + } + + tmp |= init->prsSel << _ADC_SCANCTRLX_PRSSEL_SHIFT; + + if (init->fifoOverwrite) + { + tmp |= ADC_SCANCTRLX_FIFOOFACT_OVERWRITE; + } + + adc->SCANCTRLX = tmp; +#endif + +#if defined( _ADC_CTRL_SCANDMAWU_MASK ) + BUS_RegBitWrite(&adc->CTRL, _ADC_CTRL_SCANDMAWU_SHIFT, init->scanDmaEm2Wu); +#endif + + /* Write scan input configuration */ +#if defined( _ADC_SCANINPUTSEL_MASK ) + adc->SCANINPUTSEL = init->scanInputConfig.scanInputSel; + adc->SCANMASK = init->scanInputConfig.scanInputEn; + adc->SCANNEGSEL = init->scanInputConfig.scanNegSel; +#endif + + /* Assert for any APORT bus conflicts programming errors */ +#if defined( _ADC_BUSCONFLICT_MASK ) + tmp = adc->BUSREQ; + EFM_ASSERT(!(tmp & adc->BUSCONFLICT)); + EFM_ASSERT(!(adc->STATUS & _ADC_STATUS_PROGERR_MASK)); +#endif } @@ -367,14 +816,24 @@ /* 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); + /* Load calibration data for selected reference */ + ADC_LoadDevinfoCal(adc, init->reference, false); - 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); + tmp = 0 +#if defined( _ADC_SINGLECTRL_PRSSEL_MASK ) + | (init->prsSel << _ADC_SINGLECTRL_PRSSEL_SHIFT) +#endif + | (init->acqTime << _ADC_SINGLECTRL_AT_SHIFT) +#if defined( _ADC_SINGLECTRL_INPUTSEL_MASK ) + | (init->input << _ADC_SINGLECTRL_INPUTSEL_SHIFT) +#endif +#if defined( _ADC_SINGLECTRL_POSSEL_MASK ) + | (init->posSel << _ADC_SINGLECTRL_POSSEL_SHIFT) +#endif +#if defined( _ADC_SINGLECTRL_NEGSEL_MASK ) + | (init->negSel << _ADC_SINGLECTRL_NEGSEL_SHIFT) +#endif + | ((uint32_t)(init->resolution) << _ADC_SINGLECTRL_RES_SHIFT); if (init->prsEnable) { @@ -396,10 +855,86 @@ tmp |= ADC_SINGLECTRL_REP; } + /* Set single reference. Check if reference configuraion is extended to SINGLECTRLX. */ +#if defined ( _ADC_SINGLECTRLX_MASK ) + if (init->reference & ADC_CTRLX_VREFSEL_REG) + { + /* Select extension register */ + tmp |= ADC_SINGLECTRL_REF_CONF; + } + else + { + tmp |= (init->reference << _ADC_SINGLECTRL_REF_SHIFT); + } +#else + tmp |= (init->reference << _ADC_SINGLECTRL_REF_SHIFT); +#endif adc->SINGLECTRL = tmp; + + /* Update SINGLECTRLX for reference select and PRS select */ +#if defined ( _ADC_SINGLECTRLX_VREFSEL_MASK ) + tmp = adc->SINGLECTRLX & (_ADC_SINGLECTRLX_VREFSEL_MASK + | _ADC_SINGLECTRLX_PRSSEL_MASK + | _ADC_SINGLECTRLX_FIFOOFACT_MASK); + if (init->reference & ADC_CTRLX_VREFSEL_REG) + { + tmp |= ((init->reference & ~ADC_CTRLX_VREFSEL_REG) << _ADC_SINGLECTRLX_VREFSEL_SHIFT); + } + + tmp |= ((init->prsSel << _ADC_SINGLECTRLX_PRSSEL_SHIFT)); + + if (init->fifoOverwrite) + { + tmp |= ADC_SINGLECTRLX_FIFOOFACT_OVERWRITE; + } + + adc->SINGLECTRLX = tmp; +#endif + + /* Set DMA availability in EM2 */ +#if defined( _ADC_CTRL_SINGLEDMAWU_MASK ) + BUS_RegBitWrite(&ADC0->CTRL, _ADC_CTRL_SINGLEDMAWU_SHIFT, init->singleDmaEm2Wu); +#endif + + /* Assert for any APORT bus conflicts programming errors */ +#if defined( _ADC_BUSCONFLICT_MASK ) + tmp = adc->BUSREQ; + EFM_ASSERT(!(tmp & adc->BUSCONFLICT)); + EFM_ASSERT(!(adc->STATUS & _ADC_STATUS_PROGERR_MASK)); +#endif } +#if defined( _ADC_SCANDATAX_MASK ) +/***************************************************************************//** + * @brief + * Get scan result and scan select ID. + * + * @note + * Only use if scan data valid. This function does not check the DV flag. + * The return value is intended to be used as a index for the scan select ID. + * + * @param[in] adc + * Pointer to ADC peripheral register block. + * + * @param[out] scanId + * Scan select ID of first data in scan FIFO. + * + * @return + * First scan data in scan FIFO. + ******************************************************************************/ +uint32_t ADC_DataIdScanGet(ADC_TypeDef *adc, uint32_t *scanId) +{ + uint32_t scanData; + + /* Pop data FIFO with scan ID */ + scanData = adc->SCANDATAX; + *scanId = (scanData & _ADC_SCANDATAX_SCANINPUTID_MASK) >> _ADC_SCANDATAX_SCANINPUTID_SHIFT; + return (scanData & _ADC_SCANDATAX_DATA_MASK) >> _ADC_SCANDATAX_DATA_SHIFT; +} +#endif + + /***************************************************************************//** * @brief * Calculate prescaler value used to determine ADC clock. @@ -461,19 +996,42 @@ void ADC_Reset(ADC_TypeDef *adc) { /* 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; + adc->CMD = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP; + adc->SINGLECTRL = _ADC_SINGLECTRL_RESETVALUE; +#if defined( _ADC_SINGLECTRLX_MASK ) + adc->SINGLECTRLX = _ADC_SINGLECTRLX_RESETVALUE; +#endif + adc->SCANCTRL = _ADC_SCANCTRL_RESETVALUE; +#if defined( _ADC_SCANCTRLX_MASK ) + adc->SCANCTRLX = _ADC_SCANCTRLX_RESETVALUE; +#endif + adc->CTRL = _ADC_CTRL_RESETVALUE; + adc->IEN = _ADC_IEN_RESETVALUE; + adc->IFC = _ADC_IFC_MASK; + adc->BIASPROG = _ADC_BIASPROG_RESETVALUE; +#if defined( _ADC_SCANMASK_MASK ) + adc->SCANMASK = _ADC_SCANMASK_RESETVALUE; +#endif +#if defined( _ADC_SCANINPUTSEL_MASK ) + adc->SCANINPUTSEL = _ADC_SCANINPUTSEL_RESETVALUE; +#endif +#if defined( _ADC_SCANNEGSEL_MASK ) + adc->SCANNEGSEL = _ADC_SCANNEGSEL_RESETVALUE; +#endif + + /* Clear data FIFOs */ +#if defined( _ADC_SINGLEFIFOCLEAR_MASK ) + adc->SINGLEFIFOCLEAR |= ADC_SINGLEFIFOCLEAR_SINGLEFIFOCLEAR; + adc->SCANFIFOCLEAR |= ADC_SCANFIFOCLEAR_SCANFIFOCLEAR; +#endif /* Load calibration values for the 1V25 internal reference. */ - ADC_CalibrateLoadSingle(adc, adcRef1V25); - ADC_CalibrateLoadScan(adc, adcRef1V25); + ADC_LoadDevinfoCal(adc, adcRef1V25, false); + ADC_LoadDevinfoCal(adc, adcRef1V25, true); +#if defined( _ADC_SCANINPUTSEL_MASK ) /* Do not reset route register, setting should be done independently */ +#endif } @@ -499,13 +1057,13 @@ hfperFreq = 1; } } -#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) +#if defined( _EFM32_GIANT_FAMILY ) || defined( _EFM32_WONDER_FAMILY ) /* Handle errata on Giant Gecko, max TIMEBASE is 5 bits wide or max 0x1F */ /* cycles. This will give a warmp up time of e.g. 0.645us, not the */ /* required 1us when operating at 48MHz. One must also increase acqTime */ /* to compensate for the missing clock cycles, adding up to 1us in total.*/ /* See reference manual for details. */ - if( hfperFreq > 32000000 ) + if ( hfperFreq > 32000000 ) { hfperFreq = 32000000; }