rusEFI
The most advanced open source ECU
adc_inputs.cpp
Go to the documentation of this file.
1 /**
2  * @file adc_inputs.cpp
3  * @brief Low level ADC code
4  *
5  * rusEfi uses two ADC devices on the same 16 pins at the moment. Two ADC devices are used in orde to distinguish between
6  * fast and slow devices. The idea is that but only having few channels in 'fast' mode we can sample those faster?
7  *
8  * At the moment rusEfi does not allow to have more than 16 ADC channels combined. At the moment there is no flexibility to use
9  * any ADC pins, only the hardcoded choice of 16 pins.
10  *
11  * Slow ADC group is used for IAT, CLT, AFR, VBATT etc - this one is currently sampled at 500Hz
12  *
13  * Fast ADC group is used for MAP, MAF HIP - this one is currently sampled at 10KHz
14  * We need frequent MAP for map_averaging.cpp
15  *
16  * 10KHz equals one measurement every 3.6 degrees at 6000 RPM
17  *
18  * @date Jan 14, 2013
19  * @author Andrey Belomutskiy, (c) 2012-2020
20  */
21 
22 #include "pch.h"
23 
26 }
27 
28 #if HAL_USE_ADC
29 
30 #include "adc_subscription.h"
31 #include "AdcConfiguration.h"
32 #include "mpu_util.h"
34 #include "protected_gpio.h"
35 
36 static NO_CACHE adcsample_t slowAdcSamples[SLOW_ADC_CHANNEL_COUNT];
37 
38 static adc_channel_mode_e adcHwChannelMode[HW_MAX_ADC_INDEX];
39 
41  return adcHwChannelMode[hwChannel];
42 }
43 
44 // Board voltage, with divider coefficient accounted for
45 float getVoltageDivided(const char *msg, adc_channel_e hwChannel) {
46  return getVoltage(msg, hwChannel) * getAnalogInputDividerCoefficient(hwChannel);
47 }
48 
49 // voltage in MCU universe, from zero to VDD
50 float getVoltage(const char *msg, adc_channel_e hwChannel) {
51  return adcToVolts(getAdcValue(msg, hwChannel));
52 }
53 
54 #if EFI_USE_FAST_ADC
55 
56 /* Depth of the conversion buffer, channels are sampled X times each.*/
57 #ifndef ADC_BUF_DEPTH_FAST
58 #define ADC_BUF_DEPTH_FAST 4
59 #endif
60 
61 AdcDevice::AdcDevice(ADCConversionGroup* p_hwConfig, adcsample_t *p_buf) {
62  hwConfig = p_hwConfig;
63  samples = p_buf;
64 
65  hwConfig->sqr1 = 0;
66  hwConfig->sqr2 = 0;
67  hwConfig->sqr3 = 0;
68 #if ADC_MAX_CHANNELS_COUNT > 16
69  hwConfig->sqr4 = 0;
70  hwConfig->sqr5 = 0;
71 #endif /* ADC_MAX_CHANNELS_COUNT */
73 }
74 
75 #endif // EFI_USE_FAST_ADC
76 
77 // is there a reason to have this configurable at runtime?
78 #ifndef ADC_FAST_DEVICE
79 #define ADC_FAST_DEVICE ADCD2
80 #endif /* ADC_FAST_DEVICE */
81 
82 // todo: move this flag to Engine god object
83 static int adcDebugReporting = false;
84 
85 #if EFI_USE_FAST_ADC
86 
87 // See https://github.com/rusefi/rusefi/issues/976 for discussion on this value
88 #ifndef ADC_SAMPLING_FAST
89 #define ADC_SAMPLING_FAST ADC_SAMPLE_28
90 #endif
91 
92 static void fastAdcDoneCB(ADCDriver *adcp);
93 static void fastAdcErrorCB(ADCDriver *, adcerror_t err);
94 
95 static ADCConversionGroup adcgrpcfgFast = {
96  .circular = FALSE,
97  .num_channels = 0,
98  .end_cb = fastAdcDoneCB,
99  .error_cb = fastAdcErrorCB,
100  /* HW dependent part.*/
101  .cr1 = 0,
102  .cr2 = ADC_CR2_SWSTART,
103  /**
104  * here we configure all possible channels for fast mode. Some channels would not actually
105  * be used hopefully that's fine to configure all possible channels.
106  *
107  */
108  // sample times for channels 10...18
109  .smpr1 =
110  ADC_SMPR1_SMP_AN10(ADC_SAMPLING_FAST) |
111  ADC_SMPR1_SMP_AN11(ADC_SAMPLING_FAST) |
112  ADC_SMPR1_SMP_AN12(ADC_SAMPLING_FAST) |
113  ADC_SMPR1_SMP_AN13(ADC_SAMPLING_FAST) |
114  ADC_SMPR1_SMP_AN14(ADC_SAMPLING_FAST) |
115  ADC_SMPR1_SMP_AN15(ADC_SAMPLING_FAST),
116  // In this field must be specified the sample times for channels 0...9
117  .smpr2 =
118  ADC_SMPR2_SMP_AN0(ADC_SAMPLING_FAST) |
119  ADC_SMPR2_SMP_AN1(ADC_SAMPLING_FAST) |
120  ADC_SMPR2_SMP_AN2(ADC_SAMPLING_FAST) |
121  ADC_SMPR2_SMP_AN3(ADC_SAMPLING_FAST) |
122  ADC_SMPR2_SMP_AN4(ADC_SAMPLING_FAST) |
123  ADC_SMPR2_SMP_AN5(ADC_SAMPLING_FAST) |
124  ADC_SMPR2_SMP_AN6(ADC_SAMPLING_FAST) |
125  ADC_SMPR2_SMP_AN7(ADC_SAMPLING_FAST) |
126  ADC_SMPR2_SMP_AN8(ADC_SAMPLING_FAST) |
127  ADC_SMPR2_SMP_AN9(ADC_SAMPLING_FAST),
128  .htr = 0,
129  .ltr = 0,
130  .sqr1 = 0, // Conversion group sequence 13...16 + sequence length
131  .sqr2 = 0, // Conversion group sequence 7...12
132  .sqr3 = 0, // Conversion group sequence 1...6
133 #if ADC_MAX_CHANNELS_COUNT > 16
134  .sqr4 = 0, // Conversion group sequence 19...24
135  .sqr5 = 0 // Conversion group sequence 25...30
136 #endif /* ADC_MAX_CHANNELS_COUNT */
137 };
138 
139 static NO_CACHE adcsample_t fastAdcSampleBuf[ADC_BUF_DEPTH_FAST * ADC_MAX_CHANNELS_COUNT];
140 
142 
143 static void fastAdcDoneCB(ADCDriver *adcp) {
144  // State may not be complete if we get a callback for "half done"
145  if (adcp->state == ADC_COMPLETE) {
147  onFastAdcComplete(adcp->samples);
148  }
149 }
150 
151 static volatile adcerror_t fastAdcLastError;
152 
153 static void fastAdcErrorCB(ADCDriver *, adcerror_t err)
154 {
155  fastAdcLastError = err;
156 }
157 
158 static void fastAdcTrigger(GPTDriver*) {
159 #if EFI_INTERNAL_ADC
160  /*
161  * Starts an asynchronous ADC conversion operation, the conversion
162  * will be executed in parallel to the current PWM cycle and will
163  * terminate before the next PWM cycle.
164  */
165  chSysLockFromISR();
166  if ((ADC_FAST_DEVICE.state != ADC_READY) &&
167  (ADC_FAST_DEVICE.state != ADC_COMPLETE) &&
168  (ADC_FAST_DEVICE.state != ADC_ERROR)) {
170  // todo: when? why? criticalError("ADC fast not ready?");
171  // see notes at https://github.com/rusefi/rusefi/issues/6399
172  } else {
173  adcStartConversionI(&ADC_FAST_DEVICE, &adcgrpcfgFast, fastAdc.samples, ADC_BUF_DEPTH_FAST);
174  }
175  chSysUnlockFromISR();
176 #endif /* EFI_INTERNAL_ADC */
177 }
178 #endif // EFI_USE_FAST_ADC
179 
180 static float mcuTemperature;
181 
183  return mcuTemperature;
184 }
185 
186 int getInternalAdcValue(const char *msg, adc_channel_e hwChannel) {
187  if (!isAdcChannelValid(hwChannel)) {
188  warning(ObdCode::CUSTOM_OBD_ANALOG_INPUT_NOT_CONFIGURED, "ADC: %s input is not configured", msg);
189  return -1;
190  }
191 
192 #if EFI_USE_FAST_ADC
193  if (adcHwChannelMode[hwChannel] == ADC_FAST) {
194  /* todo if ADC_BUF_DEPTH_FAST EQ 1
195  * return fastAdc.samples[internalIndex]; */
196  return fastAdc.getAvgAdcValue(hwChannel, ADC_BUF_DEPTH_FAST);
197  }
198 #endif // EFI_USE_FAST_ADC
199 
200  return slowAdcSamples[hwChannel - EFI_ADC_0];
201 }
202 
203 #if EFI_USE_FAST_ADC
205  .frequency = GPT_FREQ_FAST,
206  .callback = fastAdcTrigger,
207  .cr2 = 0,
208  .dier = 0,
209 };
210 
211 int AdcDevice::size() const {
212  return channelCount;
213 }
214 
215 void AdcDevice::init(void) {
216  hwConfig->num_channels = size();
217  /* driver does this internally */
218  //hwConfig->sqr1 += ADC_SQR1_NUM_CH(size());
219 }
220 
222  if ((channelCount + 1) >= ADC_MAX_CHANNELS_COUNT) {
223  criticalError("Too many ADC channels configured");
224  return;
225  }
226 
227  int logicChannel = channelCount++;
228 
229  /* TODO: following is correct for STM32 ADC1/2.
230  * ADC3 has another input to gpio mapping
231  * and should be handled separately */
232  size_t channelAdcIndex = hwChannel - EFI_ADC_0;
233 
234  internalAdcIndexByHardwareIndex[hwChannel] = logicChannel;
235  if (logicChannel < 6) {
236  hwConfig->sqr3 |= channelAdcIndex << (5 * logicChannel);
237  } else if (logicChannel < 12) {
238  hwConfig->sqr2 |= channelAdcIndex << (5 * (logicChannel - 6));
239  } else if (logicChannel < 18) {
240  hwConfig->sqr1 |= channelAdcIndex << (5 * (logicChannel - 12));
241  }
242 #if ADC_MAX_CHANNELS_COUNT > 16
243  else if (logicChannel < 24) {
244  hwConfig->sqr4 |= channelAdcIndex << (5 * (logicChannel - 18));
245  }
246  else if (logicChannel < 30) {
247  hwConfig->sqr5 |= channelAdcIndex << (5 * (logicChannel - 24));
248  }
249 #endif /* ADC_MAX_CHANNELS_COUNT */
250 }
251 
253  uint32_t result = 0;
254  int numChannels = size();
255  int index = fastAdc.internalAdcIndexByHardwareIndex[hwChannel];
256 
257  for (size_t i = 0; i < bufDepth; i++) {
258  adcsample_t sample = samples[index];
259 // if (sample > 0x1FFF) {
260 // // 12bit ADC expected right now, make this configurable one day
261 // criticalError("fast ADC unexpected sample %d", sample);
262 // } else
263  if (sample > ADC_MAX_VALUE) {
265  criticalError("fast ADC unexpected sample %d. Please report and use skipADC12bitAssert to disable", sample);
266  }
268  // sad hack which works around https://github.com/rusefi/rusefi/issues/6376 which we do not understand
269  sample = sample & ADC_MAX_VALUE;
271  }
272  result += sample;
273  index += numChannels;
274  }
275 
276  // this truncation is guaranteed to not be lossy - the average can't be larger than adcsample_t
277  return static_cast<adcsample_t>(result / bufDepth);
278 }
279 
281  for (size_t idx = EFI_ADC_0; idx < EFI_ADC_TOTAL_CHANNELS; idx++) {
282  if (internalAdcIndexByHardwareIndex[idx] == hwChannel) {
283  return (adc_channel_e)idx;
284  }
285  }
286  return EFI_ADC_NONE;
287 }
288 
290  return fastAdc.internalAdcIndexByHardwareIndex[hwChannel];
291 }
292 
293 #endif // EFI_USE_FAST_ADC
294 
295 static uint32_t slowAdcConversionCount = 0;
296 static uint32_t slowAdcErrorsCount = 0;
297 
298 static void printAdcValue(int channel) {
299  /* Do this check before conversion to adc_channel_e that is uint8_t based */
300  if ((channel < EFI_ADC_NONE) || (channel >= EFI_ADC_TOTAL_CHANNELS)) {
301  efiPrintf("Invalid ADC channel %d", channel);
302  return;
303  }
304  int value = getAdcValue("print", (adc_channel_e)channel);
305  float volts = adcToVoltsDivided(value, (adc_channel_e)channel);
306  efiPrintf("adc %d voltage : %.3f", channel, volts);
307 }
308 
309 static void printAdcChannedReport(const char *prefix, int internalIndex, adc_channel_e hwChannel)
310 {
311  if (isAdcChannelValid(hwChannel)) {
312  ioportid_t port = getAdcChannelPort("print", hwChannel);
313  int pin = getAdcChannelPin(hwChannel);
314  int adcValue = getAdcValue("print", hwChannel);
315  float volts = getVoltage("print", hwChannel);
316  float voltsDivided = getVoltageDivided("print", hwChannel);
317  /* Human index starts from 1 */
318  efiPrintf(" %s ch[%2d] @ %s%d ADC%d 12bit=%4d %.3fV (input %.3fV)",
319  prefix, internalIndex, portname(port), pin,
320  /* TODO: */ hwChannel - EFI_ADC_0 + 1,
321  adcValue, volts, voltsDivided);
322  }
323 }
324 
325 void printFullAdcReport(void) {
326 #if EFI_USE_FAST_ADC
327  efiPrintf("fast %d samples", fastAdc.conversionCount);
328 
329  for (int internalIndex = 0; internalIndex < fastAdc.size(); internalIndex++) {
330  adc_channel_e hwChannel = fastAdc.getAdcChannelByInternalIndex(internalIndex);
331 
332  printAdcChannedReport("F", internalIndex, hwChannel);
333  }
334 #endif // EFI_USE_FAST_ADC
335  efiPrintf("slow %d samples", slowAdcConversionCount);
336 
337  /* we assume that all slow ADC channels are enabled */
338  for (int internalIndex = 0; internalIndex < ADC_MAX_CHANNELS_COUNT; internalIndex++) {
339  adc_channel_e hwChannel = static_cast<adc_channel_e>(internalIndex + EFI_ADC_0);
340 
341  printAdcChannedReport("S", internalIndex, hwChannel);
342  }
343 }
344 
345 static void setAdcDebugReporting(int value) {
346  adcDebugReporting = value;
347  efiPrintf("adcDebug=%d", adcDebugReporting);
348 }
349 
350 void waitForSlowAdc(uint32_t lastAdcCounter) {
351  // todo: use sync.objects?
352  while (slowAdcConversionCount <= lastAdcCounter) {
353  chThdSleepMilliseconds(1);
354  }
355 }
356 
357 class SlowAdcController : public PeriodicController<UTILITY_THREAD_STACK_SIZE> {
358 public:
359  SlowAdcController()
360  : PeriodicController("ADC", PRIO_ADC, SLOW_ADC_RATE)
361  {
362  }
363 
364  void PeriodicTask(efitick_t nowNt) override {
365  {
367 
370  return;
371  }
372 
373  // Ask the port to sample the MCU temperature
375  }
376 
377  {
379 
381 
383 
384  protectedGpio_check(nowNt);
385  }
386  }
387 };
388 
389 void addChannel(const char*, adc_channel_e hwChannel, adc_channel_mode_e mode) {
390  if (!isAdcChannelValid(hwChannel)) {
391  return;
392  }
393 
394 #if EFI_USE_FAST_ADC
395  if (mode == ADC_FAST) {
396  fastAdc.enableChannel(hwChannel);
397  }
398 #endif
399 
400  adcHwChannelMode[hwChannel] = mode;
401  // Nothing to do for slow channels, input is mapped to analog in init_sensors.cpp
402 }
403 
404 void removeChannel(const char*, adc_channel_e hwChannel) {
405  if (!isAdcChannelValid(hwChannel)) {
406  return;
407  }
408 #if EFI_USE_FAST_ADC
409  if (adcHwChannelMode[hwChannel] == ADC_FAST) {
410  /* TODO: */
411  //fastAdc.disableChannel(hwChannel);
412  }
413 #endif
414 
415  adcHwChannelMode[hwChannel] = ADC_OFF;
416 }
417 
418 // Weak link a stub so that every board doesn't have to implement this function
419 __attribute__((weak)) void setAdcChannelOverrides() { }
420 
421 static void configureInputs() {
422  memset(adcHwChannelMode, ADC_OFF, sizeof(adcHwChannelMode));
423 
424  /**
425  * order of analog channels here is totally random and has no meaning
426  * we also have some weird implementation with internal indices - that all has no meaning, it's just a random implementation
427  * which does not mean anything.
428  */
429 
431 
433 
434  // not currently used addChannel("Vref", engineConfiguration->vRefAdcChannel, ADC_SLOW);
435 
437 
439 }
440 
441 static SlowAdcController slowAdcController;
442 
444  efiPrintf("initAdcInputs()");
445 
446  configureInputs();
447 
448  // migrate to 'enable adcdebug'
450 
451 #if EFI_INTERNAL_ADC
452  portInitAdc();
453 
454  // Start the slow ADC thread
455  slowAdcController.start();
456 
457 #if EFI_USE_FAST_ADC
458  fastAdc.init();
459 
460  gptStart(EFI_INTERNAL_FAST_ADC_GPT, &fast_adc_config);
461  gptStartContinuous(EFI_INTERNAL_FAST_ADC_GPT, GPT_PERIOD_FAST);
462 #endif // EFI_USE_FAST_ADC
463 
465 #else
466  efiPrintf("ADC disabled");
467 #endif
468 }
469 
471  if (!adcDebugReporting)
472  return;
474 }
475 
476 #else /* not HAL_USE_ADC */
477 
478 __attribute__((weak)) float getVoltageDivided(const char*, adc_channel_e) {
479  return 0;
480 }
481 
482 // voltage in MCU universe, from zero to VDD
483 __attribute__((weak)) float getVoltage(const char*, adc_channel_e) {
484  return 0;
485 }
486 
487 #endif
void initAdcInputs()
Definition: adc_inputs.cpp:443
float __attribute__((weak)) getAnalogInputDividerCoefficient(adc_channel_e)
Definition: adc_inputs.cpp:24
float getVoltageDivided(const char *msg, adc_channel_e hwChannel)
Definition: adc_inputs.cpp:45
void addChannel(const char *, adc_channel_e hwChannel, adc_channel_mode_e mode)
Definition: adc_inputs.cpp:389
static float mcuTemperature
Definition: adc_inputs.cpp:180
static GPTConfig fast_adc_config
Definition: adc_inputs.cpp:204
static NO_CACHE adcsample_t slowAdcSamples[SLOW_ADC_CHANNEL_COUNT]
Definition: adc_inputs.cpp:36
static void setAdcDebugReporting(int value)
Definition: adc_inputs.cpp:345
static void printAdcValue(int channel)
Definition: adc_inputs.cpp:298
adc_channel_e
Definition: adc_inputs.cpp:478
void waitForSlowAdc(uint32_t lastAdcCounter)
Definition: adc_inputs.cpp:350
static uint32_t slowAdcConversionCount
Definition: adc_inputs.cpp:295
void removeChannel(const char *, adc_channel_e hwChannel)
Definition: adc_inputs.cpp:404
float getVoltage(const char *msg, adc_channel_e hwChannel)
Definition: adc_inputs.cpp:50
static NO_CACHE adcsample_t fastAdcSampleBuf[ADC_BUF_DEPTH_FAST *ADC_MAX_CHANNELS_COUNT]
Definition: adc_inputs.cpp:139
int getInternalAdcValue(const char *msg, adc_channel_e hwChannel)
Definition: adc_inputs.cpp:186
void printFullAdcReportIfNeeded(void)
Definition: adc_inputs.cpp:470
static adc_channel_mode_e adcHwChannelMode[HW_MAX_ADC_INDEX]
Definition: adc_inputs.cpp:38
static int adcDebugReporting
Definition: adc_inputs.cpp:83
static void printAdcChannedReport(const char *prefix, int internalIndex, adc_channel_e hwChannel)
Definition: adc_inputs.cpp:309
adc_channel_mode_e getAdcMode(adc_channel_e hwChannel)
Definition: adc_inputs.cpp:40
static void fastAdcTrigger(GPTDriver *)
Definition: adc_inputs.cpp:158
float getMCUInternalTemperature()
Definition: adc_inputs.cpp:182
static volatile adcerror_t fastAdcLastError
Definition: adc_inputs.cpp:151
static ADCConversionGroup adcgrpcfgFast
Definition: adc_inputs.cpp:95
static void configureInputs()
Definition: adc_inputs.cpp:421
void printFullAdcReport(void)
Definition: adc_inputs.cpp:325
static void fastAdcDoneCB(ADCDriver *adcp)
Definition: adc_inputs.cpp:143
static SlowAdcController slowAdcController
Definition: adc_inputs.cpp:441
static void fastAdcErrorCB(ADCDriver *, adcerror_t err)
Definition: adc_inputs.cpp:153
static uint32_t slowAdcErrorsCount
Definition: adc_inputs.cpp:296
size_t FastAdcToken
Definition: adc_inputs.h:81
bool isAdcChannelValid(adc_channel_e hwChannel)
Definition: adc_inputs.h:20
void onFastAdcComplete(adcsample_t *samples)
Definition: hardware.cpp:279
adc_channel_mode_e
Definition: adc_inputs.h:55
@ ADC_OFF
Definition: adc_inputs.h:56
@ ADC_FAST
Definition: adc_inputs.h:58
void init(void)
Definition: adc_inputs.cpp:215
uint8_t internalAdcIndexByHardwareIndex[EFI_ADC_TOTAL_CHANNELS]
adcsample_t getAvgAdcValue(adc_channel_e hwChannel, size_t bufDepth)
Definition: adc_inputs.cpp:252
int size() const
Definition: adc_inputs.cpp:211
adc_channel_e getAdcChannelByInternalIndex(int index) const
Definition: adc_inputs.cpp:280
void enableChannel(adc_channel_e hwChannel)
Definition: adc_inputs.cpp:221
FastAdcToken getAdcChannelToken(adc_channel_e hwChannel)
Definition: adc_inputs.cpp:289
AdcDevice(ADCConversionGroup *p_hwConfig, adcsample_t *p_buf)
Definition: adc_inputs.cpp:61
uint32_t conversionCount
ADCConversionGroup * hwConfig
size_t channelCount
adcsample_t * samples
static void UpdateSubscribers(efitick_t nowNt)
TunerStudioOutputChannels outputChannels
Definition: engine.h:99
Base class for a controller that needs to run periodically to perform work.
virtual void PeriodicTask(efitick_t nowNt)=0
Called periodically. Override this method to do work for your controller.
void addConsoleActionI(const char *token, VoidInt callback)
Register a console command with one Integer parameter.
void(* VoidInt)(int)
Definition: cli_registry.h:54
void setAdcChannelOverrides()
bool readSlowAnalogInputs(adcsample_t *convertedSamples)
Definition: mpu_util.cpp:251
float getMcuTemperature()
Definition: mpu_util.cpp:246
void portInitAdc()
Definition: mpu_util.cpp:238
int getAdcChannelPin(adc_channel_e hwChannel)
ioportid_t getAdcChannelPort(const char *msg, adc_channel_e hwChannel)
const char * portname(ioportid_t GPIOx)
Engine * engine
AdcDevice fastAdc
bool warning(ObdCode code, const char *fmt,...)
adcerror_t
Possible ADC failure causes.
Definition: hal_adc_lld.h:202
uint16_t adcsample_t
ADC sample data type.
Definition: hal_adc_lld.h:190
gptfreq_t frequency
Timer clock in Hz.
Definition: hal_gpt_lld.h:213
GPIO_TypeDef * ioportid_t
Port Identifier.
Definition: hal_pal_lld.h:102
static FIL FDLogFile NO_CACHE
Definition: mmc_card.cpp:116
@ CUSTOM_OBD_ANALOG_INPUT_NOT_CONFIGURED
@ AdcConversionSlow
@ AdcProcessSlow
engine_configuration_s * engineConfiguration
void protectedGpio_check(efitick_t nowNt)
float getAnalogInputDividerCoefficient(adc_channel_e hwChannel)
brain_pin_e pin
Definition: stm32_adc.cpp:15
Driver configuration structure.
Definition: hal_gpt_lld.h:207
Structure representing a GPT driver.
Definition: hal_gpt_lld.h:239