A Rust embedded ecosystem for the HiSilicon RISC-V family — the WS63
(Wi-Fi 6 + BLE + SLE/SparkLink) and the BS2X SKUs (BS20 / BS21E / BS22;
BLE + SLE/NearLink), all single-core RV32IMFC (hard-float ilp32f, no atomics) SoCs.
This monorepo bundles per-chip svd2rust peripheral-access crates, a hand-written
multi-chip safe HAL, a runtime, a porting layer for the closed-source Wi-Fi/BLE
blobs, and runnable examples — buildable today with a custom Rust toolchain, and
runnable without hardware on the sister project
hisi-riscv-qemu (machines
-M ws63 / bs21 / bs21e / bs22 / bs20).
North star: connectivity. Everything here is aimed at eventually bringing up Wi-Fi/BLE on the WS63 in Rust. Current status (2026-06): WS63 Wi-Fi RF porting layer + netif→smoltcp complete but pending real blob TX/RX and on-silicon validation (ROADMAP phase 4/5). BS2X BLE is deferred: the radio interface is a closed blob boundary (
0x59000000write-only PHY regs + IRQ-26 event wall); full analysis inROADMAP.md. Full QEMU bring-up done for both chips; HIL scaffolding ready. SeeROADMAP.mdfor the staged plan anddocs/for the architecture (Chinese).
Each library crate is a standalone repository (a git submodule here) and is
published independently to crates.io; ws63-rf-rs and ws63-flashboot live
in-tree and are not published.
| Crate | Role | crates.io |
|---|---|---|
ws63-pac |
svd2rust-generated WS63 peripheral access (raw RegisterBlocks, Peripherals::take()) |
ws63-pac |
bs2x-pac |
svd2rust-generated BS21/BS2X peripheral access (the multi-chip sibling of ws63-pac) |
— |
hisi-riscv-hal |
Hand-written safe drivers on embedded-hal 1.0 (GPIO, UART, SPI, I2C, DMA, timers, clocks, …) — plus optional async (embedded-hal-async/embedded-io-async) and embassy (an embassy-time driver). Multi-chip: chip-ws63 (default) / chip-bs21 |
hisi-riscv-hal |
hisi-riscv-rt |
Runtime: startup assembly, linker scripts, interrupt vectors (over riscv-rt) |
hisi-riscv-rt |
ws63-rf-rs |
Porting layer + FFI for the closed Wi-Fi/BLE blobs (OSAL/OAL/FRW/HCC, scheduler, netif→smoltcp). In-tree, publish = false |
— |
ws63-flashboot |
Experimental bootloader (not secure boot). In-tree, publish = false |
— |
ws63-examples |
Runnable WS63 examples (blinky, uart_hello, timer_irq, gpio_irq, dma_loopback, …) | — |
bs21-examples |
BS21 examples (blinky, uart_hello, spi_loopback, gadc_read, i2c_scan, hid_demo, clock_rng, pwm_wdt, dma_mem) — isolated workspace, builds for -M bs21 |
— |
bs20-examples |
BS20 examples (same as BS21; isolated workspace, 128K RAM variant) — builds for -M bs20 |
— |
The repo uses git submodules extensively. Two are nested under the crate that owns them, so generation inputs / vendor blobs are not reached into laterally:
hisi-riscv-rs/
├── crates/ # core publishable library crates
│ ├── ws63-pac/ # submodule
│ │ └── ws63-svd/ # submodule of ws63-pac — svd2rust source (WS63.svd)
│ ├── bs2x-pac/ # submodule
│ │ └── bs2x-svd/ # submodule of bs2x-pac — svd2rust source (BS2X.svd)
│ ├── hisi-riscv-hal/ # submodule (multi-chip: chip-ws63 / chip-bs21)
│ └── hisi-riscv-rt/ # submodule
├── examples/ # application examples
│ ├── ws63/ # submodule (blinky, uart_hello, …)
│ ├── bs21/ # in-tree, isolated workspace (10+ examples: SPI, GADC, I2C, KEYSCAN, QDEC, RTC, WDT, DMA, USB, PDM)
│ └── bs20/ # in-tree, isolated workspace (BS20 variant: same examples, 128K RAM)
├── chips/ # chip-specific support
│ ├── ws63/
│ │ ├── guide/ # submodule — WS63 user guide
│ │ ├── rf/ # in-tree crate (ws63-rf-rs)
│ │ │ └── ws63-RF/ # submodule — closed Wi-Fi/BLE blobs + porting contract
│ │ └── flashboot/ # in-tree crate (ws63-flashboot)
│ └── bs2x/
│ └── guide/ # submodule — BS21/BS2X user guide
├── docs/ # architecture docs (Chinese) + review ledger
├── hil/ # hardware-in-the-loop scripts
├── CLAUDE.md # build/architecture guide
└── ROADMAP.md # staged plan toward connectivity
Always clone/update with recursion:
git submodule update --init --recursiveThe default target riscv32imfc-unknown-none-elf (hardware single-float
ilp32f, no atomics) is baked into a custom rustc as a builtin, so no
-Z build-std is needed. It is not a distributable rustup channel — install +
link it first (see rust-toolchain.toml and the
hisi-riscv-rust-toolchain repo):
curl -fLO https://github.com/hispark-rs/hisi-riscv-rust-toolchain/releases/download/v1.96.0-2/hisi-riscv-rust-1.96.0-x86_64-unknown-linux-gnu.tar.gz
tar xzf hisi-riscv-rust-1.96.0-*.tar.gz && rustup toolchain link hisi-riscv "$PWD/stage2"cargo build # libraries + the default-member examples
cargo check --workspace # full workspace (incl. flashboot)
cargo build -p blinky --releaseLint / format:
cargo clippy --workspace
cargo fmt --all -- --checkScaffold a fresh app outside this repo with
cargo generate from the
hisi-rs-template starter — it
wires up the toolchain, target, linker scripts, a QEMU cargo run runner, and the
right crates.io deps for the chip you pick:
cargo install cargo-generate
cargo generate --git https://github.com/hispark-rs/hisi-rs-template
# chip = ws63 | bs21 | bs21e | bs22 | bs20 (BS2X SKUs share one HAL)
# starter = blinky | uart_hello | async (embassy; WS63 + BS2X)hisi-riscv-qemu is a QEMU fork with an
in-tree WS63 machine (-M ws63) that models the CPU + xlinx custom ISA, memory
map, interrupt controller, and all 35 SVD peripherals. It runs ws63-rs firmware
(and real vendor C-SDK firmware) and is the software-in-the-loop stand-in for
ROADMAP phase 1 "hardware bring-up":
# in a sibling checkout of hisi-riscv-qemu
bash scripts/build.sh
WS63_RS=../ws63-rs bash scripts/smoke-test.sh # boots ws63-rs examples + asserts behaviourhisi-riscv-hal has an interrupt + waker driven async layer (no heap, no global
executor required), built on embedded-hal-async / embedded-io-async. It runs
on the no-atomics WS63 core via the existing portable-atomic + critical-section
polyfill. Two opt-in features:
async—embedded_hal_async::delay::DelayNs(on a TIMER),digital::Wait(GPIO edges),embedded_io_async::{Read, Write}(UART), plus a minimalwfiblock_on. Drivers exposeon_interrupthooks rather than installing ISRs.embassy— anembassy-timeDriver(now()from the TCXO 64-bit counter, alarms from a TIMER), soembassy-executor(platform-riscv32) runsTimer::after+ multi-task scheduling + the async drivers above.
Validated on hisi-riscv-qemu — see examples/ws63/{async_delay, embassy_multitask, embassy_async_io}.
Each published crate self-publishes from its own repository: bump + tag
vX.Y.Z in ws63-pac / hisi-riscv-hal / hisi-riscv-rt, and that repo's
.github/workflows/release.yml publishes it to crates.io (using its own
CRATES_IO_TOKEN). The monorepo v* tag cuts only a firmware GitHub
Release — it does not publish the library crates.
CLAUDE.md— build commands, architecture, design decisions.docs/src/explanation/components/overview.md— the whole picture (Chinese), with per-component docs alongside.docs/review/— the architecture review ledger.ROADMAP.md— remediation plan and the path to connectivity (incl. the BS2X BLE radio-interface feasibility analysis).- Open tasks: tracked as GitHub issues on hispark-rs/hisi-riscv-rs. Probe-rs debug support (fork hispark-rs/probe-rs branch
add-hisilicon-ws63-bs21) is software-complete, pending on-silicon validation.
MIT for the Rust code (see each crate's Cargo.toml). The closed-source vendor
blobs under chips/ws63/rf/ws63-RF carry HiSilicon's own license and are not
MIT — that delivery stays language-neutral and is only linked, never modified.