Skip to content

wch: add the CH32V00x series and the CH32V006EVT evaluation board #89361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions arch/riscv/Kconfig.isa
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,11 @@ config RISCV_ISA_EXT_ZBS
The Zbs instructions can be used for single-bit instructions that
provide a mechanism to set, clear, invert, or extract a single bit in
a register.

config RISCV_ISA_EXT_ZMMUL
bool
help
(Zmmul) - Zmmul Extension for Integer Multiplication

The Zmmul extension implements the multiplication subset of the M
extension.
5 changes: 5 additions & 0 deletions boards/wch/ch32v006evt/Kconfig.ch32v006evt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright (c) 2025 Michael Hope
# SPDX-License-Identifier: Apache-2.0

config BOARD_CH32V006EVT
select SOC_CH32V006K8U
8 changes: 8 additions & 0 deletions boards/wch/ch32v006evt/board.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2025 Michael Hope <[email protected]>
# SPDX-License-Identifier: Apache-2.0

board_runner_args(minichlink)
include(${ZEPHYR_BASE}/boards/common/minichlink.board.cmake)

board_runner_args(openocd "--use-elf" "--cmd-reset-halt" "halt")
include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
6 changes: 6 additions & 0 deletions boards/wch/ch32v006evt/board.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
board:
name: ch32v006evt
full_name: WCH CH32V006EVT
vendor: wch
socs:
- name: ch32v006
41 changes: 41 additions & 0 deletions boards/wch/ch32v006evt/ch32v006evt-pinctrl.dtsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2025 Michael Hope <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/dt-bindings/pinctrl/ch32v00x-pinctrl.h>

&pinctrl {
usart1_default: usart1_default {
group1 {
pinmux = <USART1_TX_PD5_0>;
output-high;
drive-push-pull;
};
group2 {
pinmux = <USART1_RX_PD6_0>;
bias-pull-up;
};
};

usart2_default: usart2_default {
group1 {
pinmux = <USART2_TX_PA7_0>;
output-high;
drive-push-pull;
};
group2 {
pinmux = <USART2_RX_PB3_0>;
bias-pull-up;
};
};

i2c1_default: i2c1_default {
group1 {
pinmux = <I2C1_SDA_PC1_0>, <I2C1_SCL_PC2_0>;
output-high;
drive-open-drain;
};
};
};
75 changes: 75 additions & 0 deletions boards/wch/ch32v006evt/ch32v006evt.dts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2025 Michael Hope <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

/dts-v1/;

#include <wch/ch32v0/ch32v006k8u.dtsi>
#include "ch32v006evt-pinctrl.dtsi"

#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/i2c/i2c.h>

/ {
model = "ch32v006evt";
compatible = "wch,ch32v006";

chosen {
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,console = &usart1;
zephyr,shell-uart = &usart1;
};

leds {
compatible = "gpio-leds";

/*
* Please connect the unconnected LED1 on the WCH CH32V006EVT
* board to PD0 and then change this status to "okay".
*/
status = "disabled";

blue_led1: led1 {
gpios = <&gpiod 0 GPIO_ACTIVE_LOW>;
};

blue_led2: led2 {
gpios = <&gpiob 4 GPIO_ACTIVE_LOW>;
};
};

aliases {
led0 = &blue_led1;
};
};

&clk_hse {
clock-frequency = <DT_FREQ_M(24)>;
status = "okay";
};

&pll {
clocks = <&clk_hse>;
status = "okay";
};

&rcc {
clocks = <&pll>;
};

&gpioc {
status = "okay";
};

&gpiod {
status = "okay";
};

&usart1 {
status = "okay";
current-speed = <115200>;
pinctrl-0 = <&usart1_default>;
pinctrl-names = "default";
};
12 changes: 12 additions & 0 deletions boards/wch/ch32v006evt/ch32v006evt.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
identifier: ch32v006evt
name: WCH CH32V006 Evaluation Board
type: mcu
arch: riscv
toolchain:
- cross-compile
- zephyr
ram: 8
flash: 62
supported:
- gpio
- i2c
7 changes: 7 additions & 0 deletions boards/wch/ch32v006evt/ch32v006evt_defconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (c) 2025 Michael Hope <[email protected]>
# SPDX-License-Identifier: Apache-2.0

CONFIG_GPIO=y
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
Binary file added boards/wch/ch32v006evt/doc/img/ch32v006evt.webp
Binary file not shown.
87 changes: 87 additions & 0 deletions boards/wch/ch32v006evt/doc/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
.. zephyr:board:: ch32v006evt

Overview
********

The `WCH`_ CH32V006EVT is an evaluation board for the RISC-V based CH32V006K8U6
SOC.

The board is equipped with a power LED, reset button, USB port for power, and
two user LEDs. The `WCH webpage on CH32V006`_ contains the processor's
information and the datasheet.

Hardware
********

The QingKe 32-bit RISC-V2C processor of the WCH CH32V006EVT is clocked by an
external crystal and runs at 48 MHz.

Supported Features
==================

.. zephyr:board-supported-hw::

Connections and IOs
===================

LED
---

* LED1 = Unconnected. Connect to an I/O pin (PD0).
* LED2 = Unconnected. Connect to an I/O pin (PB4).

Programming and Debugging
*************************

.. zephyr:board-supported-runners::

Applications for the ``ch32v006evt`` board can be built and flashed
in the usual way (see :ref:`build_an_application` and :ref:`application_run`
for more details); however, an external programmer is required since the board
does not have any built-in debug support.

Connect the programmer to the following pins on the PCB:

* VCC = VCC (do not power the board from the USB port at the same time)
* GND = GND
* SWIO = PD1

Flashing
========

You can use minichlink_ to flash the board. Once ``minichlink`` has been set
up, build and flash applications as usual (see :ref:`build_an_application` and
:ref:`application_run` for more details).

Here is an example for the :zephyr:code-sample:`blinky` application.

.. zephyr-app-commands::
:zephyr-app: samples/basic/blinky
:board: ch32v006evt
:goals: build flash

Debugging
=========

This board can be debugged via OpenOCD or ``minichlink``.

Testing the LED on the WCH CH32V006EVT
**************************************

The ``blinky`` sample can be used to test that the LEDs on the board are working
properly with Zephyr:

* :zephyr:code-sample:`blinky`

You can build and flash the examples to make sure Zephyr is running
correctly on your board. The LED definitions can be found in
:zephyr_file:`boards/wch/ch32v006evt/ch32v006evt.dts`.

References
**********

.. target-notes::

.. _WCH: http://www.wch-ic.com
.. _WCH webpage on CH32V006: https://www.wch-ic.com/downloads/CH32V006DS0_PDF.html
.. _minichlink: https://github.com/cnlohr/ch32fun/tree/master/minichlink
15 changes: 15 additions & 0 deletions boards/wch/ch32v006evt/support/openocd.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#interface wlink
adapter driver wlink
wlink_set
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001

set _TARGETNAME $_CHIPNAME.cpu

target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME
$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1
set _FLASHNAME $_CHIPNAME.flash

flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0

echo "Ready for Remote Connections"
5 changes: 5 additions & 0 deletions cmake/compiler/gcc/target_riscv.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ if(CONFIG_RISCV_ISA_EXT_ZBS)
string(CONCAT riscv_march ${riscv_march} "_zbs")
endif()

if (CONFIG_RISCV_ISA_EXT_ZMMUL AND
"${GCC_COMPILER_VERSION}" VERSION_GREATER_EQUAL 13.0.0)
string(CONCAT riscv_march ${riscv_march} "_zmmul")
endif()

list(APPEND TOOLCHAIN_C_FLAGS -mabi=${riscv_mabi} -march=${riscv_march})
list(APPEND TOOLCHAIN_LD_FLAGS NO_SPLIT -mabi=${riscv_mabi} -march=${riscv_march})

Expand Down
34 changes: 30 additions & 4 deletions drivers/clock_control/clock_control_wch_rcc.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#define WCH_RCC_CLOCK_ID_OFFSET(id) (((id) >> 5) & 0xFF)
#define WCH_RCC_CLOCK_ID_BIT(id) ((id) & 0x1F)
#define WCH_RCC_SYSCLK DT_PROP(DT_NODELABEL(cpu0), clock_frequency)

#if DT_NODE_HAS_COMPAT(DT_INST_CLOCKS_CTLR(0), wch_ch32v00x_pll_clock) || \
DT_NODE_HAS_COMPAT(DT_INST_CLOCKS_CTLR(0), wch_ch32v20x_30x_pll_clock)
Expand Down Expand Up @@ -78,6 +79,33 @@ static int clock_control_wch_rcc_get_rate(const struct device *dev, clock_contro
return 0;
}

static void clock_control_wch_rcc_setup_flash(void)
{
#if defined(FLASH_ACTLR_LATENCY)
uint32_t latency;

#if defined(CONFIG_SOC_CH32V003)
if (WCH_RCC_SYSCLK <= 24000000) {
latency = FLASH_ACTLR_LATENCY_0;
} else {
latency = FLASH_ACTLR_LATENCY_1;
}
#elif defined(CONFIG_SOC_SERIES_CH32V00X)
if (WCH_RCC_SYSCLK <= 15000000) {
latency = FLASH_ACTLR_LATENCY_0;
} else if (WCH_RCC_SYSCLK <= 24000000) {
latency = FLASH_ACTLR_LATENCY_1;
} else {
latency = FLASH_ACTLR_LATENCY_2;
}
FLASH->ACTLR = (FLASH->ACTLR & ~FLASH_ACTLR_LATENCY) | latency;
#else
#error Unrecognised SOC family
#endif
FLASH->ACTLR = (FLASH->ACTLR & ~FLASH_ACTLR_LATENCY) | latency;
#endif
}

static DEVICE_API(clock_control, clock_control_wch_rcc_api) = {
.on = clock_control_wch_rcc_on,
.get_rate = clock_control_wch_rcc_get_rate,
Expand All @@ -87,6 +115,8 @@ static int clock_control_wch_rcc_init(const struct device *dev)
{
const struct clock_control_wch_rcc_config *config = dev->config;

clock_control_wch_rcc_setup_flash();

if (IS_ENABLED(CONFIG_DT_HAS_WCH_CH32V00X_PLL_CLOCK_ENABLED) ||
IS_ENABLED(CONFIG_DT_HAS_WCH_CH32V20X_30X_PLL_CLOCK_ENABLED)) {
/* Disable the PLL before potentially changing the input clocks. */
Expand Down Expand Up @@ -145,10 +175,6 @@ static int clock_control_wch_rcc_init(const struct device *dev)
RCC->INTR = RCC_CSSC | RCC_PLLRDYC | RCC_HSERDYC | RCC_LSIRDYC;
/* HCLK = SYSCLK = APB1 */
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_HPRE) | RCC_HPRE_DIV1;
#if defined(CONFIG_SOC_CH32V003)
/* Set the Flash to 0 wait state */
FLASH->ACTLR = (FLASH->ACTLR & ~FLASH_ACTLR_LATENCY) | FLASH_ACTLR_LATENCY_1;
#endif

return 0;
}
Expand Down
1 change: 1 addition & 0 deletions drivers/pinctrl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_WCH_AFIO pinctrl_wch_afio.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_SY1XX pinctrl_sy1xx.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_REALTEK_RTS5912 pinctrl_realtek_rts5912.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_WCH_20X_30X_AFIO pinctrl_wch_20x_30x_afio.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_WCH_00X_AFIO pinctrl_wch_00x_afio.c)

add_subdirectory(renesas)
1 change: 1 addition & 0 deletions drivers/pinctrl/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ source "drivers/pinctrl/Kconfig.wch_afio"
source "drivers/pinctrl/Kconfig.sy1xx"
source "drivers/pinctrl/Kconfig.realtek_rts5912"
source "drivers/pinctrl/Kconfig.wch_20x_30x_afio"
source "drivers/pinctrl/Kconfig.wch_00x_afio"

rsource "renesas/Kconfig"

Expand Down
9 changes: 9 additions & 0 deletions drivers/pinctrl/Kconfig.wch_00x_afio
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2025 Michael Hope <[email protected]>
# SPDX-License-Identifier: Apache-2.0

config PINCTRL_WCH_00X_AFIO
bool "WCH AFIO pin controller driver for CH32V00x"
default y
depends on DT_HAS_WCH_00X_AFIO_ENABLED
help
WCH CH32V00x AFIO pin controller driver, excluding the CH32V003.
Loading
Loading