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