Getting Started with CH32V003 Firmware in Rust

I have been working on a small project using the WCH CH32V003 and thought it would be fun to make a version of the firmware for it in Rust. I started by having a look around for hardware support and getting started guides. As it turns out, there is a HAL and hardware support by the ch32-rs project. Also, the chip is also supported by probe-rs (also see other posts tagged probe-rs). However, when it came to getting started guides, I found little other than the examples folder in the ch32-hal project. So here we are. I’m going to rely heavily on that examples folder, but provide the step-by-step guide I was missing.

TL;DR

Here is my blinky example project: https://github.com/albertskog/ch32v003-blinky-rust.

Hardware

I used CH32V003F4P6-EVT-R0 development board and the WCH-LinkE programmer. The steps below should also work for other boards, programmers and even other CH32V chips, but I haven’t tested any.

On the CH32V003F4P6-EVT-R0, connect PD6 to LED1. This connects the pin to the actual LED so we can control it later.

Between CH32V003F4P6-EVT-R0 and WCH-LinkE, connect:

VCC to 3V3
GND to GND
PD1 to SWDIO/TMS

0. Install Tools

First, we need to install Rust. If you came here, you probably already have (or can figure out how to do so).

We are also going to use probe-rs for uploading the binary to the device. There are different options for installing it depending on your operating system, see https://probe.rs/docs/getting-started/installation/

I’m on a mac so I went with:

brew tap probe-rs/probe-rsbrew install probe-rs

1. Project Setup

I learned we need to use Rust Nightly for some of the crates to work. I created a new project and set it up to use Nightly:

cargo new ch32v003-blinky-rustcd ch32v003-blinky-rustrustup install nightlyrustup override set nightly

We also need the source for the standard libraries in order to build core later on:

rustup component add rust-src

2. Add Configuration Files

We need a few different files to work with embedded devices.

The first is a target specification file. (Because Rust does not yet have built-in support for the RISC-V variant we need, RISCV32ec.) The file is called riscv32ec-unknown-none-elf.json and should be placed in the root of the project. I borrowed this one from the examples folder of ch32-hal:

{ "arch": "riscv32", "atomic-cas": false, "cpu": "generic-rv32", "crt-objects-fallback": "false", "data-layout": "e-m:e-p:32:32-i64:64-n32-S32", "eh-frame-header": false, "emit-debug-gdb-scripts": false, "features": "+e,+c,+forced-atomics", "linker": "rust-lld", "linker-flavor": "gnu-lld", "llvm-target": "riscv32", "llvm-abiname": "ilp32e", "max-atomic-width": 32, "panic-strategy": "abort", "relocation-model": "static", "target-pointer-width": "32"}

riscv32ec-unknown-none-elf.json

Next, we need a Cargo configuration file. Create a folder called .cargo in the root of the project and in that folder, create a file called config.toml. This time, I started with the examples file but simplified as much as I could. Note that if you use a different chip, you may need to change the runner command.

[build]target = "riscv32ec-unknown-none-elf.json"[target.riscv32ec-unknown-none-elf]runner = "probe-rs run --chip ch32v003"rustflags = ["-C", "link-arg=-Tlink.x"][unstable]build-std = ["core"]

.cargo/config.toml

Finally, we add some dependencies and profile settings to Cargo.toml. The ch32-hal crate is not yet published, so we grab it directly from Github. Here, the chip used is selected as a feature. Qingke is the name of the RISC-V core used in the CH32V chips, if you were wondering. We also add some profile settings. Without these, I found the binary would not fit on the chip. It is possible to add them under a separate release profile as is done in the ch32-hal examples, but then we have to remember to add --release when uploading. I found this to be easier.

[package]name = "ch32v003-blinky-rust"version = "0.1.0"edition = "2021"[dependencies]panic-halt = "1.0.0"ch32-hal = { git = "https://github.com/ch32-rs/ch32-hal", features = [ "ch32v003f4u6", ] }qingke-rt = "0.4.0"qingke = "0.4.0"embedded-hal = "1.0.0"[profile.dev]strip = falselto = trueopt-level = "s"

Cargo.toml

3. Write Main File

Now we should have everything set up in order to write our blinky program. Here is, again, a simplified version of the ch32-hal example program:

#![no_std]#![no_main]use hal::delay::Delay;use hal::gpio::{Level, Output};use ch32_hal as hal;use panic_halt as _;#[qingke_rt::entry]fn main() -> ! { let config = hal::Config::default(); let peripherals = hal::init(config); let mut led = Output::new(peripherals.PD6, Level::Low, Default::default()); let mut delay = Delay; loop { led.toggle(); delay.delay_ms(1000); }}

src/main.rs

I took out some SDI print statements which i found made the code not run on my device. The binary would upload but the LED would not blink and no messages were printed. If I figure out why, I might add another note here!

4. Run

To compile and upload, simply run

cargo run

Project Files

This little blinky project is available on Github as a boilerplate and for future reference:

https://github.com/albertskog/ch32v003-blinky-rust

Hope this was helpful! πŸ¦€

#CH32V #EmbeddedRust #Firmware #probeRs #RISCV

CH32_Deep_Sleep (1.0.0) for ch32v by Dr. Nikolaus Klepp

➑️ https://github.com/zwieblum/ch32_deep_sleep

Ease the use of Deep Sleep with autowakeup and with/without wake on interrupt

#Arduino #ArduinoLibs #ch32v

GitHub - zwieblum/ch32_deep_sleep: Arduino library for ch32 to ease the use of Deep Sleep with autowakeup and with/without wake on interrupt

Arduino library for ch32 to ease the use of Deep Sleep with autowakeup and with/without wake on interrupt - GitHub - zwieblum/ch32_deep_sleep: Arduino library for ch32 to ease the use of Deep Slee...

GitHub

For those of you interested in my 'adventures' with CH32V MCUs and hesitating to try them...a few things may make the transition easier:

1) The I/O peripherals are mostly a direct copy from STM32 (including identically named flags)

2) The tools are open source and can run on a cmd line on all desktop OSs.

3) I recently learned that they come preloaded with serial boot loaders installed, so you don't need a special programming tool.

#RISCV
#CH32V

I finally got my #CH32V Portable Sensor Platform built and with the right LCD. My first sensor - LTR390 UV/Visible light.

This is a personal project to allow me to field test I2C sensors. Does it look like a potential product to anyone?

I assembled the first version of my CH32V203 Pocket CO2 Sensor project today. The Sharp LCD and most of the board works, but I forgot pull-up resistors on the RTC and it doesn't appreciate that. An ugly patch and I got things working; not too bad for a v1 board. The LiPo charging / LDO all work fine. I didn't solder the LSM6DS3 in case of an error and I was right to do that :)

#RISCV
#CH32V
#CO2

WCH CH32V Arduino support just released...

https://github.com/openwch/arduino_core_ch32

Edit: Almost - the files are starting to populate, but it's missing the json file needed to add it to the Arduino IDE. I'll keep you posted when it's ready.

Edit 2: Files are available, but it doesn't install on MacOS. The compiler and OpenOCD tool don't have MacOS versions.

#RISCV
#CH32V

GitHub - openwch/arduino_core_ch32: Core library for CH32duino

Core library for CH32duino. Contribute to openwch/arduino_core_ch32 development by creating an account on GitHub.

GitHub

I still have a bunch of CH32V003 MCUs, but my project ideas won't fit in the 16K of FLASH. Anyone have some good ideas for small projects that would work on the '003? Think "ATMega328 replacement".

#CH32V
#IOT

Porting #Nuttx (with its odd style requirements) to #wch #CH32V demanded producing headers for the parts. Faced with declaring 2303 registers & 4259 bitfields for #CH32v307 alone, I did what any lazy programmer would do and automated it.

The resulting program reads SVD files as produced by #WCH for their #RISC-V parts and spits out ISO C 89 (sigh) headers for the registers.

See https://github.com/robertlipe/svdtoheaders/blob/main/demo/h/ch32v307_reg.h for code a human should never have to write.

Program:
https://github.com/robertlipe/svdtoheaders

A new member joins the prestigious fast food container club:
#CH32V