1 /***************************************************************************//**
2  * @file
3  * @brief Analog to Digital Converter (ADC) Peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #include "em_adc.h"
32 #if defined(ADC_COUNT) && (ADC_COUNT > 0)
33 
34 #include "em_assert.h"
35 #include "em_cmu.h"
36 #include <stddef.h>
37 
38 /***************************************************************************//**
39  * @addtogroup adc ADC - Analog to Digital Converter
40  * @brief Analog to Digital Converter (ADC) Peripheral API
41  * @details
42  *  This module contains functions to control the ADC peripheral of Silicon
43  *  Labs 32-bit MCUs and SoCs. The ADC is used to convert analog signals into a
44  *  digital representation.
45  * @{
46  ******************************************************************************/
47 
48 /*******************************************************************************
49  *******************************   DEFINES   ***********************************
50  ******************************************************************************/
51 
52 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
53 
54 /** Validation of ADC register block pointer reference for assert statements. */
55 #if (ADC_COUNT == 1)
56 #define ADC_REF_VALID(ref)    ((ref) == ADC0)
57 #elif (ADC_COUNT == 2)
58 #define ADC_REF_VALID(ref)    (((ref) == ADC0) || ((ref) == ADC1))
59 #endif
60 
61 /** Maximum ADC clock */
62 #if defined(_SILICON_LABS_32B_SERIES_0)
63 #define ADC_MAX_CLOCK    13000000UL
64 #else
65 #define ADC_MAX_CLOCK    16000000UL
66 #endif
67 
68 /** Minimum ADC clock */
69 #define ADC_MIN_CLOCK    32000UL
70 
71 /** Helper defines for selecting ADC calibration and DEVINFO register fields. */
72 #if defined(_DEVINFO_ADC0CAL0_1V25_GAIN_MASK)
73 #define DEVINFO_ADC0_GAIN1V25_MASK _DEVINFO_ADC0CAL0_1V25_GAIN_MASK
74 #elif defined(_DEVINFO_ADC0CAL0_GAIN1V25_MASK)
75 #define DEVINFO_ADC0_GAIN1V25_MASK _DEVINFO_ADC0CAL0_GAIN1V25_MASK
76 #endif
77 
78 #if defined(_DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT)
79 #define DEVINFO_ADC0_GAIN1V25_SHIFT _DEVINFO_ADC0CAL0_1V25_GAIN_SHIFT
80 #elif defined(_DEVINFO_ADC0CAL0_GAIN1V25_SHIFT)
81 #define DEVINFO_ADC0_GAIN1V25_SHIFT _DEVINFO_ADC0CAL0_GAIN1V25_SHIFT
82 #endif
83 
84 #if defined(_DEVINFO_ADC0CAL0_1V25_OFFSET_MASK)
85 #define DEVINFO_ADC0_OFFSET1V25_MASK _DEVINFO_ADC0CAL0_1V25_OFFSET_MASK
86 #elif defined(_DEVINFO_ADC0CAL0_OFFSET1V25_MASK)
87 #define DEVINFO_ADC0_OFFSET1V25_MASK _DEVINFO_ADC0CAL0_OFFSET1V25_MASK
88 #endif
89 
90 #if defined(_DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT)
91 #define DEVINFO_ADC0_OFFSET1V25_SHIFT _DEVINFO_ADC0CAL0_1V25_OFFSET_SHIFT
92 #elif defined(_DEVINFO_ADC0CAL0_OFFSET1V25_SHIFT)
93 #define DEVINFO_ADC0_OFFSET1V25_SHIFT _DEVINFO_ADC0CAL0_OFFSET1V25_SHIFT
94 #endif
95 
96 #if defined(_DEVINFO_ADC0CAL0_2V5_GAIN_MASK)
97 #define DEVINFO_ADC0_GAIN2V5_MASK _DEVINFO_ADC0CAL0_2V5_GAIN_MASK
98 #elif defined(_DEVINFO_ADC0CAL0_GAIN2V5_MASK)
99 #define DEVINFO_ADC0_GAIN2V5_MASK _DEVINFO_ADC0CAL0_GAIN2V5_MASK
100 #endif
101 
102 #if defined(_DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT)
103 #define DEVINFO_ADC0_GAIN2V5_SHIFT _DEVINFO_ADC0CAL0_2V5_GAIN_SHIFT
104 #elif defined(_DEVINFO_ADC0CAL0_GAIN2V5_SHIFT)
105 #define DEVINFO_ADC0_GAIN2V5_SHIFT _DEVINFO_ADC0CAL0_GAIN2V5_SHIFT
106 #endif
107 
108 #if defined(_DEVINFO_ADC0CAL0_2V5_OFFSET_MASK)
109 #define DEVINFO_ADC0_OFFSET2V5_MASK _DEVINFO_ADC0CAL0_2V5_OFFSET_MASK
110 #elif defined(_DEVINFO_ADC0CAL0_OFFSET2V5_MASK)
111 #define DEVINFO_ADC0_OFFSET2V5_MASK _DEVINFO_ADC0CAL0_OFFSET2V5_MASK
112 #endif
113 
114 #if defined(_DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT)
115 #define DEVINFO_ADC0_OFFSET2V5_SHIFT _DEVINFO_ADC0CAL0_2V5_OFFSET_SHIFT
116 #elif defined(_DEVINFO_ADC0CAL0_OFFSET2V5_SHIFT)
117 #define DEVINFO_ADC0_OFFSET2V5_SHIFT _DEVINFO_ADC0CAL0_OFFSET2V5_SHIFT
118 #endif
119 
120 #if defined(_DEVINFO_ADC0CAL1_VDD_GAIN_MASK)
121 #define DEVINFO_ADC0_GAINVDD_MASK _DEVINFO_ADC0CAL1_VDD_GAIN_MASK
122 #elif defined(_DEVINFO_ADC0CAL1_GAINVDD_MASK)
123 #define DEVINFO_ADC0_GAINVDD_MASK _DEVINFO_ADC0CAL1_GAINVDD_MASK
124 #endif
125 
126 #if defined(_DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT)
127 #define DEVINFO_ADC0_GAINVDD_SHIFT _DEVINFO_ADC0CAL1_VDD_GAIN_SHIFT
128 #elif defined(_DEVINFO_ADC0CAL1_GAINVDD_SHIFT)
129 #define DEVINFO_ADC0_GAINVDD_SHIFT _DEVINFO_ADC0CAL1_GAINVDD_SHIFT
130 #endif
131 
132 #if defined(_DEVINFO_ADC0CAL1_VDD_OFFSET_MASK)
133 #define DEVINFO_ADC0_OFFSETVDD_MASK _DEVINFO_ADC0CAL1_VDD_OFFSET_MASK
134 #elif defined(_DEVINFO_ADC0CAL1_OFFSETVDD_MASK)
135 #define DEVINFO_ADC0_OFFSETVDD_MASK _DEVINFO_ADC0CAL1_OFFSETVDD_MASK
136 #endif
137 
138 #if defined(_DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT)
139 #define DEVINFO_ADC0_OFFSETVDD_SHIFT _DEVINFO_ADC0CAL1_VDD_OFFSET_SHIFT
140 #elif defined(_DEVINFO_ADC0CAL1_OFFSETVDD_SHIFT)
141 #define DEVINFO_ADC0_OFFSETVDD_SHIFT _DEVINFO_ADC0CAL1_OFFSETVDD_SHIFT
142 #endif
143 
144 #if defined(_DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK)
145 #define DEVINFO_ADC0_GAIN5VDIFF_MASK _DEVINFO_ADC0CAL1_5VDIFF_GAIN_MASK
146 #elif defined(_DEVINFO_ADC0CAL1_GAIN5VDIFF_MASK)
147 #define DEVINFO_ADC0_GAIN5VDIFF_MASK _DEVINFO_ADC0CAL1_GAIN5VDIFF_MASK
148 #endif
149 
150 #if defined(_DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT)
151 #define DEVINFO_ADC0_GAIN5VDIFF_SHIFT _DEVINFO_ADC0CAL1_5VDIFF_GAIN_SHIFT
152 #elif defined(_DEVINFO_ADC0CAL1_GAIN5VDIFF_SHIFT)
153 #define DEVINFO_ADC0_GAIN5VDIFF_SHIFT _DEVINFO_ADC0CAL1_GAIN5VDIFF_SHIFT
154 #endif
155 
156 #if defined(_DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK)
157 #define DEVINFO_ADC0_OFFSET5VDIFF_MASK _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_MASK
158 #elif defined(_DEVINFO_ADC0CAL1_OFFSET5VDIFF_MASK)
159 #define DEVINFO_ADC0_OFFSET5VDIFF_MASK _DEVINFO_ADC0CAL1_OFFSET5VDIFF_MASK
160 #endif
161 
162 #if defined(_DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT)
163 #define DEVINFO_ADC0_OFFSET5VDIFF_SHIFT _DEVINFO_ADC0CAL1_5VDIFF_OFFSET_SHIFT
164 #elif defined(_DEVINFO_ADC0CAL1_OFFSET5VDIFF_SHIFT)
165 #define DEVINFO_ADC0_OFFSET5VDIFF_SHIFT _DEVINFO_ADC0CAL1_OFFSET5VDIFF_SHIFT
166 #endif
167 
168 #if defined(_DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK)
169 #define DEVINFO_ADC0_OFFSET2XVDD_MASK _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_MASK
170 #elif defined(_DEVINFO_ADC0CAL2_OFFSET2XVDD_MASK)
171 #define DEVINFO_ADC0_OFFSET2XVDD_MASK _DEVINFO_ADC0CAL2_OFFSET2XVDD_MASK
172 #endif
173 
174 #if defined(_DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT)
175 #define DEVINFO_ADC0_OFFSET2XVDD_SHIFT _DEVINFO_ADC0CAL2_2XVDDVSS_OFFSET_SHIFT
176 #elif defined(_DEVINFO_ADC0CAL2_OFFSET2XVDD_SHIFT)
177 #define DEVINFO_ADC0_OFFSET2XVDD_SHIFT _DEVINFO_ADC0CAL2_OFFSET2XVDD_SHIFT
178 #endif
179 
180 /** @endcond */
181 
182 /*******************************************************************************
183  ***************************   LOCAL FUNCTIONS   *******************************
184  ******************************************************************************/
185 
186 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
187 
188 /***************************************************************************//**
189  * @brief
190  *   Load the ADC calibration register for a selected reference and conversion mode.
191  *
192  * @details
193  *   During production, calibration values are stored in the device
194  *   information page for internal references. Notice that, for external references,
195  *   calibration values must be determined explicitly. This function
196  *   will not modify the calibration register for external references.
197  *
198  * @param[in] adc
199  *   A pointer to ADC peripheral register block.
200  *
201  * @param[in] ref
202  *   A reference to load calibrated values for. No values are loaded for
203  *   external references.
204  *
205  * @param[in] setScanCal
206  *   Select scan mode (true) or single mode (false) calibration load.
207  ******************************************************************************/
ADC_LoadDevinfoCal(ADC_TypeDef * adc,ADC_Ref_TypeDef ref,bool setScanCal)208 static void ADC_LoadDevinfoCal(ADC_TypeDef *adc,
209                                ADC_Ref_TypeDef ref,
210                                bool setScanCal)
211 {
212   uint32_t calReg;
213   uint32_t newCal;
214   uint32_t mask;
215   uint32_t shift;
216   __IM uint32_t * diCalReg;
217 
218   if (setScanCal) {
219     shift = _ADC_CAL_SCANOFFSET_SHIFT;
220     mask  = ~(_ADC_CAL_SCANOFFSET_MASK
221 #if defined(_ADC_CAL_SCANOFFSETINV_MASK)
222               | _ADC_CAL_SCANOFFSETINV_MASK
223 #endif
224               | _ADC_CAL_SCANGAIN_MASK);
225   } else {
226     shift = _ADC_CAL_SINGLEOFFSET_SHIFT;
227     mask  = ~(_ADC_CAL_SINGLEOFFSET_MASK
228 #if defined(_ADC_CAL_SINGLEOFFSETINV_MASK)
229               | _ADC_CAL_SINGLEOFFSETINV_MASK
230 #endif
231               | _ADC_CAL_SINGLEGAIN_MASK);
232   }
233 
234   calReg = adc->CAL & mask;
235   newCal = 0;
236 
237   if (adc == ADC0) {
238     diCalReg = &DEVINFO->ADC0CAL0;
239   }
240 #if defined(ADC1)
241   else if (adc == ADC1) {
242     diCalReg = &DEVINFO->ADC1CAL0;
243   }
244 #endif
245   else {
246     return;
247   }
248 
249   switch (ref) {
250     case adcRef1V25:
251       newCal |= ((diCalReg[0] & DEVINFO_ADC0_GAIN1V25_MASK)
252                  >> DEVINFO_ADC0_GAIN1V25_SHIFT)
253                 << _ADC_CAL_SINGLEGAIN_SHIFT;
254       newCal |= ((diCalReg[0] & DEVINFO_ADC0_OFFSET1V25_MASK)
255                  >> DEVINFO_ADC0_OFFSET1V25_SHIFT)
256                 << _ADC_CAL_SINGLEOFFSET_SHIFT;
257 #if defined(_ADC_CAL_SINGLEOFFSETINV_MASK)
258       newCal |= ((diCalReg[0] & _DEVINFO_ADC0CAL0_NEGSEOFFSET1V25_MASK)
259                  >> _DEVINFO_ADC0CAL0_NEGSEOFFSET1V25_SHIFT)
260                 << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
261 #endif
262       break;
263 
264     case adcRef2V5:
265       newCal |= ((diCalReg[0] & DEVINFO_ADC0_GAIN2V5_MASK)
266                  >> DEVINFO_ADC0_GAIN2V5_SHIFT)
267                 << _ADC_CAL_SINGLEGAIN_SHIFT;
268       newCal |= ((diCalReg[0] & DEVINFO_ADC0_OFFSET2V5_MASK)
269                  >> DEVINFO_ADC0_OFFSET2V5_SHIFT)
270                 << _ADC_CAL_SINGLEOFFSET_SHIFT;
271 #if defined(_ADC_CAL_SINGLEOFFSETINV_MASK)
272       newCal |= ((diCalReg[0] & _DEVINFO_ADC0CAL0_NEGSEOFFSET2V5_MASK)
273                  >> _DEVINFO_ADC0CAL0_NEGSEOFFSET2V5_SHIFT)
274                 << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
275 #endif
276       break;
277 
278     case adcRefVDD:
279       newCal |= ((diCalReg[1] & DEVINFO_ADC0_GAINVDD_MASK)
280                  >> DEVINFO_ADC0_GAINVDD_SHIFT)
281                 << _ADC_CAL_SINGLEGAIN_SHIFT;
282       newCal |= ((diCalReg[1] & DEVINFO_ADC0_OFFSETVDD_MASK)
283                  >> DEVINFO_ADC0_OFFSETVDD_SHIFT)
284                 << _ADC_CAL_SINGLEOFFSET_SHIFT;
285 #if defined(_ADC_CAL_SINGLEOFFSETINV_MASK)
286       newCal |= ((diCalReg[1] & _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_MASK)
287                  >> _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_SHIFT)
288                 << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
289 #endif
290       break;
291 
292     case adcRef5VDIFF:
293       newCal |= ((diCalReg[1] & DEVINFO_ADC0_GAIN5VDIFF_MASK)
294                  >> DEVINFO_ADC0_GAIN5VDIFF_SHIFT)
295                 << _ADC_CAL_SINGLEGAIN_SHIFT;
296       newCal |= ((diCalReg[1] & DEVINFO_ADC0_OFFSET5VDIFF_MASK)
297                  >> DEVINFO_ADC0_OFFSET5VDIFF_SHIFT)
298                 << _ADC_CAL_SINGLEOFFSET_SHIFT;
299 #if defined(_ADC_CAL_SINGLEOFFSETINV_MASK)
300       newCal |= ((diCalReg[1] & _DEVINFO_ADC0CAL1_NEGSEOFFSET5VDIFF_MASK)
301                  >> _DEVINFO_ADC0CAL1_NEGSEOFFSET5VDIFF_SHIFT)
302                 << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
303 #endif
304       break;
305 
306     case adcRef2xVDD:
307       /* There is no gain calibration for this reference */
308       newCal |= ((diCalReg[2] & DEVINFO_ADC0_OFFSET2XVDD_MASK)
309                  >> DEVINFO_ADC0_OFFSET2XVDD_SHIFT)
310                 << _ADC_CAL_SINGLEOFFSET_SHIFT;
311 #if defined(_ADC_CAL_SINGLEOFFSETINV_MASK)
312       newCal |= ((diCalReg[2] & _DEVINFO_ADC0CAL2_NEGSEOFFSET2XVDD_MASK)
313                  >> _DEVINFO_ADC0CAL2_NEGSEOFFSET2XVDD_SHIFT)
314                 << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
315 #endif
316       break;
317 
318 #if defined(_ADC_SINGLECTRLX_VREFSEL_VDDXWATT)
319     case adcRefVddxAtt:
320       newCal |= ((diCalReg[1] & DEVINFO_ADC0_GAINVDD_MASK)
321                  >> DEVINFO_ADC0_GAINVDD_SHIFT)
322                 << _ADC_CAL_SINGLEGAIN_SHIFT;
323       newCal |= ((diCalReg[1] & DEVINFO_ADC0_OFFSETVDD_MASK)
324                  >> DEVINFO_ADC0_OFFSETVDD_SHIFT)
325                 << _ADC_CAL_SINGLEOFFSET_SHIFT;
326       newCal |= ((diCalReg[1] & _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_MASK)
327                  >> _DEVINFO_ADC0CAL1_NEGSEOFFSETVDD_SHIFT)
328                 << _ADC_CAL_SINGLEOFFSETINV_SHIFT;
329       break;
330 #endif
331 
332     /* For external references, the calibration must be determined for the
333        specific application and set by the user. Calibration data is also not
334        available for the internal references adcRefVBGR, adcRefVEntropy, and
335        adcRefVBGRlow. */
336     default:
337       newCal = 0;
338       break;
339   }
340 
341   adc->CAL = calReg | (newCal << shift);
342 }
343 
344 /** @endcond */
345 
346 /*******************************************************************************
347  **************************   GLOBAL FUNCTIONS   *******************************
348  ******************************************************************************/
349 
350 /***************************************************************************//**
351  * @brief
352  *   Initialize ADC.
353  *
354  * @details
355  *   Initializes common parts for both single conversion and scan sequence.
356  *   In addition, single and/or scan control configuration must be done. See
357  *   @ref ADC_InitSingle() and @ref ADC_InitScan() respectively.
358  *   For ADC architectures with the ADCn->SCANINPUTSEL register, use
359  *   ADC_ScanSingleEndedInputAdd() to configure single-ended scan inputs or
360  *   ADC_ScanDifferentialInputAdd() to configure differential scan inputs.
361  *   ADC_ScanInputClear() is also provided for applications that need to update
362  *   the input configuration.
363  *
364  * @note
365  *   This function will stop any ongoing conversion.
366  *
367  * @param[in] adc
368  *   A pointer to the ADC peripheral register block.
369  *
370  * @param[in] init
371  *   A pointer to the ADC initialization structure.
372  ******************************************************************************/
ADC_Init(ADC_TypeDef * adc,const ADC_Init_TypeDef * init)373 void ADC_Init(ADC_TypeDef *adc, const ADC_Init_TypeDef *init)
374 {
375   uint32_t tmp;
376   uint8_t presc = init->prescale;
377 
378   EFM_ASSERT(ADC_REF_VALID(adc));
379 
380   if (presc == 0U) {
381     /* Assume maximum ADC clock for prescaler 0. */
382     presc = ADC_PrescaleCalc(ADC_MAX_CLOCK, 0);
383   } else {
384     /* Check prescaler bounds against ADC_MAX_CLOCK and ADC_MIN_CLOCK. */
385 #if defined(_ADC_CTRL_ADCCLKMODE_MASK)
386     if ((adc->CTRL & _ADC_CTRL_ADCCLKMODE_MASK) == ADC_CTRL_ADCCLKMODE_SYNC)
387 #endif
388     {
389       EFM_ASSERT(presc >= ADC_PrescaleCalc(ADC_MAX_CLOCK, 0));
390       EFM_ASSERT(presc <= ADC_PrescaleCalc(ADC_MIN_CLOCK, 0));
391     }
392   }
393 
394   /* Make sure conversion is not in progress. */
395   adc->CMD = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP;
396 
397   tmp = ((uint32_t)(init->ovsRateSel) << _ADC_CTRL_OVSRSEL_SHIFT)
398         | (((uint32_t)(init->timebase) << _ADC_CTRL_TIMEBASE_SHIFT)
399            & _ADC_CTRL_TIMEBASE_MASK)
400         | (((uint32_t)(presc) << _ADC_CTRL_PRESC_SHIFT)
401            & _ADC_CTRL_PRESC_MASK)
402 #if defined (_ADC_CTRL_LPFMODE_MASK)
403         | ((uint32_t)(init->lpfMode) << _ADC_CTRL_LPFMODE_SHIFT)
404 #endif
405         | ((uint32_t)(init->warmUpMode) << _ADC_CTRL_WARMUPMODE_SHIFT);
406 
407   if (init->tailgate) {
408     tmp |= ADC_CTRL_TAILGATE;
409   }
410   adc->CTRL = tmp;
411 
412 #if defined(_ADC_CTRL_ADCCLKMODE_MASK)
413   /* Set ADC EM2 clock configuration. */
414   BUS_RegMaskedWrite(&adc->CTRL,
415                      _ADC_CTRL_ADCCLKMODE_MASK | _ADC_CTRL_ASYNCCLKEN_MASK,
416                      (uint32_t)init->em2ClockConfig);
417 
418 #if defined(_SILICON_LABS_32B_SERIES_1)
419   /* In asynch clock mode assert that the ADC clock frequency is
420      less or equal to 2/3 of the HFPER/HFPERC clock frequency. */
421   if ((adc->CTRL & _ADC_CTRL_ADCCLKMODE_MASK) == ADC_CTRL_ADCCLKMODE_ASYNC) {
422     CMU_Clock_TypeDef asyncClk = cmuClock_ADC0ASYNC;
423     uint32_t adcClkFreq;
424     uint32_t hfperClkFreq = 0;
425 #if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
426     if ( adc == ADC1 ) {
427       asyncClk = cmuClock_ADC1ASYNC;
428     }
429 #endif
430     adcClkFreq = CMU_ClockFreqGet(asyncClk);
431     if (adc == ADC0) {
432       hfperClkFreq = CMU_ClockFreqGet(cmuClock_ADC0);
433 #if defined(ADC1)
434     } else if (adc == ADC1) {
435       hfperClkFreq = CMU_ClockFreqGet(cmuClock_ADC1);
436 #endif
437     } else {
438       EFM_ASSERT(false);
439     }
440     EFM_ASSERT(hfperClkFreq >= (adcClkFreq * 3) / 2);
441   }
442 #endif /* #if defined(_SILICON_LABS_32B_SERIES_1) */
443 #endif /* #if defined(_ADC_CTRL_ADCCLKMODE_MASK) */
444 
445 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
446   /* A debugger can trigger the SCANUF interrupt on EFM32xG1 or EFR32xG1 */
447   ADC_IntClear(adc, ADC_IFC_SCANUF);
448 #endif
449 }
450 
451 #if defined(_ADC_SCANINPUTSEL_MASK)
452 /***************************************************************************//**
453  * @brief
454  *   Clear ADC scan input configuration.
455  *
456  * @param[in] scanInit
457  *   Structure to hold the scan configuration and input configuration.
458  ******************************************************************************/
ADC_ScanInputClear(ADC_InitScan_TypeDef * scanInit)459 void ADC_ScanInputClear(ADC_InitScan_TypeDef *scanInit)
460 {
461   /* Clear the input configuration. */
462 
463   /* Select none. */
464   scanInit->scanInputConfig.scanInputSel = ADC_SCANINPUTSEL_NONE;
465   scanInit->scanInputConfig.scanInputEn = 0;
466 
467   /* Default alternative negative inputs. */
468   scanInit->scanInputConfig.scanNegSel = _ADC_SCANNEGSEL_RESETVALUE;
469 }
470 
471 /***************************************************************************//**
472  * @brief
473  *   Initialize ADC scan single-ended input configuration.
474  *
475  * @details
476  *   Set a configuration for ADC scan conversion with single-ended inputs. The
477  *   ADC_InitScan_TypeDef structure updated from this function will be passed to
478  *   ADC_InitScan().
479  *
480  * @param[in] scanInit
481  *   ADC scan initialization structure
482  *
483  * @param[in] inputGroup
484  *   ADC scan input group. See section 25.3.4 in the reference manual for
485  *   more information.
486  *
487  * @param[in] singleEndedSel
488  *   APORT select.
489  *
490  * @return
491  *   Scan ID of selected ADC input. See section 25.3.4 in the reference manual for
492  *   more information. Note that the returned integer represents the bit position
493  *   in ADCn_SCANMASK set by this function. The accumulated mask is stored in
494  *   scanInit->scanInputConfig->scanInputEn.
495  ******************************************************************************/
ADC_ScanSingleEndedInputAdd(ADC_InitScan_TypeDef * scanInit,ADC_ScanInputGroup_TypeDef inputGroup,ADC_PosSel_TypeDef singleEndedSel)496 uint32_t ADC_ScanSingleEndedInputAdd(ADC_InitScan_TypeDef *scanInit,
497                                      ADC_ScanInputGroup_TypeDef inputGroup,
498                                      ADC_PosSel_TypeDef singleEndedSel)
499 {
500   uint32_t currentSel;
501   uint32_t newSel;
502   uint32_t scanId;
503 
504   scanInit->diff = false;
505 
506   /* Check for an illegal group. */
507   EFM_ASSERT((unsigned)inputGroup < 4U);
508 
509   /* Decode the input group select by shifting right by 3. */
510   newSel = (unsigned)singleEndedSel >> 3;
511   /* Map 0Y channels to 0X. */
512   if ((newSel == 2) || (newSel == 3)) {
513     newSel -= 2;
514   }
515 
516   currentSel = (scanInit->scanInputConfig.scanInputSel
517                 >> ((unsigned)inputGroup * 8U)) & 0xFFU;
518 
519   /* If none selected. */
520   if (currentSel == ADC_SCANINPUTSEL_GROUP_NONE) {
521     scanInit->scanInputConfig.scanInputSel &=
522       ~(0xFFU << ((unsigned)inputGroup * 8U));
523     scanInit->scanInputConfig.scanInputSel |=
524       newSel << ((unsigned)inputGroup * 8U);
525   } else if (currentSel == newSel) {
526     /* Ok, but do nothing.  */
527   } else {
528     /* Invalid channel range. A range is already selected for this group. */
529     EFM_ASSERT(false);
530   }
531 
532   /* Update and return scan input enable mask (SCANMASK). */
533   scanId = ((unsigned)inputGroup * 8U) + ((unsigned)singleEndedSel & 0x7U);
534   EFM_ASSERT(scanId < 32U);
535   scanInit->scanInputConfig.scanInputEn |= 0x1UL << scanId;
536   return scanId;
537 }
538 
539 /***************************************************************************//**
540  * @brief
541  *   Initialize the ADC scan differential input configuration.
542  *
543  * @details
544  *   Set a configuration for the ADC scan conversion with differential inputs. The
545  *   ADC_InitScan_TypeDef structure updated by this function should be passed to
546  *   ADC_InitScan().
547  *
548  * @param[in] scanInit
549  *   Structure to hold the scan and input configuration.
550  *
551  * @param[in] inputGroup
552  *   ADC scan input group. See section 25.3.4 in the reference manual for
553  *   more information.
554  *
555  * @param[in] posSel
556  *   APORT bus pair select. The negative terminal is implicitly selected by
557  *   the positive terminal.
558  *
559  * @param[in] negInput
560  *   ADC scan alternative negative input. Set to adcScanNegInputDefault to select
561  *   a default negative input (implicit from posSel).
562  *
563  * @return
564  *   Scan ID of the selected ADC input. See section 25.3.4 in the reference manual for
565  *   more information. Note that the returned integer represents the bit position
566  *   in ADCn_SCANMASK set by this function. The accumulated mask is stored in the
567  *   scanInit->scanInputConfig->scanInputEn.
568  ******************************************************************************/
ADC_ScanDifferentialInputAdd(ADC_InitScan_TypeDef * scanInit,ADC_ScanInputGroup_TypeDef inputGroup,ADC_PosSel_TypeDef posSel,ADC_ScanNegInput_TypeDef negInput)569 uint32_t ADC_ScanDifferentialInputAdd(ADC_InitScan_TypeDef *scanInit,
570                                       ADC_ScanInputGroup_TypeDef inputGroup,
571                                       ADC_PosSel_TypeDef posSel,
572                                       ADC_ScanNegInput_TypeDef negInput)
573 {
574   uint32_t negInputRegMask = 0;
575   uint32_t negInputRegShift = 0;
576   uint32_t negInputRegVal = 0;
577   uint32_t scanId;
578 
579   /* Perform a single-ended initialization, then update for differential scan. */
580   scanId = ADC_ScanSingleEndedInputAdd(scanInit, inputGroup, posSel);
581 
582   /* Reset to differential mode. */
583   scanInit->diff = true;
584 
585   /* Set negative ADC input unless the default is selected. */
586   if (negInput != adcScanNegInputDefault) {
587     if (scanId == 0U) {
588       negInputRegMask  = _ADC_SCANNEGSEL_INPUT0NEGSEL_MASK;
589       negInputRegShift = _ADC_SCANNEGSEL_INPUT0NEGSEL_SHIFT;
590       EFM_ASSERT((unsigned)inputGroup == 0U);
591     } else if (scanId == 2U) {
592       negInputRegMask  = _ADC_SCANNEGSEL_INPUT2NEGSEL_MASK;
593       negInputRegShift = _ADC_SCANNEGSEL_INPUT2NEGSEL_SHIFT;
594       EFM_ASSERT((unsigned)inputGroup == 0U);
595     } else if (scanId == 4U) {
596       negInputRegMask  = _ADC_SCANNEGSEL_INPUT4NEGSEL_MASK;
597       negInputRegShift = _ADC_SCANNEGSEL_INPUT4NEGSEL_SHIFT;
598       EFM_ASSERT((unsigned)inputGroup == 0U);
599     } else if (scanId == 6U) {
600       negInputRegMask  = _ADC_SCANNEGSEL_INPUT6NEGSEL_MASK;
601       negInputRegShift = _ADC_SCANNEGSEL_INPUT6NEGSEL_SHIFT;
602       EFM_ASSERT((unsigned)inputGroup == 0U);
603     } else if (scanId == 9U) {
604       negInputRegMask  = _ADC_SCANNEGSEL_INPUT9NEGSEL_MASK;
605       negInputRegShift = _ADC_SCANNEGSEL_INPUT9NEGSEL_SHIFT;
606       EFM_ASSERT((unsigned)inputGroup == 1U);
607     } else if (scanId == 11U) {
608       negInputRegMask  = _ADC_SCANNEGSEL_INPUT11NEGSEL_MASK;
609       negInputRegShift = _ADC_SCANNEGSEL_INPUT11NEGSEL_SHIFT;
610       EFM_ASSERT((unsigned)inputGroup == 1U);
611     } else if (scanId == 13U) {
612       negInputRegMask  = _ADC_SCANNEGSEL_INPUT13NEGSEL_MASK;
613       negInputRegShift = _ADC_SCANNEGSEL_INPUT13NEGSEL_SHIFT;
614       EFM_ASSERT((unsigned)inputGroup == 1U);
615     } else if (scanId == 15U) {
616       negInputRegMask  = _ADC_SCANNEGSEL_INPUT15NEGSEL_MASK;
617       negInputRegShift = _ADC_SCANNEGSEL_INPUT15NEGSEL_SHIFT;
618       EFM_ASSERT((unsigned)inputGroup == 1U);
619     } else {
620       /* The positive input does not have a negative input option (negInput is posInput + 1). */
621       EFM_ASSERT(false);
622     }
623 
624     /* Find ADC_SCANNEGSEL_CHxNSEL value for positive input 0, 2, 4, and 6. */
625     if ((unsigned)inputGroup == 0U) {
626       switch (negInput) {
627         case adcScanNegInput1:
628           negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT1;
629           break;
630 
631         case adcScanNegInput3:
632           negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT3;
633           break;
634 
635         case adcScanNegInput5:
636           negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT5;
637           break;
638 
639         case adcScanNegInput7:
640           negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT7;
641           break;
642 
643         default:
644           /* An invalid selection. Options are input 1, 3, 5 and 7. */
645           EFM_ASSERT(false);
646           break;
647       }
648     } else { /* inputGroup == 1 */
649       /* Find ADC_SCANNEGSEL_CHxNSEL value for positive input 9, 11, 13, and 15. */
650       switch (negInput) {
651         case adcScanNegInput8:
652           negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT8;
653           break;
654 
655         case adcScanNegInput10:
656           negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT10;
657           break;
658 
659         case adcScanNegInput12:
660           negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT12;
661           break;
662 
663         case adcScanNegInput14:
664           negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT14;
665           break;
666 
667         default:
668           /* Invalid selection. Options are input 8, 10, 12, and 14. */
669           EFM_ASSERT(false);
670           break;
671       }
672     }
673 
674     /* Update configuration. */
675     scanInit->scanInputConfig.scanNegSel &= ~negInputRegMask;
676     scanInit->scanInputConfig.scanNegSel |= negInputRegVal << negInputRegShift;
677   }
678   return scanId;
679 }
680 #endif
681 
682 /***************************************************************************//**
683  * @brief
684  *   Initialize the ADC scan sequence.
685  *
686  * @details
687  *   See ADC_Start() for starting a scan sequence.
688  *
689  *   When selecting an external reference, the gain and offset calibration
690  *   must be set explicitly (CAL register). For other references, the
691  *   calibration is updated with values defined during manufacturing.
692  *   For ADC architectures with the ADCn->SCANINPUTSEL register, use
693  *   ADC_ScanSingleEndedInputAdd() to configure single-ended scan inputs or
694  *   ADC_ScanDifferentialInputAdd() to configure differential scan inputs.
695  *   ADC_ScanInputClear() is also provided for applications that need to update
696  *   the input configuration.
697  *
698  * @note
699  *   This function will stop any ongoing scan sequence.
700  *
701  * @param[in] adc
702  *   A pointer to the ADC peripheral register block.
703  *
704  * @param[in] init
705  *   A pointer to the ADC initialization structure.
706  ******************************************************************************/
ADC_InitScan(ADC_TypeDef * adc,const ADC_InitScan_TypeDef * init)707 void ADC_InitScan(ADC_TypeDef *adc, const ADC_InitScan_TypeDef *init)
708 {
709   uint32_t tmp;
710 
711   EFM_ASSERT(ADC_REF_VALID(adc));
712 
713   /* Make sure scan sequence is not in progress. */
714   adc->CMD = ADC_CMD_SCANSTOP;
715 
716   /* Load calibration data for a selected reference. */
717   ADC_LoadDevinfoCal(adc, init->reference, true);
718 
719   tmp = 0UL
720 #if defined (_ADC_SCANCTRL_PRSSEL_MASK)
721         | ((uint32_t)init->prsSel << _ADC_SCANCTRL_PRSSEL_SHIFT)
722 #endif
723         | ((uint32_t)init->acqTime << _ADC_SCANCTRL_AT_SHIFT)
724 #if defined (_ADC_SCANCTRL_INPUTMASK_MASK)
725         | init->input
726 #endif
727         | ((uint32_t)init->resolution << _ADC_SCANCTRL_RES_SHIFT);
728 
729   if (init->prsEnable) {
730     tmp |= ADC_SCANCTRL_PRSEN;
731   }
732 
733   if (init->leftAdjust) {
734     tmp |= ADC_SCANCTRL_ADJ_LEFT;
735   }
736 
737 #if defined(_ADC_SCANCTRL_INPUTMASK_MASK)
738   if (init->diff)
739 #elif defined(_ADC_SCANINPUTSEL_MASK)
740   if (init->diff)
741 #endif
742   {
743     tmp |= ADC_SCANCTRL_DIFF;
744   }
745 
746   if (init->rep) {
747 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
748     /* Scan repeat mode does not work on EFM32JG1, EFM32PG1, or EFR32xG1x devices.
749      * The errata is called ADC_E211 in the errata document. */
750     EFM_ASSERT(false);
751 #endif
752     tmp |= ADC_SCANCTRL_REP;
753   }
754 
755   /* Set scan reference. Check if the reference configuration is extended to SCANCTRLX. */
756 #if defined (_ADC_SCANCTRLX_VREFSEL_MASK)
757   if (((uint32_t)init->reference & ADC_CTRLX_VREFSEL_REG) != 0UL) {
758     /* Select the extension register. */
759     tmp |= ADC_SCANCTRL_REF_CONF;
760   } else {
761     tmp |= (uint32_t)init->reference << _ADC_SCANCTRL_REF_SHIFT;
762   }
763 #else
764   tmp |= init->reference << _ADC_SCANCTRL_REF_SHIFT;
765 #endif
766 
767 #if defined(_ADC_SCANCTRL_INPUTMASK_MASK)
768   tmp |= init->input;
769 #endif
770 
771   adc->SCANCTRL = tmp;
772 
773   /* Update SINGLECTRLX for reference select and PRS select. */
774 #if defined (_ADC_SCANCTRLX_MASK)
775   tmp = adc->SCANCTRLX & ~(_ADC_SCANCTRLX_VREFSEL_MASK
776                            | _ADC_SCANCTRLX_PRSSEL_MASK
777                            | _ADC_SCANCTRLX_FIFOOFACT_MASK);
778   if (((uint32_t)init->reference & ADC_CTRLX_VREFSEL_REG) != 0UL) {
779     tmp |= ((uint32_t)init->reference & ~ADC_CTRLX_VREFSEL_REG) << _ADC_SCANCTRLX_VREFSEL_SHIFT;
780   }
781 
782   tmp |= (uint32_t)init->prsSel << _ADC_SCANCTRLX_PRSSEL_SHIFT;
783 
784   if (init->fifoOverwrite) {
785     tmp |= ADC_SCANCTRLX_FIFOOFACT_OVERWRITE;
786   }
787 
788   adc->SCANCTRLX = tmp;
789 #endif
790 
791 #if defined(_ADC_CTRL_SCANDMAWU_MASK)
792   BUS_RegBitWrite(&adc->CTRL,
793                   _ADC_CTRL_SCANDMAWU_SHIFT,
794                   (uint32_t)init->scanDmaEm2Wu);
795 #endif
796 
797   /* Write the scan input configuration. */
798 #if defined(_ADC_SCANINPUTSEL_MASK)
799   /* Check for valid scan input configuration. Use @ref ADC_ScanInputClear(),
800      @ref ADC_ScanSingleEndedInputAdd(), and @ref ADC_ScanDifferentialInputAdd() to set
801      the scan input configuration.  */
802   EFM_ASSERT(init->scanInputConfig.scanInputSel != ADC_SCANINPUTSEL_NONE);
803   adc->SCANINPUTSEL = init->scanInputConfig.scanInputSel;
804   adc->SCANMASK     = init->scanInputConfig.scanInputEn;
805   adc->SCANNEGSEL   = init->scanInputConfig.scanNegSel;
806 #endif
807 
808   /* Assert for any APORT bus conflicts programming errors. */
809 #if defined(_ADC_APORTCONFLICT_MASK)
810   tmp = adc->APORTREQ;
811   EFM_ASSERT(!(tmp & adc->APORTCONFLICT));
812   EFM_ASSERT(!(adc->STATUS & _ADC_STATUS_PROGERR_MASK));
813 #endif
814 }
815 
816 /***************************************************************************//**
817  * @brief
818  *   Initialize the single ADC sample conversion.
819  *
820  * @details
821  *   See ADC_Start() for starting a single conversion.
822  *
823  *   When selecting an external reference, the gain and offset calibration
824  *   must be set explicitly (CAL register). For other references, the
825  *   calibration is updated with values defined during manufacturing.
826  *
827  * @note
828  *   This function will stop any ongoing single conversion.
829  *
830  * @cond DOXYDOC_P2_DEVICE
831  * @note
832  *   This function will set the BIASPROG_GPBIASACC bit when selecting the
833  *   internal temperature sensor and clear the bit otherwise. Any
834  *   application that depends on the state of the BIASPROG_GPBIASACC bit should
835  *   modify it after a call to this function.
836  * @endcond
837  *
838  * @param[in] adc
839  *   A pointer to the ADC peripheral register block.
840  *
841  * @param[in] init
842  *   A pointer to the ADC initialization structure.
843  ******************************************************************************/
ADC_InitSingle(ADC_TypeDef * adc,const ADC_InitSingle_TypeDef * init)844 void ADC_InitSingle(ADC_TypeDef *adc, const ADC_InitSingle_TypeDef *init)
845 {
846   uint32_t tmp;
847 
848   EFM_ASSERT(ADC_REF_VALID(adc));
849 
850   /* Make sure single conversion is not in progress. */
851   adc->CMD = ADC_CMD_SINGLESTOP;
852 
853   /* Load calibration data for selected reference. */
854   ADC_LoadDevinfoCal(adc, init->reference, false);
855 
856   tmp = 0UL
857 #if defined(_ADC_SINGLECTRL_PRSSEL_MASK)
858         | ((uint32_t)init->prsSel << _ADC_SINGLECTRL_PRSSEL_SHIFT)
859 #endif
860         | ((uint32_t)init->acqTime << _ADC_SINGLECTRL_AT_SHIFT)
861 #if defined(_ADC_SINGLECTRL_INPUTSEL_MASK)
862         | (init->input << _ADC_SINGLECTRL_INPUTSEL_SHIFT)
863 #endif
864 #if defined(_ADC_SINGLECTRL_POSSEL_MASK)
865         | ((uint32_t)init->posSel << _ADC_SINGLECTRL_POSSEL_SHIFT)
866 #endif
867 #if defined(_ADC_SINGLECTRL_NEGSEL_MASK)
868         | ((uint32_t)init->negSel << _ADC_SINGLECTRL_NEGSEL_SHIFT)
869 #endif
870         | ((uint32_t)(init->resolution) << _ADC_SINGLECTRL_RES_SHIFT);
871 
872   if (init->prsEnable) {
873     tmp |= ADC_SINGLECTRL_PRSEN;
874   }
875 
876   if (init->leftAdjust) {
877     tmp |= ADC_SINGLECTRL_ADJ_LEFT;
878   }
879 
880   if (init->diff) {
881     tmp |= ADC_SINGLECTRL_DIFF;
882   }
883 
884   if (init->rep) {
885     tmp |= ADC_SINGLECTRL_REP;
886   }
887 
888 #if defined(_ADC_SINGLECTRL_POSSEL_TEMP)
889   /* Force at least 8 cycle acquisition time when reading the internal temperature
890    * sensor with 1.25 V reference */
891   if ((init->posSel == adcPosSelTEMP)
892       && (init->reference == adcRef1V25)
893       && (init->acqTime < adcAcqTime8)) {
894     tmp = (tmp & ~_ADC_SINGLECTRL_AT_MASK)
895           | ((uint32_t)adcAcqTime8 << _ADC_SINGLECTRL_AT_SHIFT);
896   }
897 #endif
898 
899   /* Set a single reference. Check if the reference configuration is extended to SINGLECTRLX. */
900 #if defined (_ADC_SINGLECTRLX_MASK)
901   if (((uint32_t)init->reference & ADC_CTRLX_VREFSEL_REG) != 0UL) {
902     /* Select the extension register. */
903     tmp |= ADC_SINGLECTRL_REF_CONF;
904   } else {
905     tmp |= (uint32_t)init->reference << _ADC_SINGLECTRL_REF_SHIFT;
906   }
907 #else
908   tmp |= (uint32_t)init->reference << _ADC_SINGLECTRL_REF_SHIFT;
909 #endif
910   adc->SINGLECTRL = tmp;
911 
912   /* Update SINGLECTRLX for reference select and PRS select. */
913 #if defined (_ADC_SINGLECTRLX_VREFSEL_MASK)
914   tmp = adc->SINGLECTRLX & ~(_ADC_SINGLECTRLX_VREFSEL_MASK
915                              | _ADC_SINGLECTRLX_PRSSEL_MASK
916                              | _ADC_SINGLECTRLX_FIFOOFACT_MASK);
917   if (((uint32_t)init->reference & ADC_CTRLX_VREFSEL_REG) != 0UL) {
918     tmp |= ((uint32_t)init->reference & ~ADC_CTRLX_VREFSEL_REG)
919            << _ADC_SINGLECTRLX_VREFSEL_SHIFT;
920   }
921 
922   tmp |= (uint32_t)init->prsSel << _ADC_SINGLECTRLX_PRSSEL_SHIFT;
923 
924   if (init->fifoOverwrite) {
925     tmp |= ADC_SINGLECTRLX_FIFOOFACT_OVERWRITE;
926   }
927 
928   adc->SINGLECTRLX = tmp;
929 #endif
930 
931   /* Set DMA availability in EM2. */
932 #if defined(_ADC_CTRL_SINGLEDMAWU_MASK)
933   BUS_RegBitWrite(&adc->CTRL,
934                   _ADC_CTRL_SINGLEDMAWU_SHIFT,
935                   (uint32_t)init->singleDmaEm2Wu);
936 #endif
937 
938 #if defined(_ADC_BIASPROG_GPBIASACC_MASK) && defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
939   if (init->posSel == adcPosSelTEMP) {
940     /* ADC should always use low accuracy setting when reading the internal
941      * temperature sensor on EFR32xG1. Using high
942      * accuracy setting can introduce a glitch. */
943     BUS_RegBitWrite(&adc->BIASPROG, _ADC_BIASPROG_GPBIASACC_SHIFT, 1);
944   } else {
945     BUS_RegBitWrite(&adc->BIASPROG, _ADC_BIASPROG_GPBIASACC_SHIFT, 0);
946   }
947 #endif
948 
949   /* Assert for any APORT bus conflicts programming errors. */
950 #if defined(_ADC_APORTCONFLICT_MASK)
951   tmp = adc->APORTREQ;
952   EFM_ASSERT(!(tmp & adc->APORTCONFLICT));
953   EFM_ASSERT(!(adc->STATUS & _ADC_STATUS_PROGERR_MASK));
954 #endif
955 }
956 
957 #if defined(_ADC_SCANDATAX_MASK)
958 /***************************************************************************//**
959  * @brief
960  *   Get a scan result and scan select ID.
961  *
962  * @note
963  *   Only use if scan data valid. This function does not check the DV flag.
964  *   The return value is meant to be used as an index for the scan select ID.
965  *
966  * @param[in] adc
967  *   A pointer to the ADC peripheral register block.
968  *
969  * @param[out] scanId
970  *   A scan select ID of the first data in the scan FIFO.
971  *
972  * @return
973  *   The first scan data in the scan FIFO.
974  ******************************************************************************/
ADC_DataIdScanGet(ADC_TypeDef * adc,uint32_t * scanId)975 uint32_t ADC_DataIdScanGet(ADC_TypeDef *adc, uint32_t *scanId)
976 {
977   uint32_t scanData;
978 
979   /* Pop data FIFO with scan ID */
980   scanData = adc->SCANDATAX;
981   *scanId = (scanData & _ADC_SCANDATAX_SCANINPUTID_MASK) >> _ADC_SCANDATAX_SCANINPUTID_SHIFT;
982   return (scanData & _ADC_SCANDATAX_DATA_MASK) >> _ADC_SCANDATAX_DATA_SHIFT;
983 }
984 #endif
985 
986 /***************************************************************************//**
987  * @brief
988  *   Calculate the prescaler value used to determine the ADC clock.
989  *
990  * @details
991  *   The ADC clock is given by: (HFPERCLK or HFPERCCLK) / (prescale + 1).
992  *
993  * @note
994  *   The return value is clamped to the maximum prescaler value that the hardware supports.
995  *
996  * @param[in] adcFreq ADC frequency wanted. The frequency will automatically
997  *   be adjusted to a valid range according to the reference manual.
998  *
999  * @param[in] hfperFreq Frequency in Hz of reference HFPER/HFPERC clock.
1000  *   Set to 0 to use currently defined HFPER/HFPERC clock setting.
1001  *
1002  * @return
1003  *   A prescaler value to use for ADC in order to achieve a clock value
1004  *   <= @p adcFreq.
1005  ******************************************************************************/
ADC_PrescaleCalc(uint32_t adcFreq,uint32_t hfperFreq)1006 uint8_t ADC_PrescaleCalc(uint32_t adcFreq, uint32_t hfperFreq)
1007 {
1008   uint32_t ret;
1009 
1010   /* Make sure that the selected ADC clock is within a valid range. */
1011   if (adcFreq > ADC_MAX_CLOCK) {
1012     adcFreq = ADC_MAX_CLOCK;
1013   } else if (adcFreq < ADC_MIN_CLOCK) {
1014     adcFreq = ADC_MIN_CLOCK;
1015   } else {
1016     /* Valid frequency. */
1017   }
1018 
1019   /* Use current HFPERCLK / HFPERCCLK frequency. */
1020   if (hfperFreq == 0UL) {
1021 #if defined(_CMU_HFPERPRESCC_MASK)
1022     hfperFreq = CMU_ClockFreqGet(cmuClock_HFPERC);
1023 #else
1024     hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
1025 #endif
1026   }
1027 
1028   ret = (hfperFreq + adcFreq - 1U) / adcFreq;
1029   if (ret > 0U) {
1030     ret--;
1031   }
1032 
1033   if (ret > (_ADC_CTRL_PRESC_MASK >> _ADC_CTRL_PRESC_SHIFT)) {
1034     ret = _ADC_CTRL_PRESC_MASK >> _ADC_CTRL_PRESC_SHIFT;
1035   }
1036 
1037   return (uint8_t)ret;
1038 }
1039 
1040 /***************************************************************************//**
1041  * @brief
1042  *   Reset ADC to a state that it was in after a hardware reset.
1043  *
1044  * @note
1045  *   The ROUTE register is NOT reset by this function to allow
1046  *   a centralized setup of this feature.
1047  *
1048  * @param[in] adc
1049  *   A pointer to ADC peripheral register block.
1050  ******************************************************************************/
ADC_Reset(ADC_TypeDef * adc)1051 void ADC_Reset(ADC_TypeDef *adc)
1052 {
1053   /* Stop conversions, before resetting other registers. */
1054   adc->CMD          = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP;
1055   adc->SINGLECTRL   = _ADC_SINGLECTRL_RESETVALUE;
1056 #if defined(_ADC_SINGLECTRLX_MASK)
1057   adc->SINGLECTRLX  = _ADC_SINGLECTRLX_RESETVALUE;
1058 #endif
1059   adc->SCANCTRL     = _ADC_SCANCTRL_RESETVALUE;
1060 #if defined(_ADC_SCANCTRLX_MASK)
1061   adc->SCANCTRLX    = _ADC_SCANCTRLX_RESETVALUE;
1062 #endif
1063   adc->CTRL         = _ADC_CTRL_RESETVALUE;
1064   adc->IEN          = _ADC_IEN_RESETVALUE;
1065   adc->IFC          = _ADC_IFC_MASK;
1066   adc->BIASPROG     = _ADC_BIASPROG_RESETVALUE;
1067 #if defined(_ADC_SCANMASK_MASK)
1068   adc->SCANMASK     = _ADC_SCANMASK_RESETVALUE;
1069 #endif
1070 #if defined(_ADC_SCANINPUTSEL_MASK)
1071   adc->SCANINPUTSEL = _ADC_SCANINPUTSEL_RESETVALUE;
1072 #endif
1073 #if defined(_ADC_SCANNEGSEL_MASK)
1074   adc->SCANNEGSEL   = _ADC_SCANNEGSEL_RESETVALUE;
1075 #endif
1076 
1077   /* Clear data FIFOs. */
1078 #if defined(_ADC_SINGLEFIFOCLEAR_MASK)
1079   adc->SINGLEFIFOCLEAR |= ADC_SINGLEFIFOCLEAR_SINGLEFIFOCLEAR;
1080   adc->SCANFIFOCLEAR   |= ADC_SCANFIFOCLEAR_SCANFIFOCLEAR;
1081 #endif
1082 
1083   /* Load calibration values for the 1V25 internal reference. */
1084   ADC_LoadDevinfoCal(adc, adcRef1V25, false);
1085   ADC_LoadDevinfoCal(adc, adcRef1V25, true);
1086 
1087 #if defined(_ADC_SCANINPUTSEL_MASK)
1088   /* Do not reset route register, setting should be done independently. */
1089 #endif
1090 }
1091 
1092 /***************************************************************************//**
1093  * @brief
1094  *   Calculate a timebase value to get a timebase providing at least 1 us.
1095  *
1096  * @param[in] hfperFreq Frequency in Hz of the reference HFPER/HFPERC clock.
1097  *   Set to 0 to use currently defined HFPER/HFPERC clock setting.
1098  *
1099  * @return
1100  *   A timebase value to use for ADC to achieve at least 1 us.
1101  ******************************************************************************/
ADC_TimebaseCalc(uint32_t hfperFreq)1102 uint8_t ADC_TimebaseCalc(uint32_t hfperFreq)
1103 {
1104   if (hfperFreq == 0UL) {
1105 #if defined(_CMU_HFPERPRESCC_MASK)
1106     hfperFreq = CMU_ClockFreqGet(cmuClock_HFPERC);
1107 #else
1108     hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
1109 #endif
1110 
1111     /* Make sure that the frequency is not 0 in below calculation. */
1112     if (hfperFreq == 0UL) {
1113       hfperFreq = 1UL;
1114     }
1115   }
1116 #if defined(_SILICON_LABS_32B_SERIES_0) \
1117   && (defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY))
1118   /* Handle errata on Giant Gecko, maximum TIMEBASE is 5 bits wide or max 0x1F */
1119   /* cycles. This will give a warm up time of e.g., 0.645 us, not the       */
1120   /* required 1 us when operating at 48 MHz. One must also increase acqTime  */
1121   /* to compensate for the missing clock cycles, adding up to 1 us total.*/
1122   /* See reference manual for details. */
1123   if ( hfperFreq > 32000000UL ) {
1124     hfperFreq = 32000000UL;
1125   }
1126 #endif
1127   /* Determine the number of HFPERCLK / HFPERCCLK cycle >= 1 us. */
1128   hfperFreq += 999999UL;
1129   hfperFreq /= 1000000UL;
1130 
1131   /* Return timebase value (N+1 format). */
1132   return (uint8_t)(hfperFreq - 1UL);
1133 }
1134 
1135 /** @} (end addtogroup adc) */
1136 #endif /* defined(ADC_COUNT) && (ADC_COUNT > 0) */
1137