rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
adc_inputs.cpp
Go to the documentation of this file.
1/**
2 * @file adc_inputs.cpp
3 * @brief Low level ADC code
4 *
5 * @date Jan 14, 2013
6 * @author Andrey Belomutskiy, (c) 2012-2020
7 */
8
9#include "pch.h"
10
14
15float PUBLIC_API_WEAK boardAdjustVoltage(float voltage, adc_channel_e /* hwChannel */) {
16 // a hack useful when we do not trust voltage just after board EN was turned on. is this just hiding electrical design flaws?
17 return voltage;
18}
19
20/* overall analog health state
21 * return negative in case of any problems
22 * return 0 if everything is ok or no diagnostic is available */
24 return ObdCode::None;
25}
26
27/* simple implementation if board does not provide advanced diagnostic */
29#if EFI_PROD_CODE
30 /* for on-chip ADC inputs we check common analog health */
32 return (boardGetAnalogDiagnostic() == ObdCode::None) ? 0 : -1;
33 }
34#endif // EFI_PROD_CODE
35
36 /* input is outside chip/ECU */
37 return 0;
38}
39
41{
42#if HAL_USE_ADC
43 float vref = getMCUVref();
44
45 // TODO: +/-10% is way too big?
46 if (vref > engineConfiguration->adcVcc * 1.1) {
48 }
49
50 if (vref < engineConfiguration->adcVcc * 0.9) {
52 }
53#endif
54
55 return ObdCode::None;
56}
57
58/* Get analog part diagnostic */
60{
61 /* TODO: debounce? */
63 if (code != ObdCode::None) {
64 return code;
65 }
66
68}
69
70#if HAL_USE_ADC
71
72#include "adc_device.h"
73#include "adc_subscription.h"
74#include "mpu_util.h"
75#include "protected_gpio.h"
76
77// voltage in MCU universe, from zero to Vref
78expected<float> adcGetRawVoltage(const char *msg, adc_channel_e hwChannel) {
79 float rawVoltage = adcRawValueToRawVoltage(adcGetRawValue(msg, hwChannel));
80 int inputStatus = boardGetAnalogInputDiagnostic(hwChannel, rawVoltage);
81
82 if (inputStatus == 0) {
83 return expected(rawVoltage);
84 }
85
86 /* TODO: convert inputStatus to unexpected? */
87 return unexpected;
88}
89
90// voltage in ECU universe, with all input dividers and OpAmps gains taken into account, voltage at ECU connector pin
91expected<float> adcGetScaledVoltage(const char *msg, adc_channel_e hwChannel) {
92 auto rawVoltage = adcGetRawVoltage(msg, hwChannel);
93
94 if (rawVoltage) {
95 // TODO: merge getAnalogInputDividerCoefficient() and boardAdjustVoltage() into single board hook?
96 float voltage = rawVoltage.value_or(0) * getAnalogInputDividerCoefficient(hwChannel);
97 return expected(boardAdjustVoltage(voltage, hwChannel));
98 }
99
100 return expected(rawVoltage);
101}
102
103extern AdcDevice fastAdc;
104
105static AdcChannelMode adcHwChannelMode[EFI_ADC_TOTAL_CHANNELS];
106
107// todo: move this flag to Engine god object
108static int adcDebugReporting = false;
109
111 return adcHwChannelMode[hwChannel];
112}
113
115
116int getInternalAdcValue(const char *msg, adc_channel_e hwChannel) {
117 if (!isAdcChannelValid(hwChannel)) {
118 warning(ObdCode::CUSTOM_OBD_ANALOG_INPUT_NOT_CONFIGURED, "ADC: %s input is not configured", msg);
119 return -1;
120 }
121
122#if EFI_USE_FAST_ADC
123 if (adcHwChannelMode[hwChannel] == AdcChannelMode::Fast) {
124 return fastAdc.getAvgAdcValue(hwChannel);
125 }
126#endif // EFI_USE_FAST_ADC
127
128 return adcOnchipSlowGetAvgRaw(hwChannel);
129}
130
131static void printAdcValue(int channel) {
132 /* Do this check before conversion to adc_channel_e that is uint8_t based */
133 if ((channel < EFI_ADC_NONE) || (channel >= EFI_ADC_TOTAL_CHANNELS)) {
134 efiPrintf("Invalid ADC channel %d", channel);
135 return;
136 }
137 int adcValue = adcGetRawValue("print", (adc_channel_e)channel);
138 float voltsInput = adcRawValueToScaledVoltage(adcValue, (adc_channel_e)channel);
139 efiPrintf("adc %d input %.3fV", channel, voltsInput);
140}
141
142void adcPrintChannelReport(const char *prefix, int internalIndex, adc_channel_e hwChannel)
143{
144 if (isAdcChannelValid(hwChannel)) {
145 ioportid_t port = getAdcChannelPort("print", hwChannel);
146 int pin = getAdcChannelPin(hwChannel);
147 int adcValue = adcGetRawValue("print", hwChannel);
148 auto volts = adcGetRawVoltage("print", hwChannel);
149 auto voltsInput = adcGetScaledVoltage("print", hwChannel);
150 /* Human index starts from 1 */
151 efiPrintf(" %s ch[%2d] @ %s%d ADC%d 12bit=%4d %.3fV input %.3fV %s",
152 prefix, internalIndex, portname(port), pin,
153 /* TODO: */ hwChannel - EFI_ADC_0 + 1,
154 adcValue, volts.value_or(0), voltsInput.value_or(0), volts ? "valid" : "INVALID");
155 }
156}
157
158extern void adcOnchipSlowShowReport();
159
161#if EFI_USE_FAST_ADC
162 efiPrintf("fast %u samples", engine->outputChannels.fastAdcConversionCount);
163
164 for (int internalIndex = 0; internalIndex < fastAdc.size(); internalIndex++) {
165 adc_channel_e hwChannel = fastAdc.getAdcChannelByInternalIndex(internalIndex);
166
167 adcPrintChannelReport("F", internalIndex, hwChannel);
168 }
169#endif // EFI_USE_FAST_ADC
170
172}
173
174static void setAdcDebugReporting(int value) {
175 adcDebugReporting = value;
176 efiPrintf("adcDebug=%d", adcDebugReporting);
177}
178
179extern void adcOnchipSlowUpdate(efitick_t nowNt);
180
181void adcInputsUpdateSubscribers(efitick_t nowNt) {
182 adcOnchipSlowUpdate(nowNt);
183
184 {
186
188
189 protectedGpio_check(nowNt);
190 }
191}
192
193void addFastAdcChannel(const char*, adc_channel_e hwChannel) {
194 if (!isAdcChannelValid(hwChannel)) {
195 return;
196 }
197
198#if EFI_USE_FAST_ADC
199 fastAdc.enableChannel(hwChannel);
200#endif
201
203 // Nothing to do for slow channels, input is mapped to analog in init_sensors.cpp
204}
205
206void removeChannel(const char*, adc_channel_e hwChannel) {
207 if (!isAdcChannelValid(hwChannel)) {
208 return;
209 }
210#if EFI_USE_FAST_ADC
211 if (adcHwChannelMode[hwChannel] == AdcChannelMode::Fast) {
212 /* TODO: */
213 //fastAdc.disableChannel(hwChannel);
214 }
215#endif
216
218}
219
220// Weak link a stub so that every board doesn't have to implement this function
222
223static void configureInputs() {
225
226 /**
227 * order of analog channels here is totally random and has no meaning
228 * we also have some weird implementation with internal indices - that all has no meaning, it's just a random implementation
229 * which does not mean anything.
230 */
231
233
234 // not currently used addFastAdcChannel("Vref", engineConfiguration->vRefAdcChannel, ADC_SLOW);
235
237
239}
240
242 efiPrintf("initAdcInputs()");
243
245
246 // migrate to 'enable adcdebug'
248
249#if EFI_INTERNAL_ADC
250 // This will start HW for all used ADCs
251 portInitAdc();
252
253#if EFI_USE_FAST_ADC
254 // After this point fastAdc is not allowed to add channels
255 fastAdc.init();
256#endif // EFI_USE_FAST_ADC
257
259#else // ! EFI_INTERNAL_ADC
260 efiPrintf("ADC disabled");
261#endif // EFI_INTERNAL_ADC
262
263 // Workaround to pre-feed all sensors with some data...
264 chThdSleepMilliseconds(1);
266}
267
270 return;
272}
273
274#else /* not HAL_USE_ADC */
275
276// voltage in MCU universe, from zero to VDD
277__attribute__((weak)) expected<float> adcGetRawVoltage(const char*, adc_channel_e) {
278 return expected(0.0f);
279}
280
281// voltage in ECU universe, with all input dividers and OpAmps gains taken into account, voltage at ECU connector pin
282__attribute__((weak)) expected<float> adcGetScaledVoltage(const char*, adc_channel_e) {
283 return expected(0.0f);
284}
285
286#endif
void adcInputsUpdateSubscribers(efitick_t nowNt)
void initAdcInputs()
expected< float > adcGetScaledVoltage(const char *msg, adc_channel_e hwChannel)
static ObdCode analogGetVrefDiagnostic()
static void setAdcDebugReporting(int value)
static void printAdcValue(int channel)
adc_channel_e
void adcPrintChannelReport(const char *prefix, int internalIndex, adc_channel_e hwChannel)
AdcChannelMode getAdcMode(adc_channel_e hwChannel)
void removeChannel(const char *, adc_channel_e hwChannel)
ObdCode analogGetDiagnostic()
adcsample_t adcOnchipSlowGetAvgRaw(adc_channel_e hwChannel)
int PUBLIC_API_WEAK boardGetAnalogInputDiagnostic(adc_channel_e channel, float)
float PUBLIC_API_WEAK boardAdjustVoltage(float voltage, adc_channel_e)
void adcOnchipSlowUpdate(efitick_t nowNt)
int getInternalAdcValue(const char *msg, adc_channel_e hwChannel)
void printFullAdcReportIfNeeded(void)
ObdCode PUBLIC_API_WEAK boardGetAnalogDiagnostic()
static AdcChannelMode adcHwChannelMode[EFI_ADC_TOTAL_CHANNELS]
static int adcDebugReporting
float PUBLIC_API_WEAK getAnalogInputDividerCoefficient(adc_channel_e)
static void configureInputs()
void printFullAdcReport(void)
AdcDevice fastAdc
void addFastAdcChannel(const char *, adc_channel_e hwChannel)
void adcOnchipSlowShowReport()
expected< float > adcGetRawVoltage(const char *msg, adc_channel_e hwChannel)
bool isAdcChannelValid(adc_channel_e hwChannel)
Definition adc_inputs.h:23
uint16_t channel
Definition adc_inputs.h:104
bool isAdcChannelOnChip(adc_channel_e hwChannel)
Definition adc_inputs.h:36
AdcChannelMode
Definition adc_inputs.h:77
float getMCUVref(void)
uint8_t code
Definition bluetooth.cpp:40
typedef __attribute__
Ignition Mode.
void init(void)
int size() const
adc_channel_e getAdcChannelByInternalIndex(int index) const
int enableChannel(adc_channel_e hwChannel)
adcsample_t getAvgAdcValue(adc_channel_e hwChannel)
static void UpdateSubscribers(efitick_t nowNt)
TunerStudioOutputChannels outputChannels
Definition engine.h:109
void addConsoleActionI(const char *token, VoidInt callback)
Register a console command with one Integer parameter.
void(* VoidInt)(int)
void setAdcChannelOverrides()
void portInitAdc()
Definition mpu_util.cpp:256
int getAdcChannelPin(adc_channel_e hwChannel)
ioportid_t getAdcChannelPort(const char *msg, adc_channel_e hwChannel)
const char * portname(ioportid_t GPIOx)
efitick_t getTimeNowNt()
Definition efitime.cpp:19
static EngineAccessor engine
Definition engine.h:413
static constexpr engine_configuration_s * engineConfiguration
bool warning(ObdCode code, const char *fmt,...)
uint16_t adcsample_t
ADC sample data type.
GPIO_TypeDef * ioportid_t
Port Identifier.
ObdCode
@ OBD_Sensor_Refence_Voltate_A_High
@ CUSTOM_OBD_ANALOG_INPUT_NOT_CONFIGURED
@ OBD_Sensor_Refence_Voltate_A_Low
@ AdcProcessSlow
void protectedGpio_check(efitick_t nowNt)
brain_pin_e pin
Definition stm32_adc.cpp:15