From 55aea7a46bd652c69a3695d83d8aba83ddadfd2d Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 3 Apr 2026 13:15:41 +0200 Subject: [PATCH] =?UTF-8?q?feat(01-01):=20LED=20driver=20=E2=80=94=20dual?= =?UTF-8?q?=20strip=20initialization=20and=20output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - led_driver.h declares StripWand (NeoGrbwFeature/RMT) + StripSchrank (NeoWs2801Spi2MhzMethod) - led_driver.cpp implements initStrips, showBothStrips, setAllWand/Schrank, applyBrightness helpers - showBothStrips calls stripWand.Show() first (non-blocking DMA) then stripSchrank.Show() (blocking SPI) - Brightness clamped to [0.0f, BRIGHTNESS_MAX] before scaling --- firmware/src/led_driver.cpp | 59 +++++++++++++++++++++++++++++++++++++ firmware/src/led_driver.h | 18 +++++++++++ 2 files changed, 77 insertions(+) create mode 100644 firmware/src/led_driver.cpp create mode 100644 firmware/src/led_driver.h diff --git a/firmware/src/led_driver.cpp b/firmware/src/led_driver.cpp new file mode 100644 index 0000000..6cc8a9b --- /dev/null +++ b/firmware/src/led_driver.cpp @@ -0,0 +1,59 @@ +#include "led_driver.h" +#include +#include + +// Strip object definitions +// StripWand: SK6812 RGBW via RMT (DMA, non-blocking transfer) +StripWand stripWand(LED_COUNT_WAND, PIN_SK6812); +// StripSchrank: WS2801 RGB via hardware SPI at 2MHz (no pin arg — uses hardware SPI pins) +StripSchrank stripSchrank(LED_COUNT_SCHRANK); + +void initStrips() { + stripWand.Begin(); + stripSchrank.Begin(); + + // Clear both strips to off on startup + stripWand.ClearTo(RgbwColor(0, 0, 0, 0)); + stripSchrank.ClearTo(RgbColor(0, 0, 0)); + + showBothStrips(); + + Serial.println("LED driver: Wand 300 RGBW (SK6812 RMT), Schrank 160 RGB (WS2801 SPI 2MHz)"); +} + +void showBothStrips() { + // RMT DMA runs concurrently; both strips finish in ~10ms window + stripWand.Show(); // Start non-blocking DMA transfer first + stripSchrank.Show(); // Blocks ~4ms (480 bytes at 2MHz); RMT DMA runs in parallel +} + +RgbwColor applyBrightnessW(RgbwColor c, float factor) { + // Clamp factor to [0.0f, BRIGHTNESS_MAX] before scaling + factor = std::max(0.0f, std::min(factor, BRIGHTNESS_MAX)); + return RgbwColor( + static_cast(c.R * factor), + static_cast(c.G * factor), + static_cast(c.B * factor), + static_cast(c.W * factor) + ); +} + +RgbColor applyBrightnessR(RgbColor c, float factor) { + // Clamp factor to [0.0f, BRIGHTNESS_MAX] before scaling + factor = std::max(0.0f, std::min(factor, BRIGHTNESS_MAX)); + return RgbColor( + static_cast(c.R * factor), + static_cast(c.G * factor), + static_cast(c.B * factor) + ); +} + +void setAllWand(RgbwColor color) { + // NeoPixelBus ClearTo fills the entire strip with the given color + stripWand.ClearTo(color); +} + +void setAllSchrank(RgbColor color) { + // NeoPixelBus ClearTo fills the entire strip with the given color + stripSchrank.ClearTo(color); +} diff --git a/firmware/src/led_driver.h b/firmware/src/led_driver.h new file mode 100644 index 0000000..88e2840 --- /dev/null +++ b/firmware/src/led_driver.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include "config.h" + +// SK6812: RGBW (4 bytes/LED) — MUST use NeoGrbwFeature, never NeoRgbFeature +using StripWand = NeoPixelBus; +// WS2801: RGB (3 bytes/LED), 2MHz SPI for cable-safe 5m run +using StripSchrank = NeoPixelBus; + +extern StripWand stripWand; +extern StripSchrank stripSchrank; + +void initStrips(); +void showBothStrips(); +void setAllWand(RgbwColor color); +void setAllSchrank(RgbColor color); +RgbwColor applyBrightnessW(RgbwColor c, float factor); +RgbColor applyBrightnessR(RgbColor c, float factor);