| core | ||
| drivers/ch32v003 | ||
| handlers | ||
| link | ||
| subfsm | ||
| .gitignore | ||
| README.md | ||
| run.sh | ||
os3-rnode
Minimal standalone CH32V003 RNode-compatible LoRa modem firmware extracted from the OS3 tree.
Article and project write-up:
This repository contains only the files required to build the CH32V003 + SX1262 RNode firmware image:
- core event kernel: core/trap.S, core/event.S, core/kernel.S, core/timer.S, core/console.S, core/fsm.S, core/events.inc
- CH32V003 drivers: drivers/ch32v003/bootstrap.S, init.S, exti.S, uart.S, vector.S, flash.S, mcu.S, spi.S, sx1262.S, led.S, mmio.inc
- FSMs: subfsm/rnode_fsm.S, subfsm/lora_fsm.S
- handlers: handlers/heartbeat.S
- linker: link/ch32v003.ld
- build entrypoint: run.sh
The extraction source commit in the original OS3 tree was: 3058b75912041138a990446e3c946457b5da8ef7
Build
The repository builds a single firmware target: CH32V003.
There is no Makefile or external build system here. The whole build is driven by run.sh, which:
- creates
build/ch32v003/ - removes previous
.o,.elf, and.binfiles for that target - assembles every module with
riscv32-unknown-elf-as - links the final image with
riscv32-unknown-elf-ld - generates the flashable binary with
riscv32-unknown-elf-objcopy - prints the resulting image sizes and registered
.kernel_initentries
Prerequisites
Install a RISC-V embedded GNU toolchain and make sure these commands are available in your PATH:
riscv32-unknown-elf-asriscv32-unknown-elf-ldriscv32-unknown-elf-objcopyriscv32-unknown-elf-sizeriscv32-unknown-elf-nm
The firmware is assembled for rv32ec_zicsr with ABI ilp32e, matching the CH32V003.
Build Command
From the repository root, run:
./run.sh
On a successful build, the script produces:
build/ch32v003/kernel.elf- ELF image with symbols and debug infobuild/ch32v003/kernel.bin- raw binary image to flash to the MCU
The script is safe to re-run; it cleans the target output directory before rebuilding.
Typical Build Output
The build ends with a short summary similar to:
Build complete:
- build/ch32v003/kernel.elf
- build/ch32v003/kernel.bin
Section sizes:
text data bss dec hex filename
....
If one of the riscv32-unknown-elf-* tools is missing, the build will fail immediately. In that case, fix the toolchain installation or PATH first.
Flashing
The build output to flash is:
build/ch32v003/kernel.bin
The simplest workflow uses minichlink with a WCH-Link compatible probe.
Write the firmware to flash:
minichlink -w build/ch32v003/kernel.bin flash -b
Write and reset immediately after flashing:
minichlink -w build/ch32v003/kernel.bin flash -b -r
Typical sequence:
- Connect the CH32V003 board to the SX1262 radio module.
- Connect the SWD probe to the CH32V003.
- Build the firmware with
./run.sh. - Flash
build/ch32v003/kernel.binwithminichlink. - Reset the board and reconnect the host UART side.
If your probe is already attached and detected, the second command is usually the one you want:
minichlink -w build/ch32v003/kernel.bin flash -b -r
Wiring
The current firmware is known to work with SX1262 modules that use:
DIO1as the IRQ lineBUSY,NSS,SCK,MOSI,MISO, andNRSTdirectlyDIO3internally for the TCXO- one external RX-side RF switch control line driven by
PC3 - SX1262
DIO2RF-switch control for the TX-side path
That wiring model is confirmed for the E22 module documented below. Other SX1262 modules that expose equivalent signals may also work, but should be treated as unverified until tested on hardware.
CH32V003 to E22-900M22S
Connect the radio module to the CH32V003 exactly like this:
PC0->NRSTPC1->BUSYPC2->DIO1PC3->RXENPC4->NSS / CSPC5->SCKPC6->MOSIPC7->MISO3V3->VCCGND->GNDDIO2->TXENon the E22 side
Attach an antenna before RF testing.
CH32V003 to Seeed Wio-SX1262 / XIAO SX1262 carrier
For the Seeed Wio-SX1262 module and XIAO carrier variants that expose the module RF_SW pin, the following wiring might work, but it has not been validated in this repository:
PC0->NRSTPC1->BUSYPC2->DIO1PC3->RF_SWPC4->NSS / CSPC5->SCKPC6->MOSIPC7->MISO3V3->VCCGND->GND
Do not add an external DIO2 wire for this module. The Wio-SX1262 datasheet states that DIO2 is internally connected to the RF switch for transmitter mode, while RF_SW is the external control input for receiver mode.
The reason this might work is that it appears to match the current firmware logic:
PC3is driven low in standby/TXPC3is driven high in RX- SX1262
DIO2RF-switch control is enabled during radio init
This has not been validated on hardware in this repository yet, so do not treat it as confirmed support. It is only a documented compatibility hypothesis until someone completes TX and RX smoke tests on the target board.
CH32V003 to WCH-Link UART bridge
For the host-side RNode UART, connect the CH32V003 USART1 pins to the WCH-Link UART bridge:
PD5(USART1 TX) -> WCH-Link UARTRXPD6(USART1 RX) -> WCH-Link UARTTXGND->GND
CH32V003 to WCH-Link debug/flash header
For flashing and debug access, connect the WCH-Link probe like this:
PD1(SWDIO / SWIO) -> WCH-LinkSWDIOPD0(NRST) -> WCH-LinkNRSTif available3V3-> WCH-Link3V3GND->GND
CH32V003 uses a single-wire debug interface on PD1, so there is no separate SWCLK pin to wire.
LEDs
The firmware uses two status LEDs on port D:
PD4-> heartbeat LEDPD2-> radio activity LED
The radio activity LED is active-low in the current driver.