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 "sl_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 #if defined(_CMU_HFPERPRESCC_MASK)
390       uint32_t hfperFreq = CMU_ClockFreqGet(cmuClock_HFPERC);
391 #else
392       uint32_t hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
393 #endif
394       uint32_t adcFreq = hfperFreq / (presc + 1);
395       EFM_ASSERT(adcFreq >= ADC_MIN_CLOCK);
396       EFM_ASSERT(adcFreq <= ADC_MAX_CLOCK);
397     }
398   }
399 
400   /* Make sure conversion is not in progress. */
401   adc->CMD = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP;
402 
403   tmp = ((uint32_t)(init->ovsRateSel) << _ADC_CTRL_OVSRSEL_SHIFT)
404         | (((uint32_t)(init->timebase) << _ADC_CTRL_TIMEBASE_SHIFT)
405            & _ADC_CTRL_TIMEBASE_MASK)
406         | (((uint32_t)(presc) << _ADC_CTRL_PRESC_SHIFT)
407            & _ADC_CTRL_PRESC_MASK)
408 #if defined (_ADC_CTRL_LPFMODE_MASK)
409         | ((uint32_t)(init->lpfMode) << _ADC_CTRL_LPFMODE_SHIFT)
410 #endif
411         | ((uint32_t)(init->warmUpMode) << _ADC_CTRL_WARMUPMODE_SHIFT);
412 
413   if (init->tailgate) {
414     tmp |= ADC_CTRL_TAILGATE;
415   }
416 #if defined(_ADC_CTRL_SINGLEDMAWU_MASK)
417   /* make sure we don't clear the ADC_CTRL_SINGLEDMAWU bit if it has been initialized by ADC_InitSingle */
418   if (adc->CTRL & _ADC_CTRL_SINGLEDMAWU_MASK) {
419     tmp |= _ADC_CTRL_SINGLEDMAWU_MASK;
420   }
421 #endif
422   adc->CTRL = tmp;
423 
424 #if defined(_ADC_CTRL_ADCCLKMODE_MASK)
425   /* Set ADC EM2 clock configuration. */
426   BUS_RegMaskedWrite(&adc->CTRL,
427                      _ADC_CTRL_ADCCLKMODE_MASK | _ADC_CTRL_ASYNCCLKEN_MASK,
428                      (uint32_t)init->em2ClockConfig);
429 
430 #if defined(_SILICON_LABS_32B_SERIES_1)
431   /* In asynch clock mode assert that the ADC clock frequency is
432      less or equal to 2/3 of the HFPER/HFPERC clock frequency. */
433   if ((adc->CTRL & _ADC_CTRL_ADCCLKMODE_MASK) == ADC_CTRL_ADCCLKMODE_ASYNC) {
434     CMU_Clock_TypeDef asyncClk = cmuClock_ADC0ASYNC;
435     uint32_t adcClkFreq;
436     uint32_t hfperClkFreq = 0;
437 #if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
438     if ( adc == ADC1 ) {
439       asyncClk = cmuClock_ADC1ASYNC;
440     }
441 #endif
442     adcClkFreq = CMU_ClockFreqGet(asyncClk);
443     if (adc == ADC0) {
444       hfperClkFreq = CMU_ClockFreqGet(cmuClock_ADC0);
445 #if defined(ADC1)
446     } else if (adc == ADC1) {
447       hfperClkFreq = CMU_ClockFreqGet(cmuClock_ADC1);
448 #endif
449     } else {
450       EFM_ASSERT(false);
451     }
452     EFM_ASSERT(hfperClkFreq >= (adcClkFreq * 3) / 2);
453   }
454 #endif /* #if defined(_SILICON_LABS_32B_SERIES_1) */
455 #endif /* #if defined(_ADC_CTRL_ADCCLKMODE_MASK) */
456 
457 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
458   /* A debugger can trigger the SCANUF interrupt on EFM32xG1 or EFR32xG1 */
459   ADC_IntClear(adc, ADC_IFC_SCANUF);
460 #endif
461 }
462 
463 #if defined(_ADC_SCANINPUTSEL_MASK)
464 /***************************************************************************//**
465  * @brief
466  *   Clear ADC scan input configuration.
467  *
468  * @param[in] scanInit
469  *   Structure to hold the scan configuration and input configuration.
470  ******************************************************************************/
ADC_ScanInputClear(ADC_InitScan_TypeDef * scanInit)471 void ADC_ScanInputClear(ADC_InitScan_TypeDef *scanInit)
472 {
473   /* Clear the input configuration. */
474 
475   /* Select none. */
476   scanInit->scanInputConfig.scanInputSel = ADC_SCANINPUTSEL_NONE;
477   scanInit->scanInputConfig.scanInputEn = 0;
478 
479   /* Default alternative negative inputs. */
480   scanInit->scanInputConfig.scanNegSel = _ADC_SCANNEGSEL_RESETVALUE;
481 }
482 
483 /***************************************************************************//**
484  * @brief
485  *   Initialize ADC scan single-ended input configuration.
486  *
487  * @details
488  *   Set a configuration for ADC scan conversion with single-ended inputs. The
489  *   ADC_InitScan_TypeDef structure updated from this function will be passed to
490  *   ADC_InitScan().
491  *
492  * @param[in] scanInit
493  *   ADC scan initialization structure
494  *
495  * @param[in] inputGroup
496  *   ADC scan input group. See section 25.3.4 in the reference manual for
497  *   more information.
498  *
499  * @param[in] singleEndedSel
500  *   APORT select.
501  *
502  * @return
503  *   Scan ID of selected ADC input. See section 25.3.4 in the reference manual for
504  *   more information. Note that the returned integer represents the bit position
505  *   in ADCn_SCANMASK set by this function. The accumulated mask is stored in
506  *   scanInit->scanInputConfig->scanInputEn.
507  ******************************************************************************/
ADC_ScanSingleEndedInputAdd(ADC_InitScan_TypeDef * scanInit,ADC_ScanInputGroup_TypeDef inputGroup,ADC_PosSel_TypeDef singleEndedSel)508 uint32_t ADC_ScanSingleEndedInputAdd(ADC_InitScan_TypeDef *scanInit,
509                                      ADC_ScanInputGroup_TypeDef inputGroup,
510                                      ADC_PosSel_TypeDef singleEndedSel)
511 {
512   uint32_t currentSel;
513   uint32_t newSel;
514   uint32_t scanId;
515 
516   scanInit->diff = false;
517 
518   /* Check for an illegal group. */
519   EFM_ASSERT((unsigned)inputGroup < 4U);
520 
521   /* Decode the input group select by shifting right by 3. */
522   newSel = (unsigned)singleEndedSel >> 3;
523   /* Map 0Y channels to 0X. */
524   if ((newSel == 2) || (newSel == 3)) {
525     newSel -= 2;
526   }
527 
528   currentSel = (scanInit->scanInputConfig.scanInputSel
529                 >> ((unsigned)inputGroup * 8U)) & 0xFFU;
530 
531   /* If none selected. */
532   if (currentSel == ADC_SCANINPUTSEL_GROUP_NONE) {
533     scanInit->scanInputConfig.scanInputSel &=
534       ~(0xFFU << ((unsigned)inputGroup * 8U));
535     scanInit->scanInputConfig.scanInputSel |=
536       newSel << ((unsigned)inputGroup * 8U);
537   } else if (currentSel == newSel) {
538     /* Ok, but do nothing.  */
539   } else {
540     /* Invalid channel range. A range is already selected for this group. */
541     EFM_ASSERT(false);
542   }
543 
544   /* Update and return scan input enable mask (SCANMASK). */
545   scanId = ((unsigned)inputGroup * 8U) + ((unsigned)singleEndedSel & 0x7U);
546   EFM_ASSERT(scanId < 32U);
547   scanInit->scanInputConfig.scanInputEn |= 0x1UL << scanId;
548   return scanId;
549 }
550 
551 /***************************************************************************//**
552  * @brief
553  *   Initialize the ADC scan differential input configuration.
554  *
555  * @details
556  *   Set a configuration for the ADC scan conversion with differential inputs. The
557  *   ADC_InitScan_TypeDef structure updated by this function should be passed to
558  *   ADC_InitScan().
559  *
560  * @param[in] scanInit
561  *   Structure to hold the scan and input configuration.
562  *
563  * @param[in] inputGroup
564  *   ADC scan input group. See section 25.3.4 in the reference manual for
565  *   more information.
566  *
567  * @param[in] posSel
568  *   APORT bus pair select. The negative terminal is implicitly selected by
569  *   the positive terminal.
570  *
571  * @param[in] negInput
572  *   ADC scan alternative negative input. Set to adcScanNegInputDefault to select
573  *   a default negative input (implicit from posSel).
574  *
575  * @return
576  *   Scan ID of the selected ADC input. See section 25.3.4 in the reference manual for
577  *   more information. Note that the returned integer represents the bit position
578  *   in ADCn_SCANMASK set by this function. The accumulated mask is stored in the
579  *   scanInit->scanInputConfig->scanInputEn.
580  ******************************************************************************/
ADC_ScanDifferentialInputAdd(ADC_InitScan_TypeDef * scanInit,ADC_ScanInputGroup_TypeDef inputGroup,ADC_PosSel_TypeDef posSel,ADC_ScanNegInput_TypeDef negInput)581 uint32_t ADC_ScanDifferentialInputAdd(ADC_InitScan_TypeDef *scanInit,
582                                       ADC_ScanInputGroup_TypeDef inputGroup,
583                                       ADC_PosSel_TypeDef posSel,
584                                       ADC_ScanNegInput_TypeDef negInput)
585 {
586   uint32_t negInputRegMask = 0;
587   uint32_t negInputRegShift = 0;
588   uint32_t negInputRegVal = 0;
589   uint32_t scanId;
590 
591   /* Perform a single-ended initialization, then update for differential scan. */
592   scanId = ADC_ScanSingleEndedInputAdd(scanInit, inputGroup, posSel);
593 
594   /* Reset to differential mode. */
595   scanInit->diff = true;
596 
597   /* Set negative ADC input unless the default is selected. */
598   if (negInput != adcScanNegInputDefault) {
599     if (scanId == 0U) {
600       negInputRegMask  = _ADC_SCANNEGSEL_INPUT0NEGSEL_MASK;
601       negInputRegShift = _ADC_SCANNEGSEL_INPUT0NEGSEL_SHIFT;
602       EFM_ASSERT((unsigned)inputGroup == 0U);
603     } else if (scanId == 2U) {
604       negInputRegMask  = _ADC_SCANNEGSEL_INPUT2NEGSEL_MASK;
605       negInputRegShift = _ADC_SCANNEGSEL_INPUT2NEGSEL_SHIFT;
606       EFM_ASSERT((unsigned)inputGroup == 0U);
607     } else if (scanId == 4U) {
608       negInputRegMask  = _ADC_SCANNEGSEL_INPUT4NEGSEL_MASK;
609       negInputRegShift = _ADC_SCANNEGSEL_INPUT4NEGSEL_SHIFT;
610       EFM_ASSERT((unsigned)inputGroup == 0U);
611     } else if (scanId == 6U) {
612       negInputRegMask  = _ADC_SCANNEGSEL_INPUT6NEGSEL_MASK;
613       negInputRegShift = _ADC_SCANNEGSEL_INPUT6NEGSEL_SHIFT;
614       EFM_ASSERT((unsigned)inputGroup == 0U);
615     } else if (scanId == 9U) {
616       negInputRegMask  = _ADC_SCANNEGSEL_INPUT9NEGSEL_MASK;
617       negInputRegShift = _ADC_SCANNEGSEL_INPUT9NEGSEL_SHIFT;
618       EFM_ASSERT((unsigned)inputGroup == 1U);
619     } else if (scanId == 11U) {
620       negInputRegMask  = _ADC_SCANNEGSEL_INPUT11NEGSEL_MASK;
621       negInputRegShift = _ADC_SCANNEGSEL_INPUT11NEGSEL_SHIFT;
622       EFM_ASSERT((unsigned)inputGroup == 1U);
623     } else if (scanId == 13U) {
624       negInputRegMask  = _ADC_SCANNEGSEL_INPUT13NEGSEL_MASK;
625       negInputRegShift = _ADC_SCANNEGSEL_INPUT13NEGSEL_SHIFT;
626       EFM_ASSERT((unsigned)inputGroup == 1U);
627     } else if (scanId == 15U) {
628       negInputRegMask  = _ADC_SCANNEGSEL_INPUT15NEGSEL_MASK;
629       negInputRegShift = _ADC_SCANNEGSEL_INPUT15NEGSEL_SHIFT;
630       EFM_ASSERT((unsigned)inputGroup == 1U);
631     } else {
632       /* The positive input does not have a negative input option (negInput is posInput + 1). */
633       EFM_ASSERT(false);
634     }
635 
636     /* Find ADC_SCANNEGSEL_CHxNSEL value for positive input 0, 2, 4, and 6. */
637     if ((unsigned)inputGroup == 0U) {
638       switch (negInput) {
639         case adcScanNegInput1:
640           negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT1;
641           break;
642 
643         case adcScanNegInput3:
644           negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT3;
645           break;
646 
647         case adcScanNegInput5:
648           negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT5;
649           break;
650 
651         case adcScanNegInput7:
652           negInputRegVal = _ADC_SCANNEGSEL_INPUT0NEGSEL_INPUT7;
653           break;
654 
655         default:
656           /* An invalid selection. Options are input 1, 3, 5 and 7. */
657           EFM_ASSERT(false);
658           break;
659       }
660     } else { /* inputGroup == 1 */
661       /* Find ADC_SCANNEGSEL_CHxNSEL value for positive input 9, 11, 13, and 15. */
662       switch (negInput) {
663         case adcScanNegInput8:
664           negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT8;
665           break;
666 
667         case adcScanNegInput10:
668           negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT10;
669           break;
670 
671         case adcScanNegInput12:
672           negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT12;
673           break;
674 
675         case adcScanNegInput14:
676           negInputRegVal = _ADC_SCANNEGSEL_INPUT9NEGSEL_INPUT14;
677           break;
678 
679         default:
680           /* Invalid selection. Options are input 8, 10, 12, and 14. */
681           EFM_ASSERT(false);
682           break;
683       }
684     }
685 
686     /* Update configuration. */
687     scanInit->scanInputConfig.scanNegSel &= ~negInputRegMask;
688     scanInit->scanInputConfig.scanNegSel |= negInputRegVal << negInputRegShift;
689   }
690   return scanId;
691 }
692 #endif
693 
694 /***************************************************************************//**
695  * @brief
696  *   Initialize the ADC scan sequence.
697  *
698  * @details
699  *   See ADC_Start() for starting a scan sequence.
700  *
701  *   When selecting an external reference, the gain and offset calibration
702  *   must be set explicitly (CAL register). For other references, the
703  *   calibration is updated with values defined during manufacturing.
704  *   For ADC architectures with the ADCn->SCANINPUTSEL register, use
705  *   ADC_ScanSingleEndedInputAdd() to configure single-ended scan inputs or
706  *   ADC_ScanDifferentialInputAdd() to configure differential scan inputs.
707  *   ADC_ScanInputClear() is also provided for applications that need to update
708  *   the input configuration.
709  *
710  * @note
711  *   This function will stop any ongoing scan sequence.
712  *
713  * @param[in] adc
714  *   A pointer to the ADC peripheral register block.
715  *
716  * @param[in] init
717  *   A pointer to the ADC initialization structure.
718  ******************************************************************************/
ADC_InitScan(ADC_TypeDef * adc,const ADC_InitScan_TypeDef * init)719 void ADC_InitScan(ADC_TypeDef *adc, const ADC_InitScan_TypeDef *init)
720 {
721   uint32_t tmp;
722 
723   EFM_ASSERT(ADC_REF_VALID(adc));
724 
725   /* Make sure scan sequence is not in progress. */
726   adc->CMD = ADC_CMD_SCANSTOP;
727 
728   /* Load calibration data for a selected reference. */
729   ADC_LoadDevinfoCal(adc, init->reference, true);
730 
731   tmp = 0UL
732 #if defined (_ADC_SCANCTRL_PRSSEL_MASK)
733         | ((uint32_t)init->prsSel << _ADC_SCANCTRL_PRSSEL_SHIFT)
734 #endif
735         | ((uint32_t)init->acqTime << _ADC_SCANCTRL_AT_SHIFT)
736 #if defined (_ADC_SCANCTRL_INPUTMASK_MASK)
737         | init->input
738 #endif
739         | ((uint32_t)init->resolution << _ADC_SCANCTRL_RES_SHIFT);
740 
741   if (init->prsEnable) {
742     tmp |= ADC_SCANCTRL_PRSEN;
743   }
744 
745   if (init->leftAdjust) {
746     tmp |= ADC_SCANCTRL_ADJ_LEFT;
747   }
748 
749 #if defined(_ADC_SCANCTRL_INPUTMASK_MASK)
750   if (init->diff)
751 #elif defined(_ADC_SCANINPUTSEL_MASK)
752   if (init->diff)
753 #endif
754   {
755     tmp |= ADC_SCANCTRL_DIFF;
756   }
757 
758   if (init->rep) {
759 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
760     /* Scan repeat mode does not work on EFM32JG1, EFM32PG1, or EFR32xG1x devices.
761      * The errata is called ADC_E211 in the errata document. */
762     EFM_ASSERT(false);
763 #endif
764     tmp |= ADC_SCANCTRL_REP;
765   }
766 
767   /* Set scan reference. Check if the reference configuration is extended to SCANCTRLX. */
768 #if defined (_ADC_SCANCTRLX_VREFSEL_MASK)
769   if (((uint32_t)init->reference & ADC_CTRLX_VREFSEL_REG) != 0UL) {
770     /* Select the extension register. */
771     tmp |= ADC_SCANCTRL_REF_CONF;
772   } else {
773     tmp |= (uint32_t)init->reference << _ADC_SCANCTRL_REF_SHIFT;
774   }
775 #else
776   tmp |= init->reference << _ADC_SCANCTRL_REF_SHIFT;
777 #endif
778 
779 #if defined(_ADC_SCANCTRL_INPUTMASK_MASK)
780   tmp |= init->input;
781 #endif
782 
783   adc->SCANCTRL = tmp;
784 
785   /* Update SINGLECTRLX for reference select and PRS select. */
786 #if defined (_ADC_SCANCTRLX_MASK)
787   tmp = adc->SCANCTRLX & ~(_ADC_SCANCTRLX_VREFSEL_MASK
788                            | _ADC_SCANCTRLX_PRSSEL_MASK
789                            | _ADC_SCANCTRLX_FIFOOFACT_MASK);
790   if (((uint32_t)init->reference & ADC_CTRLX_VREFSEL_REG) != 0UL) {
791     tmp |= ((uint32_t)init->reference & ~ADC_CTRLX_VREFSEL_REG) << _ADC_SCANCTRLX_VREFSEL_SHIFT;
792   }
793 
794   tmp |= (uint32_t)init->prsSel << _ADC_SCANCTRLX_PRSSEL_SHIFT;
795 
796   if (init->fifoOverwrite) {
797     tmp |= ADC_SCANCTRLX_FIFOOFACT_OVERWRITE;
798   }
799 
800   adc->SCANCTRLX = tmp;
801 #endif
802 
803 #if defined(_ADC_CTRL_SCANDMAWU_MASK)
804   BUS_RegBitWrite(&adc->CTRL,
805                   _ADC_CTRL_SCANDMAWU_SHIFT,
806                   (uint32_t)init->scanDmaEm2Wu);
807 #endif
808 
809   /* Write the scan input configuration. */
810 #if defined(_ADC_SCANINPUTSEL_MASK)
811   /* Check for valid scan input configuration. Use @ref ADC_ScanInputClear(),
812      @ref ADC_ScanSingleEndedInputAdd(), and @ref ADC_ScanDifferentialInputAdd() to set
813      the scan input configuration.  */
814   EFM_ASSERT(init->scanInputConfig.scanInputSel != ADC_SCANINPUTSEL_NONE);
815   adc->SCANINPUTSEL = init->scanInputConfig.scanInputSel;
816   adc->SCANMASK     = init->scanInputConfig.scanInputEn;
817   adc->SCANNEGSEL   = init->scanInputConfig.scanNegSel;
818 #endif
819 
820   /* Assert for any APORT bus conflicts programming errors. */
821 #if defined(_ADC_APORTCONFLICT_MASK)
822   tmp = adc->APORTREQ;
823   EFM_ASSERT(!(tmp & adc->APORTCONFLICT));
824   EFM_ASSERT(!(adc->STATUS & _ADC_STATUS_PROGERR_MASK));
825 #endif
826 }
827 
828 /***************************************************************************//**
829  * @brief
830  *   Initialize the single ADC sample conversion.
831  *
832  * @details
833  *   See ADC_Start() for starting a single conversion.
834  *
835  *   When selecting an external reference, the gain and offset calibration
836  *   must be set explicitly (CAL register). For other references, the
837  *   calibration is updated with values defined during manufacturing.
838  *
839  * @note
840  *   This function will stop any ongoing single conversion.
841  *
842  * @cond DOXYDOC_P2_DEVICE
843  * @note
844  *   This function will set the BIASPROG_GPBIASACC bit when selecting the
845  *   internal temperature sensor and clear the bit otherwise. Any
846  *   application that depends on the state of the BIASPROG_GPBIASACC bit should
847  *   modify it after a call to this function.
848  * @endcond
849  *
850  * @param[in] adc
851  *   A pointer to the ADC peripheral register block.
852  *
853  * @param[in] init
854  *   A pointer to the ADC initialization structure.
855  ******************************************************************************/
ADC_InitSingle(ADC_TypeDef * adc,const ADC_InitSingle_TypeDef * init)856 void ADC_InitSingle(ADC_TypeDef *adc, const ADC_InitSingle_TypeDef *init)
857 {
858   uint32_t tmp;
859 
860   EFM_ASSERT(ADC_REF_VALID(adc));
861 
862   /* Make sure single conversion is not in progress. */
863   adc->CMD = ADC_CMD_SINGLESTOP;
864 
865   /* Load calibration data for selected reference. */
866   ADC_LoadDevinfoCal(adc, init->reference, false);
867 
868   tmp = 0UL
869 #if defined(_ADC_SINGLECTRL_PRSSEL_MASK)
870         | ((uint32_t)init->prsSel << _ADC_SINGLECTRL_PRSSEL_SHIFT)
871 #endif
872         | ((uint32_t)init->acqTime << _ADC_SINGLECTRL_AT_SHIFT)
873 #if defined(_ADC_SINGLECTRL_INPUTSEL_MASK)
874         | (init->input << _ADC_SINGLECTRL_INPUTSEL_SHIFT)
875 #endif
876 #if defined(_ADC_SINGLECTRL_POSSEL_MASK)
877         | ((uint32_t)init->posSel << _ADC_SINGLECTRL_POSSEL_SHIFT)
878 #endif
879 #if defined(_ADC_SINGLECTRL_NEGSEL_MASK)
880         | ((uint32_t)init->negSel << _ADC_SINGLECTRL_NEGSEL_SHIFT)
881 #endif
882         | ((uint32_t)(init->resolution) << _ADC_SINGLECTRL_RES_SHIFT);
883 
884   if (init->prsEnable) {
885     tmp |= ADC_SINGLECTRL_PRSEN;
886   }
887 
888   if (init->leftAdjust) {
889     tmp |= ADC_SINGLECTRL_ADJ_LEFT;
890   }
891 
892   if (init->diff) {
893     tmp |= ADC_SINGLECTRL_DIFF;
894   }
895 
896   if (init->rep) {
897     tmp |= ADC_SINGLECTRL_REP;
898   }
899 
900 #if defined(_ADC_SINGLECTRL_POSSEL_TEMP)
901   /* Force at least 8 cycle acquisition time when reading the internal temperature
902    * sensor with 1.25 V reference */
903   if ((init->posSel == adcPosSelTEMP)
904       && (init->reference == adcRef1V25)
905       && (init->acqTime < adcAcqTime8)) {
906     tmp = (tmp & ~_ADC_SINGLECTRL_AT_MASK)
907           | ((uint32_t)adcAcqTime8 << _ADC_SINGLECTRL_AT_SHIFT);
908   }
909 #endif
910 
911   /* Set a single reference. Check if the reference configuration is extended to SINGLECTRLX. */
912 #if defined (_ADC_SINGLECTRLX_MASK)
913   if (((uint32_t)init->reference & ADC_CTRLX_VREFSEL_REG) != 0UL) {
914     /* Select the extension register. */
915     tmp |= ADC_SINGLECTRL_REF_CONF;
916   } else {
917     tmp |= (uint32_t)init->reference << _ADC_SINGLECTRL_REF_SHIFT;
918   }
919 #else
920   tmp |= (uint32_t)init->reference << _ADC_SINGLECTRL_REF_SHIFT;
921 #endif
922   adc->SINGLECTRL = tmp;
923 
924   /* Update SINGLECTRLX for reference select and PRS select. */
925 #if defined (_ADC_SINGLECTRLX_VREFSEL_MASK)
926   tmp = adc->SINGLECTRLX & ~(_ADC_SINGLECTRLX_VREFSEL_MASK
927                              | _ADC_SINGLECTRLX_PRSSEL_MASK
928                              | _ADC_SINGLECTRLX_FIFOOFACT_MASK);
929   if (((uint32_t)init->reference & ADC_CTRLX_VREFSEL_REG) != 0UL) {
930     tmp |= ((uint32_t)init->reference & ~ADC_CTRLX_VREFSEL_REG)
931            << _ADC_SINGLECTRLX_VREFSEL_SHIFT;
932   }
933 
934   tmp |= (uint32_t)init->prsSel << _ADC_SINGLECTRLX_PRSSEL_SHIFT;
935 
936   if (init->fifoOverwrite) {
937     tmp |= ADC_SINGLECTRLX_FIFOOFACT_OVERWRITE;
938   }
939 
940   adc->SINGLECTRLX = tmp;
941 #endif
942 
943   /* Set DMA availability in EM2. */
944 #if defined(_ADC_CTRL_SINGLEDMAWU_MASK)
945   BUS_RegBitWrite(&adc->CTRL,
946                   _ADC_CTRL_SINGLEDMAWU_SHIFT,
947                   (uint32_t)init->singleDmaEm2Wu);
948 #endif
949 
950 #if defined(_ADC_BIASPROG_GPBIASACC_MASK) && defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
951   if (init->posSel == adcPosSelTEMP) {
952     /* ADC should always use low accuracy setting when reading the internal
953      * temperature sensor on EFR32xG1. Using high
954      * accuracy setting can introduce a glitch. */
955     BUS_RegBitWrite(&adc->BIASPROG, _ADC_BIASPROG_GPBIASACC_SHIFT, 1);
956   } else {
957     BUS_RegBitWrite(&adc->BIASPROG, _ADC_BIASPROG_GPBIASACC_SHIFT, 0);
958   }
959 #endif
960 
961   /* Assert for any APORT bus conflicts programming errors. */
962 #if defined(_ADC_APORTCONFLICT_MASK)
963   tmp = adc->APORTREQ;
964   EFM_ASSERT(!(tmp & adc->APORTCONFLICT));
965   EFM_ASSERT(!(adc->STATUS & _ADC_STATUS_PROGERR_MASK));
966 #endif
967 }
968 
969 #if defined(_ADC_SCANDATAX_MASK)
970 /***************************************************************************//**
971  * @brief
972  *   Get a scan result and scan select ID.
973  *
974  * @note
975  *   Only use if scan data valid. This function does not check the DV flag.
976  *   The return value is meant to be used as an index for the scan select ID.
977  *
978  * @param[in] adc
979  *   A pointer to the ADC peripheral register block.
980  *
981  * @param[out] scanId
982  *   A scan select ID of the first data in the scan FIFO.
983  *
984  * @return
985  *   The first scan data in the scan FIFO.
986  ******************************************************************************/
ADC_DataIdScanGet(ADC_TypeDef * adc,uint32_t * scanId)987 uint32_t ADC_DataIdScanGet(ADC_TypeDef *adc, uint32_t *scanId)
988 {
989   uint32_t scanData;
990 
991   /* Pop data FIFO with scan ID */
992   scanData = adc->SCANDATAX;
993   *scanId = (scanData & _ADC_SCANDATAX_SCANINPUTID_MASK) >> _ADC_SCANDATAX_SCANINPUTID_SHIFT;
994   return (scanData & _ADC_SCANDATAX_DATA_MASK) >> _ADC_SCANDATAX_DATA_SHIFT;
995 }
996 #endif
997 
998 /***************************************************************************//**
999  * @brief
1000  *   Calculate the prescaler value used to determine the ADC clock.
1001  *
1002  * @details
1003  *   The ADC clock is given by: (HFPERCLK or HFPERCCLK) / (prescale + 1).
1004  *
1005  * @note
1006  *   The return value is clamped to the maximum prescaler value that the hardware supports.
1007  *
1008  * @param[in] adcFreq ADC frequency wanted. The frequency will automatically
1009  *   be adjusted to a valid range according to the reference manual.
1010  *
1011  * @param[in] hfperFreq Frequency in Hz of reference HFPER/HFPERC clock.
1012  *   Set to 0 to use currently defined HFPER/HFPERC clock setting.
1013  *
1014  * @return
1015  *   A prescaler value to use for ADC in order to achieve a clock value
1016  *   <= @p adcFreq.
1017  ******************************************************************************/
ADC_PrescaleCalc(uint32_t adcFreq,uint32_t hfperFreq)1018 uint8_t ADC_PrescaleCalc(uint32_t adcFreq, uint32_t hfperFreq)
1019 {
1020   uint32_t ret;
1021 
1022   /* Make sure that the selected ADC clock is within a valid range. */
1023   if (adcFreq > ADC_MAX_CLOCK) {
1024     adcFreq = ADC_MAX_CLOCK;
1025   } else if (adcFreq < ADC_MIN_CLOCK) {
1026     adcFreq = ADC_MIN_CLOCK;
1027   }
1028 
1029   /* Use current HFPERCLK / HFPERCCLK frequency. */
1030   if (hfperFreq == 0UL) {
1031 #if defined(_CMU_HFPERPRESCC_MASK)
1032     hfperFreq = CMU_ClockFreqGet(cmuClock_HFPERC);
1033 #else
1034     hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
1035 #endif
1036   }
1037 
1038   ret = (hfperFreq + adcFreq - 1U) / adcFreq;
1039   if (ret > 0U) {
1040     ret--;
1041   }
1042 
1043   EFM_ASSERT(ret <= (_ADC_CTRL_PRESC_MASK >> _ADC_CTRL_PRESC_SHIFT));
1044 
1045   if (ret > (_ADC_CTRL_PRESC_MASK >> _ADC_CTRL_PRESC_SHIFT)) {
1046     ret = _ADC_CTRL_PRESC_MASK >> _ADC_CTRL_PRESC_SHIFT;
1047   }
1048 
1049   return (uint8_t)ret;
1050 }
1051 
1052 /***************************************************************************//**
1053  * @brief
1054  *   Reset ADC to a state that it was in after a hardware reset.
1055  *
1056  * @note
1057  *   The ROUTE register is NOT reset by this function to allow
1058  *   a centralized setup of this feature.
1059  *
1060  * @param[in] adc
1061  *   A pointer to ADC peripheral register block.
1062  ******************************************************************************/
ADC_Reset(ADC_TypeDef * adc)1063 void ADC_Reset(ADC_TypeDef *adc)
1064 {
1065   /* Stop conversions, before resetting other registers. */
1066   adc->CMD          = ADC_CMD_SINGLESTOP | ADC_CMD_SCANSTOP;
1067   adc->SINGLECTRL   = _ADC_SINGLECTRL_RESETVALUE;
1068 #if defined(_ADC_SINGLECTRLX_MASK)
1069   adc->SINGLECTRLX  = _ADC_SINGLECTRLX_RESETVALUE;
1070 #endif
1071   adc->SCANCTRL     = _ADC_SCANCTRL_RESETVALUE;
1072 #if defined(_ADC_SCANCTRLX_MASK)
1073   adc->SCANCTRLX    = _ADC_SCANCTRLX_RESETVALUE;
1074 #endif
1075   adc->CTRL         = _ADC_CTRL_RESETVALUE;
1076   adc->IEN          = _ADC_IEN_RESETVALUE;
1077   adc->IFC          = _ADC_IFC_MASK;
1078   adc->BIASPROG     = _ADC_BIASPROG_RESETVALUE;
1079 #if defined(_ADC_SCANMASK_MASK)
1080   adc->SCANMASK     = _ADC_SCANMASK_RESETVALUE;
1081 #endif
1082 #if defined(_ADC_SCANINPUTSEL_MASK)
1083   adc->SCANINPUTSEL = _ADC_SCANINPUTSEL_RESETVALUE;
1084 #endif
1085 #if defined(_ADC_SCANNEGSEL_MASK)
1086   adc->SCANNEGSEL   = _ADC_SCANNEGSEL_RESETVALUE;
1087 #endif
1088 
1089   /* Clear data FIFOs. */
1090 #if defined(_ADC_SINGLEFIFOCLEAR_MASK)
1091   adc->SINGLEFIFOCLEAR |= ADC_SINGLEFIFOCLEAR_SINGLEFIFOCLEAR;
1092   adc->SCANFIFOCLEAR   |= ADC_SCANFIFOCLEAR_SCANFIFOCLEAR;
1093 #endif
1094 
1095   /* Load calibration values for the 1V25 internal reference. */
1096   ADC_LoadDevinfoCal(adc, adcRef1V25, false);
1097   ADC_LoadDevinfoCal(adc, adcRef1V25, true);
1098 
1099 #if defined(_ADC_SCANINPUTSEL_MASK)
1100   /* Do not reset route register, setting should be done independently. */
1101 #endif
1102 }
1103 
1104 /***************************************************************************//**
1105  * @brief
1106  *   Calculate a timebase value to get a timebase providing at least 1 us.
1107  *
1108  * @param[in] hfperFreq Frequency in Hz of the reference HFPER/HFPERC clock.
1109  *   Set to 0 to use currently defined HFPER/HFPERC clock setting.
1110  *
1111  * @return
1112  *   A timebase value to use for ADC to achieve at least 1 us.
1113  ******************************************************************************/
ADC_TimebaseCalc(uint32_t hfperFreq)1114 uint8_t ADC_TimebaseCalc(uint32_t hfperFreq)
1115 {
1116   if (hfperFreq == 0UL) {
1117 #if defined(_CMU_HFPERPRESCC_MASK)
1118     hfperFreq = CMU_ClockFreqGet(cmuClock_HFPERC);
1119 #else
1120     hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
1121 #endif
1122 
1123     /* Make sure that the frequency is not 0 in below calculation. */
1124     if (hfperFreq == 0UL) {
1125       hfperFreq = 1UL;
1126     }
1127   }
1128 #if defined(_SILICON_LABS_32B_SERIES_0) \
1129   && (defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY))
1130   /* Handle errata on Giant Gecko, maximum TIMEBASE is 5 bits wide or max 0x1F */
1131   /* cycles. This will give a warm up time of e.g., 0.645 us, not the       */
1132   /* required 1 us when operating at 48 MHz. One must also increase acqTime  */
1133   /* to compensate for the missing clock cycles, adding up to 1 us total.*/
1134   /* See reference manual for details. */
1135   if ( hfperFreq > 32000000UL ) {
1136     hfperFreq = 32000000UL;
1137   }
1138 #endif
1139   /* Determine the number of HFPERCLK / HFPERCCLK cycle >= 1 us. */
1140   hfperFreq += 999999UL;
1141   hfperFreq /= 1000000UL;
1142 
1143   /* Return timebase value (N+1 format). */
1144   return (uint8_t)(hfperFreq - 1UL);
1145 }
1146 
1147 /** @} (end addtogroup adc) */
1148 #endif /* defined(ADC_COUNT) && (ADC_COUNT > 0) */
1149