沁恆 CH32V208(五): CH32V208 執行FreeRTOS範例的說明

2023-05-16 06:00:20

目錄

硬體部分

  • 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 環境的設定

  1. 修改 Makefile 中的 USE_FREERTOS 選項, 設定為USE_FREERTOS ?= y, 開啟這個選項, 在編譯時會包含 FreeRTOS 庫相關檔案
  2. 修改 Makefile 中的 AFILES := Libraries/Startup/startup_ch32v20x_D8W.S, 將其替換為 AFILES := Libraries/Startup/startup_ch32v20x_D8W_RTOS.S 後者禁用了硬體堆疊, 禁用了機器模式下的中斷, 如果不禁用, FreeRTOS 無法正常工作
  3. 清空 User 目錄, 將 FreeRTOS/Task/Blink 目錄下的檔案複製到 User 目錄, 執行 make 編譯專案
  4. 連線好 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 設為 0x1800:

  • 僅工作在機器模式, 把 MPP 設定為 0x11 (對應[12,11]), 使其返回後始終保持在機器模式.
  • 在機器模式禁用中斷使能, MIE (對應[3]) 設為 0

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();

參考