1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2021 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_adc16.h"
10
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.adc16"
14 #endif
15
16 /*******************************************************************************
17 * Prototypes
18 ******************************************************************************/
19 /*!
20 * @brief Get instance number for ADC16 module.
21 *
22 * @param base ADC16 peripheral base address
23 */
24 static uint32_t ADC16_GetInstance(ADC_Type *base);
25
26 /*******************************************************************************
27 * Variables
28 ******************************************************************************/
29 /*! @brief Pointers to ADC16 bases for each instance. */
30 static ADC_Type *const s_adc16Bases[] = ADC_BASE_PTRS;
31
32 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
33 /*! @brief Pointers to ADC16 clocks for each instance. */
34 static const clock_ip_name_t s_adc16Clocks[] = ADC16_CLOCKS;
35 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
36
37 /*******************************************************************************
38 * Code
39 ******************************************************************************/
ADC16_GetInstance(ADC_Type * base)40 static uint32_t ADC16_GetInstance(ADC_Type *base)
41 {
42 uint32_t instance;
43
44 /* Find the instance index from base address mappings. */
45 for (instance = 0; instance < ARRAY_SIZE(s_adc16Bases); instance++)
46 {
47 if (s_adc16Bases[instance] == base)
48 {
49 break;
50 }
51 }
52
53 assert(instance < ARRAY_SIZE(s_adc16Bases));
54
55 return instance;
56 }
57
58 /*!
59 * brief Initializes the ADC16 module.
60 *
61 * param base ADC16 peripheral base address.
62 * param config Pointer to configuration structure. See "adc16_config_t".
63 */
ADC16_Init(ADC_Type * base,const adc16_config_t * config)64 void ADC16_Init(ADC_Type *base, const adc16_config_t *config)
65 {
66 assert(NULL != config);
67
68 uint32_t tmp32;
69
70 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
71 /* Enable the clock. */
72 CLOCK_EnableClock(s_adc16Clocks[ADC16_GetInstance(base)]);
73 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
74
75 /* ADCx_CFG1. */
76 tmp32 = ADC_CFG1_ADICLK(config->clockSource) | ADC_CFG1_MODE(config->resolution);
77 if (kADC16_LongSampleDisabled != config->longSampleMode)
78 {
79 tmp32 |= ADC_CFG1_ADLSMP_MASK;
80 }
81 tmp32 |= ADC_CFG1_ADIV(config->clockDivider);
82 if (true == config->enableLowPower)
83 {
84 tmp32 |= ADC_CFG1_ADLPC_MASK;
85 }
86 base->CFG1 = tmp32;
87
88 /* ADCx_CFG2. */
89 tmp32 = base->CFG2 & ~(ADC_CFG2_ADACKEN_MASK | ADC_CFG2_ADHSC_MASK | ADC_CFG2_ADLSTS_MASK);
90 if (kADC16_LongSampleDisabled != config->longSampleMode)
91 {
92 tmp32 |= ADC_CFG2_ADLSTS(config->longSampleMode);
93 }
94 if (true == config->enableHighSpeed)
95 {
96 tmp32 |= ADC_CFG2_ADHSC_MASK;
97 }
98 if (true == config->enableAsynchronousClock)
99 {
100 tmp32 |= ADC_CFG2_ADACKEN_MASK;
101 }
102 base->CFG2 = tmp32;
103
104 /* ADCx_SC2. */
105 tmp32 = base->SC2 & ~(ADC_SC2_REFSEL_MASK);
106 tmp32 |= ADC_SC2_REFSEL(config->referenceVoltageSource);
107 base->SC2 = tmp32;
108
109 /* ADCx_SC3. */
110 if (true == config->enableContinuousConversion)
111 {
112 base->SC3 |= ADC_SC3_ADCO_MASK;
113 }
114 else
115 {
116 base->SC3 &= ~ADC_SC3_ADCO_MASK;
117 }
118
119 #if defined(FSL_FEATURE_ADC16_HAS_HW_AVERAGE) && FSL_FEATURE_ADC16_HAS_HW_AVERAGE
120 ADC16_SetHardwareAverage(base, config->hardwareAverageMode);
121 #endif /* FSL_FEATURE_ADC16_HAS_HW_AVERAGE */
122 }
123
124 /*!
125 * brief De-initializes the ADC16 module.
126 *
127 * param base ADC16 peripheral base address.
128 */
ADC16_Deinit(ADC_Type * base)129 void ADC16_Deinit(ADC_Type *base)
130 {
131 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
132 /* Disable the clock. */
133 CLOCK_DisableClock(s_adc16Clocks[ADC16_GetInstance(base)]);
134 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
135 }
136
137 /*!
138 * brief Gets an available pre-defined settings for the converter's configuration.
139 *
140 * This function initializes the converter configuration structure with available settings. The default values are as
141 * follows.
142 * code
143 * config->referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
144 * config->clockSource = kADC16_ClockSourceAsynchronousClock;
145 * config->enableAsynchronousClock = false;
146 * config->clockDivider = kADC16_ClockDivider8;
147 * config->resolution = kADC16_ResolutionSE12Bit;
148 * config->longSampleMode = kADC16_LongSampleDisabled;
149 * config->enableHighSpeed = false;
150 * config->enableLowPower = false;
151 * config->enableContinuousConversion = false;
152 * endcode
153 * param config Pointer to the configuration structure.
154 */
ADC16_GetDefaultConfig(adc16_config_t * config)155 void ADC16_GetDefaultConfig(adc16_config_t *config)
156 {
157 assert(NULL != config);
158
159 /* Initializes the configure structure to zero. */
160 (void)memset(config, 0, sizeof(*config));
161
162 config->referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
163 config->clockSource = kADC16_ClockSourceAsynchronousClock;
164 config->enableAsynchronousClock = false;
165 config->clockDivider = kADC16_ClockDivider8;
166 config->resolution = kADC16_ResolutionSE12Bit;
167 config->longSampleMode = kADC16_LongSampleDisabled;
168 config->enableHighSpeed = false;
169 config->enableLowPower = false;
170 config->enableContinuousConversion = false;
171 #if defined(FSL_FEATURE_ADC16_HAS_HW_AVERAGE) && FSL_FEATURE_ADC16_HAS_HW_AVERAGE
172 config->hardwareAverageMode = kADC16_HardwareAverageDisabled;
173 #endif /* FSL_FEATURE_ADC16_HAS_HW_AVERAGE */
174 }
175
176 #if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
177 /*!
178 * brief Automates the hardware calibration.
179 *
180 * This auto calibration helps to adjust the plus/minus side gain automatically.
181 * Execute the calibration before using the converter. Note that the hardware trigger should be used
182 * during the calibration.
183 *
184 * param base ADC16 peripheral base address.
185 *
186 * return Execution status.
187 * retval kStatus_Success Calibration is done successfully.
188 * retval kStatus_Fail Calibration has failed.
189 */
ADC16_DoAutoCalibration(ADC_Type * base)190 status_t ADC16_DoAutoCalibration(ADC_Type *base)
191 {
192 bool bHWTrigger = false;
193 uint32_t tmp32;
194 status_t status = kStatus_Success;
195
196 /* The calibration would be failed when in hardwar mode.
197 * Remember the hardware trigger state here and restore it later if the hardware trigger is enabled.*/
198 if (0U != (ADC_SC2_ADTRG_MASK & base->SC2))
199 {
200 bHWTrigger = true;
201 base->SC2 &= ~ADC_SC2_ADTRG_MASK;
202 }
203
204 /* Clear the CALF and launch the calibration. */
205 base->SC3 |= ADC_SC3_CAL_MASK | ADC_SC3_CALF_MASK;
206 while (0U == ((uint32_t)kADC16_ChannelConversionDoneFlag & ADC16_GetChannelStatusFlags(base, 0U)))
207 {
208 /* Check the CALF when the calibration is active. */
209 if (0U != ((uint32_t)kADC16_CalibrationFailedFlag & ADC16_GetStatusFlags(base)))
210 {
211 status = kStatus_Fail;
212 break;
213 }
214 }
215 (void)base->R[0]; /* Dummy read to clear COCO caused by calibration. */
216
217 /* Restore the hardware trigger setting if it was enabled before. */
218 if (bHWTrigger)
219 {
220 base->SC2 |= ADC_SC2_ADTRG_MASK;
221 }
222 /* Check the CALF at the end of calibration. */
223 if (0U != ((uint32_t)kADC16_CalibrationFailedFlag & ADC16_GetStatusFlags(base)))
224 {
225 status = kStatus_Fail;
226 }
227 if (kStatus_Success != status) /* Check if the calibration process is succeed. */
228 {
229 return status;
230 }
231
232 /* Calculate the calibration values. */
233 tmp32 = base->CLP0;
234 tmp32 += base->CLP1;
235 tmp32 += base->CLP2;
236 tmp32 += base->CLP3;
237 tmp32 += base->CLP4;
238 tmp32 += base->CLPS;
239 tmp32 = 0x8000U | (tmp32 >> 1U);
240 base->PG = tmp32;
241
242 #if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
243 tmp32 = base->CLM0;
244 tmp32 += base->CLM1;
245 tmp32 += base->CLM2;
246 tmp32 += base->CLM3;
247 tmp32 += base->CLM4;
248 tmp32 += base->CLMS;
249 tmp32 = 0x8000U | (tmp32 >> 1U);
250 base->MG = tmp32;
251 #endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
252
253 return kStatus_Success;
254 }
255 #endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
256
257 #if defined(FSL_FEATURE_ADC16_HAS_MUX_SELECT) && FSL_FEATURE_ADC16_HAS_MUX_SELECT
258 /*!
259 * brief Sets the channel mux mode.
260 *
261 * Some sample pins share the same channel index. The channel mux mode decides which pin is used for an
262 * indicated channel.
263 *
264 * param base ADC16 peripheral base address.
265 * param mode Setting channel mux mode. See "adc16_channel_mux_mode_t".
266 */
ADC16_SetChannelMuxMode(ADC_Type * base,adc16_channel_mux_mode_t mode)267 void ADC16_SetChannelMuxMode(ADC_Type *base, adc16_channel_mux_mode_t mode)
268 {
269 if (kADC16_ChannelMuxA == mode)
270 {
271 base->CFG2 &= ~ADC_CFG2_MUXSEL_MASK;
272 }
273 else /* kADC16_ChannelMuxB. */
274 {
275 base->CFG2 |= ADC_CFG2_MUXSEL_MASK;
276 }
277 }
278 #endif /* FSL_FEATURE_ADC16_HAS_MUX_SELECT */
279
280 /*!
281 * brief Configures the hardware compare mode.
282 *
283 * The hardware compare mode provides a way to process the conversion result automatically by using hardware. Only the
284 * result
285 * in the compare range is available. To compare the range, see "adc16_hardware_compare_mode_t" or the appopriate
286 * reference
287 * manual for more information.
288 *
289 * param base ADC16 peripheral base address.
290 * param config Pointer to the "adc16_hardware_compare_config_t" structure. Passing "NULL" disables the feature.
291 */
ADC16_SetHardwareCompareConfig(ADC_Type * base,const adc16_hardware_compare_config_t * config)292 void ADC16_SetHardwareCompareConfig(ADC_Type *base, const adc16_hardware_compare_config_t *config)
293 {
294 uint32_t tmp32 = base->SC2 & ~(ADC_SC2_ACFE_MASK | ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK);
295
296 if (NULL == config) /* Pass "NULL" to disable the feature. */
297 {
298 base->SC2 = tmp32;
299 return;
300 }
301 /* Enable the feature. */
302 tmp32 |= ADC_SC2_ACFE_MASK;
303
304 /* Select the hardware compare working mode. */
305 switch (config->hardwareCompareMode)
306 {
307 case kADC16_HardwareCompareMode0:
308 break;
309 case kADC16_HardwareCompareMode1:
310 tmp32 |= ADC_SC2_ACFGT_MASK;
311 break;
312 case kADC16_HardwareCompareMode2:
313 tmp32 |= ADC_SC2_ACREN_MASK;
314 break;
315 case kADC16_HardwareCompareMode3:
316 tmp32 |= ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK;
317 break;
318 default:
319 assert(false);
320 break;
321 }
322 base->SC2 = tmp32;
323
324 /* Load the compare values. */
325 base->CV1 = ADC_CV1_CV(config->value1);
326 base->CV2 = ADC_CV2_CV(config->value2);
327 }
328
329 #if defined(FSL_FEATURE_ADC16_HAS_HW_AVERAGE) && FSL_FEATURE_ADC16_HAS_HW_AVERAGE
330 /*!
331 * brief Sets the hardware average mode.
332 *
333 * The hardware average mode provides a way to process the conversion result automatically by using hardware. The
334 * multiple
335 * conversion results are accumulated and averaged internally making them easier to read.
336 *
337 * param base ADC16 peripheral base address.
338 * param mode Setting the hardware average mode. See "adc16_hardware_average_mode_t".
339 */
ADC16_SetHardwareAverage(ADC_Type * base,adc16_hardware_average_mode_t mode)340 void ADC16_SetHardwareAverage(ADC_Type *base, adc16_hardware_average_mode_t mode)
341 {
342 uint32_t tmp32 = base->SC3 & ~(ADC_SC3_AVGE_MASK | ADC_SC3_AVGS_MASK);
343
344 if (kADC16_HardwareAverageDisabled != mode)
345 {
346 tmp32 |= ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(mode);
347 }
348 base->SC3 = tmp32;
349 }
350 #endif /* FSL_FEATURE_ADC16_HAS_HW_AVERAGE */
351
352 #if defined(FSL_FEATURE_ADC16_HAS_PGA) && FSL_FEATURE_ADC16_HAS_PGA
353 /*!
354 * brief Configures the PGA for the converter's front end.
355 *
356 * param base ADC16 peripheral base address.
357 * param config Pointer to the "adc16_pga_config_t" structure. Passing "NULL" disables the feature.
358 */
ADC16_SetPGAConfig(ADC_Type * base,const adc16_pga_config_t * config)359 void ADC16_SetPGAConfig(ADC_Type *base, const adc16_pga_config_t *config)
360 {
361 uint32_t tmp32;
362
363 if (!config) /* Passing "NULL" is to disable the feature. */
364 {
365 base->PGA = 0U;
366 return;
367 }
368
369 /* Enable the PGA and set the gain value. */
370 tmp32 = ADC_PGA_PGAEN_MASK | ADC_PGA_PGAG(config->pgaGain);
371
372 /* Configure the misc features for PGA. */
373 if (config->enableRunInNormalMode)
374 {
375 tmp32 |= ADC_PGA_PGALPb_MASK;
376 }
377 #if defined(FSL_FEATURE_ADC16_HAS_PGA_CHOPPING) && FSL_FEATURE_ADC16_HAS_PGA_CHOPPING
378 if (config->disablePgaChopping)
379 {
380 tmp32 |= ADC_PGA_PGACHPb_MASK;
381 }
382 #endif /* FSL_FEATURE_ADC16_HAS_PGA_CHOPPING */
383 #if defined(FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT) && FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT
384 if (config->enableRunInOffsetMeasurement)
385 {
386 tmp32 |= ADC_PGA_PGAOFSM_MASK;
387 }
388 #endif /* FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT */
389 base->PGA = tmp32;
390 }
391 #endif /* FSL_FEATURE_ADC16_HAS_PGA */
392
393 /*!
394 * brief Gets the status flags of the converter.
395 *
396 * param base ADC16 peripheral base address.
397 *
398 * return Flags' mask if indicated flags are asserted. See "_adc16_status_flags".
399 */
ADC16_GetStatusFlags(ADC_Type * base)400 uint32_t ADC16_GetStatusFlags(ADC_Type *base)
401 {
402 uint32_t ret = 0;
403
404 if (0U != (base->SC2 & ADC_SC2_ADACT_MASK))
405 {
406 ret |= (uint32_t)kADC16_ActiveFlag;
407 }
408 #if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
409 if (0U != (base->SC3 & ADC_SC3_CALF_MASK))
410 {
411 ret |= (uint32_t)kADC16_CalibrationFailedFlag;
412 }
413 #endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
414 return ret;
415 }
416
417 /*!
418 * brief Clears the status flags of the converter.
419 *
420 * param base ADC16 peripheral base address.
421 * param mask Mask value for the cleared flags. See "_adc16_status_flags".
422 */
ADC16_ClearStatusFlags(ADC_Type * base,uint32_t mask)423 void ADC16_ClearStatusFlags(ADC_Type *base, uint32_t mask)
424 {
425 #if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
426 if (0U != (mask & (uint32_t)kADC16_CalibrationFailedFlag))
427 {
428 base->SC3 |= ADC_SC3_CALF_MASK;
429 }
430 #endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
431 }
432
433 /*!
434 * brief Configures the conversion channel.
435 *
436 * This operation triggers the conversion when in software trigger mode. When in hardware trigger mode, this API
437 * configures the channel while the external trigger source helps to trigger the conversion.
438 *
439 * Note that the "Channel Group" has a detailed description.
440 * To allow sequential conversions of the ADC to be triggered by internal peripherals, the ADC has more than one
441 * group of status and control registers, one for each conversion. The channel group parameter indicates which group of
442 * registers are used, for example, channel group 0 is for Group A registers and channel group 1 is for Group B
443 * registers. The
444 * channel groups are used in a "ping-pong" approach to control the ADC operation. At any point, only one of
445 * the channel groups is actively controlling ADC conversions. The channel group 0 is used for both software and
446 * hardware
447 * trigger modes. Channel group 1 and greater indicates multiple channel group registers for
448 * use only in hardware trigger mode. See the chip configuration information in the appropriate MCU reference manual for
449 * the
450 * number of SC1n registers (channel groups) specific to this device. Channel group 1 or greater are not used
451 * for software trigger operation. Therefore, writing to these channel groups does not initiate a new conversion.
452 * Updating the channel group 0 while a different channel group is actively controlling a conversion is allowed and
453 * vice versa. Writing any of the channel group registers while that specific channel group is actively controlling a
454 * conversion aborts the current conversion.
455 *
456 * param base ADC16 peripheral base address.
457 * param channelGroup Channel group index.
458 * param config Pointer to the "adc16_channel_config_t" structure for the conversion channel.
459 */
ADC16_SetChannelConfig(ADC_Type * base,uint32_t channelGroup,const adc16_channel_config_t * config)460 void ADC16_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc16_channel_config_t *config)
461 {
462 assert(channelGroup < ADC_SC1_COUNT);
463 assert(NULL != config);
464
465 uint32_t sc1 = ADC_SC1_ADCH(config->channelNumber); /* Set the channel number. */
466
467 #if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
468 /* Enable the differential conversion. */
469 if (true == config->enableDifferentialConversion)
470 {
471 sc1 |= ADC_SC1_DIFF_MASK;
472 }
473 #endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
474 /* Enable the interrupt when the conversion is done. */
475 if (true == config->enableInterruptOnConversionCompleted)
476 {
477 sc1 |= ADC_SC1_AIEN_MASK;
478 }
479 base->SC1[channelGroup] = sc1;
480 }
481
482 /*!
483 * brief Gets the status flags of channel.
484 *
485 * param base ADC16 peripheral base address.
486 * param channelGroup Channel group index.
487 *
488 * return Flags' mask if indicated flags are asserted. See "_adc16_channel_status_flags".
489 */
ADC16_GetChannelStatusFlags(ADC_Type * base,uint32_t channelGroup)490 uint32_t ADC16_GetChannelStatusFlags(ADC_Type *base, uint32_t channelGroup)
491 {
492 assert(channelGroup < ADC_SC1_COUNT);
493
494 uint32_t ret = 0U;
495
496 if (0U != (base->SC1[channelGroup] & ADC_SC1_COCO_MASK))
497 {
498 ret |= (uint32_t)kADC16_ChannelConversionDoneFlag;
499 }
500 return ret;
501 }
502