Skip to main content

CH32 Environment Setup

Current mainline documentation assumes the WCH GCC15 toolchain path, with compiler prefix riscv32-wch-elf-.

The template projects already follow this line. If you only want a quick compile environment, docker-image-ch32-riscv is also aligned to the same toolchain and currently ships WCH GCC15 v240.

CMake Configuration

CH32 projects need one extra option: LIBXR_CH32_CONFIG_FILE, which tells LibXR which CH32 peripheral configuration header is active, for example ch32v30x_conf.h.

set(LIBXR_SYSTEM FreeRTOS)
set(LIBXR_DRIVER ch)

set(LIBXR_CH32_CONFIG_FILE "ch32v30x_conf.h")

add_subdirectory(libxr)

If you are using the current template projects, the compiler prefix usually does not need to be written manually. Explicit toolchain-prefix handling is only needed when you assemble the project yourself or when multiple RISC-V toolchains coexist on the same machine.

Peripheral Library Notes

The official WCH peripheral library still carries several long-standing problems. The current example projects already work around issues such as:

  • duplicated extern "C" definitions that break C++ header inclusion;
  • USB sources and headers existing in the vendor library but not being wired into the project correctly by default;
  • incorrect FreeRTOS mstatus handling affecting task switching and priority behavior;
  • peripheral-group definitions that remain present even though the actual peripheral does not exist.

If you are not starting from the example projects and instead rebuild the vendor library layout by hand, you need to solve these again on your own.

SysTick

For the LibXR timebase to work correctly, add libxr_systick_handler() inside SysTick_Handler:

void SysTick_Handler(void)
{
extern void libxr_systick_handler(void);
libxr_systick_handler();
......
}

Flash Notes

Keep the following in mind:

  • the flash write clock must stay below 60 MHz;
  • after erase but before a write, flash may look like 0xff externally while actual readback can still show magic value 0xE339u;
  • many parts include extra flash regions that are much slower than the main flash;
  • when using those extra flash areas, OpenOCD often needs wch_riscv unfreeze to keep programming stable.

Reference OpenOCD snippet:

"openOCDLaunchCommands": [
"init",
"wch_riscv unfreeze"
],

Example Projects