From 047e4135df711b34737fa87b33322db5fc4d692d Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 2 Jan 2025 18:23:43 -0800 Subject: [PATCH 01/14] set up ADC dual mode --- .../hw_layer/ports/stm32/stm32_adc_v4.cpp | 87 +++++++++++++++---- .../ports/stm32/stm32h7/cfg/mcuconf.h | 2 +- 2 files changed, 72 insertions(+), 17 deletions(-) diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp index b279658522..ca8b87a491 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp @@ -71,8 +71,8 @@ static void adc_callback(ADCDriver *adcp) { // (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; +// Sample the 16 channels that line up with the STM32F4/F7, plus PF11/12/13/14 +constexpr size_t slowChannelCount = 20; // Conversion group for slow channels // This simply samples every channel in sequence @@ -89,8 +89,7 @@ static constexpr ADCConversionGroup convGroupSlow = { .pcsel = 0xFFFFFFFF, // enable analog switches on all channels // Thresholds aren't used .ltr1 = 0, .htr1 = 0, .ltr2 = 0, .htr2 = 0, .ltr3 = 0, .htr3 = 0, - .awd2cr = 0, - .awd3cr = 0, + .awd2cr = 0, .awd3cr = 0, .smpr = { // Configure all channels to use ADC_SAMPLING_SLOW time ADC_SMPR1_SMP_AN0(ADC_SAMPLING_SLOW) | @@ -115,27 +114,71 @@ static constexpr ADCConversionGroup convGroupSlow = { ADC_SMPR2_SMP_AN19(ADC_SAMPLING_SLOW) }, .sqr = { - // The seemingly insane values here exist to put the values - // in the buffer in the same order as the ADCv2 (F4/F7) ADC + // ADC1 samples the first 10 channels: PA0-5, PB0-1, PF11-12 ADC_SQR1_SQ1_N(16) | // PA0 (aka PA0_C) ADC_SQR1_SQ2_N(17) | // PA1 (aka PA1_C) ADC_SQR1_SQ3_N(14) | // PA2 ADC_SQR1_SQ4_N(15), // PA3 ADC_SQR2_SQ5_N(18) | // PA4 ADC_SQR2_SQ6_N(19) | // PA5 - ADC_SQR2_SQ7_N(3) | // PA6 - ADC_SQR2_SQ8_N(7) | // PA7 - ADC_SQR2_SQ9_N(9), // PB0 - ADC_SQR3_SQ10_N(5) | // PB1 - ADC_SQR3_SQ11_N(10) | // PC0 - ADC_SQR3_SQ12_N(11) | // PC1 - ADC_SQR3_SQ13_N(12) | // PC2 (aka PC2_C) - ADC_SQR3_SQ14_N(13), // PC3 (aka PC3_C) - ADC_SQR4_SQ15_N(4) | // PC4 - ADC_SQR4_SQ16_N(8) // PC5 + ADC_SQR2_SQ7_N(9) | // PB0 + ADC_SQR2_SQ8_N(5) | // PB1 + ADC_SQR2_SQ9_N(2), // PF11 + ADC_SQR3_SQ10_N(6), // PF12 + 0 + }, + + // Thresholds aren't used + .sltr1 = 0, .shtr1 = 0, .sltr2 = 0, .shtr2 = 0, .sltr3 = 0, .shtr3 = 0, + .sawd2cr = 0, .sawd3cr = 0, + .ssmpr = { + // Configure all channels to use ADC_SAMPLING_SLOW time + ADC_SMPR1_SMP_AN0(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN1(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN2(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN3(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN4(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN5(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN6(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN7(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN8(ADC_SAMPLING_SLOW) | + ADC_SMPR1_SMP_AN9(ADC_SAMPLING_SLOW), + ADC_SMPR2_SMP_AN10(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN11(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN12(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN13(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN14(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN15(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN16(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN17(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN18(ADC_SAMPLING_SLOW) | + ADC_SMPR2_SMP_AN19(ADC_SAMPLING_SLOW) + }, + .ssqr = { + // ADC2 samples the second 10 channels: PA6-7, PC0-5, PF11-14 + ADC_SQR1_SQ1_N(3) | // PA6 (aka PA0_C) + ADC_SQR1_SQ2_N(7) | // PA7 (aka PA1_C) + ADC_SQR1_SQ3_N(10) | // PC0 + ADC_SQR1_SQ4_N(11), // PC1 + ADC_SQR2_SQ5_N(12) | // PC2 + ADC_SQR2_SQ6_N(13) | // PC3 + ADC_SQR2_SQ7_N(4) | // PC4 + ADC_SQR2_SQ8_N(8) | // PC5 + ADC_SQR2_SQ9_N(2), // PF13 + ADC_SQR3_SQ10_N(6), // PF14 + 0 }, }; +static const uint8_t adcChannelScramble[20] = { + 0, 1, 2, 3, 4, 5, // ADC1: PA0-5 + 10, 11, // ADC2: PA6/7 + 6, 7, // ADC1: PB0/1 + 12, 13, 14, 15, 16, 17, // ADC2: PC0-5 + 8, 9, // ADC1: PF11/12 + 18, 19 // ADC2: PF13/14 +}; + static bool didStart = false; bool readSlowAnalogInputs(adcsample_t* convertedSamples) { @@ -251,6 +294,12 @@ static const ADCConversionGroup adcConvGroupCh1 = { 0, 0 }, + + // Dual mode isn't used on knock ADC, so all zeroes + .sltr1 = 0, .shtr1 = 0, .sltr2 = 0, .shtr2 = 0, .sltr3 = 0, .shtr3 = 0, + .sawd2cr = 0, .sawd3cr = 0, + .ssmpr = {0, 0}, + .ssqr = {0, 0, 0, 0}, }; // Not all boards have a second channel - configure it if it exists @@ -276,6 +325,12 @@ static const ADCConversionGroup adcConvGroupCh2 = { 0, 0 }, + + // Dual mode isn't used on knock ADC, so all zeroes + .sltr1 = 0, .shtr1 = 0, .sltr2 = 0, .shtr2 = 0, .sltr3 = 0, .shtr3 = 0, + .sawd2cr = 0, .sawd3cr = 0, + .ssmpr = {0, 0}, + .ssqr = {0, 0, 0, 0}, }; #endif // KNOCK_HAS_CH2 diff --git a/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h b/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h index 2231726750..739a27a3f8 100644 --- a/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h +++ b/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h @@ -251,7 +251,7 @@ /* * ADC driver system settings. */ -#define STM32_ADC_DUAL_MODE FALSE +#define STM32_ADC_DUAL_MODE TRUE #define STM32_ADC_COMPACT_SAMPLES FALSE #define STM32_ADC_USE_ADC12 TRUE From a52f57eeb04bfa633ea0a5a3c67c8d4a1ba09aff Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 2 Jan 2025 18:23:49 -0800 Subject: [PATCH 02/14] new pins --- firmware/hw_layer/ports/stm32/stm32_common.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/firmware/hw_layer/ports/stm32/stm32_common.cpp b/firmware/hw_layer/ports/stm32/stm32_common.cpp index fa12f9d738..5da03a32a0 100644 --- a/firmware/hw_layer/ports/stm32/stm32_common.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_common.cpp @@ -89,6 +89,16 @@ brain_pin_e getAdcChannelBrainPin(const char*, adc_channel_e hwChannel) { return Gpio::C4; case EFI_ADC_15: return Gpio::C5; +#ifdef STM32H7XX + case EFI_ADC_16: + return Gpio::F11; + case EFI_ADC_17: + return Gpio::F12; + case EFI_ADC_18: + return Gpio::F13; + case EFI_ADC_19: + return Gpio::F14; +#endif // STM32H7xx default: /* todo: what is upper range ADC is used while lower range ADC is not used? how do we still mark pin used? external muxes for internal ADC #3350 From 62fcece9bfc8d2a134990c36a95caf420d375fe2 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 2 Jan 2025 18:33:45 -0800 Subject: [PATCH 03/14] adc channel scrambler --- firmware/hw_layer/adc/adc_inputs.cpp | 4 ++-- firmware/hw_layer/adc/adc_subscription.cpp | 2 +- firmware/hw_layer/ports/mpu_util.h | 3 +++ firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp | 4 ++++ firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp | 4 ++++ 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/firmware/hw_layer/adc/adc_inputs.cpp b/firmware/hw_layer/adc/adc_inputs.cpp index 2f81834db8..a8c1f43f95 100644 --- a/firmware/hw_layer/adc/adc_inputs.cpp +++ b/firmware/hw_layer/adc/adc_inputs.cpp @@ -22,7 +22,7 @@ #include "pch.h" float __attribute__((weak)) getAnalogInputDividerCoefficient(adc_channel_e) { - return engineConfiguration->analogInputDividerCoefficient; + return engineConfiguration->analogInputDividerCoefficient; } #if HAL_USE_ADC @@ -109,7 +109,7 @@ int getInternalAdcValue(const char *msg, adc_channel_e hwChannel) { } #endif // EFI_USE_FAST_ADC - return slowAdcSamples[hwChannel - EFI_ADC_0]; + return slowAdcSamples[indexForSlowAdcChannel(hwChannel)]; } #if EFI_USE_FAST_ADC diff --git a/firmware/hw_layer/adc/adc_subscription.cpp b/firmware/hw_layer/adc/adc_subscription.cpp index 9d88f72489..9717715186 100644 --- a/firmware/hw_layer/adc/adc_subscription.cpp +++ b/firmware/hw_layer/adc/adc_subscription.cpp @@ -83,7 +83,7 @@ TODO: this code is similar to initIfValid, what is the plan? shall we extract he brain_pin_e pin = getAdcChannelBrainPin(name, channel); if (pin != Gpio::Invalid) { // todo: external muxes for internal ADC #3350 - efiSetPadMode(name, pin, PAL_MODE_INPUT_ANALOG); + efiSetPadMode(name, pin, PAL_MODE_INPUT_ANALOG); } // if 0, default to the board's divider coefficient for given channel diff --git a/firmware/hw_layer/ports/mpu_util.h b/firmware/hw_layer/ports/mpu_util.h index b89cadd42b..0fb106d897 100644 --- a/firmware/hw_layer/ports/mpu_util.h +++ b/firmware/hw_layer/ports/mpu_util.h @@ -25,6 +25,9 @@ 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); + +// Get the position of samples for this channel in the sample buffer +size_t indexForSlowAdcChannel(adc_channel_e channel); #endif // CAN bus diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp index 68de8cc234..da11ca93e3 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp @@ -211,6 +211,10 @@ bool readSlowAnalogInputs(adcsample_t* convertedSamples) { return result; } +size_t indexForSlowAdcChannel(adc_channel_e channel) { + return channel - EFI_ADC_0; +} + #if EFI_USE_FAST_ADC #include "AdcConfiguration.h" diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp index ca8b87a491..d9261e7978 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp @@ -179,6 +179,10 @@ static const uint8_t adcChannelScramble[20] = { 18, 19 // ADC2: PF13/14 }; +size_t indexForSlowAdcChannel(adc_channel_e channel) { + return adcChannelScramble[channel - EFI_ADC_0]; +} + static bool didStart = false; bool readSlowAnalogInputs(adcsample_t* convertedSamples) { From 2e35037a3a090eaaa810fbf962871690ef075077 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Tue, 4 Feb 2025 01:41:00 -0800 Subject: [PATCH 04/14] decode packed master/slave ADC readings --- firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp index 02a993834a..baea8e729e 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp @@ -207,13 +207,13 @@ static const uint8_t adcChannelScramble[20] = { 18, 19 // ADC2: PF13/14 }; -size_t indexForSlowAdcChannel(adc_channel_e channel) { +static size_t indexForSlowAdcChannel(adc_channel_e channel) { return adcChannelScramble[channel - EFI_ADC_0]; } static bool didStart = false; -static NO_CACHE adcsample_t adcSampleBuffer[SLOW_ADC_CHANNEL_COUNT]; +static NO_CACHE adcsample_t adcSampleBuffer[slowChannelCount]; bool readSlowAnalogInputs() { // This only needs to happen once, as the timer will continue firing the ADC and writing to the buffer without our help @@ -248,7 +248,14 @@ bool readSlowAnalogInputs() { } adcsample_t getSlowAdcSample(adc_channel_e channel) { - return adcSampleBuffer[channel - EFI_ADC_0]; + auto index = indexForSlowAdcChannel(channel); + + if (index >= 10) { + // Top half of channels were sampled by the slave ADC, therefore are in the upper half of the 32-bit word + return (adcSampleBuffer[index - 10] >> 16) & 0xFFFF; + } else { + return adcSampleBuffer[index] & 0xFFFF; + } } static constexpr FastAdcToken invalidToken = (FastAdcToken)(-1); From 6587aa718db48592bfe93a497958ca50f25b541e Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 22 Jan 2026 01:10:19 -0800 Subject: [PATCH 05/14] bump submodule --- firmware/ChibiOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/ChibiOS b/firmware/ChibiOS index 7077f35b0e..b94a2146a2 160000 --- a/firmware/ChibiOS +++ b/firmware/ChibiOS @@ -1 +1 @@ -Subproject commit 7077f35b0ef5c027a264572bbd311431907da189 +Subproject commit b94a2146a2802471ed520465b3ad6201a7e47572 From ac387a5eb5794771e34ff61e49cacebd5bfaaa05 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 22 Jan 2026 01:12:11 -0800 Subject: [PATCH 06/14] bump chibios again --- firmware/ChibiOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/ChibiOS b/firmware/ChibiOS index b94a2146a2..e2d1d8fffe 160000 --- a/firmware/ChibiOS +++ b/firmware/ChibiOS @@ -1 +1 @@ -Subproject commit b94a2146a2802471ed520465b3ad6201a7e47572 +Subproject commit e2d1d8fffeb6586347eda306c69bbd0b9d5a1f58 From a2f61922cc93add29103134bde038874fdfec250 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 22 Jan 2026 01:20:36 -0800 Subject: [PATCH 07/14] bump chibios --- firmware/ChibiOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/ChibiOS b/firmware/ChibiOS index e2d1d8fffe..cb6ccf3649 160000 --- a/firmware/ChibiOS +++ b/firmware/ChibiOS @@ -1 +1 @@ -Subproject commit e2d1d8fffeb6586347eda306c69bbd0b9d5a1f58 +Subproject commit cb6ccf3649156c10c0535ce4490636bad33c92a4 From 184b6dc97d751d92b2fe0da2766622f0a271aa69 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 22 Jan 2026 17:44:45 -0800 Subject: [PATCH 08/14] use a union to get out interleaved samples --- .../hw_layer/ports/stm32/stm32_adc_v4.cpp | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp index fd61ea974c..b42318251d 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp @@ -215,7 +215,13 @@ static size_t indexForSlowAdcChannel(adc_channel_e channel) { static bool didStart = false; -static NO_CACHE adcsample_t adcSampleBuffer[slowChannelCount]; +// In dual mode, each 32-bit DMA transfer contains two 16-bit samples: +// lower 16 bits from ADC1, upper 16 bits from ADC2. +// Use a union to provide both views of the buffer. +static NO_CACHE union { + adcsample_t samples32[slowChannelCount / 2]; // 32-bit view for HAL/DMA + uint16_t samples16[slowChannelCount]; // 16-bit view for reading +} sampleBuffer; bool readSlowAnalogInputs() { // This only needs to happen once, as the timer will continue firing the ADC and writing to the buffer without our help @@ -224,10 +230,13 @@ bool readSlowAnalogInputs() { } didStart = true; + setArrayValues(sampleBuffer.samples16, 0); + { chibios_rt::CriticalSectionLocker csl; // Oversampling and right-shift happen in hardware, so we can sample directly to the output buffer - adcStartConversionI(&ADCD1, &convGroupSlow, adcSampleBuffer, 1); + // Pass the 32-bit view to the HAL - it will receive slowChannelCount/2 32-bit samples in dual mode + adcStartConversionI(&ADCD1, &convGroupSlow, sampleBuffer.samples32, 1); } constexpr uint32_t samplingRate = H7_ADC_SPEED; @@ -252,11 +261,14 @@ bool readSlowAnalogInputs() { adcsample_t getSlowAdcSample(adc_channel_e channel) { auto index = indexForSlowAdcChannel(channel); + // In dual mode, the 16-bit samples are interleaved: ADC1, ADC2, ADC1, ADC2, ... + // The scramble table returns 0-9 for ADC1 channels and 10-19 for ADC2 channels. if (index >= 10) { - // Top half of channels were sampled by the slave ADC, therefore are in the upper half of the 32-bit word - return (adcSampleBuffer[index - 10] >> 16) & 0xFFFF; + // ADC2 channels: odd indices in the interleaved 16-bit array + return sampleBuffer.samples16[(index - 10) * 2 + 1]; } else { - return adcSampleBuffer[index] & 0xFFFF; + // ADC1 channels: even indices in the interleaved 16-bit array + return sampleBuffer.samples16[index * 2]; } } From 830c5dbcc5e1a9ce2ac426ad08112156db10cc43 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 22 Jan 2026 17:46:18 -0800 Subject: [PATCH 09/14] enable MR/5v sensors --- firmware/config/boards/atlas/board_configuration.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/config/boards/atlas/board_configuration.cpp b/firmware/config/boards/atlas/board_configuration.cpp index 2ef9f6a0b5..f73f26287c 100644 --- a/firmware/config/boards/atlas/board_configuration.cpp +++ b/firmware/config/boards/atlas/board_configuration.cpp @@ -196,19 +196,19 @@ void initBoardSensors() { mrSenseFunc.configure(0, 0, 1, mrSenseRatio, 0, 50); mrSenseSensor.setFunction(mrSenseFunc); AdcSubscription::SubscribeSensor(mrSenseSensor, EFI_ADC_16, /*bandwidth*/ 20, /*ratio*/ 1); - // mrSenseSensor.Register(); + mrSenseSensor.Register(); } { static LinearFunc sensor5vFunc; static FunctionalSensor sensor5vSensor(SensorType::Sensor5vVoltage, MS2NT(100)); - const float sensor5vRatio = 2;; + const float sensor5vRatio = 2; sensor5vFunc.configure(0, 0, 1, sensor5vRatio, 0, 50); sensor5vSensor.setFunction(sensor5vFunc); AdcSubscription::SubscribeSensor(sensor5vSensor, EFI_ADC_17, /*bandwidth*/ 20, /*ratio*/ 1); - // sensor5vSensor.Register(); + sensor5vSensor.Register(); } } #endif From c0e1e5a5e334d618150cff55486289515fc6769b Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 22 Jan 2026 17:47:03 -0800 Subject: [PATCH 10/14] bump ChibiOS (again) --- firmware/ChibiOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/ChibiOS b/firmware/ChibiOS index cb6ccf3649..bbe0c138e6 160000 --- a/firmware/ChibiOS +++ b/firmware/ChibiOS @@ -1 +1 @@ -Subproject commit cb6ccf3649156c10c0535ce4490636bad33c92a4 +Subproject commit bbe0c138e622001f38552758490cbecfaa8f0c5e From b1066c874ba3c9883ffbf3c0e6ea5412089bcf4b Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 22 Jan 2026 17:54:05 -0800 Subject: [PATCH 11/14] simplify scramble table --- .../hw_layer/ports/stm32/stm32_adc_v4.cpp | 39 +++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp index b42318251d..32246b86c0 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp @@ -200,19 +200,6 @@ static constexpr ADCConversionGroup convGroupSlow = { }, }; -static const uint8_t adcChannelScramble[20] = { - 0, 1, 2, 3, 4, 5, // ADC1: PA0-5 - 10, 11, // ADC2: PA6/7 - 6, 7, // ADC1: PB0/1 - 12, 13, 14, 15, 16, 17, // ADC2: PC0-5 - 8, 9, // ADC1: PF11/12 - 18, 19 // ADC2: PF13/14 -}; - -static size_t indexForSlowAdcChannel(adc_channel_e channel) { - return adcChannelScramble[channel - EFI_ADC_0]; -} - static bool didStart = false; // In dual mode, each 32-bit DMA transfer contains two 16-bit samples: @@ -259,17 +246,21 @@ bool readSlowAnalogInputs() { } adcsample_t getSlowAdcSample(adc_channel_e channel) { - auto index = indexForSlowAdcChannel(channel); - - // In dual mode, the 16-bit samples are interleaved: ADC1, ADC2, ADC1, ADC2, ... - // The scramble table returns 0-9 for ADC1 channels and 10-19 for ADC2 channels. - if (index >= 10) { - // ADC2 channels: odd indices in the interleaved 16-bit array - return sampleBuffer.samples16[(index - 10) * 2 + 1]; - } else { - // ADC1 channels: even indices in the interleaved 16-bit array - return sampleBuffer.samples16[index * 2]; - } + // Maps ADC channel to index in the interleaved 16-bit sample buffer. + // In dual mode, samples are interleaved: ADC1[0], ADC2[0], ADC1[1], ADC2[1], ... + // ADC1 channels (seq 0-9) map to even indices, ADC2 channels (seq 0-9) map to odd indices. + static const uint8_t descramble[20] = { + 0, 2, 4, 6, 8, 10, // ADC1: PA0-5 (seq 0-5 -> indices 0,2,4,6,8,10) + 1, 3, // ADC2: PA6/7 (seq 0-1 -> indices 1,3) + 12, 14, // ADC1: PB0/1 (seq 6-7 -> indices 12,14) + 5, 7, 9, 11, 13, 15, // ADC2: PC0-5 (seq 2-7 -> indices 5,7,9,11,13,15) + 16, 18, // ADC1: PF11/12 (seq 8-9 -> indices 16,18) + 17, 19 // ADC2: PF13/14 (seq 8-9 -> indices 17,19) + }; + + auto channelIndex = channel - EFI_ADC_0; + auto bufferPosition = descramble[channelIndex]; + return sampleBuffer.samples16[bufferPosition]; } static constexpr FastAdcToken invalidToken = (FastAdcToken)(-1); From 6c6317dd1b19791851f249e6b0b6e90fb748f744 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 22 Jan 2026 18:13:19 -0800 Subject: [PATCH 12/14] I think we've been accidentally overclocking the ADC all this time --- firmware/ChibiOS | 2 +- firmware/config/boards/atlas/knock_config.h | 2 +- firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp | 2 +- firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/ChibiOS b/firmware/ChibiOS index bbe0c138e6..7d899700cb 160000 --- a/firmware/ChibiOS +++ b/firmware/ChibiOS @@ -1 +1 @@ -Subproject commit bbe0c138e622001f38552758490cbecfaa8f0c5e +Subproject commit 7d899700cb960292d54afc125d436a56d4cdf74f diff --git a/firmware/config/boards/atlas/knock_config.h b/firmware/config/boards/atlas/knock_config.h index 2a7f705e8f..03c0aed959 100644 --- a/firmware/config/boards/atlas/knock_config.h +++ b/firmware/config/boards/atlas/knock_config.h @@ -22,5 +22,5 @@ #define KNOCK_SAMPLE_RATE (STM32_ADC3_CLOCK / (H7_KNOCK_OVERSAMPLE * (32 + 8))) static_assert(KNOCK_SAMPLE_RATE == 250000); -static_assert(STM32_ADCCLK == 80000000); +static_assert(STM32_ADCCLK == 40000000); static_assert(STM32_ADC3_CLOCK == 40000000); diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp index 32246b86c0..054d5fd4a5 100644 --- a/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v4.cpp @@ -14,7 +14,7 @@ #include "mpu_util.h" -// Both ADCs should be running at 25MHz +// All ADCs should be running at 40MHz static_assert(STM32_ADC12_CLOCK == 40000000); static_assert(STM32_ADC3_CLOCK == 40000000); diff --git a/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h b/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h index dfafb69ec4..3abccf8143 100644 --- a/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h +++ b/firmware/hw_layer/ports/stm32/stm32h7/cfg/mcuconf.h @@ -127,7 +127,7 @@ #define STM32_PLL3_FRACN_VALUE 0 #define STM32_PLL3_DIVP_VALUE 2 #define STM32_PLL3_DIVQ_VALUE 20 -#define STM32_PLL3_DIVR_VALUE 12 +#define STM32_PLL3_DIVR_VALUE 24 /* * Core clocks dynamic settings (can be changed at runtime). From 7dc6d4a0f0226f1c2504823890e8db8642701705 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 22 Jan 2026 22:29:48 -0800 Subject: [PATCH 13/14] proteus H7 knock adc assertions --- firmware/config/boards/proteus/knock_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/config/boards/proteus/knock_config.h b/firmware/config/boards/proteus/knock_config.h index c7b5085cb8..f6891f8917 100644 --- a/firmware/config/boards/proteus/knock_config.h +++ b/firmware/config/boards/proteus/knock_config.h @@ -25,7 +25,7 @@ #define KNOCK_SAMPLE_RATE (STM32_ADC3_CLOCK / (H7_KNOCK_OVERSAMPLE * (32 + 8))) static_assert(KNOCK_SAMPLE_RATE == 250000); - static_assert(STM32_ADCCLK == 80000000); + static_assert(STM32_ADCCLK == 40000000); static_assert(STM32_ADC3_CLOCK == 40000000); #else From 568d8d0df9d51998a0c818b92b9e4f4e411eaef7 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 22 Jan 2026 22:46:06 -0800 Subject: [PATCH 14/14] add vboost sensor --- .../config/boards/atlas/board_configuration.cpp | 13 +++++++++++++ firmware/controllers/sensors/sensor_type.h | 1 + 2 files changed, 14 insertions(+) diff --git a/firmware/config/boards/atlas/board_configuration.cpp b/firmware/config/boards/atlas/board_configuration.cpp index f73f26287c..3225279092 100644 --- a/firmware/config/boards/atlas/board_configuration.cpp +++ b/firmware/config/boards/atlas/board_configuration.cpp @@ -210,5 +210,18 @@ void initBoardSensors() { AdcSubscription::SubscribeSensor(sensor5vSensor, EFI_ADC_17, /*bandwidth*/ 20, /*ratio*/ 1); sensor5vSensor.Register(); } + + { + static LinearFunc vboostFunc; + static FunctionalSensor vboostSensor(SensorType::VboostVoltage, MS2NT(100)); + + // 82k high side/10k low side = 9.2 + const float vboostRatio = (92.0f / 10.0f); + + vboostFunc.configure(0, 0, 1, vboostRatio, 0, 50); + vboostSensor.setFunction(vboostFunc); + AdcSubscription::SubscribeSensor(vboostSensor, EFI_ADC_18, /*bandwidth*/ 20, /*ratio*/ 1); + vboostSensor.Register(); + } } #endif diff --git a/firmware/controllers/sensors/sensor_type.h b/firmware/controllers/sensors/sensor_type.h index 84f8f438e9..5d004449c6 100644 --- a/firmware/controllers/sensors/sensor_type.h +++ b/firmware/controllers/sensors/sensor_type.h @@ -74,6 +74,7 @@ enum class SensorType : unsigned char { BatteryVoltage, MainRelayVoltage, Sensor5vVoltage, + VboostVoltage, BarometricPressure,