目錄
0. 配置
1. 體系架構
2. 記憶體管理
3. 任務/調度器
3. IPC
3.1 信號量
3.2 互斥鎖
3.3 訊息佇列
4. 臨界區保護
4.1. 全域中斷
4.2. 掛起調度器
4.3. 互斥鎖
5. 軟體定時器
6. 支持 Log 日志分級
7. Trace
8. Shell
9. Demo
都說,不會寫 RTOS 的程式員不是好廚師,那么就寫點東西吧;
V1.0 版本大概的組織是這樣的:

這個 RTOS 命名為 MxOS;
專案地址為:
https://gitee.com/stephenzhou-tech/mx-os
0. 配置
MxOS 相關的配置全部都在 os_configs.h 檔案中,配置是自注釋的,看命名就知道干嘛用的,提供的配置并不算豐富,省去了很多無意義的配置;
1. 體系架構
最先適配了 Cortex-M4 (帶 FPU) 的體系架構(后面會適配 Cortex-A 系列和 RISC-V);和體系架構相關的代碼放在 arch 目錄下,主要是和 CPU(MCU)緊密相關的部分,包含一些中斷開關,中斷初始化,OS Tick 心跳,CPU(MCU)背景關系的定義和背景關系切換的匯編等等,這部分獨立抽象出來,將介面定義完整,以便進行日后的體系架構的擴展;
針對 Cortex-M4 需要注意一點的是,Specification 里面提到的 FPU Lazy stacking 模式,在使用 OS 的情況下,最好打開它,可以提高背景關系切換的效率,至于什么是 Lazy stacking,打開它有什么好處,以及如何打開它,請自行閱讀 Cortex-M4 的 Specification;
2. 記憶體管理
一個簡單的記憶體管理模型,以預定義的記憶體 heap 為管理內容,所有的記憶體分配都在這進行;提供記憶體分配和釋放的介面,分配按照 Bestfit 原則進行分配,釋放的時候,進行相鄰記憶體合并操作;為了進一步減少記憶體碎片,一些模塊的描述符(IPC部分)都使用了預定義陣列的方式,用戶根據實際的設計情況,合理的定義描述符的個數(比如你的設計可能用到 3 個 Mutex Lock,那就定義 3 個);
記憶體分配釋放的程序類似如下所示:

這里的藍色部分是記憶體初始對齊后砍掉的部分,紅色部分是每一塊記憶體的描述符;后續會考慮實作類似 Slab 的東東;
3. 任務/調度器
RTOS 需要及時的調度出當前處于 Ready 并且優先級最高的任務來執行,MxOS 支持最大 32 級任務優先級定義,搶占式調度;
任務優先級的值越高代表優先級越高,同等優先級的任務輪流執行;
默認會啟動一個 Idle 任務;
支持任務延時,掛起;
支持主動讓出 CPU;
支持一定程度的堆疊溢位檢查;
支持動態切換優先級;
支持掛起調度器;
3. IPC
IPC 的描述符資源都是靜態定義,根據使用的具體情況,用戶來定義,以減小記憶體碎片;
3.1 信號量
支持計數信號量和二進制信號量用于任務之間,任務與中斷之間的同步;
支持 TryWait、和 WaitTimeout 操作;
3.2 互斥鎖
支持互斥鎖用于臨界區的互斥訪問,為了更好的 RT 特性,使用優先級繼承的方式來減少優先級翻轉帶來的影響;
支持 TryWait、和 WaitTimeout 操作;
3.3 訊息佇列
提供一種任務與任務,中斷與任務的資料傳輸的訊息佇列機制;
4. 臨界區保護
提供3中臨界區保護方式:
4.1. 全域中斷
支持可嵌套的,給予全域中斷開關的臨界區保護方式;
4.2. 掛起調度器
支持掛起調度器的臨界區保護方式;
4.3. 互斥鎖
支持基于互斥鎖的臨界區保護方式;
5. 軟體定時器
支持創建軟體定時器,軟體定時器以一個高優先級任務的方式運行,支持 Auto Reload 和 Oneshot 的定時器模式,超時Handler運行在任務背景關系;
6. 支持 Log 日志分級
日志等級分為 4 級輸出,輸出等級定義越高,低等級的 log 便被阻止輸出:
ERROR、WARNING、INFO、DEBUG
7. Trace
支持 Trace OS,根據需要添加 Trace point;
8. Shell
支持外掛 Shell,并注冊到內核(當前已經注冊了一個開源的 Shell);
適配 Shell 需要板級支持,具體適配方式參考發布鏈接的 Readme;
現目前 Shell 已經支持了幾個命令:
task : 查看當前任務狀態
mem : 查看當前記憶體情況
cls : 清屏
help : 幫助

9. Demo
OS_Uint32_t task1_handle = 0;
OS_Uint32_t task2_handle = 0;
OS_Uint32_t task3_handle = 0;
int main(void)
{
PlatformInit();
OS_API_KernelInit();
OS_Uint32_t TaskInputParam = 1;
TaskInitParameter Param;
OS_Memset(Param.Name, 0x00, CONFIG_TASK_NAME_LEN);
Param.Name[0] ='T';
Param.Name[1] ='1';
Param.Priority = 1;
Param.PrivateData = &TaskInputParam;
Param.StackSize = 1024;
Param.TaskEntry = TASK1_FUNC;
OS_API_TaskCreate(Param, (void *)&task1_handle);
Param.Name[0] ='T';
Param.Name[1] ='2';
Param.Priority = 2;
Param.TaskEntry = TASK2_FUNC;
OS_API_TaskCreate(Param, (void *)&task2_handle);
Param.Name[0] ='T';
Param.Name[1] ='3';
Param.Priority = 3;
Param.TaskEntry = TASK3_FUNC;
OS_API_TaskCreate(Param, (void *)&task3_handle);
OS_API_KernelStart();
while(1);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/399604.html
標籤:其他
