Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/MrJefter/sdvx-controller/llms.txt

Use this file to discover all available pages before exploring further.

All of the SDVX Controller’s inputs and outputs connect to an STM32F401 microcontroller running on a BlackPill v3.0 development board. The seven buttons land on GPIOA with internal pull-up resistors enabled, the two LPD3806 rotary encoders feed into dedicated hardware timer inputs (TIM3 and TIM4), and the WS2812B LED strip is driven from a single GPIO data line on PB0. Understanding these assignments is essential both for assembling the controller and for any future firmware modifications.
All peripherals — buttons, encoders, and the LED strip — must share a common GND with the BlackPill. Floating grounds are the most common source of erratic button reads and corrupted LED data. Use the GND pins on the BlackPill and ensure every wire run terminates at the same ground reference.

Complete Pin Assignment Table

SignalMCU PinGPIO PortTimer / ModeNotes
BTN1 (BT-A)PA5GPIOAEXTI, RISING_FALLINGInternal PULLUP; active-low when pressed
BTN2 (BT-B)PA3GPIOAEXTI, RISING_FALLINGInternal PULLUP; active-low when pressed
BTN3 (BT-C)PA2GPIOAEXTI, RISING_FALLINGInternal PULLUP; active-low when pressed
BTN4 (BT-D)PA1GPIOAEXTI, RISING_FALLINGInternal PULLUP; active-low when pressed
FX-LPA4GPIOAEXTI, RISING_FALLINGInternal PULLUP; active-low when pressed
FX-RPA9GPIOAEXTI, RISING_FALLINGInternal PULLUP; active-low when pressed
STARTPA10GPIOAEXTI, RISING_FALLINGInternal PULLUP; also triggers DFU if held ≥ 5 s
VOL-L Channel A (KNOBLA)PA6GPIOATIM3 CH1 (Encoder mode)
VOL-L Channel B (KNOBLB)PA7GPIOATIM3 CH2 (Encoder mode)
VOL-R Channel A (KNOBRA)PB6GPIOBTIM4 CH1 (Encoder mode)
VOL-R Channel B (KNOBRB)PB7GPIOBTIM4 CH2 (Encoder mode)
WS2812B DataPB0GPIOBGPIO Output (DMA/PWM)12 LEDs in series
BOOT0 ControlPA15GPIOAGPIO Output PPDriven HIGH before reset to enter DFU

Buttons

Every button shares the same wiring pattern:
  • One terminal of the switch connects to the designated GPIO pin listed in the table above.
  • Other terminal of the switch connects to GND.
No external pull-up resistor is needed — the firmware configures each button pin with the STM32’s internal pull-up (GPIO_PULLUP). This means the pin reads HIGH (logic 1) at rest and is pulled LOW (logic 0) when the button is pressed and shorts the pin to GND.
Buttons use active-low logic. A pressed button reads GPIO_PIN_RESET (0 V / logical 0) because the internal pull-up is overcome by the direct GND connection through the switch. The firmware inverts this internally when building the HID report, so button presses are correctly reported as “pressed” to the host PC.
The GPIO lines are configured with GPIO_MODE_IT_RISING_FALLING, meaning the STM32 generates an interrupt on both the press (falling edge) and release (rising edge). Software debouncing with a 3 ms lockout window prevents false triggers from switch bounce.

Verified button GPIO definitions (from main.h)

#define BTN4_Pin    GPIO_PIN_1   // PA1
#define BTN3_Pin    GPIO_PIN_2   // PA2
#define BTN2_Pin    GPIO_PIN_3   // PA3
#define FXL_Pin     GPIO_PIN_4   // PA4
#define BTN1_Pin    GPIO_PIN_5   // PA5
#define FXR_Pin     GPIO_PIN_9   // PA9
#define START_Pin   GPIO_PIN_10  // PA10

Rotary Encoders (VOL-L and VOL-R)

The two LPD3806 incremental encoders are connected to the STM32’s hardware timer encoder interface. The hardware counts pulses automatically in the background with no CPU overhead.
EncoderTimerChannel AChannel B
VOL-LTIM3PA6 (KNOBLA)PA7 (KNOBLB)
VOL-RTIM4PB6 (KNOBRA)PB7 (KNOBRB)
Each LPD3806 encoder has five wires:
  • +5V — connect to the 5 V rail (BlackPill 5V pin or USB power)
  • GND — connect to the common GND
  • A (Channel A) — connect to the Channel A pin listed in the table above
  • B (Channel B) — connect to the Channel B pin listed in the table above
  • Shield/GND (if present) — connect to GND
The timers are initialised in encoder mode with a 16-bit counter period (0xFFFF). The firmware reads the counter delta each main loop iteration, applies exponential smoothing (α = 0.15), and maps the result to the HID joystick axes reported to the PC.

Encoder GPIO definitions (from main.h)

#define KNOBLA_Pin  GPIO_PIN_6   // PA6 — TIM3 CH1 (VOL-L A)
#define KNOBLB_Pin  GPIO_PIN_7   // PA7 — TIM3 CH2 (VOL-L B)
#define KNOBRA_Pin  GPIO_PIN_6   // PB6 — TIM4 CH1 (VOL-R A)
#define KNOBRB_Pin  GPIO_PIN_7   // PB7 — TIM4 CH2 (VOL-R B)

WS2812B LED Strip

The addressable RGB LED strip uses a single data line driven by the STM32 via DMA-backed PWM output on PB0 (WS2812B_PINS = GPIO_PIN_0, WS2812B_PORT = GPIOB). The strip contains 12 LEDs in series (WS2812B_NUMBER_OF_LEDS = 12). Connect the LED strip as follows:
Strip wireConnect to
DIN (Data In)PB0 on the BlackPill / PCB data connector
+5V5 V power rail (USB 5 V or dedicated supply)
GNDCommon GND
WS2812B LEDs are optional — the controller operates fully without them. If you choose not to install the LED strip, simply leave the data connector unconnected. The firmware drives PB0 regardless, but with no LEDs attached there is no functional effect.
A 300–500 Ω resistor in series with the data line is considered good practice for WS2812B strips (to protect against ringing), though the project does not mandate one.

DFU Mode and BOOT0 Control (PA15)

The firmware includes an optional mechanism to enter USB DFU (Device Firmware Upgrade) bootloader mode without needing an ST-Link or physical BOOT0 button press. When the START button is held for 5 seconds, the firmware:
  1. Drives PA15 HIGH (via BOOT0_PORT = GPIOA, BOOT0_PIN = GPIO_PIN_15)
  2. Issues a system reset
On reset, with BOOT0 high, the STM32 boots into its built-in DFU ROM instead of your firmware, allowing a new firmware image to be flashed over USB. PA15 is configured as a push-pull output (GPIO_MODE_OUTPUT_PP) and held LOW at all other times.

Optional 150 nF capacitor modification

To make the BOOT0 control work reliably, the README describes an optional hardware modification to the BlackPill board: add a 150 nF ceramic capacitor between PA15 and the BlackPill’s BOOT0 pin. This capacitor filters the reset glitch so that the STM32 samples BOOT0 as HIGH before the reset completes. Without this capacitor, the DFU entry trick may be unreliable on some BlackPill revisions. The capacitor bridges the PA15 output pad on the BlackPill header to the BOOT0 pin on the board itself — refer to the assembly photos in the repository for the exact placement.
Do not confuse PA15 (the firmware-controlled BOOT0 signal line on the BlackPill header) with the physical BOOT0 button on the BlackPill board itself. They both influence DFU entry, but through different mechanisms. The capacitor mod bridges the firmware output to the hardware boot pin.

Wiring Summary

Buttons (×7)

One switch terminal to the assigned GPIO pin (PA1–PA10), the other to GND. No external resistors needed — internal PULLUP is enabled in firmware.

Encoders (×2)

VOL-L A/B → PA6/PA7 (TIM3). VOL-R A/B → PB6/PB7 (TIM4). Power encoder from the 5 V rail; share common GND.

LED Strip

Data → PB0. Power from 5 V rail. GND to common GND. 12 × WS2812B LEDs in series.

DFU / BOOT0

PA15 drives BOOT0 HIGH on a 5-second START hold. Optional 150 nF capacitor improves reliability.

Build docs developers (and LLMs) love