1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_adc.h"
10 
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.adc_12b1msps_sar"
14 #endif
15 
16 /*******************************************************************************
17  * Prototypes
18  ******************************************************************************/
19 /*!
20  * @brief Get instance number for ADC module.
21  *
22  * @param base ADC peripheral base address
23  */
24 static uint32_t ADC_GetInstance(ADC_Type *base);
25 
26 /*******************************************************************************
27  * Variables
28  ******************************************************************************/
29 /*! @brief Pointers to ADC bases for each instance. */
30 static ADC_Type *const s_adcBases[] = ADC_BASE_PTRS;
31 
32 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
33 /*! @brief Pointers to ADC clocks for each instance. */
34 static const clock_ip_name_t s_adcClocks[] = ADC_CLOCKS;
35 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
36 
37 /*******************************************************************************
38  * Code
39  ******************************************************************************/
ADC_GetInstance(ADC_Type * base)40 static uint32_t ADC_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_adcBases); instance++)
46     {
47         if (s_adcBases[instance] == base)
48         {
49             break;
50         }
51     }
52 
53     assert(instance < ARRAY_SIZE(s_adcBases));
54 
55     return instance;
56 }
57 
58 /*!
59  * brief Initialize the ADC module.
60  *
61  * param base ADC peripheral base address.
62  * param config Pointer to "adc_config_t" structure.
63  */
ADC_Init(ADC_Type * base,const adc_config_t * config)64 void ADC_Init(ADC_Type *base, const adc_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_adcClocks[ADC_GetInstance(base)]);
73 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
74     /* ADCx_CFG */
75     tmp32 = base->CFG & (ADC_CFG_AVGS_MASK | ADC_CFG_ADTRG_MASK); /* Reserve AVGS and ADTRG bits. */
76     tmp32 |= ADC_CFG_REFSEL(config->referenceVoltageSource) | ADC_CFG_ADSTS(config->samplePeriodMode) |
77              ADC_CFG_ADICLK(config->clockSource) | ADC_CFG_ADIV(config->clockDriver) | ADC_CFG_MODE(config->resolution);
78     if (config->enableOverWrite)
79     {
80         tmp32 |= ADC_CFG_OVWREN_MASK;
81     }
82     if (config->enableLongSample)
83     {
84         tmp32 |= ADC_CFG_ADLSMP_MASK;
85     }
86     if (config->enableLowPower)
87     {
88         tmp32 |= ADC_CFG_ADLPC_MASK;
89     }
90     if (config->enableHighSpeed)
91     {
92         tmp32 |= ADC_CFG_ADHSC_MASK;
93     }
94     base->CFG = tmp32;
95 
96     /* ADCx_GC  */
97     tmp32 = base->GC & ~(ADC_GC_ADCO_MASK | ADC_GC_ADACKEN_MASK);
98     if (config->enableContinuousConversion)
99     {
100         tmp32 |= ADC_GC_ADCO_MASK;
101     }
102     if (config->enableAsynchronousClockOutput)
103     {
104         tmp32 |= ADC_GC_ADACKEN_MASK;
105     }
106     base->GC = tmp32;
107 }
108 
109 /*!
110  * brief De-initializes the ADC module.
111  *
112  * param base ADC peripheral base address.
113  */
ADC_Deinit(ADC_Type * base)114 void ADC_Deinit(ADC_Type *base)
115 {
116 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
117     /* Disable the clock. */
118     CLOCK_DisableClock(s_adcClocks[ADC_GetInstance(base)]);
119 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
120 }
121 
122 /*!
123  * brief Gets an available pre-defined settings for the converter's configuration.
124  *
125  * This function initializes the converter configuration structure with available settings. The default values are:
126  * code
127  *  config->enableAsynchronousClockOutput = true;
128  *  config->enableOverWrite =               false;
129  *  config->enableContinuousConversion =    false;
130  *  config->enableHighSpeed =               false;
131  *  config->enableLowPower =                false;
132  *  config->enableLongSample =              false;
133  *  config->referenceVoltageSource =        kADC_ReferenceVoltageSourceAlt0;
134  *  config->samplePeriodMode =              kADC_SamplePeriod2or12Clocks;
135  *  config->clockSource =                   kADC_ClockSourceAD;
136  *  config->clockDriver =                   kADC_ClockDriver1;
137  *  config->resolution =                    kADC_Resolution12Bit;
138  * endcode
139  * param base   ADC peripheral base address.
140  * param config Pointer to the configuration structure.
141  */
ADC_GetDefaultConfig(adc_config_t * config)142 void ADC_GetDefaultConfig(adc_config_t *config)
143 {
144     assert(NULL != config);
145 
146     /* Initializes the configure structure to zero. */
147     (void)memset(config, 0, sizeof(*config));
148 
149     config->enableAsynchronousClockOutput = true;
150     config->enableOverWrite               = false;
151     config->enableContinuousConversion    = false;
152     config->enableHighSpeed               = false;
153     config->enableLowPower                = false;
154     config->enableLongSample              = false;
155     config->referenceVoltageSource        = kADC_ReferenceVoltageSourceAlt0;
156     config->samplePeriodMode              = kADC_SamplePeriod2or12Clocks;
157     config->clockSource                   = kADC_ClockSourceAD;
158     config->clockDriver                   = kADC_ClockDriver1;
159     config->resolution                    = kADC_Resolution12Bit;
160 }
161 
162 /*!
163  * brief Configures the conversion channel.
164  *
165  * This operation triggers the conversion when in software trigger mode. When in hardware trigger mode, this API
166  * configures the channel while the external trigger source helps to trigger the conversion.
167  *
168  * Note that the "Channel Group" has a detailed description.
169  * To allow sequential conversions of the ADC to be triggered by internal peripherals, the ADC has more than one
170  * group of status and control registers, one for each conversion. The channel group parameter indicates which group of
171  * registers are used, for example channel group 0 is for Group A registers and channel group 1 is for Group B
172  * registers. The
173  * channel groups are used in a "ping-pong" approach to control the ADC operation.  At any point, only one of
174  * the channel groups is actively controlling ADC conversions. The channel group 0 is used for both software and
175  * hardware
176  * trigger modes. Channel groups 1 and greater indicate potentially multiple channel group registers for
177  * use only in hardware trigger mode. See the chip configuration information in the appropriate MCU reference manual
178  * about the
179  * number of SC1n registers (channel groups) specific to this device.  None of the channel groups 1 or greater are used
180  * for software trigger operation. Therefore, writing to these channel groups does not initiate a new conversion.
181  * Updating the channel group 0 while a different channel group is actively controlling a conversion is allowed and
182  * vice versa. Writing any of the channel group registers while that specific channel group is actively controlling a
183  * conversion aborts the current conversion.
184  *
185  * param base          ADC peripheral base address.
186  * param channelGroup  Channel group index.
187  * param config        Pointer to the "adc_channel_config_t" structure for the conversion channel.
188  */
ADC_SetChannelConfig(ADC_Type * base,uint32_t channelGroup,const adc_channel_config_t * config)189 void ADC_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc_channel_config_t *config)
190 {
191     assert(NULL != config);
192     assert(channelGroup < (uint32_t)FSL_FEATURE_ADC_CONVERSION_CONTROL_COUNT);
193 
194     uint32_t tmp32;
195 
196     tmp32 = ADC_HC_ADCH(config->channelNumber);
197     if (config->enableInterruptOnConversionCompleted)
198     {
199         tmp32 |= ADC_HC_AIEN_MASK;
200     }
201     base->HC[channelGroup] = tmp32;
202 }
203 
204 /*
205  *To complete calibration, the user must follow the below procedure:
206  *  1. Configure ADC_CFG with actual operating values for maximum accuracy.
207  *  2. Configure the ADC_GC values along with CAL bit.
208  *  3. Check the status of CALF bit in ADC_GS and the CAL bit in ADC_GC.
209  *  4. When CAL bit becomes '0' then check the CALF status and COCO[0] bit status.
210  */
211 /*!
212  * brief  Automates the hardware calibration.
213  *
214  * This auto calibration helps to adjust the plus/minus side gain automatically.
215  * Execute the calibration before using the converter. Note that the software trigger should be used
216  * during calibration.
217  *
218  * param  base ADC peripheral base address.
219  *
220  * return                 Execution status.
221  * retval kStatus_Success Calibration is done successfully.
222  * retval kStatus_Fail    Calibration has failed.
223  */
ADC_DoAutoCalibration(ADC_Type * base)224 status_t ADC_DoAutoCalibration(ADC_Type *base)
225 {
226     status_t status = kStatus_Success;
227 #if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE)
228     bool bHWTrigger = false;
229 
230     /* The calibration would be failed when in hardwar mode.
231      * Remember the hardware trigger state here and restore it later if the hardware trigger is enabled.*/
232     if (0U != (ADC_CFG_ADTRG_MASK & base->CFG))
233     {
234         bHWTrigger = true;
235         ADC_EnableHardwareTrigger(base, false);
236     }
237 #endif
238 
239     /* Clear the CALF and launch the calibration. */
240     base->GS = ADC_GS_CALF_MASK; /* Clear the CALF. */
241     base->GC |= ADC_GC_CAL_MASK; /* Launch the calibration. */
242 
243     /* Check the status of CALF bit in ADC_GS and the CAL bit in ADC_GC. */
244     while (0U != (base->GC & ADC_GC_CAL_MASK))
245     {
246         /* Check the CALF when the calibration is active. */
247         if (0U != (ADC_GetStatusFlags(base) & (uint32_t)kADC_CalibrationFailedFlag))
248         {
249             status = kStatus_Fail;
250             break;
251         }
252     }
253 
254     /* When CAL bit becomes '0' then check the CALF status and COCO[0] bit status. */
255     if (0U == ADC_GetChannelStatusFlags(base, 0U)) /* Check the COCO[0] bit status. */
256     {
257         status = kStatus_Fail;
258     }
259     if (0U != (ADC_GetStatusFlags(base) & (uint32_t)kADC_CalibrationFailedFlag)) /* Check the CALF status. */
260     {
261         status = kStatus_Fail;
262     }
263 
264     /* Clear conversion done flag. */
265     (void)ADC_GetChannelConversionValue(base, 0U);
266 
267 #if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE)
268     /* Restore original trigger mode. */
269     if (true == bHWTrigger)
270     {
271         ADC_EnableHardwareTrigger(base, true);
272     }
273 #endif
274 
275     return status;
276 }
277 
278 /*!
279  * brief Set user defined offset.
280  *
281  * param base   ADC peripheral base address.
282  * param config Pointer to "adc_offest_config_t" structure.
283  */
ADC_SetOffsetConfig(ADC_Type * base,const adc_offest_config_t * config)284 void ADC_SetOffsetConfig(ADC_Type *base, const adc_offest_config_t *config)
285 {
286     assert(NULL != config);
287 
288     uint32_t tmp32;
289 
290     tmp32 = ADC_OFS_OFS(config->offsetValue);
291     if (config->enableSigned)
292     {
293         tmp32 |= ADC_OFS_SIGN_MASK;
294     }
295     base->OFS = tmp32;
296 }
297 
298 /*!
299  * brief Configures the hardware compare mode.
300  *
301  * The hardware compare mode provides a way to process the conversion result automatically by using hardware. Only the
302  * result
303  * in the compare range is available. To compare the range, see "adc_hardware_compare_mode_t" or the appopriate
304  * reference
305  * manual for more information.
306  *
307  * param base ADC peripheral base address.
308  * param Pointer to "adc_hardware_compare_config_t" structure.
309  *
310  */
ADC_SetHardwareCompareConfig(ADC_Type * base,const adc_hardware_compare_config_t * config)311 void ADC_SetHardwareCompareConfig(ADC_Type *base, const adc_hardware_compare_config_t *config)
312 {
313     uint32_t tmp32;
314 
315     tmp32 = base->GC & ~(ADC_GC_ACFE_MASK | ADC_GC_ACFGT_MASK | ADC_GC_ACREN_MASK);
316     if (NULL == config) /* Pass "NULL" to disable the feature. */
317     {
318         base->GC = tmp32;
319         return;
320     }
321     /* Enable the feature. */
322     tmp32 |= ADC_GC_ACFE_MASK;
323 
324     /* Select the hardware compare working mode. */
325     switch (config->hardwareCompareMode)
326     {
327         case kADC_HardwareCompareMode0:
328             break;
329         case kADC_HardwareCompareMode1:
330             tmp32 |= ADC_GC_ACFGT_MASK;
331             break;
332         case kADC_HardwareCompareMode2:
333             tmp32 |= ADC_GC_ACREN_MASK;
334             break;
335         case kADC_HardwareCompareMode3:
336             tmp32 |= ADC_GC_ACFGT_MASK | ADC_GC_ACREN_MASK;
337             break;
338         default:
339             assert(false);
340             break;
341     }
342     base->GC = tmp32;
343 
344     /* Load the compare values. */
345     tmp32    = ADC_CV_CV1(config->value1) | ADC_CV_CV2(config->value2);
346     base->CV = tmp32;
347 }
348 
349 /*!
350  * brief Configures the hardware average mode.
351  *
352  * The hardware average mode provides a way to process the conversion result automatically by using hardware. The
353  * multiple
354  * conversion results are accumulated and averaged internally making them easier to read.
355  *
356  * param base ADC peripheral base address.
357  * param mode Setting the hardware average mode. See "adc_hardware_average_mode_t".
358  */
ADC_SetHardwareAverageConfig(ADC_Type * base,adc_hardware_average_mode_t mode)359 void ADC_SetHardwareAverageConfig(ADC_Type *base, adc_hardware_average_mode_t mode)
360 {
361     uint32_t tmp32;
362 
363     if (mode == kADC_HardwareAverageDiasable)
364     {
365         base->GC &= ~ADC_GC_AVGE_MASK;
366     }
367     else
368     {
369         tmp32 = base->CFG & ~ADC_CFG_AVGS_MASK;
370         tmp32 |= ADC_CFG_AVGS(mode);
371         base->CFG = tmp32;
372         base->GC |= ADC_GC_AVGE_MASK; /* Enable the hardware compare. */
373     }
374 }
375 
376 /*!
377  * brief Clears the converter's status falgs.
378  *
379  * param base ADC peripheral base address.
380  * param mask Mask value for the cleared flags. See "adc_status_flags_t".
381  */
ADC_ClearStatusFlags(ADC_Type * base,uint32_t mask)382 void ADC_ClearStatusFlags(ADC_Type *base, uint32_t mask)
383 {
384     uint32_t tmp32 = 0;
385 
386     if (0U != (mask & (uint32_t)kADC_CalibrationFailedFlag))
387     {
388         tmp32 |= ADC_GS_CALF_MASK;
389     }
390     if (0U != (mask & (uint32_t)kADC_ConversionActiveFlag))
391     {
392         tmp32 |= ADC_GS_ADACT_MASK;
393     }
394     base->GS = tmp32;
395 }
396