Back to Blog
6 min read

Azure RTOS for Real-Time IoT Applications

Azure RTOS (formerly ThreadX) is a real-time operating system designed for deeply embedded IoT and edge devices. It provides deterministic performance, a small memory footprint, and seamless Azure connectivity for resource-constrained devices.

Azure RTOS Components

  • ThreadX: RTOS kernel with preemptive scheduling
  • NetX Duo: TCP/IP network stack (IPv4 and IPv6)
  • FileX: FAT-compatible embedded file system
  • GUIX: Graphics UI framework
  • USBX: USB host and device stack
  • LevelX: NAND/NOR flash wear leveling

Getting Started with ThreadX

Thread Creation

#include "tx_api.h"

#define THREAD_STACK_SIZE   1024
#define THREAD_PRIORITY     4

static TX_THREAD sensor_thread;
static TX_THREAD network_thread;
static UCHAR sensor_thread_stack[THREAD_STACK_SIZE];
static UCHAR network_thread_stack[THREAD_STACK_SIZE];

// Sensor reading thread
void sensor_thread_entry(ULONG thread_input)
{
    while (1)
    {
        // Read sensor data
        float temperature = read_temperature_sensor();
        float humidity = read_humidity_sensor();

        // Store in shared buffer (with mutex protection)
        store_sensor_data(temperature, humidity);

        // Sleep for 1 second (100 ticks at 100Hz)
        tx_thread_sleep(100);
    }
}

// Network communication thread
void network_thread_entry(ULONG thread_input)
{
    while (1)
    {
        // Wait for data to send
        tx_semaphore_get(&data_ready_semaphore, TX_WAIT_FOREVER);

        // Send to Azure IoT Hub
        send_telemetry_to_azure();
    }
}

int main(void)
{
    // Enter ThreadX kernel
    tx_kernel_enter();
    return 0;
}

void tx_application_define(void *first_unused_memory)
{
    // Create sensor thread
    tx_thread_create(
        &sensor_thread,
        "Sensor Thread",
        sensor_thread_entry,
        0,
        sensor_thread_stack,
        THREAD_STACK_SIZE,
        THREAD_PRIORITY,
        THREAD_PRIORITY,
        TX_NO_TIME_SLICE,
        TX_AUTO_START
    );

    // Create network thread (lower priority)
    tx_thread_create(
        &network_thread,
        "Network Thread",
        network_thread_entry,
        0,
        network_thread_stack,
        THREAD_STACK_SIZE,
        THREAD_PRIORITY + 1,
        THREAD_PRIORITY + 1,
        TX_NO_TIME_SLICE,
        TX_AUTO_START
    );
}

Synchronization Primitives

#include "tx_api.h"

static TX_MUTEX data_mutex;
static TX_SEMAPHORE data_ready_semaphore;
static TX_EVENT_FLAGS_GROUP event_flags;
static TX_QUEUE message_queue;

// Shared data
typedef struct {
    float temperature;
    float humidity;
    ULONG timestamp;
} sensor_data_t;

static sensor_data_t shared_data;
static UCHAR queue_memory[sizeof(sensor_data_t) * 10];

void initialize_sync_objects(void)
{
    // Create mutex for data protection
    tx_mutex_create(&data_mutex, "Data Mutex", TX_NO_INHERIT);

    // Create semaphore for signaling
    tx_semaphore_create(&data_ready_semaphore, "Data Ready", 0);

    // Create event flags
    tx_event_flags_create(&event_flags, "Sensor Events");

    // Create message queue
    tx_queue_create(
        &message_queue,
        "Sensor Queue",
        sizeof(sensor_data_t) / sizeof(ULONG),
        queue_memory,
        sizeof(queue_memory)
    );
}

void store_sensor_data(float temp, float humidity)
{
    sensor_data_t data;
    data.temperature = temp;
    data.humidity = humidity;
    data.timestamp = tx_time_get();

    // Protect shared data with mutex
    tx_mutex_get(&data_mutex, TX_WAIT_FOREVER);
    shared_data = data;
    tx_mutex_put(&data_mutex);

    // Signal data ready
    tx_semaphore_put(&data_ready_semaphore);

    // Set event flag
    tx_event_flags_set(&event_flags, 0x01, TX_OR);

    // Send to queue
    tx_queue_send(&message_queue, &data, TX_NO_WAIT);
}

NetX Duo for Azure Connectivity

#include "nx_api.h"
#include "nxd_mqtt_client.h"
#include "nx_azure_iot.h"
#include "nx_azure_iot_hub_client.h"

#define AZURE_IOT_HUB_HOSTNAME    "myhub.azure-devices.net"
#define AZURE_IOT_HUB_DEVICE_ID   "mydevice"

static NX_IP nx_ip;
static NX_PACKET_POOL nx_pool;
static NX_AZURE_IOT nx_azure_iot;
static NX_AZURE_IOT_HUB_CLIENT hub_client;

// Initialize network stack
UINT initialize_network(void)
{
    UINT status;

    // Create packet pool
    status = nx_packet_pool_create(
        &nx_pool,
        "Packet Pool",
        NX_PACKET_SIZE,
        packet_pool_memory,
        PACKET_POOL_SIZE
    );
    if (status != NX_SUCCESS) return status;

    // Create IP instance
    status = nx_ip_create(
        &nx_ip,
        "IP Instance",
        IP_ADDRESS(0, 0, 0, 0),  // DHCP will assign
        IP_MASK,
        &nx_pool,
        ethernet_driver,
        ip_thread_stack,
        IP_THREAD_STACK_SIZE,
        IP_THREAD_PRIORITY
    );
    if (status != NX_SUCCESS) return status;

    // Enable ARP, UDP, TCP
    nx_arp_enable(&nx_ip, arp_cache, ARP_CACHE_SIZE);
    nx_udp_enable(&nx_ip);
    nx_tcp_enable(&nx_ip);
    nx_icmp_enable(&nx_ip);

    // Start DHCP
    status = nx_dhcp_start(&dhcp_client);

    return status;
}

// Connect to Azure IoT Hub
UINT connect_to_azure_iot_hub(void)
{
    UINT status;

    // Initialize Azure IoT
    status = nx_azure_iot_create(
        &nx_azure_iot,
        (UCHAR *)"Azure IoT",
        &nx_ip,
        &nx_pool,
        &nx_dns,
        azure_iot_thread_stack,
        AZURE_IOT_THREAD_STACK_SIZE,
        AZURE_IOT_THREAD_PRIORITY,
        unix_time_get
    );
    if (status != NX_AZURE_IOT_SUCCESS) return status;

    // Initialize hub client
    status = nx_azure_iot_hub_client_initialize(
        &hub_client,
        &nx_azure_iot,
        (UCHAR *)AZURE_IOT_HUB_HOSTNAME,
        sizeof(AZURE_IOT_HUB_HOSTNAME) - 1,
        (UCHAR *)AZURE_IOT_HUB_DEVICE_ID,
        sizeof(AZURE_IOT_HUB_DEVICE_ID) - 1,
        NULL, 0,
        _nx_azure_iot_tls_supported_crypto,
        _nx_azure_iot_tls_supported_crypto_size,
        _nx_azure_iot_tls_ciphersuite_map,
        _nx_azure_iot_tls_ciphersuite_map_size,
        nx_azure_iot_tls_metadata_buffer,
        sizeof(nx_azure_iot_tls_metadata_buffer),
        &root_ca_cert
    );
    if (status != NX_AZURE_IOT_SUCCESS) return status;

    // Set device symmetric key
    status = nx_azure_iot_hub_client_symmetric_key_set(
        &hub_client,
        (UCHAR *)DEVICE_SYMMETRIC_KEY,
        sizeof(DEVICE_SYMMETRIC_KEY) - 1
    );
    if (status != NX_AZURE_IOT_SUCCESS) return status;

    // Connect
    status = nx_azure_iot_hub_client_connect(&hub_client, NX_TRUE, NX_WAIT_FOREVER);

    return status;
}

// Send telemetry
UINT send_telemetry(float temperature, float humidity)
{
    UINT status;
    NX_PACKET *packet;
    CHAR buffer[128];

    // Create telemetry message
    snprintf(buffer, sizeof(buffer),
        "{\"temperature\":%.2f,\"humidity\":%.2f}",
        temperature, humidity);

    // Allocate packet
    status = nx_azure_iot_hub_client_telemetry_message_create(
        &hub_client,
        &packet,
        NX_WAIT_FOREVER
    );
    if (status != NX_AZURE_IOT_SUCCESS) return status;

    // Add message body
    status = nx_packet_data_append(
        packet,
        buffer,
        strlen(buffer),
        &nx_pool,
        NX_WAIT_FOREVER
    );
    if (status != NX_SUCCESS) {
        nx_azure_iot_hub_client_telemetry_message_delete(packet);
        return status;
    }

    // Send
    status = nx_azure_iot_hub_client_telemetry_send(
        &hub_client,
        packet,
        NULL, 0,
        NX_WAIT_FOREVER
    );

    return status;
}

Device Twin Handling

// Receive desired properties
void device_twin_desired_property_callback(
    NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
    UCHAR *component_name,
    UINT component_name_length,
    NX_AZURE_IOT_JSON_READER *reader_ptr,
    UINT version,
    VOID *context)
{
    CHAR property_name[64];
    UINT property_name_length;

    while (nx_azure_iot_json_reader_next_property_name(
        reader_ptr, (UCHAR *)property_name, sizeof(property_name),
        &property_name_length) == NX_AZURE_IOT_SUCCESS)
    {
        if (strncmp(property_name, "telemetryInterval", property_name_length) == 0)
        {
            INT32 value;
            if (nx_azure_iot_json_reader_token_int32_get(reader_ptr, &value) ==
                NX_AZURE_IOT_SUCCESS)
            {
                // Update telemetry interval
                telemetry_interval = value;

                // Report back
                report_property("telemetryInterval", value, version);
            }
        }
    }
}

// Report properties
UINT report_property(const CHAR *name, INT32 value, UINT version)
{
    CHAR buffer[256];
    snprintf(buffer, sizeof(buffer),
        "{\"%s\":{\"value\":%d,\"ac\":200,\"av\":%u,\"ad\":\"Success\"}}",
        name, value, version);

    return nx_azure_iot_hub_client_reported_properties_send(
        &hub_client,
        (UCHAR *)buffer,
        strlen(buffer),
        NULL, NULL,
        NX_WAIT_FOREVER
    );
}

// Setup twin callbacks
void setup_device_twin(void)
{
    // Enable twin
    nx_azure_iot_hub_client_device_twin_enable(&hub_client);

    // Set callback
    nx_azure_iot_hub_client_device_twin_desired_properties_receive(
        &hub_client,
        device_twin_desired_property_callback,
        NULL
    );

    // Request current twin
    nx_azure_iot_hub_client_device_twin_properties_request(
        &hub_client,
        NX_WAIT_FOREVER
    );
}

Direct Method Handling

// Method callback
void direct_method_callback(
    NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
    UCHAR *method_name,
    USHORT method_name_length,
    UCHAR *payload,
    USHORT payload_length,
    VOID *context,
    USHORT context_length)
{
    UINT status = 200;
    CHAR response[128] = "{}";

    if (strncmp((CHAR *)method_name, "reboot", method_name_length) == 0)
    {
        // Schedule reboot
        schedule_reboot();
        snprintf(response, sizeof(response),
            "{\"status\":\"Rebooting in 5 seconds\"}");
    }
    else if (strncmp((CHAR *)method_name, "setLed", method_name_length) == 0)
    {
        // Parse payload and set LED
        BOOL led_state = parse_led_state(payload, payload_length);
        set_led(led_state);
        snprintf(response, sizeof(response),
            "{\"led\":%s}", led_state ? "true" : "false");
    }
    else
    {
        status = 404;
        snprintf(response, sizeof(response),
            "{\"error\":\"Method not found\"}");
    }

    // Send response
    nx_azure_iot_hub_client_direct_method_message_response(
        hub_client_ptr,
        status,
        context,
        context_length,
        (UCHAR *)response,
        strlen(response),
        NX_WAIT_FOREVER
    );
}

// Enable direct methods
void setup_direct_methods(void)
{
    nx_azure_iot_hub_client_direct_method_enable(&hub_client);
    nx_azure_iot_hub_client_direct_method_message_callback_set(
        &hub_client,
        direct_method_callback,
        NULL, 0
    );
}

Memory and Performance

// Memory usage statistics
void print_memory_stats(void)
{
    TX_THREAD *thread_ptr;
    ULONG available;
    ULONG fragments;

    // Thread stack usage
    tx_thread_info_get(
        &sensor_thread,
        TX_NULL, TX_NULL, TX_NULL,
        TX_NULL, TX_NULL, TX_NULL,
        TX_NULL, TX_NULL
    );

    // Byte pool statistics
    tx_byte_pool_info_get(
        &memory_pool,
        TX_NULL,
        &available,
        &fragments,
        TX_NULL, TX_NULL, TX_NULL
    );

    printf("Available memory: %lu bytes, Fragments: %lu\n",
        available, fragments);
}

// Performance counters
void print_performance_stats(void)
{
    ULONG total_threads;
    ULONG ready_threads;
    ULONG suspended_threads;

    tx_thread_performance_system_info_get(
        TX_NULL, TX_NULL, TX_NULL,
        &total_threads, &ready_threads, &suspended_threads,
        TX_NULL, TX_NULL, TX_NULL
    );

    printf("Threads: Total=%lu, Ready=%lu, Suspended=%lu\n",
        total_threads, ready_threads, suspended_threads);
}

Conclusion

Azure RTOS provides:

  • Deterministic performance: Predictable response times for real-time requirements
  • Small footprint: As little as 2KB ROM and 1KB RAM for the kernel
  • Safety certifications: IEC 61508, ISO 26262, IEC 62304 pre-certified
  • Azure integration: Native support for Azure IoT services
  • Rich ecosystem: Network, file system, USB, and graphics components

It’s ideal for resource-constrained devices requiring real-time performance and Azure connectivity.

Michael John Pena

Michael John Pena

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.