リアルタイム・オペレーティング・システム
このセクションでは、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を実行する場合も同じ設定が適用されます。
Having enabled FreeRTOS in a project, navigate to the FREERTOS menu found under Middleware in the "Categories" list on the left side of the project menu in STM32CubeMX. TICK_RATE_HZ
を1000に設定して、1ミリ秒ごとにティックを取得します。 Memory Management scheme
とTOTAL_HEAP_SIZE
を設定します。 この例ではheap_4を使用し、ヒープ・サイズを70000バイトに設定して、TouchGFXアプリケーションに十分な大きさのヒープを確保します。
The required heap size depends on the application, as all software modules can allocate memory in the FreeRTOS heap.
A standard TouchGFX application generated with CubeMX allocates the following objects in the FreeRTOS heap:
Object | Size |
---|---|
Frame buffer semaphore | 80 bytes |
VSync message queue | 84 bytes |
TouchGFX task control block | 96 bytes |
TouchGFX task stack | 16,384 bytes |
Default task control block | 96 bytes |
Default task stack | 512 bytes |
Total | 17,252 bytes |
This can be reduced by lowering the stack size (see below).
The Default task is not used by TouchGFX, but is created by default by CubeMX. It can be deleted.
If your application is using the LIBJPEG middleware or software based MJPEG video with TouchGFX you need more heap space. LIBJPEG is allocating many objects in the heap during decompression. The LIBJPEG memory usage depends on the video or images decompressed (mostly resolution). For one of the videos available in the TouchGFX Designer of resolution 480*272, the memory used by LIBJPEG is 42,600 bytes.
Adding this number to the heap requirements gives:
Object | Size |
---|---|
Standard objects | 17,252 bytes |
LIBJPEG objects | 42,600 bytes |
Total | 59,852 bytes |
FreeRTOS aligns the heap array on 8-bytes in both ends (loosing a few bytes) and allocates a linked list of free blocks in the heap. So it is necessary to round up the calculated number a bit, for example to 60*1024 bytes.
Main loop
次の関数を呼び出すと、TouchGFXのメイン・ループに入ります。
void MX_TouchGFX_Process(void);
開発者は、TouchGFXのメイン・ループを実行するSTM32CubeMXで独自のカスタム・タスクを設定するか、TouchGFX Generatorによって生成されるTouchGFX_Task()
ハンドルを使用することができます。
カスタム・タスク
The function void touchgfx_taskEntry(void)
is called by MX_TouchGFX_Process()
.
void MX_TouchGFX_Process(void)
{
// Calling forward to touchgfx_taskEntry in C++ domain
touchgfx_taskEntry();
}
開発者はTouchGFXのメイン・ループを実行したいタスクのタスク・ハンドラ内で、MX_TouchGFX_Process()
をコールする必要があります。 If the developer has configured a FreeRTOS task in STM32CubeMX called MyTask
for instance, then the following example shows how MX_TouchGFX_Process()
should be called in the custom task handler to start TouchGFX.
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]に設定して十分な大きさのスタックを確保します。
Here we have configured a stack size of 4,096 words (equal to 16,384 bytes). The required stack size depends on the application (mostly on the number of widgets updated at the same time). A stack size of 2048 words is enough for most applications, and many can go even further down in stack size.
Tip
コードを生成すると、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
を定義します。