2022年8月9日星期二

[STM32] FreeRTOS 手動移植至 CubeIDE 過程記錄

FreeRTOS 是一種即時作業系統,非常適用於微控制器應用。當然 STM32 也是在其中最適合於 FreeRTOS 操作的微控制器,這次來介紹 CubeIDE 環境中如何手動加入 FreeRTOS 系統。這次使用的開發板是 NUCLEO-L476RG,IDE 是 CubeIDE。

下載 FreeRTOS

在 FreerRTOS (https://www.freertos.org/) 直接下載,目前是 FreeRTOSv202112.00 這個版本

STM32,FreeRTOS

建構 FreeRTOS

下載後,解開壓縮檔。有幾個資料夾及檔案 (FreeRTOS,FreeRTOS-Plus,tools .....etc),我們只要 " FreeRTOS " 這個資料夾及內容。我採取的是刪除法,先建立一個空的資料夾,然後將 FreeRTOS 複製到剛建立的資料夾內。

複製完成後,直接在這個臨時資料夾內操作。

FreeRTOS 資料夾內有 Demo , License , Source , Test 等等內容。保留 License , Source,其他都刪除。

直接到 Source\portable 內 ,保留 GCC , 及 MemMang 這兩個資料夾,其他刪除。

L476RG 是個 M4 及含 FPU 運算的微控制器,所以

在 Source\portable\GCC 內, 只保留 ARM_CM4F 資料夾。

回到 MemMang 內
保留 heap_4.c , 其餘刪除

到這裡我們需要的檔案已經完成了。

CubeIDE 開啟新專案

我們設定 2 個 GPIO-OUT , 分別是 LD1 & LD2

STM32,FreeRTOS

在 NVIC 中斷設定, 優先權設為 NVIC_PriorityGroup_4

STM32,FreeRTOS

接著產生 BSP code。

調整

產生 BSP code 後,開始做相對應的設定。
複製 FreeRTOS code。

在 "建構 FreeRTOS" 所以建立的資料夾, 直接用拖拉的方式。複製到 CubeIDE 左側的 Project Exploper。

STM32,FreeRTOS

開啟 Project / Properties 對話框

找 C/C++ General / Paths and Symbols , 分別在 Includes , Source Location 這兩個標籤 (Tab) 設定

Includes :

FreeRTOS/Source/include
FreeRTOS/Source/portable/GCC/ARM_CM4F

STM32,FreeRTOS

Source Location :

加入 FreeRTOS/Source

STM32,FreeRTOS

修改 stm32l4xx_it.c


void SysTick_Handler(void)
void PendSV_Handler(void)
void SVC_Handler(void)

3個 function 用 /**/ 注釋掉

建立 FreeRTOSConfig.h


在 FreeRTOS 中找到
FreeRTOS/Demo/CORTEX_M4F_STM32F407ZG-SK/ FreeRTOSConfig.h
複製到 專案資料夾的 Core/Inc 內


內容做小修改


#ifdef __ICCARM__
    #include 
    extern uint32_t SystemCoreClock;
#endif

改成符合 CubeIDE


#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
    #include 
    extern uint32_t SystemCoreClock;
#endif

以下 2 個參數改為 0


#define configUSE_IDLE_HOOK                0
#define configUSE_TICK_HOOK                0

範例: 測試點亮 LED

到這裡, 開始寫 code
首先在 main() 前複製 這 2 個空 function


void vApplicationMallocFailedHook( void )
{
    /* vApplicationMallocFailedHook() will only be called if
    configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
    function that will get called if a call to pvPortMalloc() fails.
    pvPortMalloc() is called internally by the kernel whenever a task, queue,
    timer or semaphore is created.  It is also called by various parts of the
    demo application.  If heap_1.c or heap_2.c are used, then the size of the
    heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
    FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
    to query the size of free heap space that remains (although it does not
    provide information on how the remaining heap might be fragmented). */
    taskDISABLE_INTERRUPTS();


    for( ;; );
}




void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
{
    /* This function will get called if a task overflows its stack.   If the
    parameters are corrupt then inspect pxCurrentTCB to find which was the
    offending task. */


    ( void ) pxTask;
    ( void ) pcTaskName;


    for( ;; );
}

我們有 2 個 LED , 所以分別用 2 個 Thread 控制


static void Blink1_Task(void *pvParameters)
{
TickType_t xlastFlashTime;
xlastFlashTime = xTaskGetTickCount();


while(1){
     vTaskDelayUntil(&xlastFlashTime,500);


     HAL_GPIO_TogglePin(GPIOA, LD1_Pin);


}


}


static void Blink2_Task(void *pvParameters)
{
TickType_t xlastFlashTime;
xlastFlashTime = xTaskGetTickCount();


while(1){
     vTaskDelayUntil(&xlastFlashTime,500);


     HAL_GPIO_TogglePin(GPIOA, LD2_Pin);


}


}

在 main()


  xTaskCreate(Blink1_Task,"Blink1",128,NULL,1,NULL);
  xTaskCreate(Blink2_Task,"Blink2",128,NULL,2,NULL);
  vTaskStartScheduler();

執行效果是這 2 個 LED 看起來會像是同時間點亮。


範例 Source code 放在 Github,
https://github.com/cold63/STM32_Code/tree/master/Freertos_M4F