Real Time Operating System
이 섹션에서는 기능하는 TouchGFX OSAL을 갖도록 TouchGFX Generator에서 생성된 코드와 함께 작동하도록 STM32CubeMX에서 다양한 실시간 운영 체제를 구성하는 방법을 보여줍니다.
일반적으로 TouchGFX 메인 루프는 MX_TouchGFX_Process()
함수를 호출하는 것으로 시작됩니다. 이 함수에 대한 호출은 개발자가 TouchGFX를 실행하려고 하는 작업 핸들러 내부에 있어야 합니다.
No OS
TouchGFX가 운영 체제 없이 실행될 때 TouchGFX 메인 루프는 MCU가 MX_TouchGFX_Process()
를 호출하여 VSYNC
신호를 풀링하는 main()
의 무한 while 루프에서 실행됩니다.
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.
*
* Note This function returns immediately if there is no VSYNC signal.
*/
if (OSWrappers::isVSyncAvailable())
{
hal.backPorchExited();
}
}
FreeRTOS(CMSIS V1 & CMSIS V2)
다음 예제는 FreeRTOS(CMSIS V2)가 TouchGFX에서 작동하도록 구성하는 방법을 보여줍니다. 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으로 설정합니다. Memory Management scheme
및 TOTAL_HEAP_SIZE
를 구성합니다. 이 예제에서는 touchgfx 애플리케이션에서 충분히 큰 힙을 갖도록 heap_4와 힙 크기 70000바이트를 사용하고 있습니다.
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()
핸들을 사용할 수 있습니다.
Custom 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 Task에서 실행될 수 있습니다. TouchGFX Generator는 app_touchgfx.c
내에서 TouchGFX_Task()
라는 touchgfx_taskEntry()
를 호출하는 작업 핸들러를 정의합니다.
app_touchgfx.c
void TouchGFX_Task(void *argument)
{
// Calling forward to touchgfx_taskEntry in C++ domain
touchgfx_taskEntry();
}
FreeRTOS 스케줄러에서 이 작업을 예약하려면 FREERTOS 메뉴의 STM32CubeMX에서 작업을 생성해야 합니다. Tasks and Queues 탭에서 "TouchGFX_Task"가 Entry Function이고, 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 Task를 생성하여 TouchGFX 메인 루프를 시작합니다.
HAL_Delay()
를 포함하는 일부 시스템 함수에서 사용하는 SYS Timebase Source가 항상 tick을 받을 수 있도록 하려면 할당된 타이머의 NVIC 우선순위가 안전한 FreeRTOS API 함수를 인터럽트하는 호출을 생성할 때 사용하는 최고 인터럽트 우선순위보다 높아야 합니다(예: 더 낮은 숫자 ). 이는 FreeRTOS에서 configMAX_SYSCALL_INTERRUPT_PRIORITY
로 구성할 수 있으며 기본적으로 5
로 설정됩니다. 대부분의 경우 SYS Timebase Source에 사용하는 타이머는 TIM6
입니다.
ThreadX
이 섹션에서는 ThreadX를 X-CUBE Software Pack이나 Native ThreadX Middleware를 사용해서 TouchGFX 프로젝트를 구성하는 방법을 보여줍니다.
Native Middleware 구성
다음 예제는 ThreadX를 네이티브 미들웨어로 사용할 수 있도록 STM32U5 MCU에 대해 ThreadX를 구성하는 방법을 보여줍니다.
프로젝트에서 Thread 네이티브 미들웨어 활성화를 수행하면 STM32CubeMX의 프로젝트 메뉴 왼쪽에 있는 "Categories" 목록의 Middleware 아래에 있는 THREADX 메뉴로 이동합니다. Mode 목록에서 Core
를 활성화합니다. TX_TIMER_TICKS_PER_SECOND
를 1000으로 설정해서 밀리 초마다 한 번씩 틱을 발생시키고, 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는 TouchGFX 스레드를 생성하는 MX_TouchGFX_Init()
함수를 생성합니다.
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 Task 바이트 풀이 정의된 app_azure_rtos.c 파일에서 함수 tx_application_define()
의 해당 위치에 삽입됩니다.
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 구성
다음 예제는 ThreadX를 X-CUBE Software Pack으로 사용할 수 있도록 STM32H7 MCU에 대해 ThreadX를 구성하는 방법을 보여줍니다.
프로젝트에서X-CUBE Software Pack으로서 Thread 활성화를 수행하면 STM32CubeMX의 프로젝트 메뉴 왼쪽에 있는 "Categories" 목록의 Software Packs 아래에 보이는 X-CUBE-AZRTOS-XX 메뉴로 이동해서 Use Static MemPool Allocation으로 Memory Allocation
을 설정합니다.
ThreadX 설정 탭을 선택하고, TX_TIMER_TICKS_PER_SECOND
를 1000으로 설정해서 밀리 초마다 한 번씩 틱을 발생시킵니다.
X-CUBE-AZRTOS-XX 메뉴에서 구성이 완료되면, TouchGFX Generator로 이동해서 실시간 운영 체제로 ThreadX
를 선택하고 TouchGFX 작업에 대한 Memory Pool Size
및 Memory Stack Size
를 정의합니다.