LuxLibre

LuxLibre › Firmware › Ports › ESP32-C3 port

ESP32-C3 port (experimental)

LuxLibre on the Espressif ESP32-C3, written for ESP-IDF 5.x and the FlashKa keychain boards: v0.5 (../../boards/flashka-keychain-v05/board.h) with one button, v0.6 (../../boards/flashka-keychain-v06/board.h) with three buttons on a resistor ladder, of which LuxLibre uses the main one (below), and v0.7 (../../boards/flashka-keychain-v07/board.h): the v0.6 pins and ladder with a stronger LED driver (3552 mA at full duty; LuxLibre’s level 150 is 2850 mA, so the LED never gets more than its 3.0 A rating) and one 14500 Li-ion cell (Vapcell F15, 1500 mAh).

Status: experimental. The port is written against the ESP-IDF 5.x API and has been checked against declarations of that API; the GitHub workflow builds it for every FlashKa board in the espressif/idf container once the repository is published, as a job that may fail until it has passed once. It has not been compiled with ESP-IDF itself or run on a FlashKa yet. The resistor-ladder path for v0.6 is untested on hardware as well; check it with the ladder bring-up below. Until the port has passed the bring-up tests (docs/testing.md), the original FlashKa firmware (written in Rust, with the Bluetooth app and deep sleep, on v0.6 also the presenter mode) stays the reference firmware for that light: hardware/flashka-keychain-v05/, hardware/flashka-keychain-v06/ (its firmware also builds the v0.7 image, firmware 0.7.0).

Build and flash

Install ESP-IDF 5.x (Espressif’s guide), then:

cd firmware/ports/esp32c3
idf.py set-target esp32c3
idf.py -DLX_BOARD=flashka-keychain-v05 build     # or flashka-keychain-v06, flashka-keychain-v07, edco-v01
idf.py -p <serial port> flash monitor

LX_BOARD selects the folder under firmware/boards/. When you switch boards, run idf.py fullclean first, or give each board its own build directory with -B. The console (help, status, set, …) runs over the chip’s built-in USB serial/JTAG interface, so idf.py monitor or any serial terminal reaches it.

What the port uses

Function ESP32-C3 resource
Main LED LEDC PWM, 13 bit, 9.77 kHz, filtered into the current set point of the FlashKa’s buck driver; LED_EN switches the driver off at level 0
Indicator three LEDC channels for the common-anode RGB LED (v0.6: the two RGB LEDs of the light ring, in parallel on the same pins)
Button v0.5: GPIO3, digital, low = pressed, internal pull-up on. v0.6: a resistor ladder read with ADC1 on GPIO3, wake-up on GPIO9 (below)
Laser a GPIO behind the hardware slide-switch interlock (S2)
Battery voltage ADC1 channel 0 (cell / 2) with the curve-fitting calibration
Temperature ADC1 channel 1, 100 kΩ NTC (B 4250) with 100 kΩ to 3.3 V, table from lx_ntc.h
Charger TP4057 status pins; the charge-set pin selects normal current (low), 10 mA trickle (floating) or off (high). The board has no VBUS sense pin, so while charging is off the pin is floated for 100 ms every 5 s to see whether USB is plugged in, only while the cell temperature allows charging (CHG-3)
Sleep light sleep with wake-up on the button (GPIO; on v0.6 GPIO9) and a timer; while charging is allowed, also on the charger status pins, so that plugging in USB wakes the light and charging starts (to verify on hardware: no leakage from the pull-ups into the unpowered charger)
Storage one 256-byte NVS blob, written only when it changes; the RAM copy is updated only after a successful write
Watchdog task watchdog, 3 s, with panic reset; brown-out detector on (sdkconfig.defaults)
Tick FreeRTOS vTaskDelayUntil, 10 ms (CONFIG_FREERTOS_HZ=1000)

Resistor-ladder buttons (FlashKa v0.6)

A resistor ladder puts several buttons on one pin. On the v0.6 board the net BTN has a 10 kΩ pull-up (R9) to 3.3 V; the main button connects BTN straight to ground, next through 1 kΩ and previous through 2.2 kΩ, so every press gives its own voltage. BTN goes to two pins: GPIO3 measures it with the ADC, GPIO9 reads it as a digital input.

Pressed BTN LuxLibre
nothing 3.30 V released
main (alone or with any other) 0 V pressed
previous + next together 0.212 V released (ignored)
next 0.300 V released (ignored)
previous 0.595 V released (ignored)

LuxLibre’s user interface has one button (FW-3). The slide buttons belong to the original FlashKa firmware (level steps, and the presenter mode: a Bluetooth keyboard that turns slides), which LuxLibre does not have. How the port handles the ladder:

How another board declares a ladder: docs/firmware/porting.md.

Bring-up checks for the ladder

None of this has run on a board yet. On the first v0.6 board, before relying on the port:

  1. With the firmware running, measure BTN against GND for each button: 3.30 V, 0 V, 0.212 V, 0.300 V and 0.595 V (within about 10 mV with 1 % resistors, as in the bring-up plan of the FlashKa firmware). Higher readings mean an internal pull-up is still on.
  2. The main button: every gesture of user-interface.md from off, from on and in lockout.
  3. Next, previous and both together: nothing happens, from off (asleep) and while the light is on.
  4. Hold next and click main: the click counts. Hold next for more than 10 s, then hold main for 3 s: the light reacts.
  5. Standby current asleep, and with a slide button held (BAT-6); the ladder alone then draws about 0.3 mA (3.3 V across R9 plus R30 or R31: 11 kΩ or 12.2 kΩ).
  6. Plugging in USB while the light is asleep still starts charging.

Known limitations