From 31ffb0add48356833fda835541e55b456bd93006 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 7 Oct 2021 05:29:01 -0700 Subject: [PATCH] Fast adc API (#3327) * 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 --- firmware/config/stm32h7ems/efifeatures.h | 3 -- firmware/hw_layer/adc/adc_inputs.h | 15 ++++--- firmware/hw_layer/hardware.cpp | 39 +++++++------------ firmware/hw_layer/ports/cypress/mpu_util.cpp | 20 ++++++++++ firmware/hw_layer/ports/kinetis/mpu_util.cpp | 20 ++++++++++ .../hw_layer/ports/stm32/stm32_adc_v2.cpp | 26 +++++++++++++ .../hw_layer/ports/stm32/stm32_adc_v4.cpp | 33 +++++++++++++++- 7 files changed, 120 insertions(+), 36 deletions(-) diff --git a/firmware/config/stm32h7ems/efifeatures.h b/firmware/config/stm32h7ems/efifeatures.h index 6cce5e0e20..4bd948b4d3 100644 --- a/firmware/config/stm32h7ems/efifeatures.h +++ b/firmware/config/stm32h7ems/efifeatures.h @@ -2,9 +2,6 @@ #pragma once -#undef EFI_MAP_AVERAGING -#define EFI_MAP_AVERAGING FALSE - #undef EFI_USE_FAST_ADC // https://github.com/rusefi/rusefi/issues/3301 "H7 is currently actually using fast ADC exclusively - it just needs a bit of plumbing to make it work." #define EFI_USE_FAST_ADC FALSE diff --git a/firmware/hw_layer/adc/adc_inputs.h b/firmware/hw_layer/adc/adc_inputs.h index 53c08c4da8..ac684dded4 100644 --- a/firmware/hw_layer/adc/adc_inputs.h +++ b/firmware/hw_layer/adc/adc_inputs.h @@ -62,11 +62,14 @@ void removeChannel(const char *name, adc_channel_e setting); #define adcToVoltsDivided(adc) (adcToVolts(adc) * engineConfiguration->analogInputDividerCoefficient) -#endif /* HAL_USE_ADC */ - -void printFullAdcReport(void); - -#if HAL_USE_ADC // This callback is called by the ADC driver when a new fast ADC sample is ready void onFastAdcComplete(adcsample_t* samples); -#endif + + +using FastAdcToken = size_t; + +FastAdcToken enableFastAdcChannel(const char* msg, adc_channel_e channel); +adcsample_t getFastAdc(FastAdcToken token); +#endif // HAL_USE_ADC + +void printFullAdcReport(void); diff --git a/firmware/hw_layer/hardware.cpp b/firmware/hw_layer/hardware.cpp index e4c6459ef6..d9ae1bd0f3 100644 --- a/firmware/hw_layer/hardware.cpp +++ b/firmware/hw_layer/hardware.cpp @@ -137,17 +137,15 @@ SPIDriver * getSpiDevice(spi_device_e spiDevice) { } #endif -#define TPS_IS_SLOW -1 +#if HAL_USE_ADC -static int fastMapSampleIndex; -static int hipSampleIndex; -static int tpsSampleIndex; +static FastAdcToken fastMapSampleIndex; +static FastAdcToken hipSampleIndex; #if HAL_TRIGGER_USE_ADC -static int triggerSampleIndex; +static FastAdcToken triggerSampleIndex; #endif -#if HAL_USE_ADC extern AdcDevice fastAdc; #if EFI_FASTER_UNIFORM_ADC @@ -160,8 +158,7 @@ void onFastAdcCompleteInternal(adcsample_t* samples); void onFastAdcComplete(adcsample_t* samples) { #if HAL_TRIGGER_USE_ADC // we need to call this ASAP, because trigger processing is time-critical - if (triggerSampleIndex >= 0) - triggerAdcCallback(samples[triggerSampleIndex]); + triggerAdcCallback(getFastAdc(triggerSampleIndex)); #endif /* HAL_TRIGGER_USE_ADC */ // store the values for averaging @@ -193,9 +190,9 @@ void onFastAdcComplete(adcsample_t* samples) { * 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* buffer) { +void onFastAdcCompleteInternal(adcsample_t*) { #else -void onFastAdcComplete(adcsample_t* buffer) { +void onFastAdcComplete(adcsample_t*) { #endif ScopePerf perf(PE::AdcCallbackFast); @@ -212,32 +209,22 @@ void onFastAdcComplete(adcsample_t* buffer) { #endif /* EFI_SENSOR_CHART */ #if EFI_MAP_AVERAGING - mapAveragingAdcCallback(buffer[fastMapSampleIndex]); + mapAveragingAdcCallback(getFastAdc(fastMapSampleIndex)); #endif /* EFI_MAP_AVERAGING */ #if EFI_HIP_9011 if (CONFIG(isHip9011Enabled)) { - hipAdcCallback(buffer[hipSampleIndex]); + hipAdcCallback(getFastAdc(hipSampleIndex)); } #endif /* EFI_HIP_9011 */ -// if (tpsSampleIndex != TPS_IS_SLOW) { -// tpsFastAdc = buffer[tpsSampleIndex]; -// } } #endif /* HAL_USE_ADC */ static void calcFastAdcIndexes(void) { -#if HAL_USE_ADC && EFI_USE_FAST_ADC - fastMapSampleIndex = fastAdc.internalAdcIndexByHardwareIndex[engineConfiguration->map.sensor.hwChannel]; - hipSampleIndex = - isAdcChannelValid(engineConfiguration->hipOutputChannel) ? - fastAdc.internalAdcIndexByHardwareIndex[engineConfiguration->hipOutputChannel] : -1; - tpsSampleIndex = - isAdcChannelValid(engineConfiguration->tps1_1AdcChannel) ? - fastAdc.internalAdcIndexByHardwareIndex[engineConfiguration->tps1_1AdcChannel] : TPS_IS_SLOW; +#if HAL_USE_ADC + fastMapSampleIndex = enableFastAdcChannel("Fast MAP", engineConfiguration->map.sensor.hwChannel); + hipSampleIndex = enableFastAdcChannel("HIP9011", engineConfiguration->hipOutputChannel); #if HAL_TRIGGER_USE_ADC - adc_channel_e triggerChannel = getAdcChannelForTrigger(); - triggerSampleIndex = isAdcChannelValid(triggerChannel) ? - fastAdc.internalAdcIndexByHardwareIndex[triggerChannel] : -1; + triggerSampleIndex = enableFastAdcChannel("Trigger ADC", getAdcChannelForTrigger()); #endif /* HAL_TRIGGER_USE_ADC */ #endif/* HAL_USE_ADC */ diff --git a/firmware/hw_layer/ports/cypress/mpu_util.cpp b/firmware/hw_layer/ports/cypress/mpu_util.cpp index b56d4cfc1d..300e790462 100644 --- a/firmware/hw_layer/ports/cypress/mpu_util.cpp +++ b/firmware/hw_layer/ports/cypress/mpu_util.cpp @@ -275,4 +275,24 @@ bool readSlowAnalogInputs(adcsample_t* convertedSamples) { return true; } +static constexpr FastAdcToken invalidToken = (FastAdcToken)(-1); + +FastAdcToken enableFastAdcChannel(const char*, adc_channel_e channel) { + if (!isAdcChannelValid(channel)) { + return invalidToken; + } + + // TODO: implement me! + return invalidToken; +} + +adcsample_t getFastAdc(FastAdcToken token) { + if (token == invalidToken) { + return 0; + } + + // TODO: implement me! + return 0; +} + #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 73c4ce16be..ceb05539a2 100644 --- a/firmware/hw_layer/ports/kinetis/mpu_util.cpp +++ b/firmware/hw_layer/ports/kinetis/mpu_util.cpp @@ -280,4 +280,24 @@ bool readSlowAnalogInputs(adcsample_t* convertedSamples) { return true; } +static constexpr FastAdcToken invalidToken = (FastAdcToken)(-1); + +FastAdcToken enableFastAdcChannel(const char*, adc_channel_e channel) { + if (!isAdcChannelValid(channel)) { + return invalidToken; + } + + // TODO: implement me! + return invalidToken; +} + +adcsample_t getFastAdc(FastAdcToken token) { + if (token == invalidToken) { + return 0; + } + + // TODO: implement me! + return 0; +} + #endif /* EFI_PROD_CODE */ diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp index d6b4cd7449..0ec1ca94a7 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp @@ -174,4 +174,30 @@ bool readSlowAnalogInputs(adcsample_t* convertedSamples) { return true; } +#if EFI_USE_FAST_ADC + +#include "AdcConfiguration.h" + +extern AdcDevice fastAdc; + +static constexpr FastAdcToken invalidToken = (FastAdcToken)(-1); + +FastAdcToken enableFastAdcChannel(const char*, adc_channel_e channel) { + if (!isAdcChannelValid(channel)) { + return invalidToken; + } + + return fastAdc.internalAdcIndexByHardwareIndex[static_cast(channel)]; +} + +adcsample_t getFastAdc(FastAdcToken token) { + if (token == invalidToken) { + return 0; + } + + return fastAdc.samples[token]; +} + +#endif + #endif // HAL_USE_ADC diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp index 91f3d0e3b9..6433c24d21 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp @@ -8,6 +8,7 @@ #include "pch.h" #include "mpu_util.h" +#include "map_averaging.h" void portInitAdc() { // Init slow ADC @@ -23,6 +24,15 @@ float getMcuTemperature() { return 0; } +adcsample_t* fastSampleBuffer; + +static void adc_callback(ADCDriver *adcp) { + // State may not be complete if we get a callback for "half done" + if (adcp->state == ADC_COMPLETE) { + onFastAdcComplete(adcp->samples); + } +} + // ADC Clock is 25MHz // 16.5 sampling + 8.5 conversion = 25 cycles per sample total // 16 channels * 4x oversample = 64 samples per batch @@ -37,7 +47,7 @@ constexpr size_t slowChannelCount = 16; static constexpr ADCConversionGroup convGroupSlow = { .circular = true, // Continuous mode means we will auto re-trigger on every timer event .num_channels = slowChannelCount, - .end_cb = nullptr, + .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) @@ -101,6 +111,8 @@ bool readSlowAnalogInputs(adcsample_t* convertedSamples) { } didStart = true; + fastSampleBuffer = convertedSamples; + { chibios_rt::CriticalSectionLocker csl; // Oversampling and right-shift happen in hardware, so we can sample directly to the output buffer @@ -125,3 +137,22 @@ bool readSlowAnalogInputs(adcsample_t* convertedSamples) { // Return true if OK return true; } + +static constexpr FastAdcToken invalidToken = (FastAdcToken)(-1); + +FastAdcToken enableFastAdcChannel(const char*, adc_channel_e channel) { + if (!isAdcChannelValid(channel)) { + return invalidToken; + } + + // H7 always samples all fast channels, nothing to do here but compute index + return channel - EFI_ADC_0; +} + +adcsample_t getFastAdc(FastAdcToken token) { + if (token == invalidToken) { + return 0; + } + + return fastSampleBuffer[token]; +}