From abb651374425c16420a09978b43a65cbea0ffc2f Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 10 Oct 2021 19:59:25 -0700 Subject: [PATCH] faster uniform adc cleanup (#3334) * dead fast tps * oooooh map avg on hh7 * adc v4 fast support * new fast API * hardware.cpp * adc v2 * warning * guard * no check required * stub cypress/kinetis * kinetis and cypress stubs * cleanup * h7 adc speed * adc skip * configurable oversample --- .../config/boards/hellen/hellen81/board.mk | 7 +-- firmware/hw_layer/hardware.cpp | 62 +++++-------------- .../hw_layer/ports/stm32/stm32_adc_v4.cpp | 31 ++++++++-- 3 files changed, 45 insertions(+), 55 deletions(-) diff --git a/firmware/config/boards/hellen/hellen81/board.mk b/firmware/config/boards/hellen/hellen81/board.mk index 8436c8714a..0460d49b98 100644 --- a/firmware/config/boards/hellen/hellen81/board.mk +++ b/firmware/config/boards/hellen/hellen81/board.mk @@ -37,12 +37,7 @@ DDEFS += -DEFI_LOGIC_ANALYZER=FALSE TRIGGER_USE_ADC = yes -# we need fast ADC for software trigger detector -#DDEFS += -DEFI_OVERRIDE_FAST_ADC_FOR_STM32H7=TRUE -DADC_FAST_DEVICE=ADCD1 -DADC_SLOW_DEVICE=ADCD3 -DSTM32_ADC_USE_ADC3=TRUE -#DDEFS += -DADC_SLOW_DEVICE=ADCD3 -DSTM32_ADC_USE_ADC3=TRUE - -DDEFS += -DEFI_OVERRIDE_FAST_ADC_FOR_STM32H7=TRUE -DADC_FAST_DEVICE=ADCD1 -DEFI_USE_ONLY_FAST_ADC=TRUE -DEFI_FASTER_UNIFORM_ADC=TRUE -DADC_MAX_CHANNELS_COUNT=16 -DADC_BUF_DEPTH_FAST=1 -DADC_BUF_NUM_AVG=1 -#DDEFS += -DADC_SLOW_DEVICE=ADCD1 +DDEFS += -DFAST_ADC_SKIP=3 -DH7_ADC_SPEED=20000 -DH7_ADC_OVERSAMPLE=2 # We are running on Hellen-One hardware! DDEFS += -DHW_HELLEN=1 diff --git a/firmware/hw_layer/hardware.cpp b/firmware/hw_layer/hardware.cpp index d9ae1bd0f3..4ba8dc55e3 100644 --- a/firmware/hw_layer/hardware.cpp +++ b/firmware/hw_layer/hardware.cpp @@ -148,53 +148,32 @@ static FastAdcToken triggerSampleIndex; extern AdcDevice fastAdc; -#if EFI_FASTER_UNIFORM_ADC -static int adcCallbackCounter = 0; -static volatile int averagedSamples[ADC_MAX_CHANNELS_COUNT]; -static adcsample_t avgBuf[ADC_MAX_CHANNELS_COUNT]; +#ifdef FAST_ADC_SKIP +// No reason to enable if N = 1 +static_assert(FAST_ADC_SKIP > 1); +static size_t fastAdcSkipCount = 0; +#endif // FAST_ADC_SKIP -void onFastAdcCompleteInternal(adcsample_t* samples); +/** + * This method is not in the adc* lower-level file because it is more business logic then hardware. + */ +void onFastAdcComplete(adcsample_t*) { + ScopePerf perf(PE::AdcCallbackFast); -void onFastAdcComplete(adcsample_t* samples) { #if HAL_TRIGGER_USE_ADC // we need to call this ASAP, because trigger processing is time-critical triggerAdcCallback(getFastAdc(triggerSampleIndex)); #endif /* HAL_TRIGGER_USE_ADC */ - // store the values for averaging - for (int i = fastAdc.size() - 1; i >= 0; i--) { - averagedSamples[i] += samples[i]; +#ifdef FAST_ADC_SKIP + // If we run the fast ADC _very_ fast for triggerAdcCallback's benefit, we may want to + // skip most of the samples for the rest of the callback. + if (fastAdcSkipCount++ == FAST_ADC_SKIP) { + fastAdcSkipCount = 0; + } else { + return; } - - // if it's time to process the data - if (++adcCallbackCounter >= ADC_BUF_NUM_AVG) { - // get an average - for (int i = fastAdc.size() - 1; i >= 0; i--) { - avgBuf[i] = (adcsample_t)(averagedSamples[i] / ADC_BUF_NUM_AVG); // todo: rounding? - } - - // call the real callback (see below) - onFastAdcCompleteInternal(samples); - - // reset the avg buffer & counter - for (int i = fastAdc.size() - 1; i >= 0; i--) { - averagedSamples[i] = 0; - } - adcCallbackCounter = 0; - } -} - -#endif /* EFI_FASTER_UNIFORM_ADC */ - -/** - * This method is not in the adc* lower-level file because it is more business logic then hardware. - */ -#if EFI_FASTER_UNIFORM_ADC -void onFastAdcCompleteInternal(adcsample_t*) { -#else -void onFastAdcComplete(adcsample_t*) { #endif - ScopePerf perf(PE::AdcCallbackFast); /** * this callback is executed 10 000 times a second, it needs to be as fast as possible @@ -237,13 +216,6 @@ static void adcConfigListener(Engine *engine) { } static void turnOnHardware(DECLARE_ENGINE_PARAMETER_SIGNATURE) { -#if EFI_FASTER_UNIFORM_ADC - for (int i = 0; i < ADC_MAX_CHANNELS_COUNT; i++) { - averagedSamples[i] = 0; - } - adcCallbackCounter = 0; -#endif /* EFI_FASTER_UNIFORM_ADC */ - #if EFI_PROD_CODE && EFI_SHAFT_POSITION_INPUT turnOnTriggerInputPins(PASS_ENGINE_PARAMETER_SIGNATURE); #endif /* EFI_SHAFT_POSITION_INPUT */ diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp index 6433c24d21..d726974d29 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp @@ -10,6 +10,29 @@ #include "mpu_util.h" #include "map_averaging.h" +#ifndef H7_ADC_SPEED +#define H7_ADC_SPEED (10000) +#endif + +#ifndef H7_ADC_OVERSAMPLE +#define H7_ADC_OVERSAMPLE (4) +#endif + +static_assert((H7_ADC_OVERSAMPLE & (H7_ADC_OVERSAMPLE - 1)) == 0, "H7_ADC_OVERSAMPLE must be a power of 2"); + +constexpr size_t log2_int(size_t x) { + size_t result = 0; + while (x >>= 1) result++; + return result; +} + +// poor man's unit test +static_assert(log2_int(4) == 2); +static_assert(log2_int(16) == 4); + +// Shift the result by log2(N) bits to divide by N +static constexpr int H7_ADC_SHIFT_BITS = log2_int(H7_ADC_OVERSAMPLE); + void portInitAdc() { // Init slow ADC adcStart(&ADCD1, NULL); @@ -50,8 +73,8 @@ static constexpr ADCConversionGroup convGroupSlow = { .end_cb = adc_callback, .error_cb = nullptr, .cfgr = ADC_CFGR_EXTEN_0 | (4 << ADC_CFGR_EXTSEL_Pos), // External trigger ch4, rising edge: TIM3 TRGO - .cfgr2 = 3 << ADC_CFGR2_OVSR_Pos | // Oversample by 4x (register contains N-1) - 2 << ADC_CFGR2_OVSS_Pos | // shift the result right 2 bits to make a 16 bit result out of the 18 bit internal sum (4x oversampled) + .cfgr2 = (H7_ADC_OVERSAMPLE - 1) << ADC_CFGR2_OVSR_Pos | // Oversample by Nx (register contains N-1) + H7_ADC_SHIFT_BITS << ADC_CFGR2_OVSS_Pos | // shift the result right log2(N) bits to make a 16 bit result out of the internal oversample sum ADC_CFGR2_ROVSE, // Enable oversampling .ccr = 0, .pcsel = 0xFFFFFFFF, // enable analog switches on all channels @@ -119,8 +142,8 @@ bool readSlowAnalogInputs(adcsample_t* convertedSamples) { adcStartConversionI(&ADCD1, &convGroupSlow, convertedSamples, 1); } - constexpr uint32_t samplingRate = 10000; - constexpr uint32_t timerCountFrequency = samplingRate * 100; + constexpr uint32_t samplingRate = H7_ADC_SPEED; + constexpr uint32_t timerCountFrequency = samplingRate * 10; constexpr uint32_t timerPeriod = timerCountFrequency / samplingRate; static constexpr GPTConfig gptCfg = {