FreeRTOS Integration Guide
The Artok HMI Runtime is fully thread-safe and designed to thrive in FreeRTOS environments. By isolating the HMI engine into its own high-priority task, you can ensure smooth 60FPS animations even while the CPU is performing heavy background processing like TCP/IP networking or Motor Control.
📦 1. Task Configuration
To run Artok on FreeRTOS, you must allocate a dedicated task. Because the runtime handles Lua scripting and complex UI parsing, we recommend the following stack settings:
| Parameter | Recommended Value | Description |
|---|---|---|
| Task Priority | configMAX_PRIORITIES - 1 | High priority ensures UI responsiveness. |
| Stack Size | 2048 - 4096 words | Depends on UI complexity and Lua usage. |
| Tick Rate | 1000 Hz | Required for accurate 1ms timing via ART_IncTick. |
🔧 2. Hardware Abstraction (Safe HAL)
In FreeRTOS, hardware resources (SPI/I2C) are often shared. You must use Mutexes within your HAL callbacks to prevent data corruption.
Thread-Safe Callbacks
#include "FreeRTOS.h"
#include "semphr.h"
#include "atk_runtime.h"
SemaphoreHandle_t xFlashMutex;
// 1. Thread-Safe Flash Read
uint32_t freertos_flash_read(uint8_t* buf, uint32_t addr, uint32_t size) {
uint32_t read_len = 0;
if (xSemaphoreTake(xFlashMutex, portMAX_DELAY) == pdTRUE) {
// Perform SPI Flash Read
// read_len = W25Q_Read(buf, addr, size);
xSemaphoreGive(xFlashMutex);
}
return read_len;
}
// 2. Display Flush with DMA Notification
void freertos_disp_flush(void *drv, int32_t x1, int32_t y1, int32_t x2, int32_t y2, void *color) {
// Start DMA transfer to LCD
// LCD_DMA_Transmit(color, size);
// Note: ART_FlushComplete() should be called from the DMA TC Interrupt
}
🚀 3. The 4-Tier Initialization Sequence
In FreeRTOS, the HMI should be initialized inside the Task Entry function. This ensures that the scheduler is already running when the HMI starts allocating its internal resources.
void vArtokGUITask(void *pvParameters) {
HMI_Hardware_Interface_t rtos_hal;
xFlashMutex = xSemaphoreCreateMutex();
// TIER 1: Core System Init
ART_Init();
// Prepare HAL Structure
rtos_hal.read_flash = freertos_flash_read;
rtos_hal.disp_flush_cb = freertos_disp_flush;
rtos_hal.disp_buffer_1 = pvPortMalloc(ART_LCD_WIDTH * 20 * 2);
rtos_hal.disp_buffer_size_bytes = ART_LCD_WIDTH * 20 * 2;
rtos_hal.comm_send = rtos_uart_send;
// TIER 2 & 3: Connectivity and Input
ART_InitComm(&rtos_hal, NULL, 0);
ART_InitDisplay(&rtos_hal);
ART_InitInput(&rtos_hal);
// TIER 4: Launch HMI
if (ART_StartHMI(0x00000000, &rtos_hal)) {
while (1) {
// Main UI Heartbeat
ART_MainLoop();
// Yield for 5ms to allow lower priority tasks to run
vTaskDelay(pdMS_TO_TICKS(5));
}
}
}
🎮 4. Interaction API (Cross-Task Updates)
The atk_api functions are designed to be called from any task. For example, your "Sensor Task" can update a Label UUID directly without needing complex message queues.
void vSensorTask(void *pvParameters) {
while(1) {
int32_t current_val = read_adc();
// Directly push data to the HMI Task via UUID
// The Artok Engine handles the internal synchronization
atk_api_set_value("UUID_SENSOR_GAUGE", current_val);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
🛡️ 5. FreeRTOS Best Practices
-
Tick Provider: Ensure ART_IncTick(1) is called every 1ms. The best place for this is vApplicationTickHook() or a dedicated high-priority timer interrupt.
-
Memory Management: Use pvPortMalloc for your display buffers to ensure they are managed by the FreeRTOS heap (Heap_4 or Heap_5 recommended).
-
Interrupt Safety: If you trigger UI updates from an ISR, ensure you use the appropriate FromISR wrappers if your specific port requires them, though atk_api is best called from Task context.
-
Watchdog: If using a Task Watchdog, ensure ART_MainLoop() is called frequently enough to prevent a system reset during heavy UI transitions.