From c32d208854edfeb76b0e9351c57a0a9f9dbda3d1 Mon Sep 17 00:00:00 2001 From: "Adrian A. Baumann" Date: Sun, 17 May 2026 18:00:19 +0200 Subject: [PATCH] Single colour LEDs, I think, will be removed anyway --- .../Gaugecontroller_no_VFD.ino | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/Gaugecontroller_no_VFD/Gaugecontroller_no_VFD.ino b/Gaugecontroller_no_VFD/Gaugecontroller_no_VFD.ino index 1196bcf..62fae2e 100644 --- a/Gaugecontroller_no_VFD/Gaugecontroller_no_VFD.ino +++ b/Gaugecontroller_no_VFD/Gaugecontroller_no_VFD.ino @@ -7,9 +7,9 @@ static const uint8_t GAUGE_COUNT = 5; // Backlight/status LEDs use an addressable strip. Indicator LEDs are -// single-colour active-high outputs on per-gauge pins. The command protocol +// single-colour active-high PWM outputs on per-gauge pins. The command protocol // still exposes one logical LED segment per gauge. -static const uint8_t LED_DATA_PIN = 22; +static const uint8_t LED_DATA_PIN = A8; static const uint8_t BREATHE_FRAME_MS = 16; static const uint8_t LED_SHOW_MIN_INTERVAL_MS = 16; static const uint8_t LED_SHOW_MOTION_INTERVAL_MS = 50; @@ -161,6 +161,9 @@ uint8_t ledLocalIdx[TOTAL_LEDS]; bool ledIsIndicator[TOTAL_LEDS]; bool ledRgSwap[TOTAL_LEDS]; BlinkState blinkState[TOTAL_LEDS]; +volatile uint8_t indicatorPwmLevel[TOTAL_INDICATOR_LEDS]; +volatile uint8_t* indicatorPwmPort[TOTAL_INDICATOR_LEDS]; +uint8_t indicatorPwmMask[TOTAL_INDICATOR_LEDS]; bool mainLedsDirty = false; unsigned long lastLedShowMs = 0; @@ -185,18 +188,16 @@ inline int8_t indicatorPinFor(uint8_t gaugeIdx, uint8_t localIdx) { return -1; } -inline bool indicatorIsOn(uint8_t localIdx, CRGB color) { - if (localIdx == 3) return color.r >= 128; - if (localIdx == 4) return color.g >= 128; - return false; +inline uint8_t indicatorLevel(uint8_t localIdx, CRGB color) { + if (localIdx == 3) return color.r; + if (localIdx == 4) return color.g; + return 0; } inline void writeIndicatorLed(uint8_t globalIdx, CRGB color) { - uint8_t gaugeIdx = ledGaugeIdx[globalIdx]; - uint8_t localIdx = ledLocalIdx[globalIdx]; - int8_t pin = indicatorPinFor(gaugeIdx, localIdx); - if (pin >= 0) { - digitalWrite(pin, indicatorIsOn(localIdx, color) ? HIGH : LOW); + uint8_t pwmIdx = ledPhysicalIdx[globalIdx]; + if (pwmIdx < TOTAL_INDICATOR_LEDS) { + indicatorPwmLevel[pwmIdx] = indicatorLevel(ledLocalIdx[globalIdx], color); } } @@ -480,7 +481,29 @@ void setupStepperTimer() { SREG = oldSreg; } +inline void updateIndicatorPwmIsr() { + static uint8_t phase = 0; + phase++; + + for (uint8_t i = 0; i < TOTAL_INDICATOR_LEDS; i++) { + volatile uint8_t* port = indicatorPwmPort[i]; + if (port == nullptr) continue; + + uint8_t mask = indicatorPwmMask[i]; + uint8_t level = indicatorPwmLevel[i]; + if (level == 0) { + *port &= ~mask; + } else if (level == 255 || phase < level) { + *port |= mask; + } else { + *port &= ~mask; + } + } +} + ISR(TIMER1_COMPA_vect) { + updateIndicatorPwmIsr(); + for (uint8_t i = 0; i < GAUGE_COUNT; i++) { StepperRuntime& s = steppers[i]; bool pulseJustEnded = false; @@ -1219,6 +1242,7 @@ void setup() { // offsets for the addressable main strip. uint8_t ledOff = 0; uint8_t mainLedOff = 0; + uint8_t indicatorLedOff = 0; for (uint8_t i = 0; i < GAUGE_COUNT; i++) { gaugeLedCount[i] = cstrLen(gaugePins[i].ledOrder); gaugeLedOffset[i] = ledOff; @@ -1232,9 +1256,17 @@ void setup() { ledIsIndicator[globalIdx] = indicator; ledRgSwap[globalIdx] = gaugePins[i].ledOrder[localIdx] == 'G' || gaugePins[i].ledOrder[localIdx] == 'g'; - ledPhysicalIdx[globalIdx] = indicator - ? 0 - : mainLedOff + localIdx - (localIdx > 4 ? 2 : 0); + if (indicator) { + ledPhysicalIdx[globalIdx] = indicatorLedOff; + int8_t pin = indicatorPinFor(i, localIdx); + if (pin >= 0) { + indicatorPwmPort[indicatorLedOff] = portOutputRegister(digitalPinToPort(pin)); + indicatorPwmMask[indicatorLedOff] = digitalPinToBitMask(pin); + } + indicatorLedOff++; + } else { + ledPhysicalIdx[globalIdx] = mainLedOff + localIdx - (localIdx > 4 ? 2 : 0); + } } ledOff += gaugeLedCount[i];