rnode compatible firmware for ch32v003 and E22 900m22s ebyte semtech module
Find a file
2026-03-30 17:55:49 +02:00
core Compact SOFT event IDs, reduce dispatch table 192→96 bytes RAM 2026-03-30 17:31:11 +02:00
drivers/ch32v003 Set SPI clock to 12MHz for production (was 1.5MHz debug speed) 2026-03-30 11:49:57 +02:00
handlers Remove orphan event constants and debug exports 2026-03-29 23:07:09 +02:00
link Initial import of os3-rnode 2026-03-29 18:44:59 +02:00
subfsm Remove orphan event constants and debug exports 2026-03-29 23:07:09 +02:00
.gitignore Remove unused SX1262 helpers 2026-03-29 22:54:13 +02:00
README.md Document build process in README 2026-03-30 17:51:34 +02:00
run.sh Initial import of os3-rnode 2026-03-29 18:44:59 +02:00

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 .bin files 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_init entries

Prerequisites

Install a RISC-V embedded GNU toolchain and make sure these commands are available in your PATH:

  • riscv32-unknown-elf-as
  • riscv32-unknown-elf-ld
  • riscv32-unknown-elf-objcopy
  • riscv32-unknown-elf-size
  • riscv32-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 info
  • build/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:

  1. Connect the CH32V003 board to the SX1262/E22 module.
  2. Connect the SWD probe to the CH32V003.
  3. Build the firmware with ./run.sh.
  4. Flash build/ch32v003/kernel.bin with minichlink.
  5. 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

CH32V003 to E22-900M22S

Connect the radio module to the CH32V003 exactly like this:

  • PC0 -> NRST
  • PC1 -> BUSY
  • PC2 -> DIO1
  • PC3 -> RXEN
  • PC4 -> NSS / CS
  • PC5 -> SCK
  • PC6 -> MOSI
  • PC7 -> MISO
  • 3V3 -> VCC
  • GND -> GND
  • DIO2 -> TXEN on the E22 side

Attach an antenna before RF testing.

For the host-side RNode UART, connect the CH32V003 USART1 pins to the WCH-Link UART bridge:

  • PD5 (USART1 TX) -> WCH-Link UART RX
  • PD6 (USART1 RX) -> WCH-Link UART TX
  • GND -> GND

For flashing and debug access, connect the WCH-Link probe like this:

  • PD1 (SWDIO / SWIO) -> WCH-Link SWDIO
  • PD0 (NRST) -> WCH-Link NRST if available
  • 3V3 -> WCH-Link 3V3
  • GND -> 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 LED
  • PD2 -> radio activity LED

The radio activity LED is active-low in the current driver.