1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_lpadc.h"
10
11 /*******************************************************************************
12 * Prototypes
13 ******************************************************************************/
14 /*!
15 * @brief Get instance number for LPADC module.
16 *
17 * @param base LPADC peripheral base address
18 */
19 static uint32_t LPADC_GetInstance(ADC_Type *base);
20
21 /*******************************************************************************
22 * Variables
23 ******************************************************************************/
24 /*! @brief Pointers to LPADC bases for each instance. */
25 static ADC_Type *const s_lpadcBases[] = ADC_BASE_PTRS;
26 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
27 /*! @brief Pointers to LPADC clocks for each instance. */
28 static const clock_ip_name_t s_lpadcClocks[] = LPADC_CLOCKS;
29 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
30
31 /*******************************************************************************
32 * Code
33 ******************************************************************************/
LPADC_GetInstance(ADC_Type * base)34 static uint32_t LPADC_GetInstance(ADC_Type *base)
35 {
36 uint32_t instance;
37
38 /* Find the instance index from base address mappings. */
39 for (instance = 0; instance < ARRAY_SIZE(s_lpadcBases); instance++)
40 {
41 if (s_lpadcBases[instance] == base)
42 {
43 break;
44 }
45 }
46
47 assert(instance < ARRAY_SIZE(s_lpadcBases));
48
49 return instance;
50 }
51
LPADC_Init(ADC_Type * base,const lpadc_config_t * config)52 void LPADC_Init(ADC_Type *base, const lpadc_config_t *config)
53 {
54 /* Check if the pointer is available. */
55 assert(config != NULL);
56
57 uint32_t tmp32 = 0U;
58
59 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
60 /* Enable the clock for LPADC instance. */
61 CLOCK_EnableClock(s_lpadcClocks[LPADC_GetInstance(base)]);
62 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
63
64 /* Reset the module. */
65 LPADC_DoResetConfig(base);
66 LPADC_DoResetFIFO(base);
67
68 /* Disable the module before setting configuration. */
69 LPADC_Enable(base, false);
70
71 /* Configure the module generally. */
72 if (config->enableInDozeMode)
73 {
74 base->CTRL &= ~ADC_CTRL_DOZEN_MASK;
75 }
76 else
77 {
78 base->CTRL |= ADC_CTRL_DOZEN_MASK;
79 }
80
81 /* ADCx_CFG. */
82 #if defined(FSL_FEATURE_LPADC_HAS_CFG_ADCKEN) && FSL_FEATURE_LPADC_HAS_CFG_ADCKEN
83 if (config->enableInternalClock)
84 {
85 tmp32 |= ADC_CFG_ADCKEN_MASK;
86 }
87 #endif /* FSL_FEATURE_LPADC_HAS_CFG_ADCKEN */
88 #if defined(FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG) && FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG
89 if (config->enableVref1LowVoltage)
90 {
91 tmp32 |= ADC_CFG_VREF1RNG_MASK;
92 }
93 #endif /* FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG */
94 if (config->enableAnalogPreliminary)
95 {
96 tmp32 |= ADC_CFG_PWREN_MASK;
97 }
98 tmp32 |= ADC_CFG_PUDLY(config->powerUpDelay) /* Power up delay. */
99 | ADC_CFG_REFSEL(config->referenceVoltageSource) /* Reference voltage. */
100 | ADC_CFG_TPRICTRL(config->triggerPrioirtyPolicy); /* Trigger priority policy. */
101 base->CFG = tmp32;
102
103 /* ADCx_PAUSE. */
104 if (config->enableConvPause)
105 {
106 base->PAUSE = ADC_PAUSE_PAUSEEN_MASK | ADC_PAUSE_PAUSEDLY(config->convPauseDelay);
107 }
108 else
109 {
110 base->PAUSE = 0U;
111 }
112
113 /* ADCx_FCTRL. */
114 base->FCTRL = ADC_FCTRL_FWMARK(config->FIFOWatermark);
115
116 /* Enable the module after setting configuration. */
117 LPADC_Enable(base, true);
118 }
119
LPADC_GetDefaultConfig(lpadc_config_t * config)120 void LPADC_GetDefaultConfig(lpadc_config_t *config)
121 {
122 #if defined(FSL_FEATURE_LPADC_HAS_CFG_ADCKEN) && FSL_FEATURE_LPADC_HAS_CFG_ADCKEN
123 config->enableInternalClock = false;
124 #endif /* FSL_FEATURE_LPADC_HAS_CFG_ADCKEN */
125 #if defined(FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG) && FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG
126 config->enableVref1LowVoltage = false;
127 #endif /* FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG */
128 config->enableInDozeMode = true;
129 config->enableAnalogPreliminary = false;
130 config->powerUpDelay = 0x80;
131 config->referenceVoltageSource = kLPADC_ReferenceVoltageAlt1;
132 config->powerLevelMode = kLPADC_PowerLevelAlt1;
133 config->triggerPrioirtyPolicy = kLPADC_TriggerPriorityPreemptImmediately;
134 config->enableConvPause = false;
135 config->convPauseDelay = 0U;
136 config->FIFOWatermark = 0U;
137 }
138
LPADC_Deinit(ADC_Type * base)139 void LPADC_Deinit(ADC_Type *base)
140 {
141 /* Disable the module. */
142 LPADC_Enable(base, false);
143
144 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
145 /* Gate the clock. */
146 CLOCK_DisableClock(s_lpadcClocks[LPADC_GetInstance(base)]);
147 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
148 }
149
LPADC_GetConvResult(ADC_Type * base,lpadc_conv_result_t * result)150 bool LPADC_GetConvResult(ADC_Type *base, lpadc_conv_result_t *result)
151 {
152 assert(result != NULL); /* Check if the input pointer is available. */
153
154 uint32_t tmp32;
155
156 tmp32 = base->RESFIFO;
157
158 if (0U == (ADC_RESFIFO_VALID_MASK & tmp32))
159 {
160 return false; /* FIFO is empty. Discard any read from RESFIFO. */
161 }
162
163 result->commandIdSource = (tmp32 & ADC_RESFIFO_CMDSRC_MASK) >> ADC_RESFIFO_CMDSRC_SHIFT;
164 result->loopCountIndex = (tmp32 & ADC_RESFIFO_LOOPCNT_MASK) >> ADC_RESFIFO_LOOPCNT_SHIFT;
165 result->triggerIdSource = (tmp32 & ADC_RESFIFO_TSRC_MASK) >> ADC_RESFIFO_TSRC_SHIFT;
166 result->convValue = (uint16_t)(tmp32 & ADC_RESFIFO_D_MASK);
167
168 return true;
169 }
170
LPADC_SetConvTriggerConfig(ADC_Type * base,uint32_t triggerId,const lpadc_conv_trigger_config_t * config)171 void LPADC_SetConvTriggerConfig(ADC_Type *base, uint32_t triggerId, const lpadc_conv_trigger_config_t *config)
172 {
173 assert(triggerId < ADC_TCTRL_COUNT); /* Check if the triggerId is available in this device. */
174 assert(config != NULL); /* Check if the input pointer is available. */
175
176 uint32_t tmp32;
177
178 tmp32 = ADC_TCTRL_TCMD(config->targetCommandId) /* Trigger command select. */
179 | ADC_TCTRL_TDLY(config->delayPower) /* Trigger delay select. */
180 | ADC_TCTRL_TPRI(config->priority); /* Trigger priority setting. */
181 if (config->enableHardwareTrigger)
182 {
183 tmp32 |= ADC_TCTRL_HTEN_MASK;
184 }
185
186 base->TCTRL[triggerId] = tmp32;
187 }
188
LPADC_GetDefaultConvTriggerConfig(lpadc_conv_trigger_config_t * config)189 void LPADC_GetDefaultConvTriggerConfig(lpadc_conv_trigger_config_t *config)
190 {
191 assert(config != NULL); /* Check if the input pointer is available. */
192
193 config->targetCommandId = 0U;
194 config->delayPower = 0U;
195 config->priority = 0U;
196 config->enableHardwareTrigger = false;
197 }
198
LPADC_SetConvCommandConfig(ADC_Type * base,uint32_t commandId,const lpadc_conv_command_config_t * config)199 void LPADC_SetConvCommandConfig(ADC_Type *base, uint32_t commandId, const lpadc_conv_command_config_t *config)
200 {
201 assert(commandId < (ADC_CMDL_COUNT + 1U)); /* Check if the commandId is available on this device. */
202 assert(config != NULL); /* Check if the input pointer is available. */
203
204 uint32_t tmp32;
205
206 commandId--; /* The available command number are 1-15, while the index of register group are 0-14. */
207
208 /* ADCx_CMDL. */
209 tmp32 = ADC_CMDL_ADCH(config->channelNumber); /* Channel number. */
210 #if defined(FSL_FEATURE_LPADC_HAS_CMDL_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_CSCALE
211 tmp32 |= ADC_CMDL_CSCALE(config->sampleScaleMode); /* Full/Part scale input voltage. */
212 #endif /* FSL_FEATURE_LPADC_HAS_CMDL_CSCALE */
213 switch (config->sampleChannelMode) /* Sample input. */
214 {
215 case kLPADC_SampleChannelSingleEndSideB:
216 tmp32 |= ADC_CMDL_ABSEL_MASK;
217 break;
218 #if defined(FSL_FEATURE_LPADC_HAS_CMDL_DIFF) && FSL_FEATURE_LPADC_HAS_CMDL_DIFF
219 case kLPADC_SampleChannelDiffBothSideAB:
220 tmp32 |= ADC_CMDL_DIFF_MASK;
221 break;
222 case kLPADC_SampleChannelDiffBothSideBA:
223 tmp32 |= ADC_CMDL_ABSEL_MASK | ADC_CMDL_DIFF_MASK;
224 break;
225 #endif /* FSL_FEATURE_LPADC_HAS_CMDL_DIFF */
226 default: /* kLPADC_SampleChannelSingleEndSideA. */
227 break;
228 }
229 base->CMD[commandId].CMDL = tmp32;
230
231 /* ADCx_CMDH. */
232 tmp32 = ADC_CMDH_NEXT(config->chainedNextCommandNumber) /* Next Command Select. */
233 | ADC_CMDH_LOOP(config->loopCount) /* Loop Count Select. */
234 | ADC_CMDH_AVGS(config->hardwareAverageMode) /* Hardware Average Select. */
235 | ADC_CMDH_STS(config->sampleTimeMode) /* Sample Time Select. */
236 | ADC_CMDH_CMPEN(config->hardwareCompareMode); /* Hardware compare enable. */
237 if (config->enableAutoChannelIncrement)
238 {
239 tmp32 |= ADC_CMDH_LWI_MASK;
240 }
241 base->CMD[commandId].CMDH = tmp32;
242
243 /* Hardware compare settings.
244 * Not all Command Buffers have an associated Compare Value register. The compare function is only available on
245 * Command Buffers that have a corresponding Compare Value register.
246 */
247 if (kLPADC_HardwareCompareDisabled != config->hardwareCompareMode)
248 {
249 /* Check if the hardware compare feature is available for indicated command buffer. */
250 assert(commandId < ADC_CV_COUNT);
251
252 /* Set CV register. */
253 base->CV[commandId] = ADC_CV_CVH(config->hardwareCompareValueHigh) /* Compare value high. */
254 | ADC_CV_CVL(config->hardwareCompareValueLow); /* Compare value low. */
255 }
256 }
257
LPADC_GetDefaultConvCommandConfig(lpadc_conv_command_config_t * config)258 void LPADC_GetDefaultConvCommandConfig(lpadc_conv_command_config_t *config)
259 {
260 assert(config != NULL); /* Check if the input pointer is available. */
261
262 #if defined(FSL_FEATURE_LPADC_HAS_CMDL_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_CSCALE
263 config->sampleScaleMode = kLPADC_SampleFullScale;
264 #endif /* FSL_FEATURE_LPADC_HAS_CMDL_CSCALE */
265 config->sampleChannelMode = kLPADC_SampleChannelSingleEndSideA;
266 config->channelNumber = 0U;
267 config->chainedNextCommandNumber = 0U; /* No next command defined. */
268 config->enableAutoChannelIncrement = false;
269 config->loopCount = 0U;
270 config->hardwareAverageMode = kLPADC_HardwareAverageCount1;
271 config->sampleTimeMode = kLPADC_SampleTimeADCK3;
272 config->hardwareCompareMode = kLPADC_HardwareCompareDisabled;
273 config->hardwareCompareValueHigh = 0U; /* No used. */
274 config->hardwareCompareValueLow = 0U; /* No used. */
275 }
276
277 #if defined(FSL_FEATURE_LPADC_HAS_CFG_CALOFS) && FSL_FEATURE_LPADC_HAS_CFG_CALOFS
LPADC_EnableCalibration(ADC_Type * base,bool enable)278 void LPADC_EnableCalibration(ADC_Type *base, bool enable)
279 {
280 LPADC_Enable(base, false);
281 if (enable)
282 {
283 base->CFG |= ADC_CFG_CALOFS_MASK;
284 }
285 else
286 {
287 base->CFG &= ~ADC_CFG_CALOFS_MASK;
288 }
289 LPADC_Enable(base, true);
290 }
291
292 #if defined(FSL_FEATURE_LPADC_HAS_OFSTRIM) && FSL_FEATURE_LPADC_HAS_OFSTRIM
LPADC_DoAutoCalibration(ADC_Type * base)293 void LPADC_DoAutoCalibration(ADC_Type *base)
294 {
295 assert(0u == LPADC_GetConvResultCount(base));
296
297 uint32_t mLpadcCMDL;
298 uint32_t mLpadcCMDH;
299 uint32_t mLpadcTrigger;
300 lpadc_conv_trigger_config_t mLpadcTriggerConfigStruct;
301 lpadc_conv_command_config_t mLpadcCommandConfigStruct;
302 lpadc_conv_result_t mLpadcResultConfigStruct;
303
304 /* Enable the calibration function. */
305 LPADC_EnableCalibration(base, true);
306
307 /* Keep the CMD and TRG state here and restore it later if the calibration completes.*/
308 mLpadcCMDL = base->CMD[0].CMDL; /* CMD1L. */
309 mLpadcCMDH = base->CMD[0].CMDH; /* CMD1H. */
310 mLpadcTrigger = base->TCTRL[0]; /* Trigger0. */
311
312 /* Set trigger0 configuration - for software trigger. */
313 LPADC_GetDefaultConvTriggerConfig(&mLpadcTriggerConfigStruct);
314 mLpadcTriggerConfigStruct.targetCommandId = 1U; /* CMD1 is executed. */
315 LPADC_SetConvTriggerConfig(base, 0U, &mLpadcTriggerConfigStruct); /* Configurate the trigger0. */
316
317 /* Set conversion CMD configuration. */
318 LPADC_GetDefaultConvCommandConfig(&mLpadcCommandConfigStruct);
319 mLpadcCommandConfigStruct.hardwareAverageMode = kLPADC_HardwareAverageCount128;
320 LPADC_SetConvCommandConfig(base, 1U, &mLpadcCommandConfigStruct); /* Set CMD1 configuration. */
321
322 /* Do calibration. */
323 LPADC_DoSoftwareTrigger(base, 1U); /* 1U is trigger0 mask. */
324 while (!LPADC_GetConvResult(base, &mLpadcResultConfigStruct))
325 {
326 }
327 /* The valid bits of data are bits 14:3 in the RESFIFO register. */
328 LPADC_SetOffsetValue(base, (mLpadcResultConfigStruct.convValue) >> 3U);
329 /* Disable the calibration function. */
330 LPADC_EnableCalibration(base, false);
331
332 /* restore CMD and TRG registers. */
333 base->CMD[0].CMDL = mLpadcCMDL; /* CMD1L. */
334 base->CMD[0].CMDH = mLpadcCMDH; /* CMD1H. */
335 base->TCTRL[0] = mLpadcTrigger; /* Trigger0. */
336 }
337 #endif /* FSL_FEATURE_LPADC_HAS_OFSTRIM */
338 #endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */
339