feat(firmware): blink on-board WS2812 alongside GPIO 2

The DevKitC-1 has no discrete LED on GPIO 2, so the Spike 1 blink was
invisible without external wiring. Drive the on-board addressable LED
(WS2812 on GPIO 48) each cycle for visible confirmation on the bench.
This commit is contained in:
Julien Calixte
2026-07-04 16:46:53 +02:00
parent 6d573b3b6d
commit e040a8d4b7

View File

@@ -1,6 +1,14 @@
use std::time::Duration;
use esp_idf_svc::hal::delay::FreeRtos;
use esp_idf_svc::hal::gpio::PinDriver;
use esp_idf_svc::hal::peripherals::Peripherals;
use esp_idf_svc::hal::rmt::config::{TransmitConfig, TxChannelConfig};
use esp_idf_svc::hal::rmt::encoder::CopyEncoder;
use esp_idf_svc::hal::rmt::{PinState, Symbol, TxChannelDriver};
use esp_idf_svc::hal::units::Hertz;
const WS2812_RESOLUTION: Hertz = Hertz(10_000_000);
fn main() -> anyhow::Result<()> {
// Required once before any esp-idf-svc call; some runtime patches
@@ -11,16 +19,59 @@ fn main() -> anyhow::Result<()> {
let peripherals = Peripherals::take()?;
let mut led = PinDriver::output(peripherals.pins.gpio2)?;
log::info!("Typoena Spike 1 — Blink on GPIO 2");
// On-board addressable LED (WS2812) — GPIO 48 on the DevKitC-1 v1.0;
// v1.1 boards moved it to GPIO 38.
let mut rgb = TxChannelDriver::new(
peripherals.pins.gpio48,
&TxChannelConfig {
resolution: WS2812_RESOLUTION,
..Default::default()
},
)?;
log::info!("Typoena Spike 1 — Blink on GPIO 2 + on-board WS2812 (GPIO 48)");
let mut n: u32 = 0;
loop {
led.set_high()?;
ws2812_set(&mut rgb, 4, 0, 24)?; // dim green
log::info!("blink {n}");
n = n.wrapping_add(1);
FreeRtos::delay_ms(500);
led.set_low()?;
ws2812_set(&mut rgb, 0, 0, 0)?;
FreeRtos::delay_ms(500);
}
}
/// Send one WS2812 GRB frame. The ≥50 µs low reset the LED needs between
/// frames is covered by the 500 ms idle gap between calls.
fn ws2812_set(tx: &mut TxChannelDriver, r: u8, g: u8, b: u8) -> anyhow::Result<()> {
// Bit timings from the WS2812 datasheet.
let zero = Symbol::new_with(
WS2812_RESOLUTION,
PinState::High,
Duration::from_nanos(350),
PinState::Low,
Duration::from_nanos(800),
)?;
let one = Symbol::new_with(
WS2812_RESOLUTION,
PinState::High,
Duration::from_nanos(700),
PinState::Low,
Duration::from_nanos(600),
)?;
let mut symbols = [zero; 24];
for (i, byte) in [g, r, b].into_iter().enumerate() {
for bit in 0..8 {
if byte & (0x80 >> bit) != 0 {
symbols[i * 8 + bit] = one;
}
}
}
tx.send_and_wait(CopyEncoder::new()?, &symbols, &TransmitConfig::default())?;
Ok(())
}