
Hdmilight v3
esar/hdmilight-v3
HDMI Light v3 - FPGA based Ambilight clone with direct HDMI input

STM32F411CEU6 and ICM-20948 v2 self-balancing cube firmware port and integration plan.
BALANCING CUBEV1.01 is an open-source printed circuit board by Evc-r, from the Evc-r/Balancing-Cube-STM32 repository on GitHub. It is a 4-layer board of 120 × 103.9 mm with 76 parts on 73 nets, routed with 325 tracks and 55 vias.
It is built around the R-78E5.0-0.5, MMBT3904 and BSS84, with the SMBJ13CA and SUD50P04-08-VB among its other parts. Its parts include 36 resistors, 14 capacitors, 9 transistors, 8 connectors and 4 diodes.
Firmware and integration work for a three-axis reaction-wheel balancing cube based on the open-source remrc/Self-Balancing-Cube project.
This version replaces the original ESP32 and MPU6050 with:
[!WARNING] This project contains high-speed reaction wheels and a LiPo battery. Incorrect PWM polarity, wiring, firmware, or mechanical assembly can cause an unexpected full-power motor start. Read the safety section and complete every diagnostic stage before enabling closed-loop balancing.
Current phase: transitioning into firmware development and software integration. CAD and the first custom PCB design are complete; electrical bring-up and balancing validation remain ahead.
| Area | Current progress |
|---|---|
| Mechanical design / CAD | Complete for the current build |
| Mechanical assembly | Frame and reaction-wheel assembly completed; final wiring/integration remains |
| Custom four-layer PCB | First design complete and sent for fabrication; known issues require rework and validation |
| STM32 connection | Header spacing mismatch identified; plan to connect the board through wires |
| IMU connection | J7 connector unavailable; plan to solder the IMU wiring directly |
| Firmware | Next active development phase: STM32 project setup, peripheral bring-up, and integration |
| Closed-loop balancing | Not yet demonstrated or validated |
These are open integration tasks, not completed fixes. The first PCB revision should not be treated as a validated design for replication.
See JOURNAL.md for retrospective CAD/PCB notes and future session logs, and PROJECT_PLAN.md for the planned architecture and acceptance criteria.
The repository currently contains project documentation, not a buildable firmware release. CAD, KiCad source files, manufacturing outputs, photos, and firmware still need to be added here. The existing project media folder is linked for reference.
Earlier CAD/PCB work is documented retrospectively without reconstructed work hours. Future sessions should record what changed, evidence, test results, and actual tracked time.
The original Arduino/ESP32 sketch cannot be compiled unchanged for this hardware. Several subsystems are fundamentally different:
| Original design | This design |
|---|---|
| ESP32 Arduino | STM32CubeIDE and STM32 HAL |
| MPU6050 raw accelerometer/gyro | ICM-20948 v2 raw accelerometer/gyro with STM32 attitude estimation |
| Original complementary filter | STM32 complementary/Mahony filter using calibrated ICM-20948 data |
| GPIO encoder interrupts | STM32 hardware timer encoder mode |
| ESP32 LEDC PWM | STM32 timer PWM |
| EEPROM API | Versioned internal Flash record with CRC |
| BluetoothSerial | USB CDC or UART initially |
15 ms millis() loop | Deterministic 200 Hz hardware-timed loop |
The original three-wheel coordinate transformations and controller concept remain useful, but controller gains, timing, calibration, drivers, and safety behavior must be implemented and tested again.
ICM-20948 v2 breakout and STM32 breakout boards vary. Confirm from the actual boards and schematics:
Do not assume that a module accepting 5 V power also has 5 V-safe signal pins.
The architecture, interfaces, safety behavior, and timing values below are implementation targets. Firmware bring-up, execution timing, and successful balancing have not been verified.
ICM-20948 v2 interrupt
-> SPI or I2C transfer
-> register/FIFO driver and sample validation
-> calibrated accelerometer and gyro sample
-> STM32 attitude estimator
-> latest timestamped quaternion and angular rate
200 Hz control timer
-> validate IMU freshness
-> read three encoder counters
-> calculate quaternion balance error
-> determine vertex, edge, fallen, or fault state
-> run state-feedback controller
-> mix X/Y/Z corrections into three wheel commands
-> update PWM, direction, and brake
Background processing
-> command interface and telemetry
-> calibration workflow
-> Flash parameter storage
-> battery monitoring
-> diagnostics and fault reportingSerial output, Flash writes, and blocking IMU transfers must never run inside the control interrupt.
A 25 MHz external crystal is assumed for the selected board and still needs confirmation; it is not the intended CPU speed. The STM32F411 will be configured through its PLL for a target system clock of 100 MHz.
Initial timing targets:
| Function | Target |
|---|---|
| ICM-20948 accelerometer and gyro sampling | 500 Hz initially |
| STM32 attitude estimator | 500 Hz initially |
| Balance controller | 200 Hz initially |
| Motor PWM | 20 kHz |
| Maximum accepted IMU age | 15 ms initially |
The final CubeMX clock tree must also produce a valid peripheral clock if USB CDC is enabled.
The ICM-20948 is a 9-axis IMU containing a 3-axis gyroscope, 3-axis accelerometer, AK09916 3-axis magnetometer, FIFO, programmable filters, and an embedded DMP. It supports SPI up to 7 MHz or I2C up to 400 kHz. The initial controller will read raw accelerometer and gyroscope data and perform attitude estimation on the STM32.
Initial sensing strategy:
SPI is preferred for deterministic high-rate acquisition. I2C is acceptable for initial testing if the breakout exposes it more conveniently. Connect and use the data-ready interrupt. Every accepted sample must be timestamped locally, checked for plausibility, and monitored for staleness.
The exact v2 breakout must be inspected for its regulator, level shifting, pull-ups, address selection, and exposed interrupt/chip-select pins. The bare ICM-20948 has lower VDDIO limits than the STM32's 3.3 V logic, so compatibility depends on the breakout circuitry.
All sensor measurements must be transformed into a documented mechanical cube frame before they reach the controller.
The mapping will be bench-tested so that positive physical rotation around cube X, Y, and Z produces positive cube-frame gyro X, Y, and Z respectively. Axis swaps and sign changes will be centralized in one module rather than distributed through the controller.
The wheel numbering, positive rotation direction, encoder sign, and cube-frame force direction will also be documented before closed-loop testing.
The MPU6050 offset procedure will be replaced with two layers: stationary accelerometer/gyro calibration, followed by quaternion reference calibration for the mechanical vertex and edge poses.
The firmware will store:
At runtime the orientation error is calculated from:
q_error = inverse(q_reference) * q_currentCalibration will only be accepted when IMU data is fresh, sensor accuracy is acceptable, gyro magnitude is low, and the pose remains stable for a defined interval.
Planned commands:
cal vertex
cal edge
cal status
saveAn absent, corrupt, or incompatible calibration record must prevent balancing.
The controller will retain the reference project's general state-feedback structure while using explicit units:
wheel command =
angle gain * angle error
+ gyro gain * angular velocity
+ wheel velocity gain * wheel velocity
+ wheel position gain * accumulated wheel positionYaw damping uses vertical-axis gyro and combined wheel motion.
The reference three-wheel transformation will be ported and verified against the actual wheel layout:
m1 = (0.5*x - 0.866*y) / 1.37 + z
m2 = (0.5*x + 0.866*y) / 1.37 + z
m3 = -x / 1.37 + zOriginal numeric gains will not be copied blindly. The new firmware uses different units, sample timing, sensor latency, encoder scaling, and motor-command scaling.
Planned tools:
The repository will eventually contain the complete CubeIDE project and generated configuration needed for a clean build.
Core/Inc/ Public module headers
Core/Src/ Application and driver implementation
Drivers/ STM32 HAL and device support
Docs/ Wiring, coordinate frames, calibration, and tuning
Tests/ Host-side and hardware test support
JOURNAL.md Retrospective hardware notes and future session logs
PROJECT_PLAN.md Detailed engineering plan
README.md Project overview and bring-up guideDo not skip ahead to balance tuning. Each stage is a gate for the next.
The reference Nidec interface uses active-low PWM. Treat that as a hypothesis to verify electrically, not an assumption.
Only after vertex balance is reliable:
Initial transport will be UART or USB CDC. Planned commands include:
help
status
faults
imu
encoders
battery
motor <1|2|3> <command>
motor stop
brake <on|off>
cal vertex
cal edge
cal status
save
set <parameter> <value>
get <parameter>
telemetry <on|off>Manual motor commands will only work in a diagnostic state with the balance controller disabled.
The firmware must disable motor output if any of these conditions occurs:
Physical precautions:
Host-side tests are planned for:
Runtime telemetry will include:
Version v0.1.0 will require:
Edge balancing may ship in a later release if it is not reliable enough for v0.1.0.
Until the first hardware bring-up is complete, interface definitions, pin assignments, and controller parameters should be considered provisional.
When making changes:
This project is derived from and inspired by Remigijus's Self-Balancing-Cube. The original repository established the mechanical concept, Nidec motor interface, wheel mixing, balance-control structure, and practical build approach.
This repository is an independent STM32F411/ICM-20948 v2 port and will require new firmware, calibration, validation, and gain tuning.
No license has been selected yet. Until a license file is added, normal copyright restrictions apply to original work in this repository. Any reused or adapted material must continue to comply with its original licensing terms.
| Qty | Value | Footprint | References |
|---|---|---|---|
| 10 | 10 KiloOhm | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R2, R4, R8, R15, R18, R20, R23, R27, R28, R29 |
| 9 | 100 KiloOhm | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R5, R7, R11, R12, R14, R19, R24, R35, R36 |
| 5 | 1 KiloOhm | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R3, R26, R32, R33, R34 |
| 5 | 4.7 KiloOhm | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R6, R10, R13, R30, R31 |
| 5 | MMBT3904 | Package_TO_SOT_SMD:SOT-23 | Q1, Q3, Q4, Q6, Q8 |
| 4 | 100nF 25V | Capacitor_SMD:C_0805_2012Metric_Pad1.18x1.45mm_HandSolder | C3, C7, C9, C11 |
| 3 | 22 KiloOhm | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R9, R16, R21 |
| 3 | 220 Ohm | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R1, R17, R22 |
| 3 | 220 uF 25V | Capacitor_THT:CP_Radial_D8.0mm_P3.50mm | C6, C8, C10 |
| 3 | BSS84 | Package_TO_SOT_SMD:SOT-23 | Q2, Q5, Q7 |
| 3 | MountingHole_3.2mm_M3 | MountingHole:MountingHole_3.2mm_M3 | H1, H2, H3 |
| 2 | 100 nF | Capacitor_SMD:C_0805_2012Metric_Pad1.18x1.45mm_HandSolder | C12, C14 |
| 2 | 10uF 25V | Capacitor_SMD:C_1210_3225Metric_Pad1.33x2.70mm_HandSolder | C2, C4 |
| 2 | LED | LED_THT:LED_D3.0mm | D2, D3 |
| 1 | 10 uF | Capacitor_SMD:C_1210_3225Metric_Pad1.33x2.70mm_HandSolder | C13 |
| 1 | 1000uF 25V | Capacitor_THT:CP_Radial_D12.5mm_P5.00mm | C1 |
| 1 | 1N4148 | Diode_SMD:D_SOD-123 | D4 |
| 1 | 22uF 10V | Capacitor_SMD:C_1210_3225Metric_Pad1.33x2.70mm_HandSolder | C5 |
| 1 | 27 KiloOhm | Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder | R25 |
| 1 | Buzzer | Buzzer_Beeper:Buzzer_12x9.5RM7.6 | BZ1 |
| 1 | ICM_20948_MODULE | Connector_PinSocket_2.54mm:PinSocket_1x10_P2.54mm_Horizontal | J7 |
| 1 | J1 BLACKPILL_LEFT | Connector_PinSocket_2.54mm:PinSocket_1x20_P2.54mm_Vertical | J1 |
| 1 | J2 BLACKPILL_RIGHT | Connector_PinSocket_2.54mm:PinSocket_1x20_P2.54mm_Vertical | J2 |
| 1 | MOTOR_1 | Connector_JST:JST_ZH_B12B-ZR_1x12_P1.50mm_Vertical | J4 |
| 1 | MOTOR_2 | Connector_JST:JST_ZH_B12B-ZR_1x12_P1.50mm_Vertical | J5 |
| 1 | MOTOR_3 | Connector_JST:JST_ZH_B12B-ZR_1x12_P1.50mm_Vertical | J6 |
| 1 | R-78E5.0-0.5 | Converter_DCDC:Converter_DCDC_RECOM_R-78E-0.5_THT | U1 |
| 1 | SMBJ13CA | Diode_SMD:D_SMB | D1 |
| 1 | SUD50P04-08 | Package_TO_SOT_SMD:TO-252-2 | Q9 |
| 1 | Screw_Terminal_01x02 | TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-2-5.08_1x02_P5.08mm_Horizontal | J9 |
| 1 | UART | Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical | J8 |

esar/hdmilight-v3
HDMI Light v3 - FPGA based Ambilight clone with direct HDMI input

blinken/vandal
An ESP32-based lighting control system for campervans (or anything else)


Beirdo/arduino-webasto-mainboard
Custom replacement control board for Webasto Thermo Top C/E


HEAPLab/SELDestroyer
The SEL destroyer can be also used as a normal voltage, current, or power monitoring device.

Lekylouch/AquaBoard
Carte électronique AquaGuard. Conçue sous KiCad, en cours de migration vers Altium Designer.

ohmtech-rdi/eurorack-blocks
Software to Hardware Prototyping for Eurorack using C++, Max/Gen~ or Faust
It measures 120 × 103.9 mm and has 4 copper layers, 1.6 mm thick.
76 parts, built around the R-78E5.0-0.5, MMBT3904, BSS84 and SMBJ13CA. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.
From the Evc-r/Balancing-Cube-STM32 repository on GitHub, at the commit this page was made from: the board is BALANCING CUBEV1.01.kicad_pcb and its schematic BALANCING CUBEV1.01.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Its repository states no licence, so its author keeps all rights: ask Evc-r before reusing the design.