說起來RTOS,第一印象就是單片機(jī)程序、ARM M核、微控制器低頻運(yùn)行處理程序,甚至其不能算一個(gè)真正的OS。但是隨著時(shí)代發(fā)展,這些單片機(jī)程序在有限的硬件機(jī)制下非常接近像Linux這種的巨無霸O(shè)S了,例如其有線程、中斷、內(nèi)存管理、IPC、驅(qū)動(dòng)、網(wǎng)絡(luò)協(xié)議棧、shell、提供POSIX接口等,可以說其已經(jīng)是一個(gè)縮小版的OS了,甚至在A核也可以運(yùn)行,簡單修改下添加一點(diǎn)用戶空間支持等特性就可以。
在嵌入式領(lǐng)域中,定制化的軟硬件,并且沒有界面展示的時(shí)候,并不需要ARM A核這種高級(jí)的CPU,M核是一個(gè)更好的選擇,其便宜,小,省電,可靠性高,偏向?qū)S每刂?/strong>,但是頻率低,功能進(jìn)行了閹割。在其上運(yùn)行的RTOS也有對(duì)應(yīng)的特點(diǎn):
地址空間只有一個(gè),就像Linux的內(nèi)核一樣,共享地址空間
沒有高級(jí)的硬件相關(guān)MMU功能,無虛擬地址
沒有文件系統(tǒng)、UI界面等復(fù)雜服務(wù)
各種服務(wù)例如進(jìn)程調(diào)度等是一個(gè)簡單實(shí)現(xiàn)版本
之前介紹過一個(gè)典型的RTOS freeRTOS:FreeRTOS入門-概念介紹。其實(shí)RTOS的定義就是實(shí)時(shí)操作系統(tǒng),例如Linux修改下具有實(shí)時(shí)特性也可以叫RTOS了。本文講的zephyr RTOS就是一個(gè)類似freeRTOS的操作系統(tǒng),可以等價(jià)平替,下面介紹下其特點(diǎn)。
1. Zephyr介紹
1.1 Zephyr簡介
Zephyr最初是由Wind River公司開發(fā)的一個(gè)微內(nèi)核,在2016年的時(shí)候成為Linux基金會(huì)維護(hù)的一個(gè)項(xiàng)目,發(fā)展至今,已經(jīng)成為了一個(gè)功能齊全的嵌入式OS。平臺(tái)現(xiàn)在支持ARM、RISC-V、X86、Xtensa等等處理器平臺(tái),擁有原生的BLE協(xié)議棧、完整的Net協(xié)議棧,包括TCP/IP與應(yīng)用層協(xié)議,為嵌入式應(yīng)用的開發(fā)提供了有力的支持。
Zephyr它不僅僅維護(hù)了一個(gè)RTOS內(nèi)核,還維護(hù)一些編譯鏈、libc、 IDE插件、HEL層驅(qū)動(dòng)等,幾乎每一個(gè)模塊都有相關(guān)的文檔。正是因?yàn)閾碛?strong>詳細(xì)的文檔,Zephyr才能源源不斷的吸引人來進(jìn)行嘗試與開發(fā),以至于系統(tǒng)不斷的被完善,進(jìn)入開源項(xiàng)目的一個(gè)良性循環(huán)。
Linux基金會(huì)維護(hù)
所以看Zephyr就很Linux里L(fēng)inux氣的,比如make menuconfig支持、DTS支持等,可以說把Linux一些優(yōu)秀的通用特性吸引進(jìn)來了,做到了很多代碼跟Linux同步,妥妥的Linux小弟。好處就是我們?nèi)コa的時(shí)候,不,是移植代碼的時(shí)候Zephyr就是一個(gè)很好的調(diào)研對(duì)象,其完全開源嘛!
Wind River公司
大名鼎鼎的VxWorks實(shí)時(shí)操作系統(tǒng)就是Wind River公司開發(fā)的,其在實(shí)時(shí)操作系統(tǒng)領(lǐng)域早期可謂獨(dú)領(lǐng)風(fēng)騷,特別在軍工中,它以其良好的可靠性和實(shí)時(shí)性被廣泛地應(yīng)用在通信、軍事、航空、航天等高精尖技術(shù)及實(shí)時(shí)性要求極高的領(lǐng)域中,如衛(wèi)星通訊、軍事演習(xí)、彈道制導(dǎo)、飛機(jī)導(dǎo)航等。在美國的 F-16、FA-18戰(zhàn)斗機(jī)、B-2 隱形轟炸機(jī)和愛國者導(dǎo)彈上,甚至連1997年4月在火星表面登陸的火星探測器、2008年5月登陸的鳳凰號(hào),和2012年8月登陸的好奇號(hào)也都使用到了VxWorks。VxWorks不開源,這里的Zephyr可以說是出身在一流家族中,其實(shí)時(shí)特性應(yīng)該很值得借鑒。
1.2 特性介紹
Zephyr OS 基于小占用內(nèi)核,設(shè)計(jì)用于資源受限的嵌入式系統(tǒng):從簡單的嵌入式環(huán)境傳感器和 LED 可穿戴設(shè)備到復(fù)雜的嵌入式控制器、智能手表和物聯(lián)網(wǎng)無線應(yīng)用。
其中Zephyr OS為Zephyr提供的核心代碼包含了:
Kernel/HAL
內(nèi)核調(diào)度
低級(jí)的體系結(jié)構(gòu)和板級(jí)支援
各種RTOS內(nèi)核對(duì)象
電源管理框架
低級(jí)的硬件接口抽象
OS服務(wù)及底層接口
設(shè)備管理及底層驅(qū)動(dòng)API
文件系統(tǒng),Logging系統(tǒng),Debugging系統(tǒng)及IPC
加密服務(wù)
平臺(tái)相關(guān)的特殊驅(qū)動(dòng)
網(wǎng)絡(luò)協(xié)議棧
應(yīng)用服務(wù)
高層級(jí)的應(yīng)用API
標(biāo)準(zhǔn)化的數(shù)據(jù)模型
高層級(jí)網(wǎng)絡(luò)協(xié)議接口
對(duì)于Zephyr應(yīng)用開發(fā)者,需要熟知應(yīng)用服務(wù)和OS服務(wù),了解底層接口及Kernel/HAL特性。
Zephy也提供構(gòu)建系統(tǒng)及開發(fā)環(huán)境和Zephyr OS一起構(gòu)成了Zephyr Project,Zephyr Project包含了:
Zephyr的SDK,構(gòu)建工具,CI及開發(fā)環(huán)境
附加的中間件
Zephyr除了核心代碼之外還引入了其它優(yōu)秀的開源項(xiàng)目做為其功能組成部分,另外還有不同的項(xiàng)目也將Zephyr作為其組成部分,這些內(nèi)容在一起構(gòu)成了完整的Zephyr生態(tài)。Zephyr生態(tài)有如下內(nèi)容:
第三方模塊或庫:例如lvgl,fatfs,mcumgr,openthread,openamp,opencan等等。
第三方支持Zephyr的項(xiàng)目:例如Jerryscript ,Micropython , Iotivity , SwiftIO等。
SOC供應(yīng)商Hal,Zephyr將不同芯片的Hal作為外部模塊引入到Zephyr中,通過Zephyr驅(qū)動(dòng)的整合讓應(yīng)用可以通過統(tǒng)一的驅(qū)動(dòng)接口控制不同芯片的片上設(shè)備。例如:nxp,st,ti,nordic,silabs等等。
Kernel涵蓋以下內(nèi)容:
提供Kernel service,例如thread,同步,數(shù)據(jù)傳遞,中斷管理,時(shí)間管理,內(nèi)存管理等
進(jìn)行任務(wù)調(diào)度
電源管理
平臺(tái)相關(guān)的特殊驅(qū)動(dòng),例如Radios,傳感器,加密硬件,F(xiàn)lash等
OS服務(wù)涵蓋以下內(nèi)容:
設(shè)備驅(qū)動(dòng)實(shí)現(xiàn),提供統(tǒng)一的底層驅(qū)動(dòng)接口
設(shè)備管理
網(wǎng)絡(luò)L2實(shí)現(xiàn)及接口抽象
網(wǎng)絡(luò)層和傳輸層協(xié)議棧(TCP/IP),socket接口
應(yīng)用服務(wù)涵蓋以下內(nèi)容:
網(wǎng)絡(luò)應(yīng)用協(xié)議及高層級(jí)接口,例如HTTP,coap,mqtt,tls,dtls等
提供標(biāo)準(zhǔn)化的數(shù)據(jù)模型,目前尚未在Zephyr的目錄樹中找到該部分內(nèi)容
提供智能物件對(duì)象,例如基于lwm2m的IPSO
Zephyr的硬件層次結(jié)構(gòu)被抽象出6層:
架構(gòu)(Architecutre):指令架構(gòu)體系,例如ARM,RISC-V,x86等
CPU內(nèi)核(CPU core):架構(gòu)中特定的CPU,例如ARM中有Cortex-M0,M3,M4,M7等
芯片族(Soc family):具有相似特性的SoC,例如Cortex-M7中有STMicro STM32,NXP i.MX
芯片系列(SoC series):一小部分緊密關(guān)聯(lián)的SoC,例如i.MX中有i.MX RT 系列,i.MX 8系列等
芯片級(jí)(SoC):電路板上的SoC,例如i.MX RT系列中有RT1050,RT1060等芯片
板級(jí)(Board):PCB上特定的SoC和一些外設(shè)相連構(gòu)成有特定功能的電路板。例如Zephyr支援的mimxrt1050_evk,mm_swiftio開發(fā)板使用了rt1052芯片。
Zephyr 內(nèi)核支持多種架構(gòu),包括:
ARCv2 (EM and HS) and ARCv3 (HS6X)
ARMv6-M, ARMv7-M, and ARMv8-M (Cortex-M)
ARMv7-A and ARMv8-A (Cortex-A, 32- and 64-bit)
ARMv7-R, ARMv8-R (Cortex-R, 32- and 64-bit)
Intel x86 (32- and 64-bit)
MIPS (MIPS32 Release 1 specification)
NIOS II Gen 2
RISC-V (32- and 64-bit)
SPARC V8
Tensilica Xtensa
廣泛的內(nèi)核服務(wù)套件,Zephyr 提供了許多熟悉的開發(fā)服務(wù):
用于協(xié)作、基于優(yōu)先級(jí)、非搶占式和搶占式線程的多線程服務(wù),具有可選的循環(huán)時(shí)間切片。包括 POSIX pthreads 兼容 API 支持。
中斷服務(wù)用于中斷處理程序的編譯時(shí)注冊(cè)。
用于動(dòng)態(tài)分配和釋放固定大小或可變大小內(nèi)存塊的內(nèi)存分配服務(wù)。
用于二進(jìn)制信號(hào)量、計(jì)數(shù)信號(hào)量和互斥信號(hào)量的線程間同步服務(wù)。
用于基本消息隊(duì)列、增強(qiáng)消息隊(duì)列和字節(jié)流的線程間數(shù)據(jù)傳遞服務(wù)。
Zephyr 提供了一套全面的線程調(diào)度選擇:
協(xié)作和搶占式調(diào)度
最早截止日期優(yōu)先 (EDF)
元 IRQ 調(diào)度實(shí)現(xiàn)“中斷下半部分”或“tasklet”行為
時(shí)間切片:在同等優(yōu)先級(jí)的可搶占線程之間啟用時(shí)間切片
多種排隊(duì)策略:
簡單鏈表就緒隊(duì)列
紅/黑樹就緒隊(duì)列
傳統(tǒng)多隊(duì)列就緒隊(duì)列
高度可配置/模塊化以實(shí)現(xiàn)靈活性
允許應(yīng)用程序僅根據(jù)需要合并其所需的功能,并指定其數(shù)量和大小。
跨架構(gòu)
支持具有不同 CPU 架構(gòu)和開發(fā)工具的各種受支持的主板。貢獻(xiàn)增加了對(duì)越來越多 SoC、平臺(tái)和驅(qū)動(dòng)程序的支持。
內(nèi)存保護(hù)
在 x86、ARC 和 ARM 架構(gòu)、用戶空間和內(nèi)存域上實(shí)現(xiàn)可配置的特定于架構(gòu)的堆棧溢出保護(hù)、內(nèi)核對(duì)象和設(shè)備驅(qū)動(dòng)程序權(quán)限跟蹤以及具有線程級(jí)內(nèi)存保護(hù)的線程隔離。
對(duì)于沒有 MMU/MPU 和內(nèi)存受限設(shè)備的平臺(tái),支持將特定于應(yīng)用程序的代碼與自定義內(nèi)核相結(jié)合,以創(chuàng)建在系統(tǒng)硬件上加載和執(zhí)行的整體映像。應(yīng)用程序代碼和內(nèi)核代碼都在單個(gè)共享地址空間中執(zhí)行。
編譯時(shí)資源定義
允許在編譯時(shí)定義系統(tǒng)資源,從而減少代碼大小并提高資源有限系統(tǒng)的性能。
優(yōu)化的設(shè)備驅(qū)動(dòng)模型
提供用于配置屬于平臺(tái)/系統(tǒng)的驅(qū)動(dòng)程序的一致設(shè)備模型,以及用于初始化配置到系統(tǒng)中的所有驅(qū)動(dòng)程序的一致模型,并允許跨具有公共設(shè)備/IP 塊的平臺(tái)重用驅(qū)動(dòng)程序。
設(shè)備樹支持
使用devicetree來描述硬件。來自 devicetree 的信息用于創(chuàng)建應(yīng)用程序映像。
支持多種協(xié)議的本機(jī)網(wǎng)絡(luò)堆棧
網(wǎng)絡(luò)支持功能齊全且經(jīng)過優(yōu)化,包括 LwM2M 和 BSD 套接字兼容支持。還提供 OpenThread 支持(在 Nordic 芯片組上) - 一個(gè)網(wǎng)狀網(wǎng)絡(luò),旨在安全可靠地連接家庭周圍的數(shù)百個(gè)產(chǎn)品。
低功耗藍(lán)牙 5.0 支持
符合藍(lán)牙 5.0 標(biāo)準(zhǔn) (ESR10) 和藍(lán)牙低功耗控制器支持(LE 鏈路層)。包括藍(lán)牙網(wǎng)狀網(wǎng)絡(luò)和藍(lán)牙資格就緒的藍(lán)牙控制器。
網(wǎng)格支持:
中繼、朋友節(jié)點(diǎn)、低功耗節(jié)點(diǎn) (LPN) 和 GATT 代理功能
支持兩種配置承載(PB-ADV 和 PB-GATT)
高度可配置,適合具有至少 16k RAM 的設(shè)備
具有所有可能的 LE 角色的通用訪問配置文件 (GAP)
通用屬性配置文件 (GATT)
配對(duì)支持,包括藍(lán)牙 4.2 的安全連接功能
干凈的 HCI 驅(qū)動(dòng)程序抽象
原始 HCI 接口將 Zephyr 作為控制器運(yùn)行,而不是完整的主機(jī)堆棧
經(jīng)多個(gè)流行控制器驗(yàn)證
高度可配置
本機(jī) Linux、macOS 和 Windows 開發(fā)
命令行 CMake 構(gòu)建環(huán)境在流行的開發(fā)人員操作系統(tǒng)上運(yùn)行。本機(jī)端口 ( native_sim ) 允許您在 Linux 上構(gòu)建和運(yùn)行 Zephyr 作為本機(jī)應(yīng)用程序,從而幫助開發(fā)和測試。
支持 ext2、FatFs 和 LittleFS 的虛擬文件系統(tǒng)接口
ext2、LittleFS 和 FatFS 支持;FCB(閃存循環(huán)緩沖區(qū))適用于內(nèi)存受限的應(yīng)用程序。
強(qiáng)大的多后端日志框架
支持日志過濾、對(duì)象轉(zhuǎn)儲(chǔ)、恐慌模式、多個(gè)后端(內(nèi)存、網(wǎng)絡(luò)、文件系統(tǒng)、控制臺(tái)……)以及與 shell 子系統(tǒng)的集成。
用戶友好且功能齊全的 Shell 界面
多實(shí)例 shell 子系統(tǒng),具有用戶友好的功能,例如自動(dòng)完成、通配符、著色、元鍵(箭頭、退格鍵、ctrl+u 等)和歷史記錄。支持靜態(tài)命令和動(dòng)態(tài)子命令。
非易失性存儲(chǔ)上的設(shè)置
設(shè)置子系統(tǒng)為模塊提供了一種存儲(chǔ)持久的每設(shè)備配置和運(yùn)行時(shí)狀態(tài)的方法。設(shè)置項(xiàng)存儲(chǔ)為鍵值對(duì)字符串。
非易失性存儲(chǔ) (NVS)
NVS 允許存儲(chǔ)二進(jìn)制 blob、字符串、整數(shù)、長整型以及這些的任意組合。
本機(jī)端口
Native sim允許將 Zephyr 作為 Linux 應(yīng)用程序運(yùn)行,并支持各種子系統(tǒng)和網(wǎng)絡(luò)。
2. 環(huán)境搭建和代碼下載編譯
按照本指南進(jìn)行操作:
在 Ubuntu、macOS 或 Windows 上設(shè)置命令行 Zephyr 開發(fā)環(huán)境(其他 Linux 發(fā)行版的說明在安裝 Linux 主機(jī)依賴項(xiàng)中討論)
獲取源代碼
構(gòu)建、刷新并運(yùn)行示例應(yīng)用程序
具體不贅述了,提下如果在qemu下運(yùn)行,參考如下:
在QEMU中運(yùn)行應(yīng)用程序
在 Linux 和 macOS 上,當(dāng)面向 x86 或 ARM Cortex-M3 架構(gòu)時(shí),您可以使用QEMU在主機(jī)系統(tǒng)上通過仿真運(yùn)行 Zephyr 應(yīng)用程序。(QEMU 包含在 Zephyr SDK 安裝中。)
例如,您可以使用 x86 仿真板配置 ( ) 構(gòu)建并運(yùn)行Hello Worldqemu_x86示例,其中:
# From the root of the zephyr repository west build -b qemu_x86 samples/hello_world west build -t run
要退出 QEMU,請(qǐng)鍵入,然后鍵入。Ctrl-a``x
用于qemu_cortex_m3針對(duì)模擬的 Arm Cortex-M3 示例。
3. Zephyr的內(nèi)核特性
3.1 構(gòu)建
ephyr的構(gòu)建系統(tǒng)主要有三個(gè)部分cmake、kconfig、devicetree
cmake :在前期驅(qū)動(dòng)kconfig和devicetree需生成必要的頭文件,后期用來生成像ninja或makefile等編譯腳本
kconfig:平臺(tái)的區(qū)分以及代碼的裁剪,應(yīng)用開發(fā)中主要體現(xiàn)在驅(qū)動(dòng)的開關(guān),如下圖顯示,在驅(qū)動(dòng)的實(shí)現(xiàn)里面定義了wifi的kconfig宏,用戶在使用的時(shí)候可以在prj.config文件去打開這個(gè)宏,這個(gè)驅(qū)動(dòng)就會(huì)被打開。
devicetree:配置硬件參數(shù)信息,比如像WIFI的模塊,可以配置SPI引腳以及速率,還可以配置跟他相關(guān)的同步引腳。
3.2 設(shè)備驅(qū)動(dòng)模型
Zephyr幾乎為所有的外設(shè)驅(qū)動(dòng)都提供了統(tǒng)一的API接口,芯片原廠基于API接口提供自己的實(shí)現(xiàn),用戶在使用外設(shè)的時(shí)候可以直接使用Zephyr提供的外設(shè)接口來進(jìn)行應(yīng)用開發(fā)。
Zephyr的設(shè)備驅(qū)動(dòng)是在同一個(gè)地方統(tǒng)一初始化的,比如像這個(gè)SPI的驅(qū)動(dòng),它的宏函數(shù)就等效于這一段代碼,代碼的含義就是注冊(cè)了一個(gè)函數(shù)。這個(gè)函數(shù)會(huì)在main函數(shù)前運(yùn)行,運(yùn)行等級(jí)為application級(jí)別。驅(qū)動(dòng)的等級(jí)會(huì)比application高,等級(jí)越高就會(huì)越先執(zhí)行。設(shè)備驅(qū)動(dòng)一定會(huì)在main函數(shù)前初始化完畢。
3.3 線程調(diào)度和通信
Zephyr 在線程調(diào)度方面的功能更加強(qiáng)大、靈活,可以更好地滿足不同場景下的需求。
而 FreeRTOS 則更加簡單、易于使用,適合對(duì)資源需求較為簡單的嵌入式應(yīng)用場景
Zephyr 與 FreeRTOS 線程通信對(duì)比:
Zephyr提供了管道、消息隊(duì)列和信號(hào)量等多種線程通信機(jī)制,而FreeRTOS提供了二值信號(hào)量、互斥量和隊(duì)列等線程通信機(jī)制??梢钥闯觯琙ephyr提供的線程通信機(jī)制更加多樣化。
3.4 內(nèi)存管理
Zephyr在內(nèi)存管理上具備一些比起其他RTOS更加先進(jìn)機(jī)制,如下
Memory Heaps:提供了基于堆的動(dòng)態(tài)內(nèi)存分配和釋放機(jī)制
Memory Slabs:提供了預(yù)分配一定數(shù)量內(nèi)存塊的機(jī)制,并能夠快速分配和釋放內(nèi)存塊,避免了堆內(nèi)存管理的 開銷以及內(nèi)存碎片的產(chǎn)生
Memory Blocks Allocator:提供了固定大小內(nèi)存塊的動(dòng)態(tài)分配和釋放機(jī)制,適用于需要頻繁分配、釋放同一大小內(nèi)存塊 的場景
3.5 組件生態(tài)
越來越多的第三方組件庫已經(jīng)加入或者被移植進(jìn)了ZephyrProject中,第三方組件管理與接入流程也日趨成熟這為開發(fā)者節(jié)省了大量常用組件的移植與適配工作。
4. Zephyr啟動(dòng)流程
這里我們以cortex_m為例,只講下啟動(dòng)流程,其他代碼流程分析,參考:https://blog.csdn.net/qq_36115224/category_12279396.html
4.1 程序入口
include/zephyr/arch/arm/cortex_m/scripts/linker.ld中定義了ENTRY程序入口
ENTRY(CONFIG_KERNEL_ENTRY)
這個(gè)宏的定義在Kconfig.zephyr中
config KERNEL_ENTRY string "Kernel entry symbol" default "__start" help Code entry symbol, to be set at linking phase.
__start是程序的入口,但是這是gcc的規(guī)則,Cortex-M系列處理器是通過中斷向量表來確定程序入口 Cortex-M系列處理器是通過中斷向量表來確定程序入口。
在 Cortex-M 系列 MCU 中,如果設(shè)置為從 flash 啟動(dòng),flash 前1K 用于存放中斷向量表,
其中第一個(gè)字為程序棧頂指針,用于初始化棧頂
第二個(gè)字為復(fù)位向量,即 ResetHandler 的地址,作為程序跳轉(zhuǎn)地址,從而跳轉(zhuǎn)到程序中運(yùn)行
詳細(xì)說明可參考異常模型, 該機(jī)制為Cortex-M 系列 MCU 中獨(dú)有,與此相對(duì)的,不同的芯片在系統(tǒng)啟動(dòng)時(shí)對(duì)可執(zhí)行程序都有一定的格式要求,需要在程序的頭部添加符合操作規(guī)范的頭。
中斷向量表中,reset的處理地址定義在arch/arm/core/cortex_m/reset.S中
SECTION_SUBSEC_FUNC(TEXT,_reset_section,z_arm_reset)
4.2 匯編初始化
在arch/arm/core/cortex_m/reset.S中
SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start) #if defined(CONFIG_DEBUG_THREAD_INFO) /* Clear z_sys_post_kernel flag for RTOS aware debuggers */ movs.n r0, #0 ldr r1, =z_sys_post_kernel strb r0, [r1] #endif /* CONFIG_DEBUG_THREAD_INFO */ #if defined(CONFIG_INIT_ARCH_HW_AT_BOOT) /* 復(fù)位CONTROL寄存器,在特權(quán)模式和非特權(quán)模式均使用MSP, * 當(dāng)切換棧指針之后必須使用ISB指令刷新流水線, * 以保證在ISB之后執(zhí)行的指令都使用新的棧 */ movs.n r0, #0 msr CONTROL, r0 isb #if defined(CONFIG_CPU_CORTEX_M_HAS_SPLIM) /* 堆棧限制寄存器分別限制 MSP 和 PSP 寄存器可以下降的程度,此處設(shè)置為0 */ movs.n r0, #0 msr MSPLIM, r0 msr PSPLIM, r0 #endif /* CONFIG_CPU_CORTEX_M_HAS_SPLIM */ #endif /* CONFIG_INIT_ARCH_HW_AT_BOOT */ #if defined(CONFIG_PM_S2RAM) /* 低功耗相關(guān)初始化 */ bl arch_pm_s2ram_resume #endif /* CONFIG_PM_S2RAM */ #if defined(CONFIG_PLATFORM_SPECIFIC_INIT) /* 針對(duì)內(nèi)存,cache,jtag,時(shí)鐘,中斷的一些特殊配置 */ bl z_arm_platform_init #endif #if defined(CONFIG_INIT_ARCH_HW_AT_BOOT) #if defined(CONFIG_CPU_HAS_ARM_MPU) /* 操作系統(tǒng)未運(yùn)行之前使用平坦內(nèi)存模型,所有內(nèi)存均不受保護(hù), * 為避免在初始化過程中觸發(fā)讀寫保護(hù)進(jìn)入異常,一定要關(guān)閉MPU */ movs.n r0, #0 ldr r1, =_SCS_MPU_CTRL str r0, [r1] dsb #endif /* CONFIG_CPU_HAS_ARM_MPU */ /* ARM32使用滿遞減棧,棧頂指針初始時(shí)刻指向高地址, * 將MSP指向 z_main_stack 的末尾,以便后續(xù)進(jìn)行函數(shù)調(diào)用 */ ldr r0, =z_main_stack + CONFIG_MAIN_STACK_SIZE msr msp, r0 /* 清除MPU配置,關(guān)閉所有中斷,清除被掛起的中斷,重置Cache配置等 */ bl z_arm_init_arch_hw_at_boot #endif /* CONFIG_INIT_ARCH_HW_AT_BOOT */ /* 屏蔽中斷 */ #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) cpsid i #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) movs.n r0, #_EXC_IRQ_DEFAULT_PRIO msr BASEPRI, r0 #else #error Unknown ARM architecture #endif #ifdef CONFIG_WDOG_INIT /* 開啟看門狗 */ bl z_arm_watchdog_init #endif #ifdef CONFIG_INIT_STACKS /* 將棧全部設(shè)置為0xaa,可用于監(jiān)測剩余棧容量 */ ldr r0, =z_interrupt_stacks ldr r1, =0xaa ldr r2, =CONFIG_ISR_STACK_SIZE + MPU_GUARD_ALIGN_AND_SIZE bl z_early_memset #endif /* 初始化PSP,將CONTROL的SPSEL位設(shè)置為1(在特權(quán)模式下使用MSP,非特權(quán)模式下使用PSP) * 后續(xù)操作將使用 z_interrupt_stacks 作為棧進(jìn)行初始化 */ ldr r0, =z_interrupt_stacks ldr r1, =CONFIG_ISR_STACK_SIZE + MPU_GUARD_ALIGN_AND_SIZE adds r0, r0, r1 msr PSP, r0 mrs r0, CONTROL movs r1, #2 orrs r0, r1 /* CONTROL_SPSEL_Msk */ msr CONTROL, r0 isb bl z_prep_c
4.3 C語言初始化
z_prep_c()函數(shù)的定義在arch/arm/core/cortex_m/prep_c.c中
void z_arm_prep_c(void) { relocate_vector_table(); #if defined(CONFIG_CPU_HAS_FPU) z_arm_floating_point_init(); #endif z_bss_zero(); z_data_copy(); #if ((defined(CONFIG_ARMV7_R) || defined(CONFIG_ARMV7_A)) && defined(CONFIG_INIT_STACKS)) z_arm_init_stacks(); #endif z_arm_interrupt_init(); z_cstart(); CODE_UNREACHABLE; }
對(duì)于不同的平臺(tái)還需要增加額外的操作,例如浮點(diǎn)寄存器的初始化,中斷向量表的重定向,在系統(tǒng)啟動(dòng)之前還運(yùn)行了一段芯片內(nèi)置程序,這段程序?qū)⒅袛嘞蛄勘淼奈恢迷O(shè)置為 0x00000000,當(dāng)程序從boot跳轉(zhuǎn)到指定存儲(chǔ)器運(yùn)行之后,首先需要立即關(guān)閉中斷,避免中斷產(chǎn)生并跳轉(zhuǎn)到錯(cuò)誤的中斷響應(yīng)函數(shù)中,重設(shè)中斷向量表偏移位置之后,再重新開啟中斷。
初始化內(nèi)核開啟任務(wù)調(diào)度
FUNC_NO_STACK_PROTECTOR FUNC_NORETURN void z_cstart(void) { /* 代碼覆蓋率測試相關(guān) */ gcov_static_init(); /* 調(diào)用初始化級(jí)別為 INIT_LEVEL_EARLY 的函數(shù)進(jìn)行初始化 */ z_sys_init_run_level(INIT_LEVEL_EARLY); /* z_arm_interrupt_stack_setup 初始化MSP * z_arm_exc_setup 初始化PENDSV、SysTick等中斷的優(yōu)先級(jí),其中PENDSV優(yōu)先級(jí)為最低 * z_arm_fault_init 初始化 Fault 中斷。 * z_arm_cpu_idle_init 初始化 idle 線程 * z_arm_clear_faults 清除所有故障標(biāo)志 * z_arm_mpu_init 初始化MPU * z_arm_mmu_init 初始化MMU */ arch_kernel_init(); /* 日志初始化 */ LOG_CORE_INIT(); #if defined(CONFIG_MULTITHREADING) /* Note: The z_ready_thread() call in prepare_multithreading() requires * a dummy thread even if CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN=y */ struct k_thread dummy_thread; z_dummy_thread_init(&dummy_thread); #endif /* 初始化驅(qū)動(dòng)中的靜態(tài)節(jié)點(diǎn) */ z_device_state_init(); /* 其他的硬件初始化 */ z_sys_init_run_level(INIT_LEVEL_PRE_KERNEL_1); z_sys_init_run_level(INIT_LEVEL_PRE_KERNEL_2); #ifdef CONFIG_STACK_CANARIES /* CONFIG_STACK_CANARIES 用于開啟堆棧金絲雀功能,這是一種安全特性,有助于監(jiān)測堆棧溢出, * 當(dāng)啟動(dòng)該功能時(shí),系統(tǒng)啟動(dòng)時(shí)會(huì)生成一個(gè)隨機(jī)數(shù)并保存在 __stack_chk_guard 中, * 在函數(shù)返回之前會(huì)檢查該值確保它沒有被緩沖區(qū)溢出所覆蓋。 */ uintptr_t stack_guard; z_early_boot_rand_get((uint8_t *)&stack_guard, sizeof(stack_guard)); __stack_chk_guard = stack_guard; __stack_chk_guard <<= 8; #endif/* CONFIG_STACK_CANARIES */ #ifdef CONFIG_TIMING_FUNCTIONS_NEED_AT_BOOT /* timing_init 函數(shù)用于初始化系統(tǒng)計(jì)時(shí)器 */ timing_init(); timing_start(); #endif #ifdef CONFIG_MULTITHREADING /* CONFIG_MULTITHREADING為y時(shí),使用多線程,否則只會(huì)有一個(gè) main 線程, * 默認(rèn)情況下都啟用多線程,通過將 main 線程添加到就緒隊(duì)列中然后開啟任務(wù)調(diào)度 */ switch_to_main_thread(prepare_multithreading()); #else #ifdef ARCH_SWITCH_TO_MAIN_NO_MULTITHREADING /* Custom ARCH-specific routine to switch to main() * in the case of no multi-threading. */ ARCH_SWITCH_TO_MAIN_NO_MULTITHREADING(bg_thread_main, NULL, NULL, NULL); #else bg_thread_main(NULL, NULL, NULL); /* LCOV_EXCL_START * We've already dumped coverage data at this point. */ irq_lock(); while (true) { } /* LCOV_EXCL_STOP */ #endif #endif /* CONFIG_MULTITHREADING */ /* * Compiler can't tell that the above routines won't return and issues * a warning unless we explicitly tell it that control never gets this * far. */ CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ }
在進(jìn)入 z_cstart 之后,首先調(diào)用平臺(tái)相關(guān)的內(nèi)核初始化函數(shù),然后使用模塊自動(dòng)初始化機(jī)制根據(jù)不同優(yōu)先級(jí)調(diào)用相關(guān)初始化函數(shù) 需要注意的是,同一優(yōu)先級(jí)的模塊之間不應(yīng)該存在依賴關(guān)系,被依賴的模塊應(yīng)該先初始化。在調(diào)度器啟動(dòng)之前會(huì)調(diào)用優(yōu)先級(jí)為 INIT_LEVEL_PRE_KERNEL_1 和 INIT_LEVEL_PRE_KERNEL_2 的初始化函數(shù),此時(shí)調(diào)度器還未運(yùn)行,因此這些函數(shù)中不應(yīng)該使用操作系統(tǒng)提供的功能。在初始化完成之后通過將main線程添加到就緒隊(duì)列中并開啟調(diào)度器,main 線程從 bg_thread_main 函數(shù)開始運(yùn)行。
4.4 main線程
bg_thread_main的定義在kernel/init.c中,
static void bg_thread_main(void *unused1, void *unused2, void *unused3) { ARG_UNUSED(unused1); ARG_UNUSED(unused2); ARG_UNUSED(unused3); #ifdef CONFIG_MMU /* Invoked here such that backing store or eviction algorithms may * initialize kernel objects, and that all POST_KERNEL and later tasks * may perform memory management tasks (except for z_phys_map() which * is allowed at any time) */ z_mem_manage_init(); #endif /* CONFIG_MMU */ z_sys_post_kernel = true; /* 調(diào)用優(yōu)先級(jí)為INIT_LEVEL_POST_KERNEL的初始化函數(shù), * 此時(shí)內(nèi)核已經(jīng)開始運(yùn)行,可以使用操作系統(tǒng)API */ z_sys_init_run_level(INIT_LEVEL_POST_KERNEL); #if CONFIG_STACK_POINTER_RANDOM z_stack_adjust_initialized = 1; #endif /* 從控制臺(tái)輸出系統(tǒng)啟動(dòng)標(biāo)識(shí) */ boot_banner(); #if defined(CONFIG_CPP) /* 初始化CPP運(yùn)行環(huán)境 */ void z_cpp_init_static(void); z_cpp_init_static(); #endif /* 調(diào)用優(yōu)先級(jí)為 INIT_LEVEL_APPLICATION 的初始化函數(shù) */ z_sys_init_run_level(INIT_LEVEL_APPLICATION); /* Zephyr支持靜態(tài)創(chuàng)建線程,線程對(duì)應(yīng)的信息在編譯時(shí)確定, * 隨代碼一起被編譯到程序中,系統(tǒng)啟動(dòng)之后從對(duì)應(yīng)地址將線程的信息從flash中讀出, * 創(chuàng)建并初始化線程并將其添加到就緒隊(duì)列中等待操作系統(tǒng)調(diào)度。 */ z_init_static_threads(); #ifdef CONFIG_KERNEL_COHERENCE __ASSERT_NO_MSG(arch_mem_coherent(&_kernel)); #endif #ifdef CONFIG_SMP if (!IS_ENABLED(CONFIG_SMP_BOOT_DELAY)) { z_smp_init(); } z_sys_init_run_level(INIT_LEVEL_SMP); #endif #ifdef CONFIG_MMU z_mem_manage_boot_finish(); #endif /* CONFIG_MMU */ #ifdef CONFIG_CPP_MAIN extern int main(void); #else extern void main(void); #endif /* 跳轉(zhuǎn)到main函數(shù) */ (void)main(); /* Mark nonessential since main() has no more work to do */ z_main_thread.base.user_options &= ~K_ESSENTIAL; #ifdef CONFIG_COVERAGE_DUMP /* Dump coverage data once the main() has exited. */ gcov_coverage_dump(); #endif }
其中包含幾個(gè)系統(tǒng)運(yùn)行的重要的操作:配置MMU(如果存在) 調(diào)用優(yōu)先級(jí)為 INIT_LEVEL_POST_KERNEL 的初始化函數(shù) CPP運(yùn)行環(huán)境的初始化 調(diào)用優(yōu)先級(jí)為 INIT_LEVEL_APPLICATION 的初始化函數(shù) 創(chuàng)建通過宏靜態(tài)創(chuàng)建的線程,并添加到就緒隊(duì)列。初始化對(duì)稱多核處理(如果存在多個(gè)處理器并啟用了多核調(diào)度)。在這些準(zhǔn)備工作完成后跳轉(zhuǎn)到用戶編寫的main函數(shù)中,如果main函數(shù)執(zhí)行并返回,最終會(huì)返回到 z_thread_entry 被銷毀。
Zephyr RTOS整體上網(wǎng)上資料很多,大家可以自己去搜索學(xué)習(xí),也說明這個(gè)RTOS是比較流行的,各種硬件也對(duì)這個(gè)Zephyr進(jìn)行了支持,里面有很多功能非常的豐富,如果自己項(xiàng)目的RTOS缺失的功能可以去上面進(jìn)行移植。一個(gè)典型就是gcov代碼覆蓋率測試模塊,一般的RTOS是不支持的就可以移植。
對(duì)于OS在國內(nèi)可能很神秘,但是在歐美特別是高校里面各種定制版本或者學(xué)術(shù)版本的OS層出不窮,已經(jīng)算是人人都能造OS了一樣,這些小眾的OS不一定流行起來,但是也各有特點(diǎn),特別是一些特定場景下小眾OS也許能獲得更高的效率和效果,開源OS界也是天下文章一大抄。
審核編輯:湯梓紅
-
微控制器
+關(guān)注
關(guān)注
48文章
7903瀏覽量
153679 -
單片機(jī)
+關(guān)注
關(guān)注
6062文章
44915瀏覽量
646682 -
RTOS
+關(guān)注
關(guān)注
24文章
840瀏覽量
120738 -
代碼
+關(guān)注
關(guān)注
30文章
4886瀏覽量
70239
原文標(biāo)題:Zephyr RTOS入門-簡介及代碼下載編譯運(yùn)行
文章出處:【微信號(hào):OS與AUTOSAR研究,微信公眾號(hào):OS與AUTOSAR研究】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
請(qǐng)問Zephyr編譯出來的elf文件無法運(yùn)行的原因是什么?
【泰凌微TLSR9系列開發(fā)套件試用體驗(yàn)】Zephyr編譯環(huán)境搭建
Zephyr與FreeRTOS實(shí)時(shí)性測試比較
flash_download_tool燒錄zephyr程序,運(yùn)行后報(bào)錯(cuò)的原因?
flash_download_tool燒錄zephyr程序運(yùn)行后報(bào)錯(cuò)的原因?
small_rtos1.12.1源代碼下載
在Zephyr v2.6.0下如何搭建esp32的編譯調(diào)試環(huán)境?
淺析Zephyr應(yīng)用的代碼結(jié)構(gòu)中的自定義驅(qū)動(dòng)
泰凌微電子Zephyr硬件平臺(tái)及編譯步驟
泰凌微電子Zephyr固件下載及示例程序
EFR32BG22 Thunderboard擴(kuò)增支持開源Zephyr RTOS

Zephyr RTOS和HC-SR04超聲波傳感器開源

深入解析Zephyr RTOS的技術(shù)細(xì)節(jié)

評(píng)論