Hello World

This example demonstrates the simplest possible application written for CMRX RTOS. By the end of this tutorial, you’ll understand how to create a basic application and integrate it with the CMRX kernel.

What You’ll Learn

Understanding CMRX Applications

In CMRX, all user code is organized into applications (also called processes - these terms mean the same thing). Think of an application as a container that holds:

The key advantage is memory isolation: each application gets its own protected memory space that other applications cannot access. This makes your system more robust against bugs and security issues.

Basic Application Code

Here’s the simplest possible CMRX application:

#include <cmrx/application.h>

int app_main(void * data)
{
    while (1) {
        // Your application code goes here
        // This infinite loop keeps the thread running
    }
}

OS_APPLICATION_MMIO_RANGE(app, 0, 0)
OS_APPLICATION(app)
OS_THREAD_CREATE(app, app_main, NULL, 64)

What Each Line Does

  1. #include <cmrx/application.h> - Includes the CMRX application framework
  2. int app_main(void * data) - Your main application function (like main() in regular C programs)
  3. while (1) { } - An infinite loop that keeps the thread alive
  4. OS_APPLICATION_MMIO_RANGE(app, 0, 0) - Defines memory-mapped I/O ranges (none in this example)
  5. OS_APPLICATION(app) - Declares an application named “app”
  6. OS_THREAD_CREATE(app, app_main, NULL, 64) - Creates a thread that runs app_main() with the scheduler priority of 64

Building the Application

To build this code, you need to create a CMake configuration. Create a CMakeLists.txt file:

add_application(app app.c)
target_link_libraries(app stdlib)

Important: The name “app” in add_application() must match the name used in OS_APPLICATION(app).

How Memory Isolation Works

CMRX automatically creates isolated memory regions for each application. The rule is simple:

All data in the same static library as the OS_APPLICATION() macro belongs to that application.

This means you don’t need to manually configure memory partitions - CMRX handles it automatically based on your code organization.

Complete Project Setup

To create a working project, you need three parts:

  1. Hardware Configuration - Tell CMRX what microcontroller you’re using
  2. Kernel Integration - Include and configure the CMRX kernel
  3. Main Entry Point - Create the system startup code

Step 1: Hardware Configuration

For ARM-based microcontrollers, configure CMSIS support:

set(CMSIS_ROOT path/to/cmsis/inside/sdk)
set(DEVICE your_device_name)
set(CMSIS_LINKER_FILE path/to/linker/file)
include(FindCMSIS)

What These Variables Do:

Step 2: Kernel Integration

Add CMRX to your build:

set(CMRX_ARCH arm)
set(CMRX_HAL cmsis)
include(CMRX)
add_subdirectory(path/to/cmrx)

add_firmware(hello_world main.c)
target_link_libraries(hello_world vendor_sdk)
target_app_applications(hello_world app)

What This Does:

Step 3: Main Entry Point

Create a main.c file for system initialization:

#include <RTE_headers.h>
#include CMSIS_device_header

long timing_get_current_cpu_freq(void)
{
    return SystemCoreClock;
}

int main(void)
{
    // Perform hardware initialization here
    // (configure clocks, peripherals, etc.)
    
    timing_provider_setup(1);
    os_start();  // Start the CMRX kernel
}

Why This File Exists:

What Happens When You Run This

  1. Your microcontroller boots and runs main()
  2. Hardware initialization code executes
  3. os_start() launches the CMRX kernel
  4. The kernel creates your “app” application in isolated memory
  5. The kernel starts the thread running app_main()
  6. Your application runs in its infinite loop

Next Steps

This basic example doesn’t do anything visible, but it demonstrates the foundation of CMRX development. To make it useful, you could:

For more complex examples covering full hardware and SDK integration process, check the CMRX documentation which provides how-to guides for variety of hardware:

Remote Procedure Call →