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
This commit is contained in:
parent
3d7aa1eeb7
commit
abb6513744
|
@ -37,12 +37,7 @@ DDEFS += -DEFI_LOGIC_ANALYZER=FALSE
|
||||||
|
|
||||||
TRIGGER_USE_ADC = yes
|
TRIGGER_USE_ADC = yes
|
||||||
|
|
||||||
# we need fast ADC for software trigger detector
|
DDEFS += -DFAST_ADC_SKIP=3 -DH7_ADC_SPEED=20000 -DH7_ADC_OVERSAMPLE=2
|
||||||
#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
|
|
||||||
|
|
||||||
# We are running on Hellen-One hardware!
|
# We are running on Hellen-One hardware!
|
||||||
DDEFS += -DHW_HELLEN=1
|
DDEFS += -DHW_HELLEN=1
|
||||||
|
|
|
@ -148,53 +148,32 @@ static FastAdcToken triggerSampleIndex;
|
||||||
|
|
||||||
extern AdcDevice fastAdc;
|
extern AdcDevice fastAdc;
|
||||||
|
|
||||||
#if EFI_FASTER_UNIFORM_ADC
|
#ifdef FAST_ADC_SKIP
|
||||||
static int adcCallbackCounter = 0;
|
// No reason to enable if N = 1
|
||||||
static volatile int averagedSamples[ADC_MAX_CHANNELS_COUNT];
|
static_assert(FAST_ADC_SKIP > 1);
|
||||||
static adcsample_t avgBuf[ADC_MAX_CHANNELS_COUNT];
|
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
|
#if HAL_TRIGGER_USE_ADC
|
||||||
// we need to call this ASAP, because trigger processing is time-critical
|
// we need to call this ASAP, because trigger processing is time-critical
|
||||||
triggerAdcCallback(getFastAdc(triggerSampleIndex));
|
triggerAdcCallback(getFastAdc(triggerSampleIndex));
|
||||||
#endif /* HAL_TRIGGER_USE_ADC */
|
#endif /* HAL_TRIGGER_USE_ADC */
|
||||||
|
|
||||||
// store the values for averaging
|
#ifdef FAST_ADC_SKIP
|
||||||
for (int i = fastAdc.size() - 1; i >= 0; i--) {
|
// If we run the fast ADC _very_ fast for triggerAdcCallback's benefit, we may want to
|
||||||
averagedSamples[i] += samples[i];
|
// 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
|
#endif
|
||||||
ScopePerf perf(PE::AdcCallbackFast);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this callback is executed 10 000 times a second, it needs to be as fast as possible
|
* 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) {
|
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
|
#if EFI_PROD_CODE && EFI_SHAFT_POSITION_INPUT
|
||||||
turnOnTriggerInputPins(PASS_ENGINE_PARAMETER_SIGNATURE);
|
turnOnTriggerInputPins(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
#endif /* EFI_SHAFT_POSITION_INPUT */
|
#endif /* EFI_SHAFT_POSITION_INPUT */
|
||||||
|
|
|
@ -10,6 +10,29 @@
|
||||||
#include "mpu_util.h"
|
#include "mpu_util.h"
|
||||||
#include "map_averaging.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() {
|
void portInitAdc() {
|
||||||
// Init slow ADC
|
// Init slow ADC
|
||||||
adcStart(&ADCD1, NULL);
|
adcStart(&ADCD1, NULL);
|
||||||
|
@ -50,8 +73,8 @@ static constexpr ADCConversionGroup convGroupSlow = {
|
||||||
.end_cb = adc_callback,
|
.end_cb = adc_callback,
|
||||||
.error_cb = nullptr,
|
.error_cb = nullptr,
|
||||||
.cfgr = ADC_CFGR_EXTEN_0 | (4 << ADC_CFGR_EXTSEL_Pos), // External trigger ch4, rising edge: TIM3 TRGO
|
.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)
|
.cfgr2 = (H7_ADC_OVERSAMPLE - 1) << ADC_CFGR2_OVSR_Pos | // Oversample by Nx (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)
|
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
|
ADC_CFGR2_ROVSE, // Enable oversampling
|
||||||
.ccr = 0,
|
.ccr = 0,
|
||||||
.pcsel = 0xFFFFFFFF, // enable analog switches on all channels
|
.pcsel = 0xFFFFFFFF, // enable analog switches on all channels
|
||||||
|
@ -119,8 +142,8 @@ bool readSlowAnalogInputs(adcsample_t* convertedSamples) {
|
||||||
adcStartConversionI(&ADCD1, &convGroupSlow, convertedSamples, 1);
|
adcStartConversionI(&ADCD1, &convGroupSlow, convertedSamples, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint32_t samplingRate = 10000;
|
constexpr uint32_t samplingRate = H7_ADC_SPEED;
|
||||||
constexpr uint32_t timerCountFrequency = samplingRate * 100;
|
constexpr uint32_t timerCountFrequency = samplingRate * 10;
|
||||||
constexpr uint32_t timerPeriod = timerCountFrequency / samplingRate;
|
constexpr uint32_t timerPeriod = timerCountFrequency / samplingRate;
|
||||||
|
|
||||||
static constexpr GPTConfig gptCfg = {
|
static constexpr GPTConfig gptCfg = {
|
||||||
|
|
Loading…
Reference in New Issue