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.
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.
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)
#include <cmrx/application.h> - Includes the CMRX application frameworkint app_main(void * data) - Your main application function (like main() in regular C programs)while (1) { } - An infinite loop that keeps the thread aliveOS_APPLICATION_MMIO_RANGE(app, 0, 0) - Defines memory-mapped I/O ranges (none in this example)OS_APPLICATION(app) - Declares an application named “app”OS_THREAD_CREATE(app, app_main, NULL, 64) - Creates a thread that runs app_main() with the scheduler priority of 64To 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).
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.
To create a working project, you need three parts:
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:
CMSIS_ROOT - Path to CMSIS headers in your SDKDEVICE - Your microcontroller’s part name (check your SDK documentation)CMSIS_LINKER_FILE - Path to the linker script for your deviceAdd 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:
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:
os_start() is called, CMRX takes over and starts your applicationsmain()os_start() launches the CMRX kernelapp_main()This basic example doesn’t do anything visible, but it demonstrates the foundation of CMRX development. To make it useful, you could:
while(1) loopFor more complex examples covering full hardware and SDK integration process, check the CMRX documentation which provides how-to guides for variety of hardware: