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