Real-Time operating system for ARM Cortex-M — written in C++11.
سیستمعامل بلادرنگ برای ARM Cortex-M — نوشتهشده با C++11.
🚀 Quick Start Guideراهنمای شروع سریع
1. Prerequisitesپیشنیازها
1.1 Hardware You Needسختافزار مورد نیاز
| Itemقطعه | Specificationمشخصات | Where to Buyخرید |
|---|---|---|
| STM32F103C8T6 | "Blue Pill" board | AliExpress, Amazon |
| ST-Link V2 | Debugger/Programmer | AliExpress, Amazon |
| USB Cable | Micro-USB | Any electronics shop |
| Jumper Wires | Male-to-female, 10+ pcs | Any electronics shop |
| LED + Resistor | 220Ω–1kΩ | Any electronics shop |
Use your actual hardware and development-tool costs; no fixed project cost is specified.هزینه سختافزار و ابزارها به برد و تجهیزات انتخابی شما بستگی دارد.
1.2 Software You Needنرمافزار مورد نیاز
| Softwareنرمافزار | Purposeکاربرد | Linkلینک |
|---|---|---|
| STM32CubeIDE | IDE + CubeMXمحیط توسعه | st.com |
| ST-Link Driver | Debugger connectionاتصال دیباگر | Included with IDEشامل IDE |
1.3 What You Should Knowچیزهایی که باید بدانید
| Topicموضوع | Levelسطح |
|---|---|
| C/C++ programming | Basicمبتدی |
| What is an RTOS?RTOS چیست؟ | Basicمبتدی |
| ARM Cortex-M | Optional (helpful)اختیاری (مفید) |
2. Installationنصب
2.1 Install STM32CubeIDEنصب STM32CubeIDE
- Go to st.com and download STM32CubeIDE (free, ~2GB)به st.com بروید و STM32CubeIDE را دانلود کنید (رایگان، حدود ۲ گیگابایت)
- Create a free ST account if promptedدر صورت درخواست، یک حساب کاربری رایگان ST بسازید
- Install the IDE (includes ST-Link drivers)IDE را نصب کنید (شامل درایورهای ST-Link)
2.2 Download ZenOSدانلود ZenOS
git clone https://github.com/Raymon-Research-Team/ZenOS-RTOS.git
2.3 Copy Files to Your Projectکپی فایلها به پروژه شما
Copy these files from ZenOS/ to your CubeMX project:این فایلها را از ZenOS/ به پروژه CubeMX خود کپی کنید:
| Source Fileفایل مبدا | Destinationمقصد |
|---|---|
ZenOS.hpp | Inc/ |
ZenOS_c.h | Inc/ |
ZenOS_Config.hpp | Inc/ |
ZenOS_Internal.hpp | Inc/ |
ZenOS_Port.hpp | Inc/ |
ZenOS.cpp | Src/ |
ZenOS_Scheduler.cpp | Src/ |
ZenOS_IPC.cpp | Src/ |
ZenOS_Safety.cpp | Src/ |
ZenOS_Monitor.cpp | Src/ |
2.4 Configure Compilerپیکربندی کامپایلر
In STM32CubeIDE: Project → Properties → C/C++ Build → Settingsدر STM32CubeIDE: Project → Properties → C/C++ Build → Settings
MCU C++ Compiler → Miscellaneous → -std=c++11MCU C++ Compiler → Optimization → -O2
3. Your First ZenOS Projectاولین پروژه ZenOS شما
os_tick() to SysTick_Handler in Src/stm32fxxx_it.c:
مرحله حیاتی ۳: os_tick() را به SysTick_Handler در فایل Src/stm32fxxx_it.c اضافه کنید:
// In Src/stm32fxxx_it.c
#include "ZenOS.hpp" // Add at top of file
void SysTick_Handler(void) {
os_tick(); // ZenOS receives its tick interrupt here
}
main.c, but ZenOS requires C++11. You must rename Src/main.c to Src/main.cpp. Right-click the file in your IDE → Rename → change .c to .cpp. Also ensure all .cpp files are compiled as C++ (not C) in your project settings.
مرحله حیاتی ۴: CubeMX فایل main.c را تولید میکند، اما ZenOS به C++11 نیاز دارد. باید فایل Src/main.c را به Src/main.cpp تغییر نام دهید. روی فایل در IDE راست کلیک کنید → Rename → .c را به .cpp تغییر دهید. همچنین مطمئن شوید تمام فایلهای .cpp به عنوان C++ (نه C) کامپایل میشوند.
3.1 Complete main.cppفایل کامل main.cpp
#include "ZenOS.hpp"
/* ─── Task: Blink LED ─── */
void task_blink(void) {
while (1) {
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // Toggle LED
os_delay_ms(500); // Wait 500ms
}
}
/* ─── Main ─── */
int main(void) {
HAL_Init();
SystemClock_Config(); // Generated by CubeMX
MX_GPIO_Init(); // Generated by CubeMX
MX_TIM1_Init(); // Generated by CubeMX
os_init(); // Initialize ZenOS kernel
os_task_create(task_blink, 5); // Create task with priority 5
os_start(); // Start scheduler (never returns!)
while (1) {} // Never reached
}
os_start() and never returns. The task blocks for 500ms between LED toggles, and you don't write scheduling code.
همین! هسته سیستمعامل از os_start() کنترل را به دست میگیرد و هرگز برنمیگردد. تسک شما هر ۵۰۰ میلیثانیه اجرا میشود، LED چشمک میزند، و شما حتی یک خط کد زمانبندی هم ننوشتید.
4. Build & Flashبیلد و فلش
- Click Build (hammer icon) — should compile with 0 errorsروی Build (آیکون چکش) کلیک کنید — باید بدون خطا کامپایل شود
- Connect Blue Pill via ST-Link debuggerبلو پیل را از طریق دیباگر ST-Link وصل کنید
- Click Run (play icon) — flash to Blue Pillروی Run (آیکون پخش) کلیک کنید — به بلو پیل فلش شود
- The built-in LED (PC13) should toggle every 500ms while the task sleeps! 🎉LED داخلی (PC13) باید هر ۵۰۰ میلیثانیه چشمک بزند! 🎉
4.1 Common Beginner Mistakesاشتباهات رایج مبتدیان
| Mistakeاشتباه | Symptomعلائم | Solutionراهحل |
|---|---|---|
Task has no while(1) | System crashesسیستم کرش میکند | Always use while(1) {}همیشه از while(1) {} استفاده کنید |
| Task never yieldsتسک هرگز واگذاری نمیکند | Watchdog resetریست تایمر | Add os_delay_ms() |
| Forgot os_tick()os_tick() را فراموش کرده | Tick counter stuck at 0شمارنده تیک روی ۰ گیر کرده | Add to SysTick_Handlerبه SysTick_Handler اضافه کنید |
| C++ not enabledC++ فعال نیست | Compilation errorsخطاهای کامپایل | Add -std=c++11 |
| Task created after os_start()تسک بعد از os_start() ایجاد شده | Returns -1 | Create tasks before os_start()تسکها را قبل از os_start() بسازید |
📘 API Referenceمرجع API
1. Task Managementمدیریت تسکها
What is a Task? A task is an independent function that runs forever in its own context. Think of it as a separate program that runs simultaneously with other tasks. Each task has its own stack (memory for local variables), its own priority (determines execution order), and can be periodic (runs at fixed intervals) or aperiodic (runs whenever scheduled).تسک چیست؟ تسک یک تابع مستقل است که برای همیشه در بافت خودش اجرا میشود. آن را به عنوان یک برنامه مستقل در نظر بگیرید که همزمان با تسکهای دیگر اجرا میشود. هر تسک پشته خودش (حافظه برای متغیرهای محلی)، اولویت خودش (ترتیب اجرا) را دارد و میتواند دورهای (در فواصل ثابت اجرا میشود) یا غیردورهای (هر وقت زمانبندی شود اجرا میشود) باشد.
How it works: When you call os_task_create(), ZenOS allocates a Task Control Block (TCB) and a stack for the task. The TCB stores the task's state, priority, and context. When os_start() is called, the scheduler begins running the highest-priority ready task. Tasks can block (sleep) using delays or IPC, allowing lower-priority tasks to run.نحوه کار: وقتی os_task_create() را فراخوانی میکنید، ZenOS یک بلوک کنترل تسک (TCB) و یک پشته برای تسک تخصیص میدهد. TCB وضعیت تسک، اولویت و زمینه را ذخیره میکند. وقتی os_start() فراخوانی میشود، زمانبند شروع به اجرای تسک آماده با بالاترین اولویت میکند. تسکها میتوانند با استفاده از تاخیرها یا IPC بلاک (بخوابند) که به تسکهای با اولویت پایینتر اجازه اجرا میدهد.
// Create tasks (call BEFORE os_start())
os_task_create(task_function, priority); // Default stack (128 bytes, 256-byte effective floor)
os_task_create(task_function, priority, period_ms); // + Periodic
os_task_create_st(task_function, priority, period_ms, stack_bytes); // Custom stack
// Control tasks (call AFTER os_start())
os_task_start(task_function); // Activate a stopped task
os_task_stop(task_function); // Deactivate a task
bool running = os_task_isActive(task_function); // Check state
What happens: os_task_create(task_blink, 5) creates a task named "task_blink" with priority 5. The task will be scheduled to run when os_start() is called. os_task_create(task_sensor, 3, 100) creates a periodic task with a 100ms release interval. os_task_create_st(task_ui, 8, 0, 1024) creates a task with a custom 1KB stack (useful for tasks that use printf or deep function calls).چه اتفاقی میافتد: os_task_create(task_blink, 5) یک تسک به نام "task_blink" با اولویت ۵ ایجاد میکند. این تسک وقتی os_start() فراخوانی شود زمانبندی میشود. os_task_create(task_sensor, 3, 100) یک تسک دورهای ایجاد میکند که هر ۱۰۰ میلیثانیه اجرا میشود. os_task_create_st(task_ui, 8, 0, 1024) یک تسک با پشته سفارشی ۱ کیلوبایت ایجاد میکند (برای تسکهایی که از printf یا فراخوانیهای عمیق تابع استفاده میکنند مفید است).
Priority Guidelinesراهنمای اولویت
| Priorityاولویت | Usageکاربرد |
|---|---|
| 1 | Lowest application priorityپایینترین اولویت |
| 2–4 | Background tasks (sensors, logging)تسکهای پسزمینه |
| 5–10 | Normal tasks (UI, communication)تسکهای عادی |
| 11–20 | High-priority tasks (safety)تسکهای با اولویت بالا |
| 21+ | ISR-like tasks (time-critical)تسکهای حساس به زمان |
Stack Sizing Guideراهنمای اندازه پشته
| Task Typeنوع تسک | Recommended Stackپشته پیشنهادی |
|---|---|
| LED blink | 128–256 bytes |
| Sensor reading (HAL) | 256–512 bytes |
| UART communication | 512–1024 bytes |
| SPI/I2C + protocol | 512–1024 bytes |
| printf / float formatting | 1024–2048 bytes |
2. Timing & Delaysزمانبندی و تاخیرها
What is Timing? Timing is how ZenOS keeps track of time and manages task execution intervals. The kernel tick (default 100μs) is the heartbeat of the system — every tick, the scheduler checks which tasks should run. Delays allow tasks to sleep for a specified time, giving other tasks a chance to execute.زمانبندی چیست؟ زمانبندی نحوه ردیابی زمان و مدیریت فواصل اجرای تسک توسط ZenOS است. تیک هسته (پیشفرض ۱۰۰ میکروثانیه) ضربان قلب سیستم است — در هر تیک، زمانبند بررسی میکند کدام تسکها باید اجرا شوند. تاخیرها به تسکها اجازه میدهند برای مدت زمان مشخصی بخوابند و به تسکهای دیگر فرصت اجرا بدهند.
os_delay_ms(100); // Sleep ~100ms, yield CPU to other tasks
os_delay_ms(0); // No implicit yield; use os_yield() to yield
os_delay_us(10); // Busy-wait ~10µs (blocks CPU — no other task runs!)
uint32_t ms = os_get_ms(); // Milliseconds since boot
uint32_t us = os_get_us(); // Microseconds since boot (DWT counter)
uint32_t tick = os_get_tick(); // Raw tick count
What happens: os_delay_ms(100) puts the current task to sleep for 100ms. During this time, the scheduler runs other ready tasks. When 100ms passes, the task wakes up and continues. os_delay_ms(0) returns immediately without yielding; use os_yield() to yield — useful when you want to give other tasks a chance to run without actually sleeping. os_delay_us(10) busy-waits for 10μs — the CPU does nothing else during this time (use only for sub-millisecond delays).چه اتفاقی میافتد: os_delay_ms(100) تسک فعلی را به مدت ۱۰۰ میلیثانیه میخواباند. در این مدت، زمانبند تسکهای آماده دیگر را اجرا میکند. وقتی ۱۰۰ میلیثانیه بگذرد، تسک بیدار شده و ادامه میدهد. os_delay_ms(0) فوراً برمیگردد بدون واگذاری؛ از os_yield() برای واگذاری استفاده کنید — مفید وقتی میخواهید به تسکهای دیگر فرصت اجرا بدهید بدون اینکه واقعاً بخوابید. os_delay_us(10) به مدت ۱۰ میکروثانیه انتظار مشغول میکشد — CPU در این مدت کار دیگری انجام نمیدهد (فقط برای تاخیرهای زیر میلیثانیه استفاده کنید).
os_delay_us() uses DWT cycle counter for busy-waiting. It does NOT yield the CPU. Use only for very short delays (<1ms).os_delay_us() از شمارنده DWT برای انتظار مشغول استفاده میکند و CPU را واگذار نمیکند. فقط برای تاخیرهای بسیار کوتاه استفاده کنید.Elapsed Time Measurementاندازهگیری زمان سپری شده
uint32_t t0 = os_get_ms();
// ... do work ...
uint32_t elapsed = os_get_ms() - t0; // Works even if ms wraps (~49 days)
3. Critical Sections (OS_SAFE)بخشهای بحرانی (OS_SAFE)
What is a Critical Section? A critical section is a piece of code that accesses shared data that might also be accessed by an interrupt service routine (ISR). Without protection, an interrupt could happen in the middle of updating a variable, leaving it in an inconsistent state. OS_SAFE disables all interrupts for the duration of the block, ensuring atomic access to shared data.بخش بحرانی چیست؟ بخش بحرانی قطعهای از کد است که به داده مشترکی دسترسی دارد که ممکن است توسط یک روتین سرویس وقفه (ISR) نیز دسترسی داشته باشد. بدون محافظت، یک وقفه میتواند در وسط بهروزرسانی یک متغیر رخ دهد و آن را در وضعیت ناسازگار باقی بگذارد. OS_SAFE تمام وقفهها را برای مدت بلوک غیرفعال میکند و دسترسی اتمی به داده مشترک را تضمین میکند.
volatile uint32_t shared_counter = 0;
OS_SAFE {
shared_counter++; // Interrupts disabled here
}
// Interrupts re-enabled here
What happens: When the task enters OS_SAFE { ... }, all interrupts are immediately disabled (CPSID I instruction). The code inside the block executes without any interrupt interference. When the block ends, interrupts are re-enabled (CPSIE I). This is implemented using C++ RAII — even if an exception occurs, interrupts are always re-enabled. Keep critical sections short! Long critical sections increase interrupt latency.چه اتفاقی میافتد: وقتی تسک وارد OS_SAFE { ... } میشود، تمام وقفهها فوراً غیرفعال میشوند (دستورالعمل CPSID I). کد داخل بلوک بدون هیچ تداخل وقفهای اجرا میشود. وقتی بلوک تمام میشود، وقفهها دوباره فعال میشوند (دستورالعمل CPSIE I). این با استفاده از RAII C++ پیادهسازی میشود — حتی اگر خطایی رخ دهد، وقفهها همیشه دوباره فعال میشوند. بخشهای بحرانی را کوتاه نگه دارید! بخشهای بحرانی طولانی تاخیر وقفه را افزایش میدهند.
| Featureویژگی | OS_SAFE | OS_LOCK |
|---|---|---|
| Disables interruptsغیرفعال کردن وقفهها | ✅ | ❌ |
| Allows blocking callsاجازه فراخوانی بلاککننده | ❌ | ✅ |
| Protects from ISRsمحافظت از ISRs | ✅ | ❌ |
| Protects from other tasksمحافظت از تسکهای دیگر | ✅ | ✅ |
| Use caseمورد استفاده | Share data with ISRsاشتراک داده با ISRs | Protect shared resourcesمحافظت از منابع مشترک |
4. Events (OS_EVENT)رویدادها (OS_EVENT)
What is an Event? An event is a synchronization primitive used for inter-task signaling. Think of it as a "flag" that one task can raise (signal) and another task can wait for. Events use an internal counter — each signal() increments the counter, and each wait() decrements it (if > 0) or blocks until signaled or timeout. This makes events perfect for ISR-to-task communication and simple synchronization.رویداد چیست؟ رویداد یک اولیه همگامسازی برای سیگنالدهی بین تسکها است. آن را به عنوان یک "پرچم" در نظر بگیرید که یک تسک میتواند آن را بالا ببرد (سیگنال) و تسک دیگری منتظر آن باشد. رویدادها از یک شمارنده داخلی استفاده میکنند — هر signal() شمارنده را افزایش میدهد و هر wait() آن را کاهش میدهد (اگر > ۰ باشد) یا تا سیگنال یا تایماوت بلاک میشود. این رویدادها را برای ارتباط ISR-to-task و همگامسازی ساده عالی میکند.
OS_EVENT sensor_ready; // Create an event
// Waiter task (waits for the event):
if (sensor_ready.wait(1000)) { // Wait up to 1000ms
process_sensor_data(); // Event was signaled!
} else {
handle_timeout(); // Timeout — no signal received
}
// Signaler task (signals the event):
read_sensor();
sensor_ready.signal(); // Wake up the waiter
// ISR-safe signaling (use in interrupt handlers):
sensor_ready.signal_from_isr();
What happens: Task A calls sensor_ready.wait(1000) and blocks (sleeps). Task B reads a sensor, then calls sensor_ready.signal(). This wakes up Task A, which then processes the data. If Task B doesn't signal within 1000ms, Task A wakes up with false (timeout). Important: Always use signal_from_isr() in interrupt handlers — calling signal() from an ISR is undefined behavior.چه اتفاقی میافتد: تسک A فراخوانی sensor_ready.wait(1000) میکند و بلاک (میخوابد). تسک B یک حسگر میخواند، سپس sensor_ready.signal() را فراخوانی میکند. این تسک A را بیدار میکند که سپس داده را پردازش میکند. اگر تسک B ظرف ۱۰۰۰ میلیثانیه سیگنال ندهد، تسک A با false (تایماوت) بیدار میشود. مهم: همیشه از signal_from_isr() در روتینهای وقفه استفاده کنید — فراخوانی signal() از ISR رفتار تعریف نشده است.
Signal Accumulationتجمع سیگنال
OS_EVENT evt;
evt.signal(); // count = 1
evt.signal(); // count = 2
evt.signal(); // count = 3
evt.wait(); // count = 2 (returns 1)
evt.wait(); // count = 1 (returns 1)
evt.wait(); // count = 0 (returns 1)
evt.wait(); // returns 0 (timeout — count was already 0)
What happens: Multiple signals accumulate in the counter. Each wait() consumes one signal. If 3 signals are sent before any wait, the first 3 waits return immediately (count > 0). The 4th wait blocks until a new signal arrives or timeout. Use case: Multiple ISRs can signal the same event, and the task processes all pending signals one by one.چه اتفاقی میافتد: سیگنالهای متعدد در شمارنده تجمع مییابند. هر wait() یک سیگنال مصرف میکند. اگر ۳ سیگنال قبل از هر wait ارسال شود، ۳ wait اول فوراً برمیگردند (count > ۰). wait چهارم تا رسیدن سیگنال جدید یا تایماوت بلاک میشود. مورد استفاده: ISRهای متعدد میتوانند به یک رویداد سیگنال بدهند و تسک تمام سیگنالهای معلق را یکی یکی پردازش میکند.
5. Mutexes (OS_MUTEX)قفلها (OS_MUTEX)
What is a Mutex? A mutex (mutual exclusion) is a lock that ensures only one task can access a shared resource at a time. Think of it as a key to a room — only the task holding the key (locked mutex) can enter the room (use the resource). When the task leaves, it returns the key (unlocks), allowing another task to enter. ZenOS mutexes support recursive locking (same task can lock multiple times) and IPC priority ceiling (prevents priority inversion).Mutex چیست؟ mutex (حذف متقابل) یک قفل است که تضمین میکند فقط یک تسک در هر زمان بتواند به یک منبع مشترک دسترسی داشته باشد. آن را به عنوان کلید یک اتاق در نظر بگیرید — فقط تسکی که کلید (قفل mutex) را در اختیار دارد میتواند وارد اتاق (منبع را استفاده کند) شود. وقتی تسک خارج میشود، کلید را برمیگرداند (قفل را باز میکند) و به تسک دیگری اجازه ورود میدهد. mutexهای ZenOS از قفل بازگشتی (همین تسک میتواند چندین بار قفل کند) و سقف IPC (جلوگیری از وارونگی اولویت) پشتیبانی میکنند.
OS_MUTEX uart_mtx; // Create a mutex for UART
// RAII lock guard (auto-unlocked when block ends)
OS_LOCK(uart_mtx) { // Acquire mutex
HAL_UART_Transmit(&huart1, data, len, 100); // Use resource
} // Auto-released when block ends
// Manual lock/unlock
if (mtx.lock(1000)) { // Wait up to 1000ms
do_work();
mtx.unlock();
}
// With IPC priority ceiling (IPC priority ceiling)
OS_MUTEX shared_data_mtx(8); // Ceiling priority = 8
What happens: When Task A enters OS_LOCK(uart_mtx), it acquires the mutex. If Task B tries to enter while Task A holds it, Task B blocks until Task A exits. OS_LOCK is an RAII guard — it automatically releases the mutex when the block ends. IPC Ceiling: When you pass a ceiling priority (e.g., OS_MUTEX mtx(8)), the task's priority is temporarily boosted to that level while holding the mutex, preventing priority inversion.چه اتفاقی میافتد: وقتی تسک A وارد OS_LOCK(uart_mtx) میشود، mutex را به دست میآورد. اگر تسک B سعی کند وارد شود در حالی که تسک A آن را نگه داشته، تسک B بلاک میشود تا تسک A خارج شود. OS_LOCK یک محافظ RAII است — به طور خودکار mutex را آزاد میکند. سقف IPC: اولویت تسک به طور موقت به سطح سقف افزایش مییابد و از وارونگی اولویت جلوگیری میکند.
6. Queues (OS_QUEUE)صفوف (OS_QUEUE)
What is a Queue? A queue is a FIFO (First-In-First-Out) data structure for passing data between tasks or from ISRs to tasks. Think of it as a pipe — one task puts data in one end, and another task takes it out the other end. Queues are type-safe (using C++ templates), thread-safe, and can hold a fixed number of items. If the queue is full, the producer can wait or drop the data. If empty, the consumer can wait or timeout.صف چیست؟ صف یک ساختمان داده FIFO (اول وارد شده، اول خارج شده) برای انتقال داده بین تسکها یا از ISRs به تسکهاست. آن را به عنوان یک لوله در نظر بگیرید — یک تسک داده را در یک انتها میگذارد و تسک دیگر آن را از انتهای دیگر بیرون میآورد. صفها ایمن از نظر نوع (با الگوهای C++), ایمن از نظر رشتهای هستند و تعداد ثابتی آیتم نگه میدارند. اگر صف پر باشد، تولیدکننده میتواند منتظر بماند یا داده را رها کند.
How it works: When you declare OS_QUEUE<int, 8> sensor_queue;, ZenOS reserves space for 8 integers in a circular buffer. put() adds an item to the tail, get() removes from the head. If the queue is full and you call put() with a timeout, the task blocks until space is available. If the queue is empty and you call get(), the task blocks until data arrives.نحوه کار: وقتی OS_QUEUE<int, 8> sensor_queue; را اعلام میکنید، ZenOS فضایی برای ۸ عدد در بافر دایرهای رزرو میکند. put() آیتمی به انتها اضافه میکند، get() از سر حذف میکند. اگر صف پر باشد و put() را با تایماوت فراخوانی کنید، تسک تا فراهم شدن فضا بلاک میشود.
OS_QUEUE<int, 8> sensor_queue; // Capacity: 8 items of type int
// Producer — puts data into the queue:
sensor_queue.put(42); // Non-blocking: add 42 to queue
sensor_queue.put(100, 100); // Blocking: wait up to 100ms if full
// Consumer — gets data from the queue:
int value;
if (sensor_queue.get(value, 1000)) { // Wait up to 1000ms
process(value); // Got data!
} else {
handle_timeout(); // No data within 1000ms
}
// ISR-safe (use in interrupt handlers):
sensor_queue.put_from_isr(val); // Signal from ISR to task
// Check queue status:
bool empty = sensor_queue.is_empty();
bool full = sensor_queue.is_full();
uint8_t count = sensor_queue.count(); // Items waiting
Example output: If the sensor task puts values 10, 20, 30 into the queue, and the consumer calls get() three times, it receives 10, then 20, then 30 (FIFO order). If the consumer calls get() when the queue is empty, it blocks until data arrives or timeout.مثال: اگر تسک حسگر مقادیر ۱۰، ۲۰، ۳۰ را در صف بگذارد و مصرفکننده سه بار get() فراخوانی کند، به ترتیب ۱۰، سپس ۲۰، سپس ۳۰ دریافت میکند (ترتیب FIFO). اگر مصرفکننده وقتی صف خالی است get() فراخوانی کند، تا رسیدن داده یا تایماوت بلاک میشود.
Queue for Sensor Data Pipelineصف برای خط لوله داده حسگر
struct SensorData {
uint16_t temperature;
uint16_t humidity;
uint32_t timestamp;
};
OS_QUEUE<SensorData, 16> data_queue; // Queue of 16 SensorData structs
// Task 1: Read sensor every 100ms
void task_reader(void) {
while (1) {
SensorData d;
d.temperature = ADC_ReadTemp();
d.humidity = ADC_ReadHumidity();
d.timestamp = os_get_ms();
data_queue.put(d, 50); // Wait max 50ms if full
os_delay_ms(100);
}
}
// Task 2: Send data to UART
void task_sender(void) {
while (1) {
SensorData d;
if (data_queue.get(d, 1000)) {
printf("T=%u H=%u\n", d.temperature, d.humidity);
}
}
}
What happens: Task 1 reads sensor data every 100ms and puts it into the queue. Task 2 waits for data and sends it over UART. If Task 2 is slower than Task 1, the queue fills up and Task 1 waits. If Task 2 is faster, it waits for new data. The queue acts as a buffer between the two tasks, decoupling their speeds.چه اتفاقی میافتد: تسک ۱ هر ۱۰۰ میلیثانیه داده حسگر را میخواند و در صف میگذارد. تسک ۲ منتظر داده میماند و آن را از UART ارسال میکند. اگر تسک ۲ کندتر از تسک ۱ باشد، صف پر شده و تسک ۱ منتظر میماند. صف به عنوان بافر بین دو تسک عمل میکند و سرعت آنها را از هم جدا میکند.
7. Semaphores (OS_SEMAPHORE)سمافورها (OS_SEMAPHORE)
What is a Semaphore? A semaphore is a counter-based synchronization primitive. Think of it as a pool of resources — the counter represents the number of available resources. wait() decrements the counter (takes a resource), and signal() increments it (returns a resource). If the counter is 0, wait() blocks until someone signals. Semaphores are perfect for limiting concurrent access to a resource pool (e.g., 5 available buffers, 3 UART ports).سمافور چیست؟ سمافور یک اولیه همگامسازی مبتنی بر شمارنده است. آن را به عنوان مجموعهای از منابع در نظر بگیرید — شمارنده تعداد منابع موجود را نشان میدهد. wait() شمارنده را کاهش میدهد (منبعی برمیدارد) و signal() آن را افزایش میدهد (منبعی برمیگرداند). اگر شمارنده ۰ باشد، wait() تا سیگنال کسی بلاک میشود. سمافورها برای محدود کردن دسترسی همزمان به مجموعه منابع عالی هستند.
OS_SEMAPHORE(5) resource_sem; // Max 5 concurrent users
// Task that uses a shared resource:
if (resource_sem.wait(1000)) { // Wait for available resource
use_resource(); // Use the resource
resource_sem.signal(); // Return the resource
}
What happens: Imagine you have 5 buffer slots. Each task calls resource_sem.wait() before using a buffer (counter decrements: 5→4→3→...). When all 5 are in use, the next task blocks. When a task calls resource_sem.signal(), the counter increments and the next waiting task wakes up.چه اتفاقی میافتد: فرض کنید ۵ اسلات بافر دارید. هر تسک قبل از استفاده از بافر resource_sem.wait() فراخوانی میکند (شمارنده کاهش: ۵→۴→۳→...). وقتی همه ۵ در حال استفاده باشند، تسک بعدی بلاک میشود. وقتی تسکی resource_sem.signal() فراخوانی میکند، شمارنده افزایش یافته و تسک منتظر بیدار میشود.
// Example: Limit UART access to 1 task at a time
OS_SEMAPHORE(1) uart_sem; // Binary semaphore (max=1)
void task_send(const char* msg) {
if (uart_sem.wait(500)) {
HAL_UART_Transmit(&huart1, msg, strlen(msg), 100);
uart_sem.signal();
}
}
8. Periodic Tasksتسکهای دورهای
Periodic task model: ZenOS stores the third argument of os_task_create() as period_ticks and uses next_run_time as a scheduler release gate. A periodic task becomes eligible only when the current tick reaches its next release time. After the task runs, the kernel advances the next release according to the configured period. A period of 0 means no periodic release gate.مدل تسک دورهای: ZenOS آرگومان سوم os_task_create() را بهصورت period_ticks نگهداری میکند و از next_run_time بهعنوان دروازه آزادسازی در زمانبند استفاده میکند. تسک دورهای فقط وقتی واجد شرایط اجراست که تیک جاری به زمان آزادسازی بعدی برسد. پس از اجرای تسک، هسته زمان آزادسازی بعدی را بر اساس دوره تنظیم میکند. دوره 0 یعنی هیچ دروازه آزادسازی دورهای وجود ندارد.
void task_sensor(void) {
while (1) {
uint16_t val = ADC_Read();
sensor_queue.put(val, 100);
// Give the scheduler a chance to run another ready task.
os_yield();
}
}
// The period is recorded in the TCB.
// Do not describe it as an enforced wake-up interval
// until the scheduler's period gate is enabled.
os_task_create(task_sensor, 3, 100);
Why os_yield() here? A periodic-task example should use os_yield(), not an arbitrary os_delay_ms() value, when the intention is to demonstrate cooperative rescheduling. os_delay_ms() is a real blocking delay and should be documented separately as a sleep primitive.چرا اینجا os_yield()؟ در مثال یک تسک دورهای، وقتی هدف نشاندادن واگذاری اجرای CPU است، باید از os_yield() استفاده شود، نه یک مقدار دلخواه برای os_delay_ms(). تابع os_delay_ms() یک تأخیر واقعی و مسدودکننده است و باید جداگانه بهعنوان primitive خوابدادن تسک توضیح داده شود.
next_run_time before selecting a periodic task. The task should call os_yield() after its work; os_delay_ms() remains a separate blocking sleep primitive.اجرای دورهای: زمانبند پیش از انتخاب تسک دورهای، next_run_time را بررسی میکند. تسک باید پس از انجام کار از os_yield() استفاده کند؛ os_delay_ms() همچنان یک primitive برای خواب و تأخیر مسدودکننده است.Periodic vs One-Shot Tasksدورهای در مقابل یکبار اجرا
// Periodic: released every 50ms
os_task_create(task_blink, 5, 50); // 3rd param = period
// Aperiodic task: period = 0 means no release gate
os_task_create(task_handler, 5, 0);
// Stop/start explicitly when event-driven control is required:
os_task_stop(task_handler);
os_task_start(task_handler);
What happens: A task with period 50 becomes eligible at each 50-tick release boundary (50 ms when the kernel tick is 1 ms). A period of 0 means the task has no periodic release gate; it remains schedulable until it is blocked, stopped, or otherwise made ineligible.چه اتفاقی میافتد: تسک با دوره ۵۰ در هر مرز آزادسازی ۵۰ تیکی واجد شرایط اجرا میشود (اگر تیک هسته ۱ میلیثانیه باشد، یعنی هر ۵۰ میلیثانیه). دوره ۰ یعنی تسک دروازه آزادسازی دورهای ندارد و تا زمانی که بلاک یا متوقف نشده باشد، قابل زمانبندی است.
Complete Example: Sensor + LED Systemمثال کامل: سیستم حسگر + LED
OS_QUEUE<uint16_t, 8> temp_queue;
OS_EVENT temp_ready;
// Periodic sensor task (200ms release interval)
void task_sensor(void) {
while (1) {
uint16_t temp = read_temperature();
temp_queue.put(temp, 50);
temp_ready.signal(); // Notify processing task
os_yield(); // Yield to the scheduler
}
}
// Processing task (waits for sensor data)
void task_process(void) {
while (1) {
if (temp_ready.wait(500)) {
uint16_t temp;
if (temp_queue.get(temp, 100)) {
if (temp > 3000) { // > 30°C
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 0); // LED ON
} else {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 1); // LED OFF
}
}
}
}
}
int main(void) {
// ... HAL init ...
os_init();
os_task_create(task_sensor, 3, 200); // 200ms period
os_task_create(task_process, 5, 0); // Event-driven
os_start();
}
What happens: At each 200ms release boundary, task_sensor becomes eligible, reads the temperature and signals task_process. task_process waits for the signal, reads the temperature from the queue, and turns the LED on/off based on the value. This demonstrates periodic tasks, queues, and events working together.چه اتفاقی میافتد: هر ۲۰۰ میلیثانیه، task_sensor دما را میخواند و task_process را سیگنال میدهد. task_process منتظر سیگنال میماند، دما را از صف میخواند و LED را بر اساس مقدار روشن/خاموش میکند. این نشان میدهد تسکهای دورهای، صفها و رویدادها چگونه با هم کار میکنند.
9. Monitoring & Debuggingپایش و دیباگ
Why Monitor? In embedded systems, debugging is hard — you often can't attach a debugger to production devices. ZenOS provides built-in monitoring tools that help you track stack usage, CPU load, deadline compliance, and errors. These tools run in the background with minimal overhead, giving you visibility into your system's health without affecting real-time performance.چرا پایش؟ در سیستمهای توکار، دیباگ سخت است — اغلب نمیتوانید به دستگاههای تولیدی دیباگر وصل کنید. ZenOS ابزارهای پایش داخلی ارائه میدهد که به ردیابی مصرف پشته، بار CPU، رعایت ددلاین و خطاها کمک میکنند. این ابزارها در پسزمینه با حداقل سربار اجرا میشوند.
#if OS_MONITORING_EN
// Per-task stack usage — how many bytes the task has used
uint32_t bytes = os_get_stack_usage(task_function);
printf("Task stack usage: %u bytes\n", bytes);
// Full stack report — shows all tasks at once
uint8_t count = os_get_stack_report_count();
for (uint8_t i = 0; i < count; i++) {
os_stack_report_entry_t rep;
os_get_stack_report(i, &rep);
printf("%s: %u/%u bytes used\n", rep.name, rep.peak_bytes, rep.size_bytes);
}
// CPU usage — percentage of time each task runs
uint8_t total_cpu = os_get_cpu_usage_total(); // Total CPU usage %
uint8_t task_cpu = os_get_task_cpu_usage(task_function); // Per-task %
printf("Total CPU: %u%%, Task: %u%%\n", total_cpu, task_cpu);
#endif
// Deadline monitoring — detect if tasks miss their deadlines
#if OS_MONITORING_EN
os_task_set_deadline(task_safety, 50); // Set 50ms deadline
uint32_t misses = os_get_deadline_miss_count(task_safety);
if (misses > 0) {
printf("WARNING: Task missed deadline %u times!\n", misses);
}
#endif
// Error reporting — log errors with severity levels
os_log_error(OSError::SENSOR_TIMEOUT, (uint8_t)ErrorSeverity::WARNING);
uint32_t total_errors = os_get_error_count();
OSError last = os_get_last_error();
printf("Total errors: %u, Last: %d\n", total_errors, (int)last);
// Suppress expected errors during testing (won't trigger watchdog)
os_error_expect_begin();
/* intentionally trigger and verify the expected error */
os_event_signal(-1);
os_error_expect_end();
os_event_signal(-1); // Deliberately invalid — expected error
os_error_expect_end();
What happens: os_get_stack_usage() returns how many bytes of stack a task has used (peak watermark). If a task has a 512-byte stack and uses 480 bytes, you're close to overflow — increase the stack size. os_get_cpu_usage_total() returns total CPU utilization (0-100%). If it's above 80%, your system is overloaded. os_get_task_cpu_usage() shows which task is consuming the most CPU.چه اتفاقی میافتد: os_get_stack_usage() تعداد بایتهای استفادهشده از پشته تسک را برمیگرداند. اگر تسکی پشته ۵۱۲ بایتی دارد و ۴۸۰ بایت استفاده کرده، نزدیک به سرریز هستید — پشته را بزرگتر کنید. os_get_cpu_usage_total() کل استفاده CPU را برمیگرداند (۰-۱۰۰٪). اگر بالای ۸۰٪ باشد، سیستم بیش از حد بارگذاری شده است.
Monitoring Dashboard Exampleمثال داشبورد پایش
void task_monitor(void) {
while (1) {
printf("\n=== System Status ===\n");
printf("Uptime: %u ms\n", os_get_ms());
printf("CPU Usage: %u%%\n", os_get_cpu_usage_total());
// Stack report
uint8_t count = os_get_stack_report_count();
for (uint8_t i = 0; i < count; i++) {
os_stack_report_entry_t rep;
os_get_stack_report(i, &rep);
printf(" %s: %u/%u bytes (%u%% used)\n",
rep.name, rep.peak_bytes, rep.size_bytes,
(rep.peak_bytes * 100) / rep.size_bytes);
}
os_delay_ms(5000); // Print status every 5 seconds
}
}
os_task_create(task_monitor, 1, 0); // Low priority, aperiodic
Example output:خروجی مثال:
=== System Status ===
Uptime: 15230 ms
CPU Usage: 45%
task_blink: 48/256 bytes (18% used)
task_sensor: 128/512 bytes (25% used)
task_uart: 256/1024 bytes (25% used)
🛡️ Safety Featuresویژگیهای ایمنی
1. Safety Mechanismsمکانیسمهای ایمنی
Safety mechanisms are configurable and not all are enabled by default; they can be individually toggled in ZenOS_Config.hpp.مکانیسمهای ایمنی قابل پیکربندی هستند و همه به طور پیشفرض فعال نیستند؛ هر کدام را میتوان به طور جداگانه در ZenOS_Config.hpp تنظیم کرد.
| Mechanismمکانیسم | Config Macroماکرو | What it doesعملکرد |
|---|---|---|
| 🔍 Stack Canary | Always activeهمیشه فعال | Canary + SP bounds checking (runs every 16 ticks)بررسی کاناری + محدوده SP (هر ۱۶ تیک) |
| 🔐 TCB Integrity | OS_MONITORING_EN | Magic number validationاعتبارسنجی عدد جادو |
| ⏱️ Deadline Monitor | OS_MONITORING_EN | Detects deadline missesتشخیص از دست رفتن ددلاین |
| 📋 Error Log | OS_MONITORING_EN | Ring buffer with timestampبافر حلقهای با زمان |
| 🐕 HW Watchdog | OS_SAFETY_HW_WATCHDOG_EN | STM32 IWDG integrationادغام IWDG STM32 |
| 💤 SW Watchdog | OS_SAFETY_SOFT_WATCHDOG_EN | Detects stuck tasksتشخیص تسکهای گیر کرده |
| 🧪 RAM Test | OS_SAFETY_RAM_TEST_EN | Bounded SRAM integrity test (background)آزمون یکپارچگی SRAM محدود (پسزمینه) |
| ✅ CRC Check | OS_SAFETY_CRC_EN | Flash integrity via CRCیکپارچگی فلش از طریق CRC |
| 🛡️ MPU | OS_SAFETY_MPU_EN | Per-task memory protectionحفاظت حافظه هر تسک |
Safety Features APIAPI ویژگیهای ایمنی
#if OS_SAFETY_HW_WATCHDOG_EN
// Hardware watchdog feed (call from dedicated task)
void task_wdg_feeder(void) {
while (1) {
os_hw_watchdog_feed(); // Unconditional feed
os_delay_ms(1000); // Feed every 1s; timeout depends on the target IWDG configuration
}
}
// Or conditional feed (skip if unhealthy)
os_hw_watchdog_check(); // Only feeds if error_count < 10
#endif
#if OS_SAFETY_RAM_TEST_EN
// Background RAM test (call from idle or low-priority task)
os_ram_test_step(); // Test one word per call
if (os_ram_test_complete() && os_get_ram_test_error_count() > 0) {
// SRAM fault detected!
}
#endif
#if OS_SAFETY_CRC_EN
// ROM integrity check
// os_crc_init() is called automatically inside os_init()
os_crc_check_step(); // In background task / idle
if (os_crc_check_complete() && os_get_crc_error_count() > 0) {
// ROM corruption detected!
}
#endif
#if OS_SAFETY_MPU_EN
// MPU protection setup
os_mpu_init();
os_mpu_enable();
os_mpu_add_region(&task_tcb, 0x20001000, 4096, 3); // Per-task region
#endif
3. IEC 62304/61508 Target Profilesپروفایلهای هدف
-DOS_TARGET_MEDICAL_CLASS=3 for IEC 62304 Class C or -DOS_TARGET_INDUSTRIAL_SIL=3 for IEC 61508 SIL 3. The build will fail if any required feature is disabled.
با -DOS_TARGET_MEDICAL_CLASS=3 برای کلاس C یا -DOS_TARGET_INDUSTRIAL_SIL=3 برای SIL 3 بسازید. اگر هر ویژگی الزامی غیرفعال باشد، build شکست میخورد.
IEC 62304 Medical Classesکلاسهای پزشکی IEC 62304
-DOS_TARGET_MEDICAL_CLASS=X compiler flag where X is 1 (Class A), 2 (Class B), or 3 (Class C). The build will fail with #error if required features are disabled.
توجه: از پرچم کامپایلر -DOS_TARGET_MEDICAL_CLASS=X استفاده کنید که X برابر ۱ (کلاس A)، ۲ (کلاس B) یا ۳ (کلاس C) است. اگر ویژگیهای الزامی غیرفعال باشند، build با #error شکست میخورد.
| Class | Risk Levelسطح ریسک | Required Featuresویژگیهای الزامی |
|---|---|---|
| A | No injury possibleآسیب غیرممکن | None (all optional)هیچ (همه اختیاری) |
| B | Non-serious injuryآسیب غیرجدی | OS_MONITORING_EN (deadline + error log), SOFT_WATCHDOG, OS_MONITORING_DEADLINE_ACTION ≥ 1OS_MONITORING_EN (ددلاین + ثبت خطا)، SOFT_WATCHDOG، OS_MONITORING_DEADLINE_ACTION ≥ ۱ |
| C | Death/serious injuryمرگ/آسیب جدی | All features required (HW_WATCHDOG, TCB_INTEGRITY, MPU, CRC, RAM_TEST)تمام ویژگیها الزامی |
IEC 61508 SIL Levelsسطوح SIL
-DOS_TARGET_INDUSTRIAL_SIL=X compiler flag where X is 1 (SIL 1), 2 (SIL 2), 3 (SIL 3), or 4 (SIL 4).
توجه: از پرچم کامپایلر -DOS_TARGET_INDUSTRIAL_SIL=X استفاده کنید که X برابر ۱ (SIL 1)، ۲ (SIL 2)، ۳ (SIL 3) یا ۴ (SIL 4) است.
| SIL | Risk Levelسطح ریسک | Required Featuresویژگیهای الزامی |
|---|---|---|
| 1 | Lowپایین | SOFT_WATCHDOG, OS_MONITORING_EN (event recording)SOFT_WATCHDOG، OS_MONITORING_EN (ثبت رخداد) |
| 2 | Mediumمتوسط | + OS_IPC_TOOLS_EN (mutual exclusion), HW_WATCHDOG, OS_MONITORING_DEADLINE_ACTION ≥ 1+ OS_IPC_TOOLS_EN (قطعسازی متقابل)، HW_WATCHDOG، OS_MONITORING_DEADLINE_ACTION ≥ ۱ |
| 3 | Highبالا | + MPU, RAM_TEST, CRC+ MPU، RAM_TEST، CRC |
🔌 Serial Output (printf)خروجی سریال (printf)
Why Serial Output? In embedded development, you can't use a graphical debugger in production. Serial output (via UART) is your window into the system — it lets you print debug messages, sensor values, and system status. ZenOS provides a simple way to redirect printf() to UART so you can see what's happening in real-time.چرا خروجی سریال؟ در توسعه توکار، نمیتوانید از دیباگر گرافیکی در تولید استفاده کنید. خروجی سریال (از طریق UART) پنجره شما به سیستم است — به شما اجازه میدهد پیامهای دیباگ، مقادیر حسگر و وضعیت سیستم را چاپ کنید.
Step-by-Step Setupتنظیم گام به گام
- Enable USART1 in CubeMX (Pinout & Configuration → Connectivity → USART1)USART1 را در CubeMX فعال کنید (Pinout & Configuration → Connectivity → USART1)
- Set pins: PA9 = USART1_TX, PA10 = USART1_RXپینها را تنظیم کنید: PA9 = USART1_TX, PA10 = USART1_RX
- Set Baud rate: 115200, Data Bits: 8, Stop Bits: 1, Parity: Noneنرخ بیت: ۱۱۵۲۰۰, بیتهای داده: ۸, بیتهای توقف: ۱, بیت زوجیت: بدون
- Connect a USB-to-Serial adapter (e.g., CH340, CP2102) to PA9/PA10آداپتور USB به سریال (مثلاً CH340, CP2102) را به PA9/PA10 وصل کنید
- Add the printf redirect in main.cpp:redirect printf را به main.cpp اضافه کنید:
#include <cstdio>
// Redirect printf() to UART1
extern "C" int _write(int fd, char* ptr, int len) {
HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, HAL_MAX_DELAY);
return len;
}
// Now you can use printf() anywhere!
printf("ZenOS %s\n", os_get_version_string());
printf("Tasks: %d\n", os_get_task_count());
printf("Uptime: %u ms\n", os_get_ms());
What happens: The _write() function is called by printf() internally. By overriding it, we redirect all output to UART1. The extern "C" is needed because printf is a C function. HAL_MAX_DELAY means wait forever for the UART to be ready. Now anywhere in your code you call printf(), the output appears on the serial terminal.چه اتفاقی میافتد: تابع _write() توسط printf() به طور داخلی فراخوانی میشود. با بازنویسی آن، تمام خروجی را به UART1 هدایت میکنیم. extern "C" لازم است زیرا printf یک تابع C است. حالا هر جای کد printf() فراخوانی کنید، خروجی در ترمینال سریال ظاهر میشود.
Using a Terminal Programاستفاده از برنامه ترمینال
| Softwareنرمافزار | Platformپلتفرم | Linkلینک |
|---|---|---|
| PuTTY | Windows | putty.org |
| Tera Term | Windows | ttssh2.osdn.jp |
| minicom | Linux | Built-inداخلی |
| screen | macOS/Linux | Built-inداخلی |
# Linux/macOS:
screen /dev/ttyUSB0 115200
# Windows (PuTTY):
# Serial line: COM3 (check Device Manager)
# Speed: 115200
🚨 Error Handling & Monitoringمدیریت خطاها و پایش
Why Error Handling? In safety-critical systems, you need to know when something goes wrong. ZenOS provides a built-in error reporting system with severity levels, timestamps, and error logs. You can report errors from any task, and the system tracks them for you. These mechanisms can contribute evidence to a project-specific IEC 62304/61508 process, but they do not establish compliance by themselves.چرا مدیریت خطا؟ در سیستمهای حیاتی ایمنی، باید بدانید کی چیزی اشتباه میشود. ZenOS یک سیستم گزارشدهی خطا داخلی با سطوح شدت، زمان و لاگ خطا ارائه میدهد.
// Report a custom error with severity level
os_log_error(OSError::SENSOR_TIMEOUT, (uint8_t)ErrorSeverity::WARNING);
os_log_error(OSError::STACK_OVERFLOW, (uint8_t)ErrorSeverity::CRITICAL);
// Check error counts
uint32_t total = os_get_error_count(); // Total errors logged
uint32_t unexpected = os_get_unexpected_error_count(); // Unexpected errors
uint32_t expected = os_get_expected_error_count(); // Expected errors (suppressed)
OSError last = os_get_last_error(); // Last error code
printf("Errors: %u total, %u unexpected\n", total, unexpected);
// Suppress expected errors during testing
// Use this when you intentionally trigger errors for testing
os_error_expect_begin();
/* intentionally trigger and verify the expected error */
os_event_signal(-1);
os_error_expect_end();
os_event_signal(-1); // Deliberately invalid — expected error
os_error_expect_end();
// os_get_unexpected_error_count() does NOT increase
// os_get_expected_error_count() DOES increase
// Read error log (if OS_MONITORING_EN is enabled)
#if OS_MONITORING_EN
uint32_t count = os_get_error_log_count();
for (uint32_t i = 0; i < count; i++) {
OSErrorEntry entry = os_get_error_log_entry(i);
printf("[%u] Error %d in task %d (severity %d)\n",
entry.timestamp_tick, entry.code, entry.task_id, entry.severity);
}
#endif
What happens: os_log_error() records an error with a code and severity level. The error is stored in a ring buffer (circular log) with a timestamp. os_error_expect_begin();
/* intentionally trigger and verify the expected error */
os_event_signal(-1);
os_error_expect_end(); ... } marks a block where errors are expected — they won't trigger the watchdog or count as unexpected errors. This is useful during testing when you intentionally test error paths.چه اتفاقی میافتد: os_log_error() خطایی را با کد و سطح شدت ثبت میکند. خطا در بافر حلقهای (لاگ دایرهای) با زمان ذخیره میشود. os_error_expect_begin();
/* intentionally trigger and verify the expected error */
os_event_signal(-1);
os_error_expect_end(); ... } بلوکی را علامتگذاری میکند که در آن خطاها مورد انتظار هستند.
Error Severity Levelsسطوح شدت خطا
| Levelسطح | Meaningمعنی | Actionاقدام |
|---|---|---|
| INFO | Informational messageپیام اطلاعاتی | Log onlyفقط ثبت |
| WARNING | Something unusual happenedچیز غیرعادی رخ داده | Log + alertثبت + هشدار |
| ERROR | Function failed but system OKتابع ناموفق اما سیستم OK | Log + recoverثبت + بازیابی |
| CRITICAL | System integrity at riskیکپارچگی سیستم در خطر | Reset / safe stateریست / حالت ایمن |
os_get_error_count() in your monitoring task. If unexpected errors are increasing, investigate immediately — it indicates a bug or hardware fault.مهم: همیشه os_get_error_count() را در تسک پایش خود بررسی کنید. اگر خطاهای غیرمنتظره در حال افزایش هستند، فوراً بررسی کنید.🎓 Advanced Tips & Tricksنکات پیشرفته
Task Lifecycle Managementمدیریت چرخه حیات تسک
Why Control Task Lifecycle? In many systems, you don't want all tasks running all the time. For example, a heater task should only run when temperature is low. ZenOS lets you start and stop tasks dynamically at runtime, saving CPU and power.چرا کنترل چرخه حیات تسک؟ در بسیاری از سیستمها، نمیخواهید تمام تسکها همیشه اجرا شوند. مثلاً تسک هیتر فقط وقتی دما پایین است باید اجرا شود.
// Pre-create all tasks, start/stop as needed
os_task_create(task_heater, 5);
os_task_create(task_cooler, 5);
os_task_stop(task_heater); // Start inactive
os_task_stop(task_cooler); // Start inactive
// Runtime control
if (temperature > 70) {
os_task_start(task_cooler); // Activate cooler
os_task_stop(task_heater); // Deactivate heater
} else if (temperature < 20) {
os_task_start(task_heater); // Activate heater
os_task_stop(task_cooler); // Deactivate cooler
}
What happens: Tasks are created but immediately stopped (dormant). They don't use CPU until os_task_start() is called. This is more efficient than creating/destroying tasks repeatedly. The task's stack and TCB remain allocated but the scheduler ignores stopped tasks.چه اتفاقی میافتد: تسکها ایجاد اما فوراً متوقف میشوند (غیرفعال). تا فراخوانی os_task_start() از CPU استفاده نمیکنند.
Power Management with Tickless Idleمدیریت مصرف با حالت idle بدون تیک
What is Tickless Idle? In normal mode, the SysTick interrupt fires every 100μs even when nothing is happening — wasting power. Tickless idle disables SysTick during long delays and uses a hardware timer to wake up exactly when the next task is due. This dramatically reduces power consumption in battery-powered devices.idle بدون تیک چیست؟ در حالت عادی، وقفه SysTick هر ۱۰۰ میکروثانیه حتی وقتی هیچ اتفاقی نمیافتد فعال میشود — مصرف بیهوده انرژی. idle بدون تیک SysTick را در تاخیرهای طولانی غیرفعال کرده و از تایمر سختافزاری برای بیدار کردن دقیقاً وقتی تسک بعدی لازم است استفاده میکند.
// Enable OS_KERNEL_TICKLESS_IDLE_EN in config
// The OS will use WFI (Wait For Interrupt) when no tasks are ready
// This puts the CPU into low-power mode automatically
// Design tips for low power:
// 1. Use os_delay_ms() instead of busy-wait loops
// 2. Long delays → deep sleep (CPU stops)
// 3. Short delays → partial sleep (CPU slows)
// 4. The scheduler releases periodic tasks at their next release time
Debugging Tipsنکات دیباگ
// 1. Print task count at startup
printf("Tasks: %d\n", os_get_task_count());
// 2. Monitor stack usage periodically
uint32_t peak = os_get_stack_usage(task_function);
printf("Stack peak: %d bytes\n", peak);
// 3. Check CPU usage
uint8_t cpu = os_get_task_cpu_usage(task_function);
printf("Task CPU: %d%%\n", cpu);
// 4. Print version
printf("ZenOS %s\n", os_get_version_string());
// 5. Check for unexpected errors
if (os_get_unexpected_error_count() > 0) {
printf("UNEXPECTED ERRORS: %d\n", os_get_unexpected_error_count());
}
Memory Mapنقشه حافظه
Understanding Memory Usage: ZenOS uses zero heap allocation — all memory is statically allocated at compile time. This means you know exactly how much RAM your system uses before running it. No malloc() calls, no fragmentation, no surprises.درک مصرف حافظه: ZenOS از تخصیص حافظه پویا صفر استفاده میکند — تمام حافظه به طور ایستا در زمان کامپایل تخصیص مییابد. یعنی دقیقاً میدانید چقدر RAM سیستم شما استفاده میکند.
📚 Common Patterns Cookbookکتابخانه الگوهای رایج
State Machine in a Taskماشین حالت در یک تسک
enum State { INIT, RUNNING, ERROR, SLEEP };
static State state = INIT;
void task_state_machine(void) {
while (1) {
switch (state) {
case INIT:
if (hardware_ready()) state = RUNNING;
break;
case RUNNING:
if (error_detected()) state = ERROR;
else do_work();
break;
case ERROR:
if (error_cleared()) state = RUNNING;
else enter_safe_state();
break;
case SLEEP:
os_delay_ms(1000);
break;
}
os_yield(); // Always yield
}
}
Debounced Button Handlingمدیریت دکمه با دبیونس
OS_KEY_EVT;
void EXTI0_IRQHandler(void) {
OS_KEY_EVT.signal_from_isr();
}
void task_button(void) {
while (1) {
if (OS_KEY_EVT.wait(5000)) {
os_delay_ms(50); // Debounce delay
if (read_button()) {
handle_button_press();
}
}
}
}
Software PWM via Periodic TaskPWM نرمافزاری با تسک دورهای
void task_pwm(void) {
uint8_t duty = 128; // 50% duty
while (1) {
HAL_GPIO_WritePin(PWM_PORT, PWM_PIN, GPIO_PIN_SET);
os_delay_us(duty * 10); // ON time
HAL_GPIO_WritePin(PWM_PORT, PWM_PIN, GPIO_PIN_RESET);
os_delay_us((255 - duty) * 10); // OFF time
}
}
os_task_create(task_pwm, 15); // High priority for timing
Multi-Stage Sensor Pipelineخط لوله حسگر چند مرحلهای
OS_QUEUE<RawData, 8> raw_queue;
OS_QUEUE<ProcessedData, 8> processed_queue;
void task_acquire(void) {
while (1) {
RawData raw = read_sensor();
raw_queue.put(raw);
os_yield();
}
}
void task_process(void) {
while (1) {
RawData raw;
if (raw_queue.get(raw, 100)) {
ProcessedData proc = filter_and_calibrate(raw);
processed_queue.put(proc);
}
}
}
void task_output(void) {
while (1) {
ProcessedData proc;
if (processed_queue.get(proc, 100)) {
display(proc);
}
}
}
// Pipeline: acquire(3) → process(5) → output(4)
os_task_create(task_acquire, 3, 10);
os_task_create(task_process, 5);
os_task_create(task_output, 4);
Graceful Shutdownخاموش کردن صحیح
static volatile bool shutdown_requested = false;
void task_shutdown_handler(void) {
while (1) {
if (shutdown_button.wait(1000)) {
shutdown_requested = true;
os_task_stop(task_ui);
os_task_stop(task_led);
save_critical_data();
enter_safe_mode();
}
}
}
📋 Complete API Referenceمرجع کامل API
Core Functions (C)توابع هسته (C)
| Functionتابع | Descriptionتوضیحات |
|---|---|
os_init() | Initialize RTOS (call before task creation)مقداردهی اولیه RTOS |
os_start() | Start scheduler (never returns)شروع زمانبند (هرگز برنمیگردد) |
os_tick() | Tick handler (call from SysTick_Handler)هندلر تیک |
os_delay_ms(ms) | Sleep for ms millisecondsخواب به مدت ms میلیثانیه |
os_delay_us(us) | Busy-wait for us microsecondsانتظار مشغول به مدت us میکروثانیه |
os_yield() | Yield to next ready taskواگذاری به تسک بعدی |
os_get_tick() | Get raw tick countدریافت شمارنده تیک خام |
os_get_ms() | Get milliseconds since bootدریافت میلیثانیه از شروع |
os_get_us() | Get microseconds since bootدریافت میکروثانیه از شروع |
os_task_start(entry) | Start a stopped taskشروع تسک متوقف شده |
os_task_stop(entry) | Stop a running taskتوقف تسک در حال اجرا |
os_task_isActive(entry) | Check if task is activeبررسی فعال بودن تسک |
os_get_task_count() | Get number of registered tasksدریافت تعداد تسکهای ثبت شده |
os_get_task_priority(entry) | Get task's active priorityدریافت اولویت فعال تسک |
os_get_stack_usage(entry) | Get peak stack usage (bytes)دریافت حداکثر مصرف پشته |
os_get_task_cpu_usage(entry) | Get task CPU usage (%)دریافت مصرف CPU تسک |
os_get_version_string() | Get version stringدریافت رشته نسخه |
RAII Classes (C++)کلاسهای RAII (C++)
| Classکلاس | Macroماکرو | Descriptionتوضیحات |
|---|---|---|
_OsSafeGuard | OS_SAFE { ... } | Interrupt-disable guardمحافظ غیرفعال کردن وقفه |
_OsLockGuard | OS_LOCK(mtx) { ... } | Mutex lock guardمحافظ قفل mutex |
OS_EVENT | — | Inter-task event signalingسیگنالدهی رویداد بین تسکها |
OS_MUTEX | — | Mutex with IPC priority ceilingMutex با سقف اولویت IPC |
OS_QUEUE<T,N> | — | Bounded FIFO queueصف FIFO محدود |
OS_SEMAPHORE | — | Counting semaphoreسمافور شمارشی |
⚙️ Configuration Guideراهنمای پیکربندی
ZenOS is configured via ZenOS_Config.hpp. Safety mechanisms are configurable and not all are enabled by default. This guide helps you decide what to enable based on your application needs.ZenOS از طریق ZenOS_Config.hpp پیکربندی میشود. مکانیسمهای ایمنی قابل پیکربندی هستند و همه به طور پیشفرض فعال نیستند. این راهنما به شما کمک میکند بر اساس نیازهای برنامهتان تصمیم بگیرید چه چیزی را فعال کنید.
1. What Do You Need?چه چیزی نیاز دارید؟
Answer these questions to determine your configuration:این سؤالات را پاسخ دهید تا پیکربندی خود را تعیین کنید:
| Questionسؤال | If YESاگر بله | What to Enableچه چیزی فعال شود |
|---|---|---|
| Is this a hobby/learning project?آیا این پروژه تفریحی/آموزشی است؟ | Keep defaultsپیشفرضها را نگه دارید | Use the repository defaults; optional mechanisms are not all enabledهمه چیز (از قبل فعال) |
| Is memory very limited (<20KB RAM)?آیا حافظه بسیار محدود است؟ | Disable unused featuresویژگیهای استفاده نشده را غیرفعال کنید | See "Minimal Config"به "حداقل پیکربندی" مراجعه کنید |
| Is this a medical device?آیا این یک دستگاه پزشکی است؟ | Enable IEC 62304IEC 62304 را فعال کنید | -DOS_TARGET_MEDICAL_CLASS=2 or -DOS_TARGET_MEDICAL_CLASS=3 |
| Is this an industrial system?آیا این یک سیستم صنعتی است؟ | Enable IEC 61508IEC 61508 را فعال کنید | -DOS_TARGET_INDUSTRIAL_SIL=2 or -DOS_TARGET_INDUSTRIAL_SIL=3 |
| Do you need hardware watchdog?آیا به تایمر سختافزاری نیاز دارید؟ | Enable IWDG in CubeMXIWDG را در CubeMX فعال کنید | OS_SAFETY_HW_WATCHDOG_EN = 1 |
2. Configuration Profilesپروفایلهای پیکربندی
2.1 Minimal Configuration (Constrained Devices)حداقل پیکربندی (دستگاههای محدود)
For devices with <20KB RAM or when you need maximum flash/RAM savings:برای دستگاههایی با کمتر از ۲۰KB RAM یا زمانی که به حداکثر صرفهجویی نیاز دارید:
// ZenOS_Config.hpp — Minimal configuration (explicit overrides)
// Source defaults: tick=100us, stack request=128B (effective floor=256B),
// priorities=16 slots, IPC=1, monitoring=0, safety features=0.
#define OS_KERNEL_TICK_PERIOD_US 1000UL // override: valid 100..1000us; must divide 1000
#define OS_KERNEL_DEFAULT_STACK_SIZE 128 // source default request; effective floor=256B
#define OS_KERNEL_MAX_PRIORITIES 2 // override: valid 2..256; priority 0=idle
#define OS_IPC_TOOLS_EN 0 // explicit override: disable all IPC
#define OS_MONITORING_EN 0 // source default
#define OS_SAFETY_RAM_TEST_EN 0
#define OS_SAFETY_MPU_EN 0
#define OS_SAFETY_HW_WATCHDOG_EN 0
#define OS_SAFETY_CRC_EN 0
#define OS_SAFETY_SOFT_WATCHDOG_EN 0
2.2 Standard Configuration (Recommended)پیکربندی استاندارد (پیشنهادی)
Repository defaults — optional mechanisms are not all enabled; verify each default and its valid range in the configuration reference:تنظیمات پیشفرض مخزن — مکانیسمهای اختیاری همگی فعال نیستند؛ مقدار پیشفرض و محدوده هر گزینه را در مرجع پیکربندی بررسی کنید:
// ZenOS_Config.hpp — Standard configuration (all defaults)
// No changes needed — features follow the defaults in ZenOS_Config.hpp.
// Just use the file as-is.
2.3 Medical Device Configuration (IEC 62304 Class B)پیکربندی دستگاه پزشکی (کلاس B)
// ZenOS_Config.hpp — Medical Class B
// Keep ALL defaults (optional mechanisms are not all enabled)
// Then add to compiler flags: -DOS_TARGET_MEDICAL_CLASS=2
// This enables compile-time enforcement:
// - OS_MONITORING_EN must be 1
// - OS_SAFETY_SOFT_WATCHDOG_EN must be 1
// - OS_MONITORING_DEADLINE_ACTION must be >= 1
2.4 Medical Device Configuration (IEC 62304 Class C)پیکربندی دستگاه پزشکی (کلاس C)
// ZenOS_Config.hpp — Medical Class C (life-critical)
// Keep ALL defaults (optional mechanisms are not all enabled)
// Then add to compiler flags: -DOS_TARGET_MEDICAL_CLASS=3
// This enables compile-time enforcement for ALL features:
// - OS_MONITORING_EN must be 1
// - OS_SAFETY_SOFT_WATCHDOG_EN must be 1
// - OS_SAFETY_HW_WATCHDOG_EN must be 1
// - OS_SAFETY_MPU_EN must be 1
// - OS_SAFETY_CRC_EN must be 1
// - OS_SAFETY_RAM_TEST_EN must be 1
2.5 Industrial Configuration (IEC 61508 SIL 2)پیکربندی صنعتی (SIL 2)
// ZenOS_Config.hpp — Industrial SIL 2
// Keep ALL defaults (optional mechanisms are not all enabled)
// Then add to compiler flags: -DOS_TARGET_INDUSTRIAL_SIL=2
// Required features:
// - OS_SAFETY_SOFT_WATCHDOG_EN = 1
// - OS_MONITORING_EN = 1
// - OS_IPC_TOOLS_EN = 1
// - OS_SAFETY_HW_WATCHDOG_EN = 1
// - OS_MONITORING_DEADLINE_ACTION >= 1
3. What ZenOS Handles AutomaticallyZenOS چه چیزی را خودکار مدیریت میکند
These are configured automatically by os_init() — you don't need to set them up:این موارد به طور خودکار توسط os_init() پیکربندی میشوند — نیازی به تنظیم دستی نیست:
| Featureویژگی | Statusوضعیت | Detailsجزئیات |
|---|---|---|
| PendSV handler | ✅ Automatic✅ خودکار | Context switch interruptوقفه تغییر زمینه |
| Fault handlers | ✅ Automatic✅ خودکار | HardFault, MemManage, BusFault, UsageFaultانواع خطاهای پردازنده |
| DWT cycle counter | ✅ Automatic✅ خودکار | For microsecond timingبرای زمانبندی میکروثانیه |
| MCU family detection | ✅ Automatic✅ خودکار | Via ZenOS_Port.hppاز طریق ZenOS_Port.hpp |
4. What You Must Configureچه چیزی را باید خودتان پیکربندی کنید
| Settingتنظیم | Whereمحل | Detailsجزئیات |
|---|---|---|
| HAL Timebase | CubeMX | System Core → SYS → Timebase = TIM1System Core → SYS → Timebase = TIM1 |
os_tick() | stm32fxxx_it.c | Must be in SysTick_Handlerباید در SysTick_Handler باشد |
| C++11 flag | Compiler settings | -std=c++11 |
| IWDG (if using HW watchdog) | CubeMX | Enable IWDG timeout configured for the target applicationIWDG را با تایماوت متناسب با کاربرد تنظیم کنید |
| CRC (if using CRC check) | CubeMX | Enable CRC peripheralپیرفرال CRC را فعال کنید |
5. Complete Configuration Referenceمرجع کامل پیکربندی
| Constantثابت | Defaultپیشفرض | Valid values / limitمحدوده / محدودیت | Descriptionتوضیحات |
|---|---|---|---|
OS_KERNEL_TICK_PERIOD_US | 100 | 100..1000 µs; must divide 1000 evenly | Kernel tick period.دوره تیک هسته؛ باید ۱۰۰۰ را بدون باقیمانده تقسیم کند. |
OS_KERNEL_DEFAULT_STACK_SIZE | 128 B | Request ≥64 B; effective allocation floor 256 B; no explicit source max | Default task stack request; practical maximum is constrained by target RAM, linker/toolchain and uint32_t.درخواست پیشفرض پشته؛ حداکثر عملی به RAM هدف، ابزار لینک/کامپایل و uint32_t وابسته است. |
OS_KERNEL_MAX_PRIORITIES | 16 slots | 2..256 slots; priority 0 reserved; application range 1..N-1 | At 256 slots, application priorities are 1..255; larger numeric values mean higher priority.در ۲۵۶ اسلات، اولویتهای کاربردی 1..255 هستند؛ عدد بزرگتر یعنی اولویت بالاتر. |
OS_KERNEL_TICKLESS_IDLE_EN | 1 | 0 or 1 | WFI-based tickless idle.idle بدون تیک مبتنی بر WFI. |
OS_IPC_TOOLS_EN | 1 | 0 or 1 | Single master switch for events, mutexes, queues, semaphores and lock guards; all are enabled/disabled together.کلید واحد برای فعال/غیرفعال کردن همه IPC. |
OS_MONITORING_EN | 0 | 0 or 1 | Master switch for deadline, TCB integrity, error log and CPU/stack instrumentation.کلید اصلی پایش deadline، یکپارچگی TCB، ثبت خطا و آمار CPU/stack. |
OS_MONITORING_DEADLINE_ACTION | 1 | 0..2 | 0 = log only; 1 = reset task; 2 = disable task.۰ = فقط ثبت؛ ۱ = ریست تسک؛ ۲ = غیرفعال کردن تسک. |
OS_MONITORING_ERROR_LOG_SIZE | 16 | >=1 entry | RAM ring-buffer capacity.ظرفیت بافر حلقهای خطا در RAM. |
OS_SAFETY_RAM_TEST_EN | 0 | 0 or 1 | Background March-C SRAM integrity test.آزمون یکپارچگی SRAM به روش March-C. |
OS_SAFETY_MPU_EN | 0 | 0 or 1; 1 requires MPU | Per-task MPU protection; unsupported hardware causes a compile-time error.حفاظت MPU هر تسک؛ سختافزار فاقد MPU باعث خطای کامپایل میشود. |
OS_SAFETY_HW_WATCHDOG_EN | 0 | 0 or 1; 1 requires IWDG | STM32 IWDG integration; unsupported hardware causes a compile-time error.ادغام IWDG؛ نبود IWDG باعث خطای کامپایل میشود. |
OS_SAFETY_CRC_EN | 0 | 0 or 1; 1 requires CRC | Flash CRC integrity check; unsupported hardware causes a compile-time error.بررسی CRC فلش؛ نبود CRC باعث خطای کامپایل میشود. |
OS_SAFETY_SOFT_WATCHDOG_EN | 0 | 0 or 1 | Software stuck-task detection and recovery.تشخیص و بازیابی تسکهای گیرکرده. |
OS_SAFETY_TASK_MAX_RECOVERY | 3 | >=0 | Maximum recovery attempts; 0 means immediate safe-state/disable path.حداکثر تلاش بازیابی؛ ۰ یعنی مسیر حالت ایمن/غیرفعالسازی فوری. |
OS_SAFETY_SOFT_WDG_TIMEOUT_MS | 3000 ms | >=0 ms; bounded by application safety/process time | Software watchdog timeout.تایماوت watchdog نرمافزاری. |
OS_SAFETY_MAX_CRITICAL_US | 1000 µs | >=0 µs; 0 disables check | Maximum diagnostic duration of an OS_SAFE section.حد تشخیصی مدت OS_SAFE. |
OS_TARGET_MEDICAL_CLASS | 0 | 0..3; 0 disabled, 1=A, 2=B, 3=C | IEC 62304 target profile selector.انتخاب پروفایل هدف IEC 62304. |
OS_TARGET_INDUSTRIAL_SIL | 0 | 0..4; 0 disabled, 1..4=SIL 1..4 | IEC 61508 target profile selector.انتخاب پروفایل هدف IEC 61508. |
📊 ZenOS vs FreeRTOS vs Zephyrمقایسه ZenOS با FreeRTOS و Zephyr
| Featureویژگی | ZenOS | FreeRTOS | Zephyr |
|---|---|---|---|
| Tick resolutionرزولوشن تیک | 100μs | 1ms | 10ms |
| Schedulerزمانبند | Priority bitmap + queue scan for eligibility | O(n) | O(n) |
| Heapحافظه پویا | Never | Available | Available |
| Safetyایمنی | Built-in | Optional | Optional |
| IEC 62304/61508IEC 62304/61508 | Compile-time | None | None |
| C++ RAIIC++ RAII | Full | None | Partial |
| Periodic tasksتسکهای دورهای | Period information is recorded; verify scheduler behavior | Timers | Timers |
| IPC priority ceilingسقف IPC | Immediate | Inheritance | None |
🏗️ Architectureمعماری
🚨 Error Codes Referenceمرجع کدهای خطا
| Code | Nameنام | Descriptionتوضیحات | Typical Causeعلت معمول |
|---|---|---|---|
| 4 | STACK_OVERFLOW | Stack canary check failedبررسی کاناری پشته ناموفق | Stack too smallپشته خیلی کوچک |
| 5 | INVALID_EVENT_ID | Out-of-range event IDشناسه رویداد خارج از محدوده | Uninitialized eventرویداد مقداردهی نشده |
| 6 | TASK_AFTER_START | Task created after os_start()تسک بعد از os_start() ایجاد شده | Wrong creation orderترتیب ایجاد نادرست |
| 7 | TASK_STUCK | Software watchdog timeoutتایمر نرمافزاری منقضی شده | Task not yieldingتسک واگذاری نمیکند |
| 8 | SAFE_TOO_LONG | OS_SAFE exceeded max durationOS_SAFE از حداکثر مدت تجاوز کرده | Long critical sectionبخش بحرانی طولانی |
| 9 | HARDFAULT | CPU fault exceptionخطای پردازنده | Memory access violationنقض دسترسی حافظه |
| 10 | PRIORITY_CONFLICT | Mutex ceiling conflictتعارض سقف mutex | Misconfigured ceilingپیکربندی نادرست سقف |
| 11 | DEADLINE_MISS | Task missed its deadlineتسک ددلاین را از دست داده | Task overloadedتسک بیش از حد بارگذاری شده |
| 12 | TCB_CORRUPTED | TCB magic number invalidعدد جادوی TCB نامعتبر | Memory corruptionخرابی حافظه |
| 15 | RAM_TEST_FAIL | RAM test detected faultآزمون RAM خطا تشخیص داده | Hardware SRAM failureخرابی سختافزاری SRAM |
🔧 Troubleshootingعیبیابی
| Issueمشکل | Solutionراهحل |
|---|---|
| LED doesn't blinkLED چشمک نمیزند | Set HAL timebase to TIM1 in CubeMXتایمر HAL را روی TIM1 تنظیم کنید |
| HardFault on startupخطا در شروع | Add os_tick() to SysTick_Handleros_tick() را به SysTick_Handler اضافه کنید |
| Stack overflow detectedسرریز پشته تشخیص داده شده | Increase stack size, use os_get_stack_usage()اندازه پشته را افزایش دهید |
| Watchdog resetریست تایمر | Add os_delay_ms() or os_yield()os_delay_ms() یا os_yield() اضافه کنید |
| Compilation error about C++خطای کامپایل مربوط به C++ | Add -std=c++11 to compiler flags |
| Priority inversionوارونگی اولویت | Set correct IPC priority ceiling priorityاولویت سقف IPC را درست تنظیم کنید |
📬 Contact Usتماس با ما
Raymon Research Team — Rahman Heidariتیم تحقیقاتی رایمون — رحمان حیدری
📧 Email: rahman.h22@gmail.com
🔗 GitHub: github.com/Raymon-Research-Team/ZenOS-RTOS
For questions, suggestions, or collaboration opportunities, feel free to reach out.برای سؤالات، پیشنهادات یا فرصتهای همکاری، با ما در تماس باشید.
💰 Support ZenOSحمایت از ZenOS
This is a solo project. I build it, test it, write the docs, and maintain it — all in my spare time, without funding. Your donation directly funds development, testing, certification, and documentation.این یک پروژه تکنفره است. من آن را میسازم، تست میکنم، مستندات مینویسم و نگهداری میکنم — همه در اوقات فراغت، بدون بودجه. حمایت مالی شما مستقیماً توسعه، تست، گواهینامه و مستندات را تأمین میکند.
📩 After making a donation, please send an email to rahman.h22@gmail.com with your transaction ID so I can personally thank you.📩 پس از انجام پرداخت، لطفاً شناسه تراکنش خود را به rahman.h22@gmail.com ارسال کنید تا شخصاً از شما قدردانی شود.
