說起來RTOS,第一印象就是單片機程序、ARM M核、微控制器低頻運行處理程序,甚至其不能算一個真正的OS。但是隨著時代發展,這些單片機程序在有限的硬件機制下非常接近像Linux這種的巨無霸OS了,例如其有線程、中斷、內存管理、IPC、驅動、網絡協議棧、shell、提供POSIX接口等,可以說其已經是一個縮小版的OS了,甚至在A核也可以運行,簡單修改下添加一點用戶空間支持等特性就可以。
在嵌入式領域中,定制化的軟硬件,并且沒有界面展示的時候,并不需要ARM A核這種高級的CPU,M核是一個更好的選擇,其便宜,小,省電,可靠性高,偏向專用控制,但是頻率低,功能進行了閹割。在其上運行的RTOS也有對應的特點:
地址空間只有一個,就像Linux的內核一樣,共享地址空間
沒有高級的硬件相關MMU功能,無虛擬地址
沒有文件系統、UI界面等復雜服務
各種服務例如進程調度等是一個簡單實現版本
之前介紹過一個典型的RTOS freeRTOS:FreeRTOS入門-概念介紹。其實RTOS的定義就是實時操作系統,例如Linux修改下具有實時特性也可以叫RTOS了。本文講的zephyr RTOS就是一個類似freeRTOS的操作系統,可以等價平替,下面介紹下其特點。
1. Zephyr介紹
1.1 Zephyr簡介
Zephyr最初是由Wind River公司開發的一個微內核,在2016年的時候成為Linux基金會維護的一個項目,發展至今,已經成為了一個功能齊全的嵌入式OS。平臺現在支持ARM、RISC-V、X86、Xtensa等等處理器平臺,擁有原生的BLE協議棧、完整的Net協議棧,包括TCP/IP與應用層協議,為嵌入式應用的開發提供了有力的支持。
Zephyr它不僅僅維護了一個RTOS內核,還維護一些編譯鏈、libc、 IDE插件、HEL層驅動等,幾乎每一個模塊都有相關的文檔。正是因為擁有詳細的文檔,Zephyr才能源源不斷的吸引人來進行嘗試與開發,以至于系統不斷的被完善,進入開源項目的一個良性循環。
Linux基金會維護
所以看Zephyr就很Linux里Linux氣的,比如make menuconfig支持、DTS支持等,可以說把Linux一些優秀的通用特性吸引進來了,做到了很多代碼跟Linux同步,妥妥的Linux小弟。好處就是我們去抄代碼的時候,不,是移植代碼的時候Zephyr就是一個很好的調研對象,其完全開源嘛!
Wind River公司
大名鼎鼎的VxWorks實時操作系統就是Wind River公司開發的,其在實時操作系統領域早期可謂獨領風騷,特別在軍工中,它以其良好的可靠性和實時性被廣泛地應用在通信、軍事、航空、航天等高精尖技術及實時性要求極高的領域中,如衛星通訊、軍事演習、彈道制導、飛機導航等。在美國的 F-16、FA-18戰斗機、B-2 隱形轟炸機和愛國者導彈上,甚至連1997年4月在火星表面登陸的火星探測器、2008年5月登陸的鳳凰號,和2012年8月登陸的好奇號也都使用到了VxWorks。VxWorks不開源,這里的Zephyr可以說是出身在一流家族中,其實時特性應該很值得借鑒。
1.2 特性介紹
Zephyr OS 基于小占用內核,設計用于資源受限的嵌入式系統:從簡單的嵌入式環境傳感器和 LED 可穿戴設備到復雜的嵌入式控制器、智能手表和物聯網無線應用。
其中Zephyr OS為Zephyr提供的核心代碼包含了:
Kernel/HAL
內核調度
低級的體系結構和板級支援
各種RTOS內核對象
電源管理框架
低級的硬件接口抽象
OS服務及底層接口
設備管理及底層驅動API
文件系統,Logging系統,Debugging系統及IPC
加密服務
平臺相關的特殊驅動
網絡協議棧
應用服務
高層級的應用API
標準化的數據模型
高層級網絡協議接口
對于Zephyr應用開發者,需要熟知應用服務和OS服務,了解底層接口及Kernel/HAL特性。
Zephy也提供構建系統及開發環境和Zephyr OS一起構成了Zephyr Project,Zephyr Project包含了:
Zephyr的SDK,構建工具,CI及開發環境
附加的中間件
Zephyr除了核心代碼之外還引入了其它優秀的開源項目做為其功能組成部分,另外還有不同的項目也將Zephyr作為其組成部分,這些內容在一起構成了完整的Zephyr生態。Zephyr生態有如下內容:
第三方模塊或庫:例如lvgl,fatfs,mcumgr,openthread,openamp,opencan等等。
第三方支持Zephyr的項目:例如Jerryscript ,Micropython , Iotivity , SwiftIO等。
SOC供應商Hal,Zephyr將不同芯片的Hal作為外部模塊引入到Zephyr中,通過Zephyr驅動的整合讓應用可以通過統一的驅動接口控制不同芯片的片上設備。例如:nxp,st,ti,nordic,silabs等等。
Kernel涵蓋以下內容:
提供Kernel service,例如thread,同步,數據傳遞,中斷管理,時間管理,內存管理等
進行任務調度
電源管理
平臺相關的特殊驅動,例如Radios,傳感器,加密硬件,Flash等
OS服務涵蓋以下內容:
設備驅動實現,提供統一的底層驅動接口
設備管理
網絡L2實現及接口抽象
網絡層和傳輸層協議棧(TCP/IP),socket接口
應用服務涵蓋以下內容:
網絡應用協議及高層級接口,例如HTTP,coap,mqtt,tls,dtls等
提供標準化的數據模型,目前尚未在Zephyr的目錄樹中找到該部分內容
提供智能物件對象,例如基于lwm2m的IPSO
Zephyr的硬件層次結構被抽象出6層:
架構(Architecutre):指令架構體系,例如ARM,RISC-V,x86等
CPU內核(CPU core):架構中特定的CPU,例如ARM中有Cortex-M0,M3,M4,M7等
芯片族(Soc family):具有相似特性的SoC,例如Cortex-M7中有STMicro STM32,NXP i.MX
芯片系列(SoC series):一小部分緊密關聯的SoC,例如i.MX中有i.MX RT 系列,i.MX 8系列等
芯片級(SoC):電路板上的SoC,例如i.MX RT系列中有RT1050,RT1060等芯片
板級(Board):PCB上特定的SoC和一些外設相連構成有特定功能的電路板。例如Zephyr支援的mimxrt1050_evk,mm_swiftio開發板使用了rt1052芯片。
Zephyr 內核支持多種架構,包括:
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
廣泛的內核服務套件,Zephyr 提供了許多熟悉的開發服務:
用于協作、基于優先級、非搶占式和搶占式線程的多線程服務,具有可選的循環時間切片。包括 POSIX pthreads 兼容 API 支持。
中斷服務用于中斷處理程序的編譯時注冊。
用于動態分配和釋放固定大小或可變大小內存塊的內存分配服務。
用于二進制信號量、計數信號量和互斥信號量的線程間同步服務。
用于基本消息隊列、增強消息隊列和字節流的線程間數據傳遞服務。
Zephyr 提供了一套全面的線程調度選擇:
協作和搶占式調度
最早截止日期優先 (EDF)
元 IRQ 調度實現“中斷下半部分”或“tasklet”行為
時間切片:在同等優先級的可搶占線程之間啟用時間切片
多種排隊策略:
簡單鏈表就緒隊列
紅/黑樹就緒隊列
傳統多隊列就緒隊列
高度可配置/模塊化以實現靈活性
允許應用程序僅根據需要合并其所需的功能,并指定其數量和大小。
跨架構
支持具有不同 CPU 架構和開發工具的各種受支持的主板。貢獻增加了對越來越多 SoC、平臺和驅動程序的支持。
內存保護
在 x86、ARC 和 ARM 架構、用戶空間和內存域上實現可配置的特定于架構的堆棧溢出保護、內核對象和設備驅動程序權限跟蹤以及具有線程級內存保護的線程隔離。
對于沒有 MMU/MPU 和內存受限設備的平臺,支持將特定于應用程序的代碼與自定義內核相結合,以創建在系統硬件上加載和執行的整體映像。應用程序代碼和內核代碼都在單個共享地址空間中執行。
編譯時資源定義
允許在編譯時定義系統資源,從而減少代碼大小并提高資源有限系統的性能。
優化的設備驅動模型
提供用于配置屬于平臺/系統的驅動程序的一致設備模型,以及用于初始化配置到系統中的所有驅動程序的一致模型,并允許跨具有公共設備/IP 塊的平臺重用驅動程序。
設備樹支持
使用devicetree來描述硬件。來自 devicetree 的信息用于創建應用程序映像。
支持多種協議的本機網絡堆棧
網絡支持功能齊全且經過優化,包括 LwM2M 和 BSD 套接字兼容支持。還提供 OpenThread 支持(在 Nordic 芯片組上) - 一個網狀網絡,旨在安全可靠地連接家庭周圍的數百個產品。
低功耗藍牙 5.0 支持
符合藍牙 5.0 標準 (ESR10) 和藍牙低功耗控制器支持(LE 鏈路層)。包括藍牙網狀網絡和藍牙資格就緒的藍牙控制器。
網格支持:
中繼、朋友節點、低功耗節點 (LPN) 和 GATT 代理功能
支持兩種配置承載(PB-ADV 和 PB-GATT)
高度可配置,適合具有至少 16k RAM 的設備
具有所有可能的 LE 角色的通用訪問配置文件 (GAP)
通用屬性配置文件 (GATT)
配對支持,包括藍牙 4.2 的安全連接功能
干凈的 HCI 驅動程序抽象
原始 HCI 接口將 Zephyr 作為控制器運行,而不是完整的主機堆棧
經多個流行控制器驗證
高度可配置
本機 Linux、macOS 和 Windows 開發
命令行 CMake 構建環境在流行的開發人員操作系統上運行。本機端口 ( native_sim ) 允許您在 Linux 上構建和運行 Zephyr 作為本機應用程序,從而幫助開發和測試。
支持 ext2、FatFs 和 LittleFS 的虛擬文件系統接口
ext2、LittleFS 和 FatFS 支持;FCB(閃存循環緩沖區)適用于內存受限的應用程序。
強大的多后端日志框架
支持日志過濾、對象轉儲、恐慌模式、多個后端(內存、網絡、文件系統、控制臺……)以及與 shell 子系統的集成。
用戶友好且功能齊全的 Shell 界面
多實例 shell 子系統,具有用戶友好的功能,例如自動完成、通配符、著色、元鍵(箭頭、退格鍵、ctrl+u 等)和歷史記錄。支持靜態命令和動態子命令。
非易失性存儲上的設置
設置子系統為模塊提供了一種存儲持久的每設備配置和運行時狀態的方法。設置項存儲為鍵值對字符串。
非易失性存儲 (NVS)
NVS 允許存儲二進制 blob、字符串、整數、長整型以及這些的任意組合。
本機端口
Native sim允許將 Zephyr 作為 Linux 應用程序運行,并支持各種子系統和網絡。
2. 環境搭建和代碼下載編譯
按照本指南進行操作:
在 Ubuntu、macOS 或 Windows 上設置命令行 Zephyr 開發環境(其他 Linux 發行版的說明在安裝 Linux 主機依賴項中討論)
獲取源代碼
構建、刷新并運行示例應用程序
具體不贅述了,提下如果在qemu下運行,參考如下:
在QEMU中運行應用程序
在 Linux 和 macOS 上,當面向 x86 或 ARM Cortex-M3 架構時,您可以使用QEMU在主機系統上通過仿真運行 Zephyr 應用程序。(QEMU 包含在 Zephyr SDK 安裝中。)
例如,您可以使用 x86 仿真板配置 ( ) 構建并運行Hello Worldqemu_x86示例,其中:
# From the root of the zephyr repository west build -b qemu_x86 samples/hello_world west build -t run
要退出 QEMU,請鍵入,然后鍵入。Ctrl-a``x
用于qemu_cortex_m3針對模擬的 Arm Cortex-M3 示例。
3. Zephyr的內核特性
3.1 構建
ephyr的構建系統主要有三個部分cmake、kconfig、devicetree
cmake :在前期驅動kconfig和devicetree需生成必要的頭文件,后期用來生成像ninja或makefile等編譯腳本
kconfig:平臺的區分以及代碼的裁剪,應用開發中主要體現在驅動的開關,如下圖顯示,在驅動的實現里面定義了wifi的kconfig宏,用戶在使用的時候可以在prj.config文件去打開這個宏,這個驅動就會被打開。
devicetree:配置硬件參數信息,比如像WIFI的模塊,可以配置SPI引腳以及速率,還可以配置跟他相關的同步引腳。
3.2 設備驅動模型
Zephyr幾乎為所有的外設驅動都提供了統一的API接口,芯片原廠基于API接口提供自己的實現,用戶在使用外設的時候可以直接使用Zephyr提供的外設接口來進行應用開發。
Zephyr的設備驅動是在同一個地方統一初始化的,比如像這個SPI的驅動,它的宏函數就等效于這一段代碼,代碼的含義就是注冊了一個函數。這個函數會在main函數前運行,運行等級為application級別。驅動的等級會比application高,等級越高就會越先執行。設備驅動一定會在main函數前初始化完畢。
3.3 線程調度和通信
Zephyr 在線程調度方面的功能更加強大、靈活,可以更好地滿足不同場景下的需求。
而 FreeRTOS 則更加簡單、易于使用,適合對資源需求較為簡單的嵌入式應用場景
Zephyr 與 FreeRTOS 線程通信對比:
Zephyr提供了管道、消息隊列和信號量等多種線程通信機制,而FreeRTOS提供了二值信號量、互斥量和隊列等線程通信機制。可以看出,Zephyr提供的線程通信機制更加多樣化。
3.4 內存管理
Zephyr在內存管理上具備一些比起其他RTOS更加先進機制,如下
Memory Heaps:提供了基于堆的動態內存分配和釋放機制
Memory Slabs:提供了預分配一定數量內存塊的機制,并能夠快速分配和釋放內存塊,避免了堆內存管理的 開銷以及內存碎片的產生
Memory Blocks Allocator:提供了固定大小內存塊的動態分配和釋放機制,適用于需要頻繁分配、釋放同一大小內存塊 的場景
3.5 組件生態
越來越多的第三方組件庫已經加入或者被移植進了ZephyrProject中,第三方組件管理與接入流程也日趨成熟這為開發者節省了大量常用組件的移植與適配工作。
4. Zephyr啟動流程
這里我們以cortex_m為例,只講下啟動流程,其他代碼流程分析,參考: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)
這個宏的定義在Kconfig.zephyr中
config KERNEL_ENTRY string "Kernel entry symbol" default "__start" help Code entry symbol, to be set at linking phase.
__start是程序的入口,但是這是gcc的規則,Cortex-M系列處理器是通過中斷向量表來確定程序入口 Cortex-M系列處理器是通過中斷向量表來確定程序入口。
在 Cortex-M 系列 MCU 中,如果設置為從 flash 啟動,flash 前1K 用于存放中斷向量表,
其中第一個字為程序棧頂指針,用于初始化棧頂
第二個字為復位向量,即 ResetHandler 的地址,作為程序跳轉地址,從而跳轉到程序中運行
詳細說明可參考異常模型, 該機制為Cortex-M 系列 MCU 中獨有,與此相對的,不同的芯片在系統啟動時對可執行程序都有一定的格式要求,需要在程序的頭部添加符合操作規范的頭。
中斷向量表中,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) /* 復位CONTROL寄存器,在特權模式和非特權模式均使用MSP, * 當切換棧指針之后必須使用ISB指令刷新流水線, * 以保證在ISB之后執行的指令都使用新的棧 */ movs.n r0, #0 msr CONTROL, r0 isb #if defined(CONFIG_CPU_CORTEX_M_HAS_SPLIM) /* 堆棧限制寄存器分別限制 MSP 和 PSP 寄存器可以下降的程度,此處設置為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) /* 低功耗相關初始化 */ bl arch_pm_s2ram_resume #endif /* CONFIG_PM_S2RAM */ #if defined(CONFIG_PLATFORM_SPECIFIC_INIT) /* 針對內存,cache,jtag,時鐘,中斷的一些特殊配置 */ bl z_arm_platform_init #endif #if defined(CONFIG_INIT_ARCH_HW_AT_BOOT) #if defined(CONFIG_CPU_HAS_ARM_MPU) /* 操作系統未運行之前使用平坦內存模型,所有內存均不受保護, * 為避免在初始化過程中觸發讀寫保護進入異常,一定要關閉MPU */ movs.n r0, #0 ldr r1, =_SCS_MPU_CTRL str r0, [r1] dsb #endif /* CONFIG_CPU_HAS_ARM_MPU */ /* ARM32使用滿遞減棧,棧頂指針初始時刻指向高地址, * 將MSP指向 z_main_stack 的末尾,以便后續進行函數調用 */ ldr r0, =z_main_stack + CONFIG_MAIN_STACK_SIZE msr msp, r0 /* 清除MPU配置,關閉所有中斷,清除被掛起的中斷,重置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 /* 將棧全部設置為0xaa,可用于監測剩余棧容量 */ 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位設置為1(在特權模式下使用MSP,非特權模式下使用PSP) * 后續操作將使用 z_interrupt_stacks 作為棧進行初始化 */ 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()函數的定義在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; }
對于不同的平臺還需要增加額外的操作,例如浮點寄存器的初始化,中斷向量表的重定向,在系統啟動之前還運行了一段芯片內置程序,這段程序將中斷向量表的位置設置為 0x00000000,當程序從boot跳轉到指定存儲器運行之后,首先需要立即關閉中斷,避免中斷產生并跳轉到錯誤的中斷響應函數中,重設中斷向量表偏移位置之后,再重新開啟中斷。
初始化內核開啟任務調度
FUNC_NO_STACK_PROTECTOR FUNC_NORETURN void z_cstart(void) { /* 代碼覆蓋率測試相關 */ gcov_static_init(); /* 調用初始化級別為 INIT_LEVEL_EARLY 的函數進行初始化 */ z_sys_init_run_level(INIT_LEVEL_EARLY); /* z_arm_interrupt_stack_setup 初始化MSP * z_arm_exc_setup 初始化PENDSV、SysTick等中斷的優先級,其中PENDSV優先級為最低 * z_arm_fault_init 初始化 Fault 中斷。 * z_arm_cpu_idle_init 初始化 idle 線程 * z_arm_clear_faults 清除所有故障標志 * 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 /* 初始化驅動中的靜態節點 */ 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 用于開啟堆棧金絲雀功能,這是一種安全特性,有助于監測堆棧溢出, * 當啟動該功能時,系統啟動時會生成一個隨機數并保存在 __stack_chk_guard 中, * 在函數返回之前會檢查該值確保它沒有被緩沖區溢出所覆蓋。 */ 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 函數用于初始化系統計時器 */ timing_init(); timing_start(); #endif #ifdef CONFIG_MULTITHREADING /* CONFIG_MULTITHREADING為y時,使用多線程,否則只會有一個 main 線程, * 默認情況下都啟用多線程,通過將 main 線程添加到就緒隊列中然后開啟任務調度 */ 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 */ }
在進入 z_cstart 之后,首先調用平臺相關的內核初始化函數,然后使用模塊自動初始化機制根據不同優先級調用相關初始化函數 需要注意的是,同一優先級的模塊之間不應該存在依賴關系,被依賴的模塊應該先初始化。在調度器啟動之前會調用優先級為 INIT_LEVEL_PRE_KERNEL_1 和 INIT_LEVEL_PRE_KERNEL_2 的初始化函數,此時調度器還未運行,因此這些函數中不應該使用操作系統提供的功能。在初始化完成之后通過將main線程添加到就緒隊列中并開啟調度器,main 線程從 bg_thread_main 函數開始運行。
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; /* 調用優先級為INIT_LEVEL_POST_KERNEL的初始化函數, * 此時內核已經開始運行,可以使用操作系統API */ z_sys_init_run_level(INIT_LEVEL_POST_KERNEL); #if CONFIG_STACK_POINTER_RANDOM z_stack_adjust_initialized = 1; #endif /* 從控制臺輸出系統啟動標識 */ boot_banner(); #if defined(CONFIG_CPP) /* 初始化CPP運行環境 */ void z_cpp_init_static(void); z_cpp_init_static(); #endif /* 調用優先級為 INIT_LEVEL_APPLICATION 的初始化函數 */ z_sys_init_run_level(INIT_LEVEL_APPLICATION); /* Zephyr支持靜態創建線程,線程對應的信息在編譯時確定, * 隨代碼一起被編譯到程序中,系統啟動之后從對應地址將線程的信息從flash中讀出, * 創建并初始化線程并將其添加到就緒隊列中等待操作系統調度。 */ 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 /* 跳轉到main函數 */ (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 }
其中包含幾個系統運行的重要的操作:配置MMU(如果存在) 調用優先級為 INIT_LEVEL_POST_KERNEL 的初始化函數 CPP運行環境的初始化 調用優先級為 INIT_LEVEL_APPLICATION 的初始化函數 創建通過宏靜態創建的線程,并添加到就緒隊列。初始化對稱多核處理(如果存在多個處理器并啟用了多核調度)。在這些準備工作完成后跳轉到用戶編寫的main函數中,如果main函數執行并返回,最終會返回到 z_thread_entry 被銷毀。
Zephyr RTOS整體上網上資料很多,大家可以自己去搜索學習,也說明這個RTOS是比較流行的,各種硬件也對這個Zephyr進行了支持,里面有很多功能非常的豐富,如果自己項目的RTOS缺失的功能可以去上面進行移植。一個典型就是gcov代碼覆蓋率測試模塊,一般的RTOS是不支持的就可以移植。
對于OS在國內可能很神秘,但是在歐美特別是高校里面各種定制版本或者學術版本的OS層出不窮,已經算是人人都能造OS了一樣,這些小眾的OS不一定流行起來,但是也各有特點,特別是一些特定場景下小眾OS也許能獲得更高的效率和效果,開源OS界也是天下文章一大抄。
審核編輯:湯梓紅
-
微控制器
+關注
關注
48文章
7492瀏覽量
151078 -
單片機
+關注
關注
6032文章
44522瀏覽量
633188 -
RTOS
+關注
關注
22文章
809瀏覽量
119442 -
代碼
+關注
關注
30文章
4752瀏覽量
68362
原文標題:Zephyr RTOS入門-簡介及代碼下載編譯運行
文章出處:【微信號:OS與AUTOSAR研究,微信公眾號:OS與AUTOSAR研究】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論