Skip to content

pdlsurya/sanoRTOS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

103 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

sanoRTOS

sanoRTOS is a minimal Real-Time Operating System (RTOS) designed for ARM Cortex-M and RISC-V microcontrollers. This implementation provides a simple yet effective API for task management, synchronization, and communication, enabling efficient and predictable multitasking in embedded systems.

Features

  • Priority-Based Preemptive Scheduling
    Efficient task management with support for preemptive scheduling based on task priority levels.

  • Optional Priority Inheritance
    Prevents priority inversion during mutex acquisition by temporarily elevating the priority of lower-priority tasks.

  • Symmetric Multiprocessing (SMP) Support
    Fully supports multi-core systems with per-task core affinity configuration for optimal load balancing.

  • Dynamic Stack Overflow Detection
    Runtime monitoring of task stacks to catch and handle stack overflows proactively.

  • Configurable Tick Rate
    Easily adjustable tick frequency to match application-specific timing and power requirements.

  • Task Synchronization Primitives
    Includes mutexes, semaphores, condition variables, and event objects for safe and efficient coordination between tasks.

  • Inter-Task Communication
    Enables message passing between tasks using message queues, stream buffers, message buffers, and mailboxes.

  • Minimalistic and Lightweight Design
    Designed for embedded systems with limited resources — small footprint, fast context switches, and no unnecessary bloat.

API Reference

The detailed API reference, including example code for each kernel object, lives in API_REFERENCE.md.

Building and Running

Example for STM32F4 using STM32Cube IDE

  1. Clone the Repository:

    • Open a terminal and clone the sanoRTOS repository git clone https://github.com/pdlsurya/sanoRTOS.git
  2. Open STM32Cube IDE:

    • Launch STM32Cube IDE and create a new STM32F4 project or open an existing one.
  3. Include sanoRTOS in Project:

    • Right-click on your project and select Properties.
    • Go to C/C++ Build > Settings.
    • Under Tool Settings, go to MCU GCC Compiler > Include paths and add the path to sanoRTOS/include and sanoRTOS/ports/arm/stm32f4/include directory.
  4. Add Source Files:

    • Navigate to C/C++ General > Paths and Symbols.
    • In the Source Location tab, click on Link folder and add the path to sanoRTOS/source and sanoRTOS/ports/arm/stm32f4 directory by selecting Link to folder in the filesystem.
  5. Edit stm32xxxx_it.c file:

    • STM32 initializes the SysTick timer during its clock initialization process and defines the SysTick_Handler ISR function for the implementation of the delay function in the Core > Src > stm32xxxx_it.c file. Hence, the SysTick_Handler ISR function cannot be redefined inside the sanoRTOS. Instead, call sanoRTOS_SysTickHook() from the SDK's SysTick_Handler() implementation.

    • Moreover, sanoRTOS includes definition for PendSV_Handler used for task scheduling and context switching. STM32 also defines this ISR in stm32xxxx_it.c file; Hence, we need to remove the definition of this ISR from the stm32xxxx_it.c file to avoid multiple definition error.

Example for RP2350(Raspberry Pi pico 2) using pico-sdk

  1. Clone the Repository:

    • Open a terminal and clone the sanoRTOS repository git clone https://github.com/pdlsurya/sanoRTOS.git
  2. Set Up Your Pico Project:

  • You can either create a new CMake-based Pico SDK project or add sanoRTOS to an existing one. Add sanoRTOS folder to your project folder
  • sanoRTOS supports both ARM and RISC-V cores of the RP2350.
  1. Include sanoRTOS in Your CMakeLists.txt:
  • Update your CMakeLists.txt to include sanoRTOS headers and sources as follows:
file(GLOB_RECURSE SANORTOS_SRCS
    sanoRTOS/source/*.c
    sanoRTOS/ports/arm/rp2350/port.c)
#for Hazard3 RISC-V cores, add source files from risc-v port of rp2350 (sanoRTOS/ports/riscv/rp2350/port.c and  sanoRTOS/ports/riscv/rp2350/port.S)

target_include_directories(project_name PRIVATE
   sanoRTOS/include
   sanoRTOS/ports/arm/rp2350/include #for RISC-V port replace this line  with sanoRTOS/ports/risc-v/rp2350/include 
) 
target_sources(project_name PRIVATE ${SANORTOS_SRCS})

Example for RP2040 (Raspberry Pi Pico) using pico-sdk

  1. Add sanoRTOS to your Pico SDK project and include the RP2040 ARM port files.
file(GLOB_RECURSE SANORTOS_SRCS
    sanoRTOS/source/*.c
    sanoRTOS/ports/arm/rp2040/port.c)

target_include_directories(project_name PRIVATE
   sanoRTOS/include
   sanoRTOS/ports/arm/rp2040/include
)

target_sources(project_name PRIVATE ${SANORTOS_SRCS})
target_link_libraries(project_name PRIVATE pico_stdlib pico_multicore hardware_sync)
  1. The RP2040 port uses:
    • SysTick_Handler() from the sanoRTOS port for the scheduler tick
    • PendSV_Handler() from the sanoRTOS port for context switching
    • multicore_launch_core1() when CONFIG_SMP is enabled
    • RP2040 hardware spin lock PICO_SPINLOCK_ID_OS1 to serialize RTOS CAS operations on Cortex-M0+

Example Code:

#include "sanoRTOS/config.h"
#include "sanoRTOS/scheduler.h"
#include "sanoRTOS/task.h"
//Include MCU-specific header files here

// Define two tasks with 1024-byte stacks.
// These tasks are assigned to any available core using AFFINITY_CORE_ANY.
//
// On multicore MCUs (e.g. RP2350), sanoRTOS can schedule tasks on different cores
// depending on the affinity setting. AFFINITY_CORE_ANY allows the scheduler to choose any core.
// This can help distribute load across both cores and enable true parallel execution.
//
// On single-core MCUs, this setting is safely ignored — all tasks will run on the only available core.
TASK_DEFINE(task1, 1024, firstTask, NULL, 1, AFFINITY_CORE_ANY);
TASK_DEFINE(task2, 1024, secondTask, NULL, 1, AFFINITY_CORE_ANY);
taskHandleType *dynamicTask = NULL;


// Task 1 function – user-defined logic inside this loop
void firstTask(void *args) {
   while (1) {
       // Task1 code to run repeatedly
   }
}

// Task 2 function – user-defined logic inside this loop
void secondTask(void *args) {
   while (1) {
       // Task2 code to run repeatedly
   }
}

// Dynamically created task function
void thirdTask(void *args) {
   while (1) {
       // Dynamic task code to run repeatedly
   }
}

int main() {
   // Perform MCU-specific initializations here
   // Example: initialize GPIO, UART, peripherals, etc.

   // Start tasks
   taskStart(&task1);
   taskStart(&task2);

   // Create and start a dynamic task
   int ret = taskCreate(&dynamicTask,
                        "dynamicTask",
                        1024,
                        thirdTask,
                        NULL,
                        1,
                        AFFINITY_CORE_ANY);
   if (ret != RET_SUCCESS) {
       // Handle task creation failure
       while (1) {
       }
   }

   // Start the sanoRTOS scheduler (will not return)
   schedulerStart();

   // Control should never reach here if scheduler is working correctly
   return 0;
}

ESP32 Ports

This RTOS includes ports for the following Espressif RISC-V based MCUs:

  • ESP32-C6
  • ESP32-P4

Unlike most ESP32 projects, these ports do not use Espressif's ESP-IDF.
Instead, they are built on top of custom ESP32 RISC-V bare-metal SDK developed specifically for low-level control and minimal system overhead.

The bare-metal SDK provides:

  • Startup code and linker scripts
  • Register definitions and peripheral structures
  • Interrupt and exception handling
  • Basic hardware initialization
  • Minimal HAL required for RTOS operation

This SDK allows the RTOS to run without the ESP-IDF framework, making the implementation closer to traditional embedded RTOS ports.

Notes

  • The RTOS ports assume the system is initialized using the corresponding bare-metal SDK.
  • ESP-IDF is not required to build or run these ports.

License

This project is licensed under the MIT License-see the LICENSE file for details.

Releases

No releases published

Packages

 
 
 

Contributors