以沁恆的FreeRTOS示例項目為例, 說明如何在 CH32V208 評估上運行 FreeRTOS, 以及運行 FreeRTOS 涉及的庫文件改動. ...
目錄
- 沁恆 CH32V208(一): CH32V208WBU6 評估板上手報告和Win10環境配置
- 沁恆 CH32V208(二): CH32V208的儲存結構, 啟動模式和時鐘
- 沁恆 CH32V208(三): CH32V208 Ubuntu22.04 Makefile VSCode環境配置
- 沁恆 CH32V208(四): CH32V208 網路DHCP示例代碼分析
- 沁恆 CH32V208(五): CH32V208 運行FreeRTOS示例的說明
硬體部分
- CH32V208WBU6 評估板
- WCH-LinkE 或 WCH-Link
軟體部分
本節以沁恆的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 環境的配置
- 修改 Makefile 中的
USE_FREERTOS
選項, 設置為USE_FREERTOS ?= y
, 打開這個選項, 在編譯時會包含 FreeRTOS 庫相關文件 - 修改 Makefile 中的
AFILES := Libraries/Startup/startup_ch32v20x_D8W.S
, 將其替換為AFILES := Libraries/Startup/startup_ch32v20x_D8W_RTOS.S
後者禁用了硬體堆棧, 禁用了機器模式下的中斷, 如果不禁用, FreeRTOS 無法正常工作 - 清空 User 目錄, 將 FreeRTOS/Task/Blink 目錄下的文件複製到 User 目錄, 運行
make
編譯項目 - 連接好 WCH-Link 和 CH32V208 評估板, 運行
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 文件變動
在 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
804寄存器
CSR 0x804地址對應的是 INTSYSCR, 中斷系統控制寄存器. 青稞V4手冊第13頁.
位 | 名稱 | 讀寫 | 描述 | 複位值 |
---|---|---|---|---|
1 | INESTEN | RW | 中斷嵌套使能, 0:關閉, 1:開啟 | 0 |
0 | HWSTKEN | RW | 硬體壓棧使能, 0:關閉, 1:開啟 | 0 |
運行 FreeRTOS 時, 需要關閉硬體壓棧使能, 因此上面對 0x804 寫入 0x2.
mstatus寄存器
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] | -- |
- FS
用於描述和維護浮點單元狀態, 所以該域只有在含有硬體浮點功能的青稞 V4F 微處理器上才有意義. 當其值為 0 時, 表示浮點單元為關閉狀態, 且如果此時使用浮點指令, 將觸發異常;若其值為 1 或 2, 當執行了浮點指令後, 該域會被更新為 3. 若用戶在使用 V4F 微處理器時, 不期望使用硬體浮點功能, 可在機器模式下, 手動清除該兩位, 以關閉硬體浮點並降低功耗. - MPP
用於保存進入異常或中斷前的特權模式, 用於退出異常或中斷後的特權模式恢復 - MPIE
用於保存進入異常或中斷前的中斷使能狀態(MIE的值), 用於退出異常或中斷後中斷使能狀態恢復 - MIE
全局中斷使能位, 當進入異常或中斷時, MPIE 的值被更新為 MIE 值, 需要註意的是青稞 V4 在最後一級嵌套中斷前 MIE 不會被更新為 0, 以保證機器模式下的中斷嵌套繼續執行.
當退出異常或中斷後, 處理器恢復為 MPP 保存的機器模式, MIE 恢復為 MPIE 保存的使能狀態.
運行FreeRTOS時, 對 mstatus 使用 csrs 指令寫入 0x1800, 即將 MPP bit[12,11]設置為 0x11, 使其返回後始終保持在機器模式.
LD 腳本
需要增加 __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 任務
這部分就是正常的 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();
參考
- https://www.cnblogs.com/wchmcu/p/17390935.html
- https://www.eevblog.com/forum/microcontrollers/wch-0-10-risc-v-mcu/100/