跳轉到主要內容

即時作業系統

本節說明如何在STM32CubeMX設定不同的即時作業系統,以搭配使用TouchGFX Generator產生的程式碼,實現可正常運作的TouchGFX OSAL。

一般來說,TouchGFX主迴圈是以呼叫MX_TouchGFX_Process()函數的方式啟動。 呼叫此函數的位置,應該位在開發人員執行TouchGFX的工作處理常式內部。

無OS

TouchGFX在沒有作業系統的情況下執行時,TouchGFX主迴圈會在main()執行無限的While迴圈,其中MCU會呼叫MX_TouchGFX_Process()以共用VSYNC訊號。

main.c
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
MX_TouchGFX_Process();
/* USER CODE BEGIN 3 */
}

MX_TouchGFX_Process()呼叫轉送至touchgfx_taskEntry(),其中TouchGFX會在偵測到VSYNC時開始處理下一個畫面。

TouchGFXConfiguration.cpp
void touchgfx_taskEntry()
{
/*
* Main event loop will check for VSYNC signal, and then process next frame.
*
* 請注意如果沒有VSYNC訊號,此函數會立即傳回。
*/
if (OSWrappers::isVSyncAvailable())
{
hal.backPorchExited();
}
}

FreeRTOS (CMSIS V1及CMSIS V2)

以下範例顯示如何設定FreeRTOS (CMSIS V2)以搭配使用TouchGFX。 執行CMSIS V1時也適用相同設定。

在專案中啟用FreeRTOS,導覽至STM32CubeMX專案選單左側「Categories」(類別)清單之中Middleware (中介軟體)之下的FREERTOS選單。 將TICK_RATE_HZ設定為1000,也就是每毫秒一個時標。 設定Memory Management scheme (記憶體管理配置)及TOTAL_HEAP_SIZE。 我們在此範例中使用heap_470000位元組的堆積大小,讓堆積足以因應TouchGFX應用程式需求。

為FreeRTOS建立TouchGFX工作

Tip
您可針對特定應用程式反覆試驗,找出更理想的TOTAL_HEAP_SIZE

呼叫下列函數時會進入TouchGFX主迴圈。

void MX_TouchGFX_Process(void);

開發人員可在STM32CubeMX設定自己的客製工作,讓TouchGFX主迴圈在其中執行,或使用TouchGFX Generator產生的TouchGFX_Task()控制代碼。

客製工作

函數void touchgfx_taskEntry(void)會由MX_TouchGFX_Process()呼叫。

void MX_TouchGFX_Process(void)
{
// Calling forward to touchgfx_taskEntry in C++ domain
touchgfx_taskEntry();
}

開發人員必須在打算執行TouchGFX主迴圈的工作中,於工作處理常式呼叫MX_TouchGFX_Process()。 舉例來說,如果開發人員在名為MyTask的STM32CubeMX之中設定了FeeRTOS工作,以下範例顯示應如何在客製工作處理常式中呼叫MX_TouchGFX_Process(),以便啟動TouchGFX。

void StartMyTask(void *argument)
{
/* USER CODE BEGIN 5 */
MX_TouchGFX_Process();
/* USER CODE END 5 */
}

TouchGFX工作

TouchGFX主迴圈可於TouchGFX Task (TouchGFX工作)中執行。 TouchGFX Generator會定義工作處理常式以呼叫名為TouchGFX_Task()touchgfx_taskEntry(),位於app_touchgfx.c內部。

app_touchgfx.c
void TouchGFX_Task(void *argument)
{
// Calling forward to touchgfx_taskEntry in C++ domain
touchgfx_taskEntry();
}

如果要利用FreeRTOS排程器排程此項工作,就必須在STM32CubeMX的FREERTOS選單中建立工作。 在Tasks and Queues (工作及佇列)索引標籤,新增工作以「TouchGFX_Task」作為Entry Function,並且要有夠大的堆疊,其中的Code Generation Option (程式碼產生選項)要設定為As external (外部)。

為FreeRTOS建立TouchGFX工作

STM32CubeMX將在產生程式碼時於main.c建立TouchGFX工作,用於啟動TouchGFX主迴圈。

ThreadX

本節說明如何使用ThreadX作為X-CUBE套裝軟體或原生ThreadX中介軟體以設定TouchGFX專案。

原生中介軟體設定

以下範例顯示如何為STM32U5 MCU設定ThreadX,其中ThreadX可作為原生中介軟體使用。

在專案中啟用執行緒原生中介軟體,導覽至STM32CubeMX專案選單左側「Categories」(類別)清單中Middleware (中介軟體)之下的THREADX選單。 啟用Core (核心):請由Mode (模式)清單啟用。 將TX_TIMER_TICKS_PER_SECOND設定為1000,也就是每毫秒一個時標,然後將Memory Pool Allocation (記憶體集區分配)設定為Use Static Allocation (使用靜態分配)。

啟用及設定原生ThreadX中介軟體

Caution
  • STM32CubeMX只有在使用原生ThreadX中介軟體時,在Memory Pool Allocation (記憶體集區分配)設定為Use Static Allocation (使用靜態分配)的情況下,才會產生完整的OSAL
    • 如果Memory Pool Allocation (記憶體集區分配)設定為Use Dynamic Allocation (使用動態分配),則:
      • 使用者必須在產生的app_azure_rtos.c檔案中,於USER CODE BEGIN DYNAMIC_MEM_ALLOC區段新增缺失的程式碼。
      • 使用者還需要根據產生的app_azure_rtos.c檔案中程式碼註解所說明的建議更新連結器檔案。
      • 視STM32CubeMX版本而定,Dynamic Allocation (動態分配)可能無法正常運作。

    STM32CubeMX並不負責產生程式碼,在使用ThreadX時分配及排程工作。 因此呼叫函數MX_TouchGFX_PreOSInit()用於初始化TouchGFX架構時,將由STM32CubeMX產生該呼叫。 在此之後,將會產生另一次呼叫,以呼叫函數MX_ThreadX_Init()初始化及啟動ThreadX核心。

    main.c
    int main(void)
    {
    ...
    /* Call PreOsInit function */
    MX_TouchGFX_PreOSInit();
    ...
    MX_ThreadX_Init();
    ...
    }

    TouchGFX Generator將產生MX_TouchGFX_Init()函數,用於建立TouchGFX執行緒。

    app_touchgfx.c
    UINT MX_TouchGFX_Init(VOID *memory_ptr)
    {
    UINT ret = TX_SUCCESS;
    CHAR *pointer = 0;

    /* Allocate the stack for TouchGFX Thread. */
    if (tx_byte_allocate((TX_BYTE_POOL*)memory_ptr, (VOID **) &pointer,
    TOUCHGFX_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS)
    {
    ret = TX_POOL_ERROR;
    }

    /* Create TouchGFX Thread */
    else if (tx_thread_create(&TouchGFXThread, (CHAR *)"TouchGFX", TouchGFX_Task, 0,
    pointer, TOUCHGFX_STACK_SIZE,
    5, 5,
    TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS)
    {
    ret = TX_THREAD_ERROR;
    }

    return ret;
    }

    TouchGFX Generator接著將產生程式碼,以建立TouchGFX工作位元組集區,並呼叫MX_TouchGFX_Init()。 此程式碼將插入至函數tx_application_define()的適當位置;該函數位於app_azure_rtos.c檔案之中,TouchGFX工作位元組集區就是在此定義。

    tx_application_define()函數是由ThreadX核心在初始化時間呼叫。 ThreadX核心啟動時,TouchGFX執行緒會稍後啟動。

    app_azure_rtos.c
    #include "app_touchgfx.h"
    ...
    __ALIGN_BEGIN static UCHAR touchgfx_byte_pool_buffer[TOUCHGFX_APP_MEM_POOL_SIZE] __ALIGN_END;
    static TX_BYTE_POOL touchgfx_app_byte_pool;
    ...
    VOID tx_application_define(VOID *first_unused_memory)
    {
    ...
    if (tx_byte_pool_create(&touchgfx_app_byte_pool, "TouchGFX App memory pool", touchgfx_byte_pool_buffer, TOUCHGFX_APP_MEM_POOL_SIZE) != TX_SUCCESS)
    {
    /* USER CODE BEGIN TouchGFX_Byte_Pool_Error */

    /* USER CODE END TouchGFX_Byte_Pool_Error */
    }
    else
    {
    /* USER CODE BEGIN TouchGFX_Byte_Pool_Success */

    /* USER CODE END TouchGFX_Byte_Pool_Success */

    memory_ptr = (VOID *)&touchgfx_app_byte_pool;
    if (MX_TouchGFX_Init(memory_ptr) != TX_SUCCESS)
    {
    /* USER CODE BEGIN MX_X-CUBE-TOUCHGFX_Init_Error */

    /* USER CODE END MX_X-CUBE-TOUCHGFX_Init_Error */
    }
    /* USER CODE BEGIN MX_X-CUBE-TOUCHGFX_Init_Success */

    /* USER CODE END MX_X-CUBE-TOUCHGFX_Init_Success */
    }

    ...
    }

    X-CUBE-AZRTOS設定

    以下範例顯示如何為STM32H7 MCU設定ThreadX,其中ThreadX可作為X-CUBE套裝軟體使用。

    在專案中啟用執行緒作為X-CUBE套裝軟體,導覽至STM32CubeMX專案選單左側「Categories」(類別)清單Software Packs (套裝軟體)之下的X-CUBE-AZRTOS-XX選單,並將Memory Allocation (記憶體分配)設定為Use Static MemPool Allocation (使用靜態記憶體集區分配)。

    ThreadX設定:X-CUBE-AZRTOS套裝軟體

    選擇ThreadX設定索引標籤,將TX_TIMER_TICKS_PER_SECOND設定為1000,也就是每毫秒一個時標。

    ThreadX設定:X-CUBE-AZRTOS套裝軟體

    X-CUBE-AZRTOS-XX選單完成設定後,請導覽至TouchGFX Generator選擇ThreadX作為Real Time Operating System (即時作業系統),並為TouchGFX工作定義Memory Pool Size (記憶體集區大小)和Memory Stack Size (記憶體堆疊大小)。

    為FreeRTOS建立TouchGFX工作

    Caution
    可惜的是根據TouchGFX 4.21.0,最新版X-CUBE-AZRTOS-XX產生的程式碼,將無法在ThreadX驅動程式建立及初始化TouchGFX工作。 開發人員需要手動新增程式碼:由原生中介軟體設定區段顯示的程式碼片段新增,才能讓應用程式正常運作。