Skip to main content
Version: v2.4.0 (Current)

Zephyr RTOS Integration Guide

The Artok HMI Runtime is designed to integrate deeply with the Zephyr RTOS ecosystem. By leveraging the Zephyr Device Driver Model (Display, Flash, and Input), Artok can be treated as a high-level application service that interacts with hardware via standard Device Tree (DTS) labels.


📦 1. System Requirements

Zephyr requires explicit stack and heap configuration in your prj.conf to handle the Artok engine's object registry and Lua scripting environment.

Kconfig SymbolRecommended ValueDescription
CONFIG_MAIN_STACK_SIZE4096Sufficient depth for UI parsing threads.
CONFIG_HEAP_MEM_POOL_SIZE16384Minimum pool for dynamic widget allocation.
CONFIG_DISPLAYyEnables the standard Zephyr display driver API.

🔧 2. Hardware Abstraction (Zephyr API)

In Zephyr, we use the device_get_binding or DEVICE_DT_GET macros to interact with hardware. The Artok HAL acts as a bridge between these Zephyr devices and the HMI kernel.

Flash & Display Bridge

#include <zephyr/kernel.h>
#include <zephyr/drivers/display.h>
#include <zephyr/drivers/flash.h>
#include "atk_runtime.h"

const struct device *display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
const struct device *flash_dev = DEVICE_DT_GET(DT_NODELABEL(w25qxx));

// 1. Flash Read (Using Zephyr Flash API)
uint32_t zephyr_flash_read(uint8_t* buf, uint32_t addr, uint32_t size) {
if (flash_read(flash_dev, addr, buf, size) == 0) {
return size;
}
return 0;
}

// 2. Display Flush (Using Zephyr Display API)
void zephyr_disp_flush(void *drv, int32_t x1, int32_t y1, int32_t x2, int32_t y2, void *color) {
struct display_buffer_descriptor desc;
desc.buf_size = (x2 - x1 + 1) * (y2 - y1 + 1) * 2;
desc.width = (x2 - x1 + 1);
desc.height = (y2 - y1 + 1);
desc.pitch = desc.width;

display_write(display_dev, x1, y1, &desc, color);

// Note: If using asynchronous drivers, call this in the callback
ART_FlushComplete();
}

🚀 3. The 4-Tier Initialization Sequence

In Zephyr, the initialization should follow the tiered model within a dedicated thread. This ensures the HMI doesn't block critical system threads like the Bluetooth stack or networking.

void artok_thread(void) {
HMI_Hardware_Interface_t zephyr_hal;

// TIER 1: Core System Init
ART_Init();

// Prepare HAL Structure
zephyr_hal.read_flash = zephyr_flash_read;
zephyr_hal.disp_flush_cb = zephyr_disp_flush;
zephyr_hal.disp_buffer_1 = k_malloc(ART_LCD_WIDTH * 20 * 2);
zephyr_hal.disp_buffer_size_bytes = ART_LCD_WIDTH * 20 * 2;
zephyr_hal.comm_send = zephyr_uart_send;

// TIER 2 & 3: Connectivity and Input
ART_InitComm(&zephyr_hal, NULL, 0);
ART_InitDisplay(&zephyr_hal);
ART_InitInput(&zephyr_hal);

// TIER 4: Start HMI Logic
// 0x100000: Address offset in your flash device
if (ART_StartHMI(0x100000, &zephyr_hal)) {
while (1) {
ART_MainLoop();
k_msleep(5); // Yield to other threads
}
}
}

K_THREAD_DEFINE(artok_tid, 4096, artok_thread, NULL, NULL, NULL, 7, 0, 0);

🎮 4. Interaction API

Zephyr encourages a producer-consumer model. You can push data to the HMI using the UUID-based API from any other thread (e.g., a sensor thread or a Bluetooth event handler).

void sensor_process(void) {
while(1) {
int battery_level = get_soc();

// Thread-safe update via UUID
atk_api_set_value("UUID_BATTERY_GAUGE", battery_level);

if (battery_level < 20) {
atk_api_set_text("UUID_STATUS_LABEL", "Low Battery!");
}

k_sleep(K_SECONDS(1));
}
}

🛡️ 5. Zephyr Optimization Notes

  • Device Tree: Ensure your LCD and Flash are correctly defined in your .overlay file. Artok relies on the driver's ability to handle the communication bus (SPI/I2C) correctly.

  • K-Heap vs Malloc: Artok can be configured to use k_malloc to take advantage of Zephyr's system heap management and memory protection features.

  • Tick Source: Call ART_IncTick(1) within a system timer callback or a high-frequency thread.

  • Logging: Use LOG_INF() or LOG_ERR() to wrap Artok status codes for integrated debugging via the Zephyr Shell.