iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
💨

Using ch32v00x-hal with CH32V003J4M6 Microcontroller

に公開

In the sample from Blinking an LED with Rust on a CH32V003J4M6 Microcontroller, I was manipulating memory directly.

This time, I tried using ch32v00x-hal, which is a HAL for the CH32V00X series.

Changes to Cargo.toml

[dependencies]
ch32v-rt = "0.0.3"
ch32v00x-hal = { version = "0.1.0", git = "https://github.com/ch32-rs/ch32v00x-hal.git", default-features = false, features = ["ch32v003j4m6"] }

Previously, I specified the riscv-rt crate, but I have changed it to ch32v-rt.
Looking at https://github.com/ch32-rs/ch32v-rt, it seems this is already deprecated and it says to use qingke-rt instead. I plan to try that out later.

Since ch32v00x-hal is not yet available on crates.io, I am using the version directly from the repository (a0a0500).
While it would likely work with default features, I specified more accurate ones.

Changes to the Build Process

Since ch32v00x-hal handles build.rs and memory.x internally, I deleted those files and added the following configuration.

.cargo/config.toml
[target.riscv32ec-unknown-none-elf]
rustflags = [
  "-C", "link-arg=-Tlink.x",
]

Additionally, previously I was building with:

$ cargo +custom-rv32ec build

However, by running

$ rustup override set custom-rv32ec

within the project directory, I can now simply use

$ cargo build

(I'm not entirely sure why this works.)

Improved Flashing

In the previous article, I used a tool called minichlink, but I have switched to wlink provided by ch32-rs.

$ cargo install --git https://github.com/ch32-rs/wlink
.cargo/toml
[target.riscv32ec-unknown-none-elf]
runner = "wlink -v flash"

This allows flashing and execution directly from the IDE.

Changes to the Source Code

src/main.rs
#![no_std]
#![no_main]

use ch32v_rt::entry;
use ch32v00x_hal::prelude::*;
use ch32v00x_hal::pac::Peripherals;
use panic_halt as _;

#[entry]
fn main() -> ! {
    let pac = Peripherals::take().unwrap();

    let mut rcc = pac.RCC.constrain();
    let _clocks = rcc.config.freeze();

    let gpioc = pac.GPIOC.split(&mut rcc);
    let mut led = gpioc.pc1.into_push_pull_output();
    loop {
        led.toggle();

        for _ in 0..1_000_000 {
            core::hint::black_box(()); // Do nothing, but keep the loop
        }
    }
}

In the ch32v00x-hal sample, the waiting part is implemented as follows, which feels cleaner and easier to handle:

unsafe {
    qingke::riscv::asm::delay(10000000);
}

Conclusion

In this post, I used HAL to improve the source code. I've also refined the build and execution process, setting up a foundation for efficient development.

https://github.com/task-jp/ch32v003j4m6-led/tree/ch32v00x_hal

Discussion