リアルタイム・オペレーティング・システム
このセクションでは、TouchGFX Generatorで生成されたコードとともに動作して、TouchGFX OSALが機能するように、STM32CubeMXでさまざまなリアルタイム・オペレーティング・システムを設定する方法について説明します。
通常、TouchGFXのメイン・ループはMX_TouchGFX_Process()
関数をコールすることで開始します。 この関数のコールは、開発者がTouchGFXを実行したいと考えるタスク・ハンドラ内で行う必要があります。
No OS
オペレーティング・システムなしでTouchGFXを実行する場合、TouchGFXのメイン・ループはmain()
内の無限のwhileループで実行され、ここでマイクロコントローラは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()
をコールします。ここでVSYNC
が検出されると、TouchGFXが次のフレームの処理を開始します。
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)
次の例は、TouchGFXで動作するようにFreeRTOS(CMSIS V2)を設定する方法を示しています。 CMSIS V1を実行する場合も同じ設定が適用されます。
プロジェクト内でFreeRTOSを有効化した後、STM32CubeMXのプロジェクト・メニューの左側にある[Categories]リストで、[Middleware]の下にある[FREERTOS]メニューに移動します。 TICK_RATE_HZ
を1000に設定して、1ミリ秒ごとにティックを取得します。 Memory Management scheme
とTOTAL_HEAP_SIZE
を設定します。 この例ではheap_4を使用し、ヒープ・サイズを70000バイトに設定して、TouchGFXアプリケーションに十分な大きさのヒープを確保します。
Tip
次の関数を呼び出すと、TouchGFXのメイン・ループに入ります。
void MX_TouchGFX_Process(void);
開発者は、TouchGFXのメイン・ループを実行するSTM32CubeMXで独自のカスタム・タスクを設定するか、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()
をコールする必要があります。 次の例は、開発者がSTM32CubeMXで、たとえばMyTask
という名前のFeeRTOSタスクを設定した場合に、TouchGFXを開始するためにカスタム・タスク・ハンドラ内でMX_TouchGFX_Process()
をコールする方法を示しています。
void StartMyTask(void *argument)
{
/* USER CODE BEGIN 5 */
MX_TouchGFX_Process();
/* USER CODE END 5 */
}
TouchGFXタスク
TouchGFXのメイン・ループはTouchGFXタスク内で実行できます。 TouchGFX Generatorはapp_touchgfx.c
内で、touchgfx_taskEntry()
をコールするTouchGFX_Task()
という名前のタスク・ハンドラを定義します。
app_touchgfx.c
void TouchGFX_Task(void *argument)
{
// Calling forward to touchgfx_taskEntry in C++ domain
touchgfx_taskEntry();
}
このタスクをFreeRTOSスケジューラによってスケジュールするには、STM32CubeMXの[FREERTOS]メニューでタスクを作成する必要があります。 [Tasks and Queues]タブで、[Entry Function]をTouchGFX_Taskに設定してタスクを追加し、[Code Generation Option]を[As external]に設定して十分な大きさのスタックを確保します。
コードを生成すると、STM32CubeMXによってmain.c
にTouchGFXタスクが作成され、これによってTouchGFXのメイン・ループが開始されます。
SYSタイムベース・ソースが常にティック(HAL_Delay()
などの一部のシステム関数で使用)を受信するためには、割り当てられたタイマのNVIC優先度が、安全なFreeRTOS API関数の割込みの呼出しをするために使用する最も高い割込み優先度よりも高い(つまり、番号が小さい)必要があります。 これは、FreeRTOS内のconfigMAX_SYSCALL_INTERRUPT_PRIORITY
で設定でき、デフォルトで5
に設定されます。 多くの場合、SYSタイムベース・ソースに使用されるタイマはTIM6
です。
ThreadX
このセクションでは、X-CUBEソフトウェア・パックまたはネイティブのThreadXミドルウェアとしてThreadXを使用して、TouchGFXプロジェクトを設定する方法について説明します。
ネイティブのミドルウェア設定
次の例は、STM32U5マイクロコントローラ用にThreadXを設定する方法を示しています。これにより、ThreadXがネイティブのミドルウェアとして使用できるようになります。
プロジェクト内でThreadのネイティブのミドルウェアを有効化した後、STM32CubeMXのプロジェクト・メニューの左側にある[Categories]リストで、[Middleware]の下にある[THREADX]メニューに移動します。 [Mode]リストでCore
を有効にします。 TX_TIMER_TICKS_PER_SECOND
を1000に設定して1ミリ秒ごとにティックするようにし、Memory Pool Allocation
を[Use Static Allocation]に設定します。
Caution
- [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の使用時にタスクの割り当てとスケジュールを行うコードを生成する役割はありません。 このため、TouchGFXフレームワークを初期化するMX_TouchGFX_PreOSInit()
関数へのコールは、STM32CubeMXによって生成されます。 その後、ThreadXカーネルを初期化して開始するMX_ThreadX_Init()
関数への別のコールが生成されます。
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()
をコールします。 このコードは、TouchGFXタスクのバイト・プールを定義されているapp_azure_rtos.cファイル内にあるtx_application_define()
関数の適切な位置に挿入されます。
tx_application_define()
関数は、初期化時にThreadXカーネルによってコールされます。 TouchGFXスレッドは、その後ThreadXカーネルが開始するときに開始されます。
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マイクロコントローラ用にThreadXを設定する方法を示しています。これにより、ThreadXがX-CUBEソフトウェア・パックとして使用できるようになります。
プロジェクト内でX-CUBEソフトウェア・パックを有効化した後、STM32CubeMXのプロジェクト・メニューの左側にある[Categories]リストで、[Software Packs]の下にある[X-CUBE-AZRTOS-XX]メニューに移動して、Memory Allocation
を[Use Static MemPool Allocation]に設定します。
[ThreadX]設定タブを選択し、TX_TIMER_TICKS_PER_SECOND
を1000に設定して、1ミリ秒ごとにティックするようにします。
[X-CUBE-AZRTOS-XX]メニューの設定が完了したら、TouchGFX Generatorに移動して、[Real Time Operating System]にThreadX
を選択し、TouchGFXタスクのMemory Pool Size
とMemory Stack Size
を定義します。