From f22f318bdbdb03d7a5ceb03e00ec179e088e8e24 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 4 Mar 2021 16:55:09 -0800 Subject: [PATCH] Extract slow adc (#2402) * extract * guard * put some back * put back * slow is actually 500hz so slow is fine here * no magic * fix printFullAdcReport * cast * if we turn those off is it happy * stub cypress/kinetis * guard fast stuff better * bad merge Co-authored-by: Matthew Kennedy --- firmware/hw_layer/adc/adc_inputs.cpp | 126 +++++------------- firmware/hw_layer/ports/cypress/mpu_util.cpp | 5 + firmware/hw_layer/ports/kinetis/mpu_util.cpp | 5 + firmware/hw_layer/ports/mpu_util.h | 5 +- .../hw_layer/ports/stm32/stm32_adc_v2.cpp | 75 +++++++++++ 5 files changed, 119 insertions(+), 97 deletions(-) diff --git a/firmware/hw_layer/adc/adc_inputs.cpp b/firmware/hw_layer/adc/adc_inputs.cpp index 8e3ef05635..a4d6ee9f7e 100644 --- a/firmware/hw_layer/adc/adc_inputs.cpp +++ b/firmware/hw_layer/adc/adc_inputs.cpp @@ -38,7 +38,7 @@ #include "perf_trace.h" #include "thread_priority.h" -static NO_CACHE adcsample_t slowAdcSampleBuf[ADC_BUF_DEPTH_SLOW * ADC_MAX_CHANNELS_COUNT]; +static adcsample_t slowAdcSamples[ADC_MAX_CHANNELS_COUNT]; static NO_CACHE adcsample_t fastAdcSampleBuf[ADC_BUF_DEPTH_FAST * ADC_MAX_CHANNELS_COUNT]; static adc_channel_mode_e adcHwChannelEnabled[HW_MAX_ADC_INDEX]; @@ -55,6 +55,7 @@ float getVoltage(const char *msg, adc_channel_e hwChannel DECLARE_ENGINE_PARAMET return adcToVolts(getAdcValue(msg, hwChannel)); } +#if EFI_USE_FAST_ADC AdcDevice::AdcDevice(ADCConversionGroup* hwConfig, adcsample_t *buf, size_t buf_len) { this->hwConfig = hwConfig; this->samples = buf; @@ -82,17 +83,14 @@ AdcDevice::AdcDevice(ADCConversionGroup* hwConfig, adcsample_t *buf, size_t buf_ #define GPT_PERIOD_FAST 10 /* PWM period (in PWM ticks). */ #endif /* GPT_FREQ_FAST GPT_PERIOD_FAST */ -// is there a reason to have this configurable at runtime? -#ifndef ADC_SLOW_DEVICE -#define ADC_SLOW_DEVICE ADCD1 -#endif /* ADC_SLOW_DEVICE */ +#endif // EFI_USE_FAST_ADC // is there a reason to have this configurable at runtime? #ifndef ADC_FAST_DEVICE #define ADC_FAST_DEVICE ADCD2 #endif /* ADC_FAST_DEVICE */ -static volatile int slowAdcCounter = 0; +static uint32_t slowAdcCounter = 0; static LoggingWithStorage logger("ADC"); // todo: move this flag to Engine god object @@ -115,57 +113,6 @@ static adcsample_t getAvgAdcValue(int index, adcsample_t *samples, int bufDepth, // See https://github.com/rusefi/rusefi/issues/976 for discussion on these values #define ADC_SAMPLING_SLOW ADC_SAMPLE_56 #define ADC_SAMPLING_FAST ADC_SAMPLE_28 -/* - * ADC conversion group. - */ -static ADCConversionGroup adcgrpcfgSlow = { - .circular = FALSE, - .num_channels = 0, - .end_cb = nullptr, - .error_cb = nullptr, - /* HW dependent part.*/ - .cr1 = 0, - .cr2 = ADC_CR2_SWSTART, - /** - * here we configure all possible channels for slow mode. Some channels would not actually - * be used hopefully that's fine to configure all possible channels. - */ - // sample times for channels 10...18 - .smpr1 = - ADC_SMPR1_SMP_AN10(ADC_SAMPLING_SLOW) | - ADC_SMPR1_SMP_AN11(ADC_SAMPLING_SLOW) | - ADC_SMPR1_SMP_AN12(ADC_SAMPLING_SLOW) | - ADC_SMPR1_SMP_AN13(ADC_SAMPLING_SLOW) | - ADC_SMPR1_SMP_AN14(ADC_SAMPLING_SLOW) | - ADC_SMPR1_SMP_AN15(ADC_SAMPLING_SLOW) | -#if defined(STM32F7XX) - ADC_SMPR1_SMP_VBAT(ADC_SAMPLE_144) | /* input18 - temperature and vbat input on some STM32F7xx */ -#endif - ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_144), /* input16 - temperature sensor input on STM32F4xx */ - // In this field must be specified the sample times for channels 0...9 - .smpr2 = - ADC_SMPR2_SMP_AN0(ADC_SAMPLING_SLOW) | - ADC_SMPR2_SMP_AN1(ADC_SAMPLING_SLOW) | - ADC_SMPR2_SMP_AN2(ADC_SAMPLING_SLOW) | - ADC_SMPR2_SMP_AN3(ADC_SAMPLING_SLOW) | - ADC_SMPR2_SMP_AN4(ADC_SAMPLING_SLOW) | - ADC_SMPR2_SMP_AN5(ADC_SAMPLING_SLOW) | - ADC_SMPR2_SMP_AN6(ADC_SAMPLING_SLOW) | - ADC_SMPR2_SMP_AN7(ADC_SAMPLING_SLOW) | - ADC_SMPR2_SMP_AN8(ADC_SAMPLING_SLOW) | - ADC_SMPR2_SMP_AN9(ADC_SAMPLING_SLOW), - .htr = 0, - .ltr = 0, - .sqr1 = 0, // Conversion group sequence 13...16 + sequence length - .sqr2 = 0, // Conversion group sequence 7...12 - .sqr3 = 0, // Conversion group sequence 1...6 -#if ADC_MAX_CHANNELS_COUNT > 16 - .sqr4 = 0, // Conversion group sequence 19...24 - .sqr5 = 0 // Conversion group sequence 25...30 -#endif /* ADC_MAX_CHANNELS_COUNT */ -}; - -AdcDevice slowAdc(&adcgrpcfgSlow, slowAdcSampleBuf, ARRAY_SIZE(slowAdcSampleBuf)); #if EFI_USE_FAST_ADC void adc_callback_fast(ADCDriver *adcp); @@ -271,11 +218,11 @@ int getInternalAdcValue(const char *msg, adc_channel_e hwChannel) { #endif // EFI_USE_FAST_ADC if (adcHwChannelEnabled[hwChannel] != ADC_SLOW) { - // todo: make this not happen during hardware continuous integration + // todo: make this not happen during hardware continuous integration warning(CUSTOM_OBD_WRONG_ADC_MODE, "ADC is off [%s] index=%d", msg, hwChannel); } - return slowAdc.getAdcValueByHwChannel(hwChannel); + return slowAdcSamples[hwChannel - 1]; } #if EFI_USE_FAST_ADC @@ -287,10 +234,6 @@ static GPTConfig fast_adc_config = { #endif /* EFI_USE_FAST_ADC */ adc_channel_mode_e getAdcMode(adc_channel_e hwChannel) { - if (slowAdc.isHwUsed(hwChannel)) { - return ADC_SLOW; - } - #if EFI_USE_FAST_ADC if (fastAdc.isHwUsed(hwChannel)) { return ADC_FAST; @@ -300,6 +243,8 @@ adc_channel_mode_e getAdcMode(adc_channel_e hwChannel) { return ADC_OFF; } +#if EFI_USE_FAST_ADC + int AdcDevice::size() const { return channelCount; } @@ -364,19 +309,25 @@ void AdcDevice::enableChannelAndPin(const char *msg, adc_channel_e hwChannel) { efiSetPadMode(msg, pin, PAL_MODE_INPUT_ANALOG); } +adc_channel_e AdcDevice::getAdcHardwareIndexByInternalIndex(int index) const { + return hardwareIndexByIndernalAdcIndex[index]; +} + +#endif // EFI_USE_FAST_ADC + static void printAdcValue(int channel) { int value = getAdcValue("print", (adc_channel_e)channel); float volts = adcToVoltsDivided(value); scheduleMsg(&logger, "adc voltage : %.2f", volts); } -adc_channel_e AdcDevice::getAdcHardwareIndexByInternalIndex(int index) const { - return hardwareIndexByIndernalAdcIndex[index]; -} + +static uint32_t slowAdcConversionCount = 0; +static uint32_t slowAdcErrorsCount = 0; static void printFullAdcReport(Logging *logger) { #if EFI_USE_FAST_ADC - scheduleMsg(logger, "fast %d slow %d", fastAdc.conversionCount, slowAdc.conversionCount); + scheduleMsg(logger, "fast %d slow %d", fastAdc.conversionCount, slowAdcConversionCount); for (int index = 0; index < fastAdc.size(); index++) { appendMsgPrefix(logger); @@ -399,16 +350,16 @@ static void printFullAdcReport(Logging *logger) { } #endif // EFI_USE_FAST_ADC - for (int index = 0; index < slowAdc.size(); index++) { + for (int index = 0; index < ADC_MAX_CHANNELS_COUNT; index++) { appendMsgPrefix(logger); - adc_channel_e hwIndex = slowAdc.getAdcHardwareIndexByInternalIndex(index); + adc_channel_e hwIndex = static_cast(index + EFI_ADC_0); if (isAdcChannelValid(hwIndex)) { ioportid_t port = getAdcChannelPort("print", hwIndex); int pin = getAdcChannelPin(hwIndex); - int adcValue = slowAdc.getAdcValueByIndex(index); + int adcValue = slowAdcSamples[index]; logger->appendPrintf(" S ch%d %s%d", index, portname(port), pin); logger->appendPrintf(" ADC%d 12bit=%d", hwIndex, adcValue); float volts = adcToVolts(adcValue); @@ -426,10 +377,6 @@ static void setAdcDebugReporting(int value) { } void waitForSlowAdc(int lastAdcCounter) { - // don't halt the firmware if there are no slow channels assigned - if (slowAdc.size() < 1) - return; - // we use slowAdcCounter instead of slowAdc.conversionCount because we need ADC_COMPLETE state // todo: use sync.objects? while (slowAdcCounter <= lastAdcCounter) { @@ -453,12 +400,9 @@ public: { ScopePerf perf(PE::AdcConversionSlow); - slowAdc.conversionCount++; - msg_t result = adcConvert(&ADC_SLOW_DEVICE, &adcgrpcfgSlow, slowAdc.samples, ADC_BUF_DEPTH_SLOW); - - // If something went wrong - try again later - if (result == MSG_RESET || result == MSG_TIMEOUT) { - slowAdc.errorsCount++; + slowAdcConversionCount++; + if (!readSlowAnalogInputs(slowAdcSamples)) { + slowAdcErrorsCount++; return; } @@ -474,15 +418,6 @@ public: { ScopePerf perf(PE::AdcProcessSlow); - /* Calculates the average values from the ADC samples.*/ - for (int i = 0; i < slowAdc.size(); i++) { - adcsample_t value = getAvgAdcValue(i, slowAdc.samples, ADC_BUF_DEPTH_SLOW, slowAdc.size()); - adcsample_t prev = slowAdc.values.adc_data[i]; - float result = (slowAdcCounter == 0) ? value : - CONFIG(slowAdcAlpha) * value + (1 - CONFIG(slowAdcAlpha)) * prev; - - slowAdc.values.adc_data[i] = (adcsample_t)result; - } slowAdcCounter++; AdcSubscription::UpdateSubscribers(nowNt); @@ -501,15 +436,16 @@ void addChannel(const char *name, adc_channel_e setting, adc_channel_mode_e mode adcHwChannelEnabled[setting] = mode; - AdcDevice* dev = &slowAdc; - #if EFI_USE_FAST_ADC if (mode == ADC_FAST) { - dev = &fastAdc; + fastAdc.enableChannelAndPin(name, setting); + return; } #endif - dev->enableChannelAndPin(name, setting); + // Slow ADC always samples all channels, simply set the input mode + brain_pin_e pin = getAdcChannelBrainPin(name, setting); + efiSetPadMode(name, pin, PAL_MODE_INPUT_ANALOG); } void removeChannel(const char *name, adc_channel_e setting) { @@ -533,7 +469,7 @@ static void configureInputs(void) { */ addChannel("MAP", engineConfiguration->map.sensor.hwChannel, ADC_FAST); - addChannel("MAF", engineConfiguration->mafAdcChannel, ADC_FAST); + addChannel("MAF", engineConfiguration->mafAdcChannel, ADC_SLOW); addChannel("HIP9011", engineConfiguration->hipOutputChannel, ADC_FAST); @@ -595,8 +531,6 @@ void initAdcInputs() { #if EFI_INTERNAL_ADC portInitAdc(); - slowAdc.init(); - // Start the slow ADC thread slowAdcController.Start(); diff --git a/firmware/hw_layer/ports/cypress/mpu_util.cpp b/firmware/hw_layer/ports/cypress/mpu_util.cpp index 3d83200b6f..78650fe145 100644 --- a/firmware/hw_layer/ports/cypress/mpu_util.cpp +++ b/firmware/hw_layer/ports/cypress/mpu_util.cpp @@ -270,4 +270,9 @@ float getMcuTemperature() { return 0; } +bool readSlowAnalogInputs(adcsample_t* convertedSamples) { + // TODO: implement me! + return true; +} + #endif /* EFI_PROD_CODE */ diff --git a/firmware/hw_layer/ports/kinetis/mpu_util.cpp b/firmware/hw_layer/ports/kinetis/mpu_util.cpp index a473465562..3be2a1a2c0 100644 --- a/firmware/hw_layer/ports/kinetis/mpu_util.cpp +++ b/firmware/hw_layer/ports/kinetis/mpu_util.cpp @@ -275,4 +275,9 @@ float getMcuTemperature() { return 0; } +bool readSlowAnalogInputs(adcsample_t* convertedSamples) { + // TODO: implement me! + return true; +} + #endif /* EFI_PROD_CODE */ diff --git a/firmware/hw_layer/ports/mpu_util.h b/firmware/hw_layer/ports/mpu_util.h index 4545852298..881ab7b1b2 100644 --- a/firmware/hw_layer/ports/mpu_util.h +++ b/firmware/hw_layer/ports/mpu_util.h @@ -11,9 +11,12 @@ void baseMCUInit(void); void jump_to_bootloader(); // ADC +#if HAL_USE_ADC void portInitAdc(); float getMcuTemperature(); - +// Convert all slow ADC inputs. Returns true if the conversion succeeded, false if a failure occured. +bool readSlowAnalogInputs(adcsample_t* convertedSamples); +#endif // CAN bus #if HAL_USE_CAN diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp index 6285be4cce..e08e43bfbb 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp @@ -13,6 +13,11 @@ EXTERN_CONFIG; +/* Depth of the conversion buffer, channels are sampled X times each.*/ +#ifndef ADC_BUF_DEPTH_SLOW +#define ADC_BUF_DEPTH_SLOW 8 +#endif /* ADC_BUF_DEPTH_SLOW */ + void portInitAdc() { // Init slow ADC adcStart(&ADCD1, NULL); @@ -101,4 +106,74 @@ float getMcuTemperature() { return degrees; } +// See https://github.com/rusefi/rusefi/issues/976 for discussion on these values +#define ADC_SAMPLING_SLOW ADC_SAMPLE_56 +#define ADC_SAMPLING_FAST ADC_SAMPLE_28 + +// Slow ADC has 16 channels we can sample +constexpr size_t slowChannelCount = 16; + +// Conversion group for slow channels +// This simply samples every channel in sequence +static constexpr ADCConversionGroup convGroupSlow = { + .circular = FALSE, + .num_channels = slowChannelCount, + .end_cb = nullptr, + .error_cb = nullptr, + /* HW dependent part.*/ + .cr1 = 0, + .cr2 = ADC_CR2_SWSTART, + // Configure all channels to ADC_SAMPLING_SLOW sample time + .smpr1 = + ADC_SMPR1_SMP_AN10(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN11(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN12(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN13(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN14(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN15(ADC_SAMPLING_SLOW), + .smpr2 = + ADC_SMPR2_SMP_AN0(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN1(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN2(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN3(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN4(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN5(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN6(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN7(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN8(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN9(ADC_SAMPLING_SLOW), + .htr = 0, + .ltr = 0, + // Simply sequence every channel in order + .sqr1 = ADC_SQR1_SQ13_N(12) | ADC_SQR1_SQ14_N(13) | ADC_SQR1_SQ15_N(14) | ADC_SQR1_SQ16_N(15) | ADC_SQR1_NUM_CH(16), // Conversion group sequence 13...16 + sequence length + .sqr2 = ADC_SQR2_SQ7_N(6) | ADC_SQR2_SQ8_N(7) | ADC_SQR2_SQ9_N(8) | ADC_SQR2_SQ10_N(8) | ADC_SQR2_SQ11_N(10) | ADC_SQR2_SQ12_N(11), // Conversion group sequence 7...12 + .sqr3 = ADC_SQR3_SQ1_N(0) | ADC_SQR3_SQ2_N(1) | ADC_SQR3_SQ3_N(2) | ADC_SQR3_SQ4_N(3) | ADC_SQR3_SQ5_N(4) | ADC_SQR3_SQ6_N(5), // Conversion group sequence 1...6 +}; + +static NO_CACHE adcsample_t slowSampleBuffer[ADC_BUF_DEPTH_SLOW * slowChannelCount]; + +bool readSlowAnalogInputs(adcsample_t* convertedSamples) { + msg_t result = adcConvert(&ADCD1, &convGroupSlow, slowSampleBuffer, ADC_BUF_DEPTH_SLOW); + + // If something went wrong - try again later + if (result == MSG_RESET || result == MSG_TIMEOUT) { + return false; + } + + // Average samples to get some noise filtering and oversampling + for (int i = 0; i < slowChannelCount; i++) { + uint32_t sum = 0; + size_t index = i; + for (size_t j = 0; j < ADC_BUF_DEPTH_SLOW; j++) { + sum += slowSampleBuffer[index]; + index += slowChannelCount; + } + + adcsample_t value = static_cast(sum / ADC_BUF_DEPTH_SLOW); + convertedSamples[i] = value; + } + + return true; +} + #endif // HAL_USE_ADC