USB relay firmware for STM32 and RP2040 boards that exposes a simple serial command interface over USB CDC-ACM.
- Control up to 8 relay outputs from a host computer over USB serial.
- Turn relays on/off, toggle, pulse for a duration, or set all channels with a bitmask.
- Identify devices by unique MCU-based serial number.
- Reboot directly into on-chip USB bootloader mode from software.
This firmware currently targets these board families (default TinyUSB board in parentheses):
STM32F0(stm32f072disco)STM32F1(stm32f103_bluepill)STM32F4(stm32f411blackpill)RP2040(raspberry_pi_pico)
Hardware behavior is family-port specific (GPIO mapping, relay polarity, UID base, DFU ROM address).
Connect each USB relay module input (IN1..IN8) to the corresponding MCU GPIO below, and connect grounds together.
STM32F0(stm32f072disco):IN1=PA0,IN2=PA1,IN3=PA2,IN4=PA3,IN5=PA4,IN6=PA5,IN7=PA6,IN8=PA7STM32F1(stm32f103_bluepill):IN1=PB12,IN2=PB13,IN3=PB14,IN4=PB15,IN5=PB8,IN6=PB9,IN7=PB10,IN8=PB11(active-low outputs)STM32F4(stm32f411blackpill):IN1=PB0,IN2=PB1,IN3=PB2,IN4=PB10,IN5=PB3,IN6=PB4,IN7=PB5,IN8=PB7RP2040(generic):IN1=GP2,IN2=GP3,IN3=GP4,IN4=GP5,IN5=GP6,IN6=GP7,IN7=GP8,IN8=GP9
- Build firmware for your board family.
- Flash with ST-Link or J-Link.
- Connect over USB CDC serial from your host.
- Send line-based commands and parse machine-readable responses.
After USB enumeration, open the device serial port (for example with picocom, minicom, or screen) and send one command per line.
Examples:
help
id
version
state
set 1 on
set 1 off
toggle 1
pulse 1 1000
setmask 0xff
all off
reboot-dfu
Typical responses:
OK
ERR invalid-relay
ERR invalid-arg
STATE 0x03
ID 045101780587252555FFC660
VERSION usb-relay-stm32 0.1.0
UPTIME 12345
Notes:
- Relay indices are
1..NwhereNis board-configured (up to 8). - Commands are line-oriented (
\nor\r\n). - On USB mount, firmware emits
OK.
- ARM GCC toolchain
- CMake
3.20+ - Python 3
- TinyUSB checkout at
tinyusb(or vendored infirmware/tinyusb)
cd firmware
git clone https://github.com/hathach/tinyusb.git ../tinyusb
python3 ../tinyusb/tools/get_deps.py stm32f0 stm32f1 stm32f4 rp2040cmake -S firmware -B build-f0 -DBOARD_FAMILY=STM32F0
cmake --build build-f0
cmake -S firmware -B build-f1 -DBOARD_FAMILY=STM32F1
cmake --build build-f1
cmake -S firmware -B build-f4 -DBOARD_FAMILY=STM32F4
cmake --build build-f4
cmake -S firmware -B build-rp2040 -DBOARD_FAMILY=RP2040
cmake --build build-rp2040Output artifacts include .elf, .bin, .hex in the selected build directory.
Use TinyUSB family flash targets after configure/build.
cmake --build build-f0 --target usb-relay-stm32-stlink
cmake --build build-f1 --target usb-relay-stm32-stlink
cmake --build build-f4 --target usb-relay-stm32-stlinkIf you prefer flashing directly (without CMake flash targets), use STM32CubeProgrammer CLI. Linux CLI example:
# STM32F0 build output
STM32_Programmer_CLI --connect port=swd \
--write build-f0/usb-relay-stm32.bin 0x08000000 \
--verify --go
# STM32F1 build output
STM32_Programmer_CLI --connect port=swd \
--write build-f1/usb-relay-stm32.bin 0x08000000 \
--verify --go
# STM32F4 build output
STM32_Programmer_CLI --connect port=swd \
--write build-f4/usb-relay-stm32.bin 0x08000000 \
--verify --goOptional alternative with st-flash (from stlink):
st-flash --reset write build-f0/usb-relay-stm32.bin 0x08000000
st-flash --reset write build-f1/usb-relay-stm32.bin 0x08000000
st-flash --reset write build-f4/usb-relay-stm32.bin 0x08000000cmake --build build-f0 --target usb-relay-stm32-jlink
cmake --build build-f1 --target usb-relay-stm32-jlink
cmake --build build-f4 --target usb-relay-stm32-jlinkRP2040 boards expose a ROM USB mass-storage bootloader (RPI-RP2) in BOOTSEL mode.
Enter BOOTSEL mode:
- Hold
BOOTSEL. - Plug in USB (or press reset while holding
BOOTSEL). - Release
BOOTSELafter the board appears asRPI-RP2.
Flash by copying UF2 from the shell:
# Optional: verify the RP2040 boot volume is present
lsblk -o NAME,LABEL,MOUNTPOINT | grep RPI-RP2
# Copy firmware UF2 to the mounted RP2040 drive
cp build-rp2040/usb-relay-stm32.uf2 /media/$USER/RPI-RP2/
syncOptional picotool workflow (Linux CLI):
# If the board is already running this firmware, ask it to reboot to USB bootloader:
picotool reboot -u
# Program flash directly, then reboot
picotool load -f build-rp2040/usb-relay-stm32.elf
picotool rebootThis repo includes a udev rule for VID:PID cafe:4010.
Install:
./udev/install-udev-rules.shIf you change USB VID/PID in firmware/src/usb_descriptors.c, update udev/99-usb-relay-stm32.rules accordingly.
- TinyUSB device stack with CDC-ACM transport.
- Line-based command parser with machine-readable status/error responses.
- USB serial descriptor string is generated from STM32 96-bit unique ID.
- Relay ports are split by family:
firmware/boards/ports/port_stm32f0.cfirmware/boards/ports/port_stm32f1.cfirmware/boards/ports/port_stm32f4.cfirmware/boards/ports/port_rp2040.c
reboot-dfujumps to STM32 system-memory DFU ROM on STM32, and enters USB boot mode on RP2040.