本节以沁恒的FreeRTOS示例项目为例进行说明.
示例代码位于 CH32V20xEVT 压缩包的 EVT/EXAM/FreeRTOS 目录.
对应 GCC 环境的项目代码位于 https://github.com/IOsetting/ch32v208-template/tree/main/Examples/FreeRTOS/Task/Blink
青稞V4的手册下载地址 https://www.wch.cn/downloads/QingKeV4_Processor_Manual_PDF.html
这里只介绍 GCC & Makefile 环境的编译和烧录. 参考上一节进行 GCC 环境的配置
USE_FREERTOS
选项, 设置为USE_FREERTOS ?= y
, 打开这个选项, 在编译时会包含 FreeRTOS 库相关文件AFILES := Libraries/Startup/startup_ch32v20x_D8W.S
, 将其替换为 AFILES := Libraries/Startup/startup_ch32v20x_D8W_RTOS.S
后者禁用了硬件堆栈, 禁用了机器模式下的中断, 如果不禁用, FreeRTOS 无法正常工作make
编译项目make flash
烧录将 PA0, PA1 分别连接到 LED1 和 LED2, 观察两个GPIO任务的输出.
将评估板的串口输出连接到 WCH-Link, 在PC端使用串口工具, 波特率115200打开 /dev/ttyACM0 观察两个GPIO任务的printf输出
运行时, 除了 LED1 间隔半秒 和 LED2 间隔一秒闪烁外, 串口会打印以下内容(忽略其中的时间戳部分)
SystemClk:96000000 FreeRTOS Kernel Version:V10.4.6 task2 entry task1 entry 32:33.611 task1 entry 32:34.611 task2 entry task1 entry 32:35.611 task1 entry 32:36.610 task2 entry task1 entry 32:37.611 task1 entry 32:38.611 task2 entry task1 entry 32:39.611 task1 entry
CH32V20x 运行 FreeRTOS 时不支持硬件压栈, 中断只能使用软件压栈
在无系统场景时的中断处理
void NMI_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); void HardFault_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
就要换成不带WCH-Interrupt-fast
的中断处理
void NMI_Handler(void) __attribute__((interrupt())); void HardFault_Handler(void) __attribute__((interrupt()));
在 startup 文件中需要禁用硬件堆栈, 并在机器模式下禁用中断,
在无系统场景时的 0x804 和 mstatus 设置
/* Enable nested and hardware stack */ li t0, 0x3 csrw 0x804, t0 /* Enable interrupt */ li t0, 0x88 csrs mstatus, t0
就要替换为下面的设置
/* Enable nested stack, no hardware stack */ li t0, 0x2 csrw 0x804, t0 /* Machine mode, no interrupt */ li t0, 0x1800 csrs mstatus, t0
CSR 0x804地址对应的是 INTSYSCR, 中断系统控制寄存器. 青稞V4手册第13页.
位 | 名称 | 读写 | 描述 | 复位值 |
---|---|---|---|---|
1 | INESTEN | RW | 中断嵌套使能, 0:关闭, 1:开启 | 0 |
0 | HWSTKEN | RW | 硬件压栈使能, 0:关闭, 1:开启 | 0 |
运行 FreeRTOS 时, 需要关闭硬件压栈使能, 因此上面对 0x804 写入了 0x2.
mstatus 是 机器模式状态寄存器, 青稞V4手册第30页, 每一位的定义为
位 | 名称 | 读写 | 描述 | 复位值 |
---|---|---|---|---|
[31:15] | -- | |||
[14:13] | FS | RW | 浮点单元状态, 00:OFF, 01:Initial, 10:Clean, 11:Dirty | 00 |
[12:11] | MPP | RW | 进中断前特权模式 | 00 |
[10:8] | -- | |||
[7] | MPIE | RW | 进中断之前中断使能状态 | 00 |
[6:4] | -- | |||
[3] | MIE | RW | 机器模式中断使能 | 00 |
[2:0] | -- |
运行FreeRTOS时, 需要将 mstatus 设为 0x1800:
需要增加 __freertos_irq_stack_top
锚定栈顶地址
.stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : { PROVIDE( _heap_end = . ); . = ALIGN(4); PROVIDE(_susrstack = . ); . = . + __stack_size; PROVIDE( _eusrstack = .); __freertos_irq_stack_top = .; } >RAM
这部分就是正常的 FreeRTOS 调用了
xTaskCreate((TaskFunction_t )task2_task, (const char* )"task2", (uint16_t )TASK2_STK_SIZE, (void* )NULL, (UBaseType_t )TASK2_TASK_PRIO, (TaskHandle_t* )&Task2Task_Handler); xTaskCreate((TaskFunction_t )task1_task, (const char* )"task1", (uint16_t )TASK1_STK_SIZE, (void* )NULL, (UBaseType_t )TASK1_TASK_PRIO, (TaskHandle_t* )&Task1Task_Handler); vTaskStartScheduler();