rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
adc_inputs_onchip.cpp
Go to the documentation of this file.
1/**
2 * @file adc_inputs_onchip.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 order 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 * Slow ADC group is used for IAT, CLT, AFR, VBATT etc - this one is currently sampled at 500Hz
9 *
10 * Fast ADC group is used for MAP, MAF HIP - this one is currently sampled at 10KHz
11 * We need frequent MAP for map_averaging.cpp
12 *
13 * 10KHz equals one measurement every 3.6 degrees at 6000 RPM
14 *
15 * PS: analog muxes allow to double number of analog inputs
16 * oh, and ADC3 is dedicated for knock
17 *
18 * @date Jan 14, 2013
19 * @author Andrey Belomutskiy, (c) 2012-2020
20 */
21
22#include "pch.h"
23
24#if HAL_USE_ADC
25
26#include "adc_subscription.h"
27#include "AdcDevice.h"
28#include "mpu_util.h"
30#include "protected_gpio.h"
31
32// voltage in MCU universe, from zero to Vref
33float adcGetRawVoltage(const char *msg, adc_channel_e hwChannel) {
34 return adcRawValueToRawVoltage(adcGetRawValue(msg, hwChannel));
35}
36
37// voltage in ECU universe, with all input dividers and OpAmps gains taken into account, voltage at ECU connector pin
38float adcGetScaledVoltage(const char *msg, adc_channel_e hwChannel) {
39 // TODO: merge getAnalogInputDividerCoefficient() and boardAdjustVoltage() into single board hook?
40 float voltage = adcGetRawVoltage(msg, hwChannel) * getAnalogInputDividerCoefficient(hwChannel);
41 return boardAdjustVoltage(voltage, hwChannel);
42}
43
44#if EFI_USE_FAST_ADC
45
46// is there a reason to have this configurable at runtime?
47#ifndef ADC_FAST_DEVICE
48#define ADC_FAST_DEVICE ADCD2
49#endif
50
51// Depth of the conversion buffer, channels are sampled X times each
52#ifndef ADC_BUF_DEPTH_FAST
53#define ADC_BUF_DEPTH_FAST 4
54#endif
55
56// See https://github.com/rusefi/rusefi/issues/976 for discussion on this value
57#ifndef ADC_SAMPLING_FAST
58#define ADC_SAMPLING_FAST ADC_SAMPLE_28
59#endif
60
61AdcDevice::AdcDevice(ADCDriver *p_adcp, ADCConversionGroup* p_hwConfig, volatile adcsample_t *p_buf, size_t p_depth) {
62 adcp = p_adcp;
63 depth = p_depth;
64 hwConfig = p_hwConfig;
65 samples = p_buf;
66
67 hwConfig->sqr1 = 0;
68 hwConfig->sqr2 = 0;
69 hwConfig->sqr3 = 0;
70#if ADC_MAX_CHANNELS_COUNT > 16
71 hwConfig->sqr4 = 0;
72 hwConfig->sqr5 = 0;
73#endif /* ADC_MAX_CHANNELS_COUNT */
75}
76
77static void fastAdcDoneCB(ADCDriver *adcp);
78static void fastAdcErrorCB(ADCDriver *, adcerror_t err);
79
80static ADCConversionGroup adcgrpcfgFast = {
81#if defined(EFI_INTERNAL_FAST_ADC_PWM)
82 .circular = TRUE,
83#elif defined (EFI_INTERNAL_FAST_ADC_GPT)
84 .circular = FALSE,
85#endif
86 .num_channels = 0,
87 .end_cb = fastAdcDoneCB,
88 .error_cb = fastAdcErrorCB,
89 /* HW dependent part.*/
90 .cr1 = 0,
91#if defined(EFI_INTERNAL_FAST_ADC_PWM)
92 /* HW start using TIM8 CC 1 event rising edge
93 * See "External trigger for regular channels" for magic 13 number
94 * NOTE: Currently only TIM8 in PWM mode is supported */
95 .cr2 = ADC_CR2_EXTEN_0 | (13 << ADC_CR2_EXTSEL_Pos),
96#elif defined (EFI_INTERNAL_FAST_ADC_GPT)
97 /* SW start through GPT callback and SW kick */
98 .cr2 = ADC_CR2_SWSTART,
99#endif
100 /**
101 * here we configure all possible channels for fast mode. Some channels would not actually
102 * be used hopefully that's fine to configure all possible channels.
103 *
104 */
105 // sample times for channels 10...18
106 .smpr1 =
107 ADC_SMPR1_SMP_AN10(ADC_SAMPLING_FAST) |
108 ADC_SMPR1_SMP_AN11(ADC_SAMPLING_FAST) |
109 ADC_SMPR1_SMP_AN12(ADC_SAMPLING_FAST) |
110 ADC_SMPR1_SMP_AN13(ADC_SAMPLING_FAST) |
111 ADC_SMPR1_SMP_AN14(ADC_SAMPLING_FAST) |
112 ADC_SMPR1_SMP_AN15(ADC_SAMPLING_FAST),
113 // In this field must be specified the sample times for channels 0...9
114 .smpr2 =
115 ADC_SMPR2_SMP_AN0(ADC_SAMPLING_FAST) |
116 ADC_SMPR2_SMP_AN1(ADC_SAMPLING_FAST) |
117 ADC_SMPR2_SMP_AN2(ADC_SAMPLING_FAST) |
118 ADC_SMPR2_SMP_AN3(ADC_SAMPLING_FAST) |
119 ADC_SMPR2_SMP_AN4(ADC_SAMPLING_FAST) |
120 ADC_SMPR2_SMP_AN5(ADC_SAMPLING_FAST) |
121 ADC_SMPR2_SMP_AN6(ADC_SAMPLING_FAST) |
122 ADC_SMPR2_SMP_AN7(ADC_SAMPLING_FAST) |
123 ADC_SMPR2_SMP_AN8(ADC_SAMPLING_FAST) |
124 ADC_SMPR2_SMP_AN9(ADC_SAMPLING_FAST),
125 .htr = 0,
126 .ltr = 0,
127 .sqr1 = 0, // Conversion group sequence 13...16 + sequence length
128 .sqr2 = 0, // Conversion group sequence 7...12
129 .sqr3 = 0, // Conversion group sequence 1...6
130#if ADC_MAX_CHANNELS_COUNT > 16
131 .sqr4 = 0, // Conversion group sequence 19...24
132 .sqr5 = 0 // Conversion group sequence 25...30
133#endif /* ADC_MAX_CHANNELS_COUNT */
134};
135
136static volatile NO_CACHE adcsample_t fastAdcSampleBuf[ADC_BUF_DEPTH_FAST * ADC_MAX_CHANNELS_COUNT];
137
139
140static efitick_t lastTick = 0;
141
142static void fastAdcDoneCB(ADCDriver *adcp) {
143 // State may not be complete if we get a callback for "half done"
144 if (adcIsBufferComplete(adcp)) {
145 efitick_t nowTick = getTimeNowNt();
146 efitick_t diff = nowTick - lastTick;
147 lastTick = nowTick;
148
149 engine->outputChannels.fastAdcPeriod = (uint32_t)diff;
151
152 onFastAdcComplete(adcp->samples);
153 }
154}
155
156static void fastAdcErrorCB(ADCDriver *, adcerror_t err) {
157 engine->outputChannels.fastAdcLastError = (uint8_t)err;
159 if (err == ADC_ERR_OVERFLOW) {
161 }
162 // TODO: restart?
163}
164
165#if defined(EFI_INTERNAL_FAST_ADC_PWM)
166
167static const PWMConfig pwmcfg = {
168 /* on each trigger event regular group of channels is converted,
169 * to get whole buffer filled we need ADC_BUF_DEPTH_FAST trigger events */
170 .frequency = GPT_FREQ_FAST * ADC_BUF_DEPTH_FAST,
171 .period = GPT_PERIOD_FAST,
172 .callback = nullptr,
173 .channels = {
174 {PWM_OUTPUT_ACTIVE_HIGH, nullptr},
175 {PWM_OUTPUT_ACTIVE_HIGH, nullptr},
176 {PWM_OUTPUT_ACTIVE_HIGH, nullptr},
177 {PWM_OUTPUT_ACTIVE_HIGH, nullptr}
178 },
179 .cr2 = 0,
180 .bdtr = 0,
181 .dier = 0,
182};
183
184#elif defined (EFI_INTERNAL_FAST_ADC_GPT)
185
187{
188#if EFI_INTERNAL_ADC
189 /*
190 * Starts an asynchronous ADC conversion operation, the conversion
191 * will be executed in parallel to the current PWM cycle and will
192 * terminate before the next PWM cycle.
193 */
195#endif /* EFI_INTERNAL_ADC */
196}
197
199 .frequency = GPT_FREQ_FAST,
200 .callback = fastAdcStartTrigger,
201 .cr2 = 0,
202 .dier = 0,
203};
204
205#else
206 #error Please define EFI_INTERNAL_FAST_ADC_PWM or EFI_INTERNAL_FAST_ADC_GPT for Fast ADC
207#endif
208
209int AdcDevice::size() const {
210 return channelCount;
211}
212
213void AdcDevice::init(void) {
214 hwConfig->num_channels = size();
215 /* driver does this internally */
216 //hwConfig->sqr1 += ADC_SQR1_NUM_CH(size());
217
218#if defined(EFI_INTERNAL_FAST_ADC_PWM)
219 // Start the timer running
220 pwmStart(EFI_INTERNAL_FAST_ADC_PWM, &pwmcfg);
221 pwmEnableChannel(EFI_INTERNAL_FAST_ADC_PWM, 0, /* width */ 1);
222 adcStartConversion(adcp, hwConfig, (adcsample_t *)samples, depth);
223#elif defined (EFI_INTERNAL_FAST_ADC_GPT)
224 gptStart(EFI_INTERNAL_FAST_ADC_GPT, &fast_adc_config);
225 gptStartContinuous(EFI_INTERNAL_FAST_ADC_GPT, GPT_PERIOD_FAST);
226#endif
227}
228
230 if ((channelCount + 1) >= ADC_MAX_CHANNELS_COUNT) {
231 criticalError("Too many ADC channels configured");
232 return -1;
233 }
234
235 int logicChannel = channelCount++;
236
237 /* TODO: following is correct for STM32 ADC1/2.
238 * ADC3 has another input to gpio mapping
239 * and should be handled separately */
240 size_t channelAdcIndex = hwChannel - EFI_ADC_0;
241
242 internalAdcIndexByHardwareIndex[hwChannel] = logicChannel;
243 if (logicChannel < 6) {
244 hwConfig->sqr3 |= channelAdcIndex << (5 * logicChannel);
245 } else if (logicChannel < 12) {
246 hwConfig->sqr2 |= channelAdcIndex << (5 * (logicChannel - 6));
247 } else if (logicChannel < 18) {
248 hwConfig->sqr1 |= channelAdcIndex << (5 * (logicChannel - 12));
249 }
250#if ADC_MAX_CHANNELS_COUNT > 16
251 else if (logicChannel < 24) {
252 hwConfig->sqr4 |= channelAdcIndex << (5 * (logicChannel - 18));
253 }
254 else if (logicChannel < 30) {
255 hwConfig->sqr5 |= channelAdcIndex << (5 * (logicChannel - 24));
256 }
257#endif /* ADC_MAX_CHANNELS_COUNT */
258
259 return channelAdcIndex;
260}
261
263{
264 chSysLockFromISR();
265 if ((ADC_FAST_DEVICE.state == ADC_READY) ||
266 (ADC_FAST_DEVICE.state == ADC_ERROR)) {
267 /* drop volatile type qualifier - this is safe */
268 adcStartConversionI(adcp, hwConfig, (adcsample_t *)samples, depth);
269 } else {
271 // todo: when? why? criticalError("ADC fast not ready?");
272 // see notes at https://github.com/rusefi/rusefi/issues/6399
273 }
274 chSysUnlockFromISR();
275}
276
278 uint32_t result = 0;
279 int numChannels = size();
280 int index = fastAdc.internalAdcIndexByHardwareIndex[hwChannel];
281 if (index == 0xff) {
282 criticalError("Fast ADC attempt to read unconfigured input %d.", hwChannel);
283 return 0;
284 }
285
286 for (size_t i = 0; i < depth; i++) {
287 adcsample_t sample = samples[index];
288 if (sample > ADC_MAX_VALUE) {
289 // 12bit ADC expected right now. An error here usually means major RAM corruption?
290 criticalError("ADC unexpected sample %d at %ld uptime.",
291 sample,
292 (uint32_t)getTimeNowS());
293 }
294 result += sample;
295 index += numChannels;
296 }
297
298 // this truncation is guaranteed to not be lossy - the average can't be larger than adcsample_t
299 return static_cast<adcsample_t>(result / depth);
300}
301
303 for (size_t idx = EFI_ADC_0; idx < EFI_ADC_TOTAL_CHANNELS; idx++) {
304 if (internalAdcIndexByHardwareIndex[idx] == hwChannel) {
305 return (adc_channel_e)idx;
306 }
307 }
308 return EFI_ADC_NONE;
309}
310
314
315#endif // EFI_USE_FAST_ADC
316
317#endif // HAL_USE_ADC
float PUBLIC_API_WEAK boardAdjustVoltage(float voltage, adc_channel_e)
AdcDevice fastAdc
void onFastAdcComplete(adcsample_t *samples)
Definition hardware.cpp:276
uint32_t AdcToken
Definition adc_inputs.h:103
static void fastAdcStartTrigger(GPTDriver *)
static const PWMConfig pwmcfg
AdcDevice fastAdc & ADC_FAST_DEVICE
float adcGetScaledVoltage(const char *msg, adc_channel_e hwChannel)
static volatile NO_CACHE adcsample_t fastAdcSampleBuf[ADC_BUF_DEPTH_FAST *ADC_MAX_CHANNELS_COUNT]
static efitick_t lastTick
static const GPTConfig fast_adc_config
static void fastAdcDoneCB(ADCDriver *adcp)
static void fastAdcErrorCB(ADCDriver *, adcerror_t err)
float adcGetRawVoltage(const char *msg, adc_channel_e hwChannel)
static ADCConversionGroup adcgrpcfgFast
void startConversionI(void)
size_t depth
Definition AdcDevice.h:47
uint8_t internalAdcIndexByHardwareIndex[EFI_ADC_TOTAL_CHANNELS]
Definition AdcDevice.h:48
int size() const
adc_channel_e getAdcChannelByInternalIndex(int index) const
AdcToken getAdcChannelToken(adc_channel_e hwChannel)
int enableChannel(adc_channel_e hwChannel)
ADCConversionGroup * hwConfig
Definition AdcDevice.h:45
size_t channelCount
Definition AdcDevice.h:52
adcsample_t getAvgAdcValue(adc_channel_e hwChannel)
AdcDevice(ADCDriver *p_adcp, ADCConversionGroup *p_hwConfig, volatile adcsample_t *p_buf, size_t p_depth)
volatile adcsample_t * samples
Definition AdcDevice.h:46
ADCDriver * adcp
Definition AdcDevice.h:44
TunerStudioOutputChannels outputChannels
Definition engine.h:108
efitick_t getTimeNowNt()
Definition efitime.cpp:19
efitimesec_t getTimeNowS()
Current system time in seconds (32 bits)
Definition efitime.cpp:42
static EngineAccessor engine
Definition engine.h:410
adcerror_t
Possible ADC failure causes.
uint16_t adcsample_t
ADC sample data type.
@ ADC_ERR_OVERFLOW
gptfreq_t frequency
Timer clock in Hz.
static union @47 NO_CACHE
float getAnalogInputDividerCoefficient(adc_channel_e hwChannel)
Driver configuration structure.
Structure representing a GPT driver.
Type of a PWM driver configuration structure.
uint32_t frequency
Timer clock in Hz.