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