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