Skip to content

Mac下开发沁恒CH32V2xx

CH32V微处理器沁恒是基于标准 RISC-V 指令集架构RV32IMAC的32 位通用 MCU 微处理器。 微处理器内含一个硬件调试模块,支持复杂的调试操作,调试模块遵循 RISC-V External Debug Support Version0.13.2 规范

但是

CH32V区别于标准的 RISC-V 定义的 JTAG 接口,其采用两线调试接口,是沁恒私有协议没有公开只能使用自家的 WCH_Link模块。WCH_Link固件没有开源,

调试CH32V微处理器只能通过openoc与WCH_Link,沁恒提供了 MAC 下的 Openocd 的二进制程序,使其在 Mac下调试成为可能。

工程目录结构

├── App                #应用程序
├── CH32F2xxSDK        #
├── CH32V2xxSDK        #
├── CMakeLists.text    
├── README.md
├── README_howto.md
├── cmake              #cmake工程配置环境、包括 arm,riscv 两种架构 
├── components         #基它部件如freertos\Fatfs
└── tools              #Openocd 二进制程序及相关的配置文件
├── App                #应用程序
├── CH32F2xxSDK        #
├── CH32V2xxSDK        #
├── CMakeLists.text    
├── README.md
├── README_howto.md
├── cmake              #cmake工程配置环境、包括 arm,riscv 两种架构 
├── components         #基它部件如freertos\Fatfs
└── tools              #Openocd 二进制程序及相关的配置文件

riscV 交叉编译器

  • 下载Mac交叉编译器xpack-riscv-none-elf-gcc-13.2.0-2-darwin-arm64.tar.gz

  • 配置环境变量 配置环境变量 RISCVGCC_DIR=~/.toolchain/xpack-riscv-none-elf-gcc-v13.2.0-2 具体位置依据你解压 copy的位置 cmake依赖该环境变量来查找riscv编译器。

配制openocd

将 tools/openocd_mac/openocd文件copy到与原始openocd 一起并改名为openocd_wch 如果你需要调试他家的ARM的MCU 需要拷贝tools/openocd_mac/ch32f1x.cfg 到openocd的target脚本目录

$ pwd
/opt/openocd/bin         #这个目录可能与你安装的位置不同
$ ls
openocd       openocd_wch   wch-arm.cfg   wch-riscv.cfg

$ cp tools/openocd_mac/ch32f1x.cfg /opt/openocd/share/openocd/scripts/target
#具体目录仍依赖 openocd的安装目录
$ pwd
/opt/openocd/bin         #这个目录可能与你安装的位置不同
$ ls
openocd       openocd_wch   wch-arm.cfg   wch-riscv.cfg

$ cp tools/openocd_mac/ch32f1x.cfg /opt/openocd/share/openocd/scripts/target
#具体目录仍依赖 openocd的安装目录

配置clion

  • 用clion打开工程(将目录拖放至clion)

  • 配置工具链

    打开设置>构建、执行、部署>工具链 依据下图添加配置项

  • 配置openocd_wch

    打开设置>构建、执行、部署>嵌入式开发 依据下图添加配置项

  • 调试配置

    打开设置>构建、执行、部署>运行/调试配置 依据下图添加配置项

编译下载执行

RISCV内核的CSR+GPR寄存器,可以用来观测内核状态,有几个寄存器在出现HARDFAULT 错误时可以帮助定位问题,在进入硬件错误中断处理函数时,mepc显示的是出错时的地址,mcause 显示的是原因,mtval 显示的是出错时cpu取到的值,mcause值含义如下图。

   uint32_t v_mepc,v_mcause,v_mtval;
    printf("hardfault\n");

    v_mepc=__get_MEPC();
    v_mcause=__get_MCAUSE();
    v_mtval=__get_MTVAL();

    printf("mepc:%08x\n",v_mepc);
    printf("mcause:%08x\n",v_mcause);
    printf("mtval:%08x\n",v_mtval);
    while(1);v
   uint32_t v_mepc,v_mcause,v_mtval;
    printf("hardfault\n");

    v_mepc=__get_MEPC();
    v_mcause=__get_MCAUSE();
    v_mtval=__get_MTVAL();

    printf("mepc:%08x\n",v_mepc);
    printf("mcause:%08x\n",v_mcause);
    printf("mtval:%08x\n",v_mtval);
    while(1);v