yss OS (Yi Sun-Sin OS) is a lightweight, high-performance C++ Real-Time Operating System (RTOS) engineered specifically for ARM Cortex-M microcontrollers. Developed by an active embedded firmware and hardware engineer, yss OS combines modern C++ object-oriented design with low-overhead kernel scheduling to deliver a robust platform for real-world production systems.
The name yss stands for the lowercase initials of General Yi Sun-Sin (μ΄μμ μ₯κ΅°λ), one of history's most celebrated naval commanders.
"While watching a historical documentary about General Yi Sun-Sin, I was inspired by how he overcame overwhelming odds and harsh circumstances to achieve brilliant victories. Much like Linux took its name from a person, I decided to name this OS after General Yi Sun-Sin, driven by the vision to build a competitive, world-class RTOS despite realistic development challenges."
Initially shared simply as "yss OS", the project earned its full name Yi Sun-Sin OS after proven success in practical firmware deployment, demonstrating real-world reliability and performance.
- Preemptive/Cooperative Threads (
thread::add,thread::yield,thread::delay,thread::delayUs) powered bySysTick&PendSV. - Ultra-lightweight one-shot Triggers (
trigger::add,trigger::run) β a unique yss OS concept for ISR-deferred processing that rebuilds the execution context on every call, allowing the function to always restart from the beginning. - Signal/WaitForSignal mechanism for efficient thread synchronization with automatic CPU sleep (
__WFI) when no threads are runnable. - Multi-core scheduling support (
YSS__MULTI_CORE) with hardware semaphore-based cross-core scheduling locks.
The yss OS scheduler is fundamentally a Preemptive Round-Robin RTOS. It uses a hardware timer (SysTick on Cortex-M, or Physical Timer on Cortex-A) to enforce strict time-slicing (configured via THREAD_GIVEN_CLOCK). This guarantees that the CPU is forcibly reclaimed at regular intervals, preventing any single thread from monopolizing the system (no starvation), even if a thread runs heavy computations.
Despite this preemptive safety net, the scheduler logic is intentionally simple: round-robin selection is O(1) and the context switch path is highly optimized (roughly tens to ~150 cycles on Cortex-M4/M7). There are no complex priority queues and no heavy per-thread accounting.
Because all threads share equal priority, the intended usage pattern for optimal real-time latency is cooperative: when a thread has nothing to do, it should call thread::yield() immediately and hand the CPU to a thread that has work. Threads woken by signal() or trigger bypass the round-robin order and are dispatched immediately.
while (1)
{
if (canfd0.isNewRxMessage())
handleMessage(); // real work: keeps the CPU
thread::yield(); // nothing to do: pass it on right away
}| Aspect | Polling + yield() |
Event-driven (signal / trigger / delay) |
|---|---|---|
| Implementation | Simple | Needs wake-up logic |
| Reaction time (few threads) | Very fast | Comparable |
| Power | Core never enters WFI while any thread is runnable |
Core sleeps when all threads wait |
| CPU load visibility | Always looks 100% busy | Idle time is measurable |
Things to keep in mind:
- Worst-case latency is set by the longest section that does not yield (or by the SysTick time slice), not by the number of polling threads.
- Power: a single polling thread keeps the core awake, which cancels the benefit of
the timer-based
delay(). For battery-powered products, wait withthread::delay()(evendelay(1)) orsignal()/triggerinstead of spinning onyield(). - Short delays:
delayUs()of about 500 us or less is still a busy wait, and targets withoutYSS_DELAY_TIMERalways busy-wait. - A hybrid works well: poll in latency-critical threads (touch, CAN) and use
delay()or events everywhere else.
- Ticket-Lock Mutex with fair FIFO ordering β all peripheral drivers inherit
Mutexautomatically via theDrvbase class. - Mutex Watchdog (
THREAD_WATCHDOG_ENABLE) that detects deadlocks and invokes a user-defined handler. - Thread protect/unprotect API to guard against unsafe
thread::remove()during critical sections. - IRQ-associated Mutex:
setIrq()automatically disables the linked hardware interrupt while the lock is held.
malloc()for internal SRAM (default heap).cmalloc()for fast CCM (Core Coupled Memory) DATA RAM.hmalloc()for high-speed SRAM β used internally for scheduler stacks.lmalloc()for multi-megabyte external SDRAM / HyperRAM pools (FrameBuffers & graphics).- Stack watermark pattern (
FILL_THREAD_STACK) for high-water analysis.
Unified C++ driver classes for 36+ peripheral types:
| Category | Peripherals |
|---|---|
| Communication | UART, USART, SPI, QSPI, I2C, I2S, PDM |
| Bus | CAN, CAN-FD, USB Device |
| Storage | SDMMC, SDRAM, HBI (HyperBus) |
| Analog | ADC, DAC |
| Motion | PWM, Timer, Capture, Quadrature Encoder |
| System | GPIO, EXTI, DMA, DMA2D, NVIC, CRC, Flash, Watchdog, RTC |
| Wireless | BLE 4.0 Radio |
- FAT32 File System abstraction layer (Read-only).
- TurtleShip C++ embedded GUI framework with
FrameBuffer,Brush,Font,Button,Label,Container,DisplayPageManager, and full RGB565/BGR565/RGB888 color support. - BLE 4.0 support via
Ble4p0/BleRadioHAL abstraction.
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application / BSP Layer β
β thread::, trigger::, mutex::, event:: β
βββββββββββββββββββββββ¬βββββββββββββββββββββββββββ€
β System Services β Middleware β
β scheduler, malloc β FAT32, TurtleShip GUI β
βββββββββββββββββββββββ΄βββββββββββββββββββββββββββ€
β HAL Layer β
β hal::Ble, hal::MassStorage, hal::Memory β
ββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Driver Layer (drv) β
β Uart, Spi, I2c, Gpio, Timer, Adc, Can ... β
β (Drv base class β Mutex inherited) β
ββββββββββββββββββββββββββββββββββββββββββββββββββ€
β MCU Target Implementation β
β nordic/ nuvoton/ analog_devices/ st/ ... β
ββββββββββββββββββββββββββββββββββββββββββββββββββ
All peripheral drivers inherit from Drv, which inherits from Mutex. This means every driver is automatically thread-safe with lock() / unlock() β no manual synchronization wrappers needed.
#include <yss.h>
#include <bsp.h>
// Each function runs as an independent RTOS thread
void thread_led1(void)
{
while (1)
{
gpioA.setOutput(0, true);
thread::delay(500); // yields CPU to other threads
gpioA.setOutput(0, false);
thread::delay(500);
}
}
// Trigger: one-shot deferred handler (e.g., from ISR context)
triggerId_t gTriggerTxLed;
void trigger_txLed(void)
{
led::setLed1(true);
thread::delay(20);
led::setLed1(false);
}
int main(void)
{
// 1. Initialize yss RTOS kernel
initializeYss();
// 2. Initialize board peripherals
initializeBoard();
// 3. Register threads and triggers
thread::add(thread_led1, 512);
gTriggerTxLed = trigger::add(trigger_txLed, 512);
// 4. Idle loop
while (1)
{
thread::yield();
}
}The following real-world projects have been built and verified using yss OS:
| Board / Product | MCU | Verified Features |
|---|---|---|
| nRF52840-DK | Nordic nRF52840 | LED, UART, Timer (1kHz~100kHz), BLE 4.0 Advertising |
| NuMaker-M251KG | Nuvoton M251 | SPI TFT-LCD (ST7789V), GUI, Font rendering, MutexWatchdog |
| GM100 | Nuvoton M4xx | QSPI LCD, I2C Touch (GT911), FRAM, CAN-FD, HyperRAM, SD Card |
| Feature | yss OS | Arduino |
|---|---|---|
| Execution Model | Preemptive RTOS (PendSV context switch) | Single loop (setup() + loop()) |
| Multitasking | Built-in (thread::add) |
Not available by default |
| Thread Safety | Ticket-Lock Mutex, auto-lock per driver | None (single-thread assumed) |
| Timing Precision | Β΅s-accurate real-time (SysTick) | millis() β vulnerable to ISR delays |
| C++ Usage | Inheritance, virtual functions, namespaces, strong-typed error codes | Global objects, minimal OOP |
| Error Handling | error_t enum (130+ codes) |
Mostly silent failures |
| ISR Handling | trigger:: one-shot deferred context |
attachInterrupt() simple callback |
| GUI | TurtleShip framework (OS-level integration) | Third-party (Adafruit GFX, LVGL) |
| Multi-core | Built-in (YSS__MULTI_CORE) |
Board-specific, experimental |
Positioning: yss OS is not a replacement for Arduino β it is the next step. Arduino is ideal for rapid prototyping; yss OS is designed for production firmware where real-time guarantees, thread safety, and hardware control matter.
yss OS is primarily developed and tested using Rowley Crossworks for ARM on Ubuntu Linux.
- Recommended IDE: Rowley Crossworks for ARM
- Why Crossworks for ARM?
- Full C++ standard library support optimized for embedded microcontrollers.
- Native cross-platform support for Linux (Ubuntu).
- Professional-grade debugging, flashing, and toolchain features for production firmware.
- Remove debug artifact (
if(id == 3) __NOP();in scheduler) - Fix typos in
error.h(ERROR_INTERRUP,NOT_HAVE_SPECIFICATON) - Add stack overflow detection (MPU guard or canary pattern)
- Unit test infrastructure for host-side simulation
- Priority-based scheduling (alongside existing Round-Robin)
- FAT32 write support
- STM32H7 dual-core support
- PlatformIO integration
- POSIX-compatible thread API wrapper
- RISC-V porting exploration
- Package manager support (vcpkg / conan)
For comprehensive technical guides, architecture deep-dives, API references, and subsystem tutorials, visit the project wiki:
π yss RTOS GitHub Wiki
This project is open-source and released under the MIT License.
This README was reviewed and updated on 2026-09-11 based on a comprehensive static analysis of the yss OS source code, scheduler implementation, driver architecture, and verified example projects.
The analysis covered:
- Core kernel internals (
yss_scheduler.cpp,yss_multi_core_scheduler.cpp) - Mutex / synchronization primitives (
Mutex.h,Drv.h) - All 36+ peripheral driver headers
- 18 MCU-family configuration files
- Real-world example projects: nRF52840-DK, NuMaker-M251KG, GM100
Reviewed and updated by Claude Sonnet 4.6 (Thinking) (Anthropic) via Antigravity (Google DeepMind) β 2026-09-11