CH592 Setup

2025-07-30

Hardware Setup

The files currently target the ch582f chip, they will be updated in due course. But the chips are basically identical.

We'll use the WeActStudio CH592F board. To flash the chip, use WCH-Link debugger probe, available on Aliexpress. They come in various versions, for our purpose the old ch549 based one is adequate.

Fix permissions

On Linux, to access the debugger without sudo access you need the following files.

/etc/udev/rules.d/50-wchlink.rules:

# 1a86:8010 WCH Link
SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="8010", OWNER="username"

/etc/udev/rules.d/50-usb-serial.rules:

SUBSYSTEM=="tty", SUBSYSTEMS=="usb", OWNER="username"

Note to replace username. You may have to use relevant idVendor and idProduct if you're using a different hardware version. Run dmesg to find out.

Attach the probe

You need four wires to hook the mcu to the probe.

TCK - PB15

TIO - PB14

And 3V3, GND, power lines.

debugger-attached

Before using a probe, the icsp must be enabled on the target chip! As the factory setting is to disable by default.

To enable debug use wchisp. Connect the board direct via USB and wchisp config enable-debug.

Use wlink to program. Run wlink status and it should detect the chip.

Install the toolchain

Download MRS Toolchain. Then extract it. You can do this by (current version V210 as of this writing, otherwise change it):

# cd to downloaded directory
mkdir -p $HOME/.local/opt
tar xvf MRS_Toolchain_Linux_x64_V210.tar.xz -C $HOME/.local/opt

Next, add these programs to your $PATH. For bash users, this can typically be accomplished by:

echo 'export PATH=$HOME/.local/opt/MRS_Toolchain_Linux_x64_V210/RISC-V\ Embedded\ GCC/bin/:$HOME/.local/opt/MRS_Toolchain_Linux_x64_V210/OpenOCD/OpenOCD/bin/:$PATH' >> $HOME/.bashrc

The following Makefiles assume you have this installed.

Also make sure you have make and git installed on your system.

Setting up our Makefile SDK

The SDK is provided in Github. The vendor's library is located in EVT/EXAM/SRC/ directory. Create a workspace directory for our projects and put the contents into a dir named vendor. The workspace directory should look like this.

.
├── ble-lib
│   ├── HAL
│   │   ├── include
│   │   │   ├── CONFIG.h
│   │   │   ├── HAL.h
│   │   │   ├── KEY.h
│   │   │   ├── LED.h
│   │   │   ├── RTC.h
│   │   │   └── SLEEP.h
│   │   ├── KEY.c
│   │   ├── LED.c
│   │   ├── MCU.c
│   │   ├── RTC.c
│   │   └── SLEEP.c
│   ├── LIB
│   │   ├── CH58xBLE_LIB.h
│   │   ├── CH58xBLE_ROM.h
│   │   ├── CH58xBLE_ROM.hex
│   │   ├── CH58xBLE_ROMx.hex
│   │   └── LIBCH58xBLE.a
│   └── LWNS
│       ├── LIBWCHLWNS.a
│       └── WCH_LWNS_LIB.h
├── myapps
│   └── blinky
│       ├── Makefile
│       └── src
│           └── main.c
└── vendor
    ├── Ld
    │   └── Link.ld
    ├── RVMSIS
    │   ├── core_riscv.c
    │   └── core_riscv.h
    ├── Startup
    │   └── startup_CH583.S
    └── StdPeriphDriver
        ├── CH58x_adc.c
        ├── CH58x_clk.c
        ├── CH58x_flash.c
        ├── CH58x_gpio.c
        ├── CH58x_i2c.c
        ├── CH58x_pwm.c
        ├── CH58x_pwr.c
        ├── CH58x_spi0.c
        ├── CH58x_spi1.c
        ├── CH58x_sys.c
        ├── CH58x_timer0.c
        ├── CH58x_timer1.c
        ├── CH58x_timer2.c
        ├── CH58x_timer3.c
        ├── CH58x_uart0.c
        ├── CH58x_uart1.c
        ├── CH58x_uart2.c
        ├── CH58x_uart3.c
        ├── CH58x_usb2dev.c
        ├── CH58x_usb2hostBase.c
        ├── CH58x_usb2hostClass.c
        ├── CH58x_usbdev.c
        ├── CH58x_usbhostBase.c
        ├── CH58x_usbhostClass.c
        ├── inc
        │   ├── CH583SFR.h
        │   ├── CH58x_adc.h
        │   ├── CH58x_clk.h
        │   ├── CH58x_common.h
        │   ├── CH58x_flash.h
        │   ├── CH58x_gpio.h
        │   ├── CH58x_i2c.h
        │   ├── CH58x_pwm.h
        │   ├── CH58x_pwr.h
        │   ├── CH58x_spi.h
        │   ├── CH58x_sys.h
        │   ├── CH58x_timer.h
        │   ├── CH58x_uart.h
        │   ├── CH58x_usbdev.h
        │   ├── CH58x_usbhost.h
        │   └── ISP583.h
        └── libISP583.a

Don't concern about the ble-lib folder. But it should have vendor and myapps which we'll now create.

The contents of the Makefile and main.c are as follows. (We'll study them in the following article)

main.c:


#include "CH58x_common.h"

void board_led_init(void)
{
    GPIOA_SetBits(GPIO_Pin_8);
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeOut_PP_5mA);
}

void board_led_toggle(void)
{
    GPIOA_InverseBits(GPIO_Pin_8);
}

void board_led_set(uint8_t set)
{
    if (set)
        GPIOA_ResetBits(GPIO_Pin_8);
    else
        GPIOA_SetBits(GPIO_Pin_8);
}

int main()
{
    uint8_t s;
    SetSysClock(CLK_SOURCE_PLL_60MHz);

    board_led_init();

    while(1)
    {
      mDelaymS(100);
      board_led_toggle(); 
      mDelaymS(100);
    }
}

Makefile:

######################################
# target
######################################
TARGET = ch582_blinky
# ../../


######################################
# building variables
######################################
# debug build?
DEBUG = 1
# optimization for size
OPT = -Os


#######################################
# paths
#######################################
# Build path
BUILD_DIR = build

######################################
# source
######################################
# C sources
C_SOURCES = \
src/main.c \
../../vendor/StdPeriphDriver/CH58x_clk.c \
../../vendor/StdPeriphDriver/CH58x_gpio.c \
../../vendor/StdPeriphDriver/CH58x_pwr.c \
../../vendor/StdPeriphDriver/CH58x_sys.c \
../../vendor/RVMSIS/core_riscv.c \


# ASM sources
ASM_SOURCES =  \
../../vendor/Startup/startup_CH583.S

#######################################
# binaries
#######################################
#PREFIX = riscv-none-elf-
#PREFIX = riscv64-elf-
PREFIX = riscv-wch-elf-

CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size

HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S

#######################################
# CFLAGS
#######################################
# cpu
CPU = -march=rv32imac_zicsr -mabi=ilp32 -msmall-data-limit=8 

# For gcc version less than v12
# CPU = -march=rv32imac -mabi=ilp32 -msmall-data-limit=8

# fpu
FPU = 

# float-abi
FLOAT-ABI =

# mcu
MCU = $(CPU) $(FPU) $(FLOAT-ABI)

# AS includes
AS_INCLUDES = 

# C includes
C_INCLUDES =  \
-I../../vendor/StdPeriphDriver/inc \
-I../../vendor/RVMSIS \
-I../../vendor/Core \
-Isrc/include

# compile gcc flags
ASFLAGS = $(MCU) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

CFLAGS = $(MCU) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif


# Generate dependency information
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"


#######################################
# LDFLAGS
#######################################
# link script
LDSCRIPT = ../../vendor/Ld/Link.ld 

# libraries
LIBS = -lc -lm -lnosys ../../vendor/StdPeriphDriver/libISP583.a
LIBDIR = 
LDFLAGS = $(MCU) -mno-save-restore -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -Wunused -Wuninitialized -T $(LDSCRIPT) -nostartfiles -Xlinker --gc-sections -Wl,-Map=$(BUILD_DIR)/$(TARGET).map --specs=nano.specs $(LIBS)

# default action: build all
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin


#######################################
# build the application
#######################################
# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))

# list of ASM program objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.S=.o)))
vpath %.S $(sort $(dir $(ASM_SOURCES)))

$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
	$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@

$(BUILD_DIR)/%.o: %.S Makefile | $(BUILD_DIR)
	$(AS) -c $(CFLAGS) $< -o $@
#$(LUAOBJECTS) $(OBJECTS)
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
	$(CC) $(OBJECTS) $(LDFLAGS) -o $@
	$(SZ) $@

$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(HEX) $< $@
	
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(BIN) $< $@	
	
$(BUILD_DIR):
	mkdir $@		

#######################################
# Program
#######################################

flash: $(BUILD_DIR)/$(TARGET).bin
	wlink flash $(BUILD_DIR)/$(TARGET).bin

#######################################
# clean up
#######################################
clean:
	-rm -fR $(BUILD_DIR)
  
#######################################
# dependencies
#######################################
-include $(wildcard $(BUILD_DIR)/*.d)

# *** EOF ***

Building our first example

The example project we created is a blinky example. Run make to build. Assuming you have the toolchain correctly installed it should succeed. Now run

wlink flash build/ch582_blinky.bin