From f70c844c600e1cdd268634a7a0d1b7b5f3ed09c8 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Fri, 23 Jul 2021 11:50:35 -0700 Subject: [PATCH] H7 ADC triggered by hardware timer (#3028) * config * allow changing adc speed * timer triggered ADC * ICU on nucleo * turn that off too * 10khz * make those default for all h7 * I can't type --- firmware/config/stm32h7ems/efifeatures.h | 15 ++++++ firmware/hw_layer/adc/adc_inputs.h | 2 + .../hw_layer/ports/stm32/stm32_adc_v4.cpp | 48 ++++++++++++++----- .../ports/stm32/stm32h7/cfg/halconf.h | 2 +- .../ports/stm32/stm32h7/cfg/mcuconf.h | 8 ++-- 5 files changed, 59 insertions(+), 16 deletions(-) diff --git a/firmware/config/stm32h7ems/efifeatures.h b/firmware/config/stm32h7ems/efifeatures.h index 386a9ecf3f..3b8d2e6633 100644 --- a/firmware/config/stm32h7ems/efifeatures.h +++ b/firmware/config/stm32h7ems/efifeatures.h @@ -34,3 +34,18 @@ #undef ENABLE_PERF_TRACE #define ENABLE_PERF_TRACE TRUE + +// H7 runs faster "slow" ADC to make up for reduced oversampling +#define SLOW_ADC_RATE 1000 + +#undef EFI_ICU_INPUTS +#define EFI_ICU_INPUTS FALSE + +#undef HAL_TRIGGER_USE_PAL +#define HAL_TRIGGER_USE_PAL TRUE + +#undef EFI_LOGIC_ANALYZER +#define EFI_LOGIC_ANALYZER FALSE + +#undef HAL_VSS_USE_PAL +#define HAL_VSS_USE_PAL TRUE diff --git a/firmware/hw_layer/adc/adc_inputs.h b/firmware/hw_layer/adc/adc_inputs.h index b3a35f58ef..efbd1b694b 100644 --- a/firmware/hw_layer/adc/adc_inputs.h +++ b/firmware/hw_layer/adc/adc_inputs.h @@ -11,7 +11,9 @@ #include "global.h" #include "adc_math.h" +#ifndef SLOW_ADC_RATE #define SLOW_ADC_RATE 500 +#endif static inline bool isAdcChannelValid(adc_channel_e hwChannel) { if (hwChannel <= EFI_ADC_NONE) { diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp index a8fc5d9731..d5abf6477e 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp @@ -25,10 +25,10 @@ float getMcuTemperature() { } // ADC Clock is 25MHz -// 32.5 sampling + 8.5 conversion = 41 cycles per sample total -// 16 channels * 16x oversample = 256 samples per batch -// (41 * 256) / 25MHz -> 419 microseconds to sample all channels -#define ADC_SAMPLING_SLOW ADC_SMPR_SMP_32P5 +// 16.5 sampling + 8.5 conversion = 25 cycles per sample total +// 16 channels * 4x oversample = 64 samples per batch +// (25 * 64) / 25MHz -> 64 microseconds to sample all channels +#define ADC_SAMPLING_SLOW ADC_SMPR_SMP_16P5 // Sample the 16 channels that line up with the STM32F4/F7 constexpr size_t slowChannelCount = 16; @@ -36,13 +36,13 @@ constexpr size_t slowChannelCount = 16; // Conversion group for slow channels // This simply samples every channel in sequence static constexpr ADCConversionGroup convGroupSlow = { - .circular = FALSE, + .circular = true, // Continuous mode means we will auto re-trigger on every timer event .num_channels = slowChannelCount, .end_cb = nullptr, .error_cb = nullptr, - .cfgr = 0, - .cfgr2 = 15 << ADC_CFGR2_OVSR_Pos | // Oversample by 16x (register contains N-1) - 4 << ADC_CFGR2_OVSS_Pos | // shift the result right 4 bits to make a 16 bit result + .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) ADC_CFGR2_ROVSE, // Enable oversampling .ccr = 0, .pcsel = 0xFFFFFFFF, // enable analog switches on all channels @@ -93,10 +93,36 @@ static constexpr ADCConversionGroup convGroupSlow = { }, }; +static bool didStart = false; + bool readSlowAnalogInputs(adcsample_t* convertedSamples) { - // Oversampling and right-shift happen in hardware, so we can sample directly to the output buffer - msg_t result = adcConvert(&ADCD1, &convGroupSlow, convertedSamples, 1); + // This only needs to happen once, as the timer will continue firing the ADC and writing to the buffer without our help + if (didStart) { + return true; + } + didStart = true; + + { + chibios_rt::CriticalSectionLocker csl; + // Oversampling and right-shift happen in hardware, so we can sample directly to the output buffer + adcStartConversionI(&ADCD1, &convGroupSlow, convertedSamples, 1); + } + + constexpr uint32_t samplingRate = 10000; + constexpr uint32_t timerCountFrequency = samplingRate * 100; + constexpr uint32_t timerPeriod = timerCountFrequency / samplingRate; + + static constexpr GPTConfig gptCfg = { + timerCountFrequency, + nullptr, + TIM_CR2_MMS_1, // TRGO on update event + 0 + }; + + // Start timer + gptStart(&GPTD3, &gptCfg); + gptStartContinuous(&GPTD3, timerPeriod); // Return true if OK - return result == MSG_OK; + return true; } diff --git a/firmware/hw_layer/ports/stm32/stm32h7/cfg/halconf.h b/firmware/hw_layer/ports/stm32/stm32h7/cfg/halconf.h index 2fdd5bc873..916824442f 100644 --- a/firmware/hw_layer/ports/stm32/stm32h7/cfg/halconf.h +++ b/firmware/hw_layer/ports/stm32/stm32h7/cfg/halconf.h @@ -67,7 +67,7 @@ * @brief Enables the ICU subsystem. */ #if !defined(HAL_USE_ICU) || defined(__DOXYGEN__) -#define HAL_USE_ICU TRUE +#define HAL_USE_ICU FALSE #endif /** diff --git a/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h b/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h index 547dca90b2..b484e49595 100644 --- a/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h +++ b/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h @@ -264,7 +264,7 @@ */ #define STM32_GPT_USE_TIM1 FALSE #define STM32_GPT_USE_TIM2 FALSE -#define STM32_GPT_USE_TIM3 FALSE +#define STM32_GPT_USE_TIM3 TRUE #define STM32_GPT_USE_TIM4 FALSE #define STM32_GPT_USE_TIM5 FALSE #define STM32_GPT_USE_TIM6 TRUE @@ -306,9 +306,9 @@ /* * ICU driver system settings. */ -#define STM32_ICU_USE_TIM1 TRUE -#define STM32_ICU_USE_TIM2 TRUE -#define STM32_ICU_USE_TIM3 TRUE +#define STM32_ICU_USE_TIM1 FALSE +#define STM32_ICU_USE_TIM2 FALSE +#define STM32_ICU_USE_TIM3 FALSE #define STM32_ICU_USE_TIM4 FALSE #define STM32_ICU_USE_TIM5 FALSE #define STM32_ICU_USE_TIM8 FALSE