rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
hal_adc_lld.c
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2014 Derek Mulcahy
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file ADCv1/hal_adc_lld.c
19 * @brief KINETIS ADC subsystem low level driver source.
20 * @author andreika <prometheus.pcb@gmail.com>
21 *
22 * @addtogroup ADC
23 * @{
24 */
25
26#include "hal.h"
27
28#if HAL_USE_ADC || defined(__DOXYGEN__)
29
30#include "fsl_adc12.h"
31
32/*===========================================================================*/
33/* Driver local definitions. */
34/*===========================================================================*/
35
36#define ADC_CHANNEL_MASK 0x1f
37
38/*===========================================================================*/
39/* Driver exported variables. */
40/*===========================================================================*/
41
42/** @brief ADC1 driver identifier.*/
43#if KINETIS_ADC_USE_ADC0 || defined(__DOXYGEN__)
44ADCDriver ADCD1;
45#endif
46
47/** @brief ADC2 driver identifier.*/
48#if KINETIS_ADC_USE_ADC1 || defined(__DOXYGEN__)
49ADCDriver ADCD2;
50#endif
51
52/** @brief ADC3 driver identifier.*/
53#if KINETIS_ADC_USE_ADC2 || defined(__DOXYGEN__)
54ADCDriver ADCD3;
55#endif
56
57/*===========================================================================*/
58/* Driver local variables and types. */
59/*===========================================================================*/
60
61/*===========================================================================*/
62/* Driver local functions. */
63/*===========================================================================*/
64
65static void calibrate(ADCDriver *adcp) {
66#ifdef KE1xF
67 ADC12_DoAutoCalibration(adcp->adc);
68#else
69 /* Clock Divide by 8, Use Bus Clock Div 2 */
70 /* At 48MHz this results in ADCCLK of 48/8/2 == 3MHz */
71 adcp->adc->CFG1 = ADCx_CFG1_ADIV(ADCx_CFG1_ADIV_DIV_8) |
72 ADCx_CFG1_ADICLK(ADCx_CFG1_ADIVCLK_BUS_CLOCK_DIV_2);
73
74 /* Use software trigger and disable DMA etc. */
75 adcp->adc->SC2 = 0;
76
77 /* Enable Hardware Average, Average 32 Samples, Calibrate */
78 adcp->adc->SC3 = ADCx_SC3_AVGE |
79 ADCx_SC3_AVGS(ADCx_SC3_AVGS_AVERAGE_32_SAMPLES) |
80 ADCx_SC3_CAL;
81
82 /* FIXME: May take several ms. Use an interrupt instead of busy wait */
83 /* Wait for calibration completion */
84 while (!(adcp->adc->SC1A & ADCx_SC1n_COCO))
85 ;
86
87 uint16_t gain = ((adcp->adc->CLP0 + adcp->adc->CLP1 + adcp->adc->CLP2 +
88 adcp->adc->CLP3 + adcp->adc->CLP4 + adcp->adc->CLPS) / 2) | 0x8000;
89 adcp->adc->PG = gain;
90
91 gain = ((adcp->adc->CLM0 + adcp->adc->CLM1 + adcp->adc->CLM2 +
92 adcp->adc->CLM3 + adcp->adc->CLM4 + adcp->adc->CLMS) / 2) | 0x8000;
93 adcp->adc->MG = gain;
94#endif /* KE1xF */
95}
96
97/*===========================================================================*/
98/* Driver interrupt handlers. */
99/*===========================================================================*/
100
101/**
102 * @brief ADC interrupt handler.
103 *
104 * @isr
105 */
106static void adc_lld_irq_handler(ADCDriver *adcp) {
107#ifdef KE1xF
108 /* Disable Interrupt, Disable Channel */
109 adcp->adc12ChannelCfg.channelNumber = ADCx_SC1n_ADCH_DISABLED;
110 adcp->adc12ChannelCfg.enableInterruptOnConversionCompleted = false;
111 ADC12_SetChannelConfig(adcp->adc, adcp->channelGroup, &adcp->adc12ChannelCfg);
112 /* Read the sample into the buffer */
113 adcp->samples[adcp->current_index++] = ADC12_GetChannelConversionValue(adcp->adc, adcp->channelGroup);
114#else
115 /* Disable Interrupt, Disable Channel */
116 adcp->adc->SC1A = ADCx_SC1n_ADCH(ADCx_SC1n_ADCH_DISABLED);
117
118 /* Read the sample into the buffer */
119 adcp->samples[adcp->current_index++] = adcp->adc->RA;
120#endif /* KE1xF */
121
122 bool more = true;
123
124 /* At the end of the buffer then we may be finished */
125 if (adcp->current_index == adcp->number_of_samples) {
126 /* We are never finished in circular mode */
127 more = adcp->grpp->circular;
128
129 _adc_isr_full_code(adcp);
130
131 adcp->current_index = 0;
132
133 }
134
135 if (more) {
136
137 /* Signal half completion in circular mode. */
138 if (adcp->grpp->circular &&
139 (adcp->current_index == (adcp->number_of_samples / 2))) {
140
141 _adc_isr_half_code(adcp);
142 }
143
144#ifdef KE1xF
145 adcp->current_channel = (adcp->current_channel + 1) % adcp->grpp->num_channels;
146 adcp->adc12ChannelCfg.channelNumber = adcp->channelIndices[adcp->current_channel];
147 adcp->adc12ChannelCfg.enableInterruptOnConversionCompleted = true;
148 /* Enable Interrupt, Select the Channel */
149 ADC12_SetChannelConfig(adcp->adc, adcp->channelGroup, &adcp->adc12ChannelCfg);
150#else
151 /* Skip to the next channel */
152 do {
153 adcp->current_channel = (adcp->current_channel + 1) & ADC_CHANNEL_MASK;
154 } while (((1 << adcp->current_channel) & adcp->channel_mask) == 0);
155
156 /* Enable Interrupt, Select the Channel */
157 adcp->adc->SC1A = ADCx_SC1n_AIEN | ADCx_SC1n_ADCH(adcp->current_channel);
158#endif /* KE1xF */
159 }
160}
161
162#if KINETIS_ADC_USE_ADC0 || defined(__DOXYGEN__)
163OSAL_IRQ_HANDLER(KINETIS_ADC0_IRQ_VECTOR) {
164 OSAL_IRQ_PROLOGUE();
166 OSAL_IRQ_EPILOGUE();
167}
168#endif
169
170#if KINETIS_ADC_USE_ADC1 || defined(__DOXYGEN__)
171OSAL_IRQ_HANDLER(KINETIS_ADC1_IRQ_VECTOR) {
172 OSAL_IRQ_PROLOGUE();
174 OSAL_IRQ_EPILOGUE();
175}
176#endif
177
178#if KINETIS_ADC_USE_ADC2 || defined(__DOXYGEN__)
179OSAL_IRQ_HANDLER(KINETIS_ADC2_IRQ_VECTOR) {
180 OSAL_IRQ_PROLOGUE();
182 OSAL_IRQ_EPILOGUE();
183}
184#endif
185
186/*===========================================================================*/
187/* Driver exported functions. */
188/*===========================================================================*/
189
190/**
191 * @brief Low level ADC driver initialization.
192 *
193 * @notapi
194 */
195void adc_lld_init(void) {
196
197#if KINETIS_ADC_USE_ADC0
198 /* Driver initialization.*/
199 adcObjectInit(&ADCD1);
200 /* The shared vector is initialized on driver initialization and never
201 disabled.*/
202 nvicEnableVector(ADC0_IRQn, KINETIS_ADC_IRQ_PRIORITY);
203#endif
204
205#if KINETIS_ADC_USE_ADC1
206 /* Driver initialization.*/
207 adcObjectInit(&ADCD2);
208 /* The shared vector is initialized on driver initialization and never
209 disabled.*/
210 nvicEnableVector(ADC1_IRQn, KINETIS_ADC_IRQ_PRIORITY);
211#endif
212
213#if KINETIS_ADC_USE_ADC2
214 /* Driver initialization.*/
215 adcObjectInit(&ADCD3);
216 /* The shared vector is initialized on driver initialization and never
217 disabled.*/
218 nvicEnableVector(ADC2_IRQn, KINETIS_ADC_IRQ_PRIORITY);
219#endif
220
221}
222
223/**
224 * @brief Configures and activates the ADC peripheral.
225 *
226 * @param[in] adcp pointer to the @p ADCDriver object
227 *
228 * @notapi
229 */
230void adc_lld_start(ADCDriver *adcp) {
231
232 /* If in stopped state then enables the ADC clock.*/
233 if (adcp->state == ADC_STOP) {
234#if KINETIS_ADC_USE_ADC0
235 if (&ADCD1 == adcp) {
236#ifndef KE1xF
237 SIM->SCGC6 |= SIM_SCGC6_ADC0;
238#endif /* KE1xF */
239 adcp->adc = ADC0;
240 }
241#endif /* KINETIS_ADC_USE_ADC0 */
242
243#if KINETIS_ADC_USE_ADC1
244 if (&ADCD2 == adcp) {
245#ifndef KE1xF
246 SIM->SCGC6 |= SIM_SCGC6_ADC1;
247#endif /* KE1xF */
248 adcp->adc = ADC1;
249 }
250#endif /* KINETIS_ADC_USE_ADC1 */
251
252#if KINETIS_ADC_USE_ADC2
253 if (&ADCD3 == adcp) {
254#ifndef KE1xF
255 SIM->SCGC6 |= SIM_SCGC6_ADC2;
256#endif /* KE1xF */
257 adcp->adc = ADC2;
258 }
259#endif /* KINETIS_ADC_USE_ADC2 */
260 }
261
262#ifdef KE1xF
263 adcp->channelGroup = 0; // software-triggered
264 adcp->adc12ChannelCfg.channelNumber = 0; // we'll set it later, in adc_lld_start_conversion()
265 adcp->adc12ChannelCfg.enableInterruptOnConversionCompleted = true;
266
267 ADC12_GetDefaultConfig(&adcp->adc12Cfg);
268 adcp->adc12Cfg.resolution = kADC12_Resolution12Bit;
269 ADC12_Init(adcp->adc, &adcp->adc12Cfg);
270#else
271 adcp->channel_mask = adcp->grpp->channel_mask;
272#endif /* KE1xF */
273
274 if (adcp->config->calibrate) {
275 calibrate(adcp);
276 }
277
278
279}
280
281/**
282 * @brief Deactivates the ADC peripheral.
283 *
284 * @param[in] adcp pointer to the @p ADCDriver object
285 *
286 * @notapi
287 */
288void adc_lld_stop(ADCDriver *adcp) {
289
290 /* If in ready state then disables the ADC clock.*/
291 if (adcp->state == ADC_READY) {
292#ifdef KE1xF
293 ADC12_Deinit(adcp->adc);
294#else
295 SIM->SCGC6 &= ~SIM_SCGC6_ADC0;
296 /* Disable Interrupt, Disable Channel */
297 adcp->adc->SC1A = ADCx_SC1n_ADCH(ADCx_SC1n_ADCH_DISABLED);
298#endif /* KE1xF */
299 }
300}
301
302/**
303 * @brief Starts an ADC conversion.
304 *
305 * @param[in] adcp pointer to the @p ADCDriver object
306 *
307 * @notapi
308 */
309void adc_lld_start_conversion(ADCDriver *adcp) {
310 const ADCConversionGroup *grpp = adcp->grpp;
311
312#ifdef KE1xF
313 // select first 16 channels
314 int chn;
315 adcp->channelIndices[0] = ADCx_SC1n_ADCH_DISABLED;
316 for (chn = 0; chn < grpp->num_channels; chn++) {
317 /*
318 if (chn < 10 && ((grpp->smpr2 >> (chn * 3)) & 7) == 0) // ADC_SMPR1_SMP_ANx(n)
319 continue;
320 if (chn >= 10 && ((grpp->smpr1 >> ((chn - 10) * 3)) & 7) == 0) // ADC_SMPR1_SMP_ANx(n)
321 continue;
322 */
323 if (chn < 6) {
324 adcp->channelIndices[chn] = (grpp->sqr3 >> (chn * 5)) & 31;
325 } else if (chn < 12) {
326 adcp->channelIndices[chn] = (grpp->sqr2 >> ((chn - 6) * 5)) & 31;
327 } else {
328 adcp->channelIndices[chn] = (grpp->sqr1 >> ((chn - 12) * 5)) & 31;
329 }
330 }
331
332 bool hw = (grpp->cr2 & ADC_CR2_SWSTART) ? false : true;
333
334 ADC12_EnableHardwareTrigger(adcp->adc, hw); /* enable software trigger mode */
335
336#else
337 /* Enable the Bandgap Buffer if channel mask includes BANDGAP */
338 if (adcp->channel_mask & ADC_BANDGAP) {
339 PMC->REGSC |= PMC_REGSC_BGBE;
340 }
341#endif /* KE1xF */
342
343 adcp->number_of_samples = adcp->depth * grpp->num_channels;
344 adcp->current_index = 0;
345
346 /* Skip to the next channel */
347 adcp->current_channel = 0;
348#ifdef KE1xF
349 adcp->adc12ChannelCfg.channelNumber = adcp->channelIndices[adcp->current_channel];
350 adcp->adc12ChannelCfg.enableInterruptOnConversionCompleted = true;
351 ADC12_SetChannelConfig(adcp->adc, adcp->channelGroup, &adcp->adc12ChannelCfg);
352#else
353 while (((1 << adcp->current_channel) & adcp->channel_mask) == 0) {
354 adcp->current_channel = (adcp->current_channel + 1) & ADC_CHANNEL_MASK;
355 }
356
357 /* Set clock speed and conversion size */
358 adcp->adc->CFG1 = grpp->cfg1;
359
360 /* Set averaging */
361 adcp->adc->SC3 = grpp->sc3;
362
363 /* Enable Interrupt, Select Channel */
364 adcp->adc->SC1A = ADCx_SC1n_AIEN | ADCx_SC1n_ADCH(adcp->current_channel);
365#endif /* KE1xF */
366}
367
368/**
369 * @brief Stops an ongoing conversion.
370 *
371 * @param[in] adcp pointer to the @p ADCDriver object
372 *
373 * @notapi
374 */
375void adc_lld_stop_conversion(ADCDriver *adcp) {
376#ifndef KE1xF
377 const ADCConversionGroup *grpp = adcp->grpp;
378 /* Disable the Bandgap buffer if channel mask includes BANDGAP */
379 if (adcp->channel_mask & ADC_BANDGAP) {
380 /* Clear BGBE, ACKISO is w1c, avoid setting */
381 PMC->REGSC &= ~(PMC_REGSC_BGBE | PMC_REGSC_ACKISO);
382 }
383#endif /* KE1xF */
384}
385
386#endif /* HAL_USE_ADC */
387
388/** @} */
ADCDriver ADCD3
ADC3 driver identifier.
Definition hal_adc_lld.c:54
void adc_lld_stop_conversion(ADCDriver *adcp)
Stops an ongoing conversion.
void adc_lld_init(void)
Low level ADC driver initialization.
ADCDriver ADCD2
ADC2 driver identifier.
Definition hal_adc_lld.c:49
void adc_lld_start_conversion(ADCDriver *adcp)
Starts an ADC conversion.
void adc_lld_stop(ADCDriver *adcp)
Deactivates the ADC peripheral.
void adc_lld_start(ADCDriver *adcp)
Configures and activates the ADC peripheral.
OSAL_IRQ_HANDLER(KINETIS_ADC0_IRQ_VECTOR)
static void calibrate(ADCDriver *adcp)
Definition hal_adc_lld.c:65
ADCDriver ADCD1
ADC1 driver identifier.
Definition hal_adc_lld.c:44
static void adc_lld_irq_handler(ADCDriver *adcp)
ADC interrupt handler.
static void ADC12_EnableHardwareTrigger(ADC_Type *base, bool enable)
Enable of disable the hardware trigger mode.
Definition fsl_adc12.h:322
status_t ADC12_DoAutoCalibration(ADC_Type *base)
Automate the hardware calibration.
Definition fsl_adc12.c:292
void ADC12_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc12_channel_config_t *config)
Configure the conversion channel.
Definition fsl_adc12.c:237
static uint32_t ADC12_GetChannelConversionValue(ADC_Type *base, uint32_t channelGroup)
Get the conversion value.
Definition fsl_adc12.h:228
void ADC12_GetDefaultConfig(adc12_config_t *config)
Gets an available pre-defined settings for converter's configuration.
Definition fsl_adc12.c:198
void ADC12_Deinit(ADC_Type *base)
De-initialize the ADC12 module.
Definition fsl_adc12.c:174
void ADC12_Init(ADC_Type *base, const adc12_config_t *config)
Initialize the ADC12 module.
Definition fsl_adc12.c:133
@ kADC12_Resolution12Bit
Definition fsl_adc12.h:59