亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        實時操作系統(tǒng)mbedOS啟動流程剖析

        2020-10-19 04:40:40劉長勇王宜懷蔡闖華蔣建武
        計算機工程與應用 2020年20期

        劉長勇,王宜懷 ,蔡闖華,蔣建武

        1.武夷學院 數(shù)學與計算機學院,福建 武夷山 354300

        2.蘇州大學 計算機科學與技術學院,江蘇 蘇州 215006

        3.認知計算與智能信息處理福建省高校重點實驗室,福建 武夷山 354300

        1 引言

        2014 年ARM 公司推出了mbedOS,它是一種專為物聯(lián)網(wǎng)(IoT)中的“物體”設計的開源嵌入式實時操作系統(tǒng)(Real-Time Operating System,RTOS)[1-2],能提供精確的實時控制,以保證系統(tǒng)的實時性需求[3],具有線程管理與調(diào)度、內(nèi)存管理、時間管理、隊列管理等基本功能要素,在協(xié)議棧和IP 網(wǎng)絡組件[4]、通信技術和安全訪問服務機制[5]、物聯(lián)網(wǎng)設備平臺[6]等方面得到廣泛應用?;赗TOS 的嵌入式開發(fā),對應用系統(tǒng)的穩(wěn)定性、實時性和啟動時間等都有嚴格的要求,在啟動過程中要完成棧空間、堆空間、線程棧大小、時間嘀嗒、線程調(diào)度機制等方面的設置[7],具有啟動時間短且復雜性高的特點。因此,充分理解RTOS 的啟動流程,有助于開發(fā)人員設計出響應速度快、穩(wěn)定性強的嵌入式系統(tǒng)。目前,有關操作系統(tǒng)啟動的研究集中在Android 操作系統(tǒng)[8]、MQX 操作 系 統(tǒng)[9]、μC/OS-III 操 作 系 統(tǒng)[10]、Linux 操 作 系 統(tǒng)[11]、MTX 操作系統(tǒng)[12]以及ARM 嵌入式系統(tǒng)的啟動過程[13]等方面,但對mbedOS的啟動剖析研究方面缺乏相關資料。為此,本文將利用蘇州大學與ARM 公司聯(lián)合出品的嵌入式開發(fā)集成開發(fā)環(huán)境AHL-GEC-IDE 和金葫蘆AHL-A 系列Cortex-M0+內(nèi)核的KL36 微控制器[14](即AHL-AN100VL 型號開發(fā)板),基于SD-mbedOS 工程框架對mbedOS的啟動流程進行分析,剖析其從芯片上電啟動,到main函數(shù),最終進入mbedOS啟動的全過程,結合關鍵代碼、宏定義函數(shù)、流程圖、SVC中斷[15]等分析其實現(xiàn)的原理,可為mbedOS的應用研究和在不同微控制器上的移植提供基礎,也可為其他RTOS的啟動分析提供借鑒參考。

        2 SD-mbedOS工程框架啟動流程

        SD-mbedOS工程框架的啟動過程分為芯片上電啟動和實時操作系統(tǒng)mbedOS 啟動兩部分,如圖1 所示。芯片上電啟動包括堆棧指針初始化、啟動復位向量、關中斷、關閉看門狗、系統(tǒng)時鐘初始化、開中斷、復制初始化數(shù)據(jù)至RAM、清空BSS數(shù)據(jù)段、初始化標準庫函數(shù)和運行主函數(shù)main,這一部分的內(nèi)容與操作系統(tǒng)無關。當進入主函數(shù)main 中調(diào)用mbedOS_start 函數(shù)時,才會將系統(tǒng)控制權移交給mbedOS,由它完成線程的調(diào)度工作。

        圖1 SD-mbedOS工程框架啟動流程

        芯片上電啟動是從調(diào)用startup_MKL36Z4.S這個啟動文件開始,芯片內(nèi)部機制首先從Flash 的0x00000000地址處取出中斷向量表第一個表項的內(nèi)容,賦給內(nèi)核寄存器主棧指針MSP,即完成堆棧指針的設置;芯片內(nèi)部機制從Flash 的0x00000004 地址處取出第二個表項(即復位向量Reset_Handler 的首地址),賦給程序計數(shù)器PC。然后,關中斷、調(diào)用系統(tǒng)初始化函數(shù)SystemInit 完成系統(tǒng)時鐘初始化和開中斷。接著,將已初始化的數(shù)據(jù)復制到RAM 中、清空BSS 數(shù)據(jù)段和調(diào)用__libc_init_array 完成系統(tǒng)標準庫函數(shù)的初始化。最后,轉入main函數(shù)執(zhí)行,調(diào)用mbedOS_start函數(shù)完成mbedOS啟動。

        3 mbedOS啟動流程解析

        從芯片上電啟動到main函數(shù)后,將進行mbedOS啟動。在該函數(shù)中會將主線程thd_main 和主線程執(zhí)行函數(shù)app_init 作為參數(shù)傳入mbedOS_start 函數(shù),由它負責mbedOS 啟動。mbedOS 啟動過程包括定義臨時變量、設置mbedOS 堆棧區(qū)、重定向中斷向量表至RAM、內(nèi)核初始化、設置主線程屬性、創(chuàng)建主線程、啟動內(nèi)核等方面。

        3.1 設置堆棧區(qū)和重定向中斷向量表

        (1)定義臨時變量

        定義三個臨時變量用于創(chuàng)建主線程,變量main_obj用于存儲線程控制塊,變量main_attr用于存儲將要創(chuàng)建的主線程屬性,main_stack數(shù)組用來作為主線程的棧空間。

        os_thread_t main_obj;

        osThreadAttr_t main_attr;

        __attribute__((aligned(8)))char main_stack[512];

        (2)設置mbedOS堆棧區(qū)

        在mbedOS中只有一個主棧,主棧的棧底位置通常設置在RAM 的最高地址加1 處,由高地址向低地址方向分配??臻g,主棧指針MSP 指向棧頂位置。堆通常用于存放臨時變量,由程序員動態(tài)分配和釋放,它一般采用鏈表的方式來管理變量,堆在內(nèi)存中位于bss 區(qū)和棧區(qū)之間,堆是從RAM 的低地址向高地址方向使用。調(diào)用函數(shù)mbed_set_stack_heap 設置mbedOS 的堆與棧的起始位置和大小,主要是對已定義的四個變量進行初始化操作。

        //取得空閑RAM起始地址與大小

        unsigned char *free_start=HEAP_START;

        uint32_t free_size=HEAP_SIZE;

        //初始化棧大小與起始地址

        mbed_stack_isr_size=ISR_STACK_SIZE<free_size?ISR_STACK_SIZE:free_size;

        mbed_stack_isr_start=free_start+free_size-mbed_stack_isr_size;

        free_size-=mbed_stack_isr_size;

        //初始化堆大小與起始地址

        mbed_heap_size=free_size;

        mbed_heap_start=free_start;

        (3)重定向中斷向量表

        在系統(tǒng)啟動時中斷向量表是在Flash中的,位于Flash的0x00000000地址處,通過函數(shù)mbed_cpy_nvic重定向中斷向量表到RAM 中,實際上就是將中斷向量表拷貝到RAM中。這樣做的好處在于當用戶程序需要改寫中斷服務程序時,可以將相應的中斷向量指向用戶改寫后的中斷服務程序,即將中斷向量表中相應的表項改寫為中斷服務程序的地址。

        //取得系統(tǒng)控制塊VTOR寄存器的值

        uint32_t*old_vectors=(uint32_t*)SCB->VTOR;

        //內(nèi)存地址起始地址:0x1FFFF800

        uint32_t*vectors=(uint32_t*)NVIC_RAM_VECTOR_ADDRESS;

        //將48個中斷向量拷貝到內(nèi)存地址中

        for(int i=0;i<NVIC_NUM_VECTORS;i++)

        vectors[i]=old_vectors[i];

        //設置VTOR寄存器指向新的地址

        SCB->VTOR=(uint32_t)NVIC_RAM_VECTOR_ADDRESS;

        3.2 內(nèi)核初始化

        內(nèi)核初始化過程主要由內(nèi)核初始化函數(shù)osKernel-Initialize、SVC 觸發(fā)封裝函數(shù)__svcKernelInitialize、實際初始化函數(shù)svcRtxKernelInitialize 以及中斷服務程序SVC_Handler 組成。其調(diào)用順序為osKernelInitialize→__svcKernelInitialize→ 觸 發(fā) SVC 中 斷 SVC_Handler→svcRtxKernelInitialize。

        (1)SVC觸發(fā)封裝函數(shù)

        內(nèi)核初始化函數(shù)osKernelInitialize 功能是判斷當前是否處于中斷服務程序中或已經(jīng)屏蔽了中斷,若處于中斷服務程序中或已經(jīng)屏蔽了中斷,則返回出錯代碼;否則調(diào)用SVC 觸發(fā)封裝函數(shù)。SVC 觸發(fā)封裝函數(shù)__svcKernelInitialize 是一個宏定義函數(shù),展開后是C 語言與匯編語言混合編程代碼,其功能是為觸發(fā)SVC 中斷服務程序做前期準備工作,主要有:①將要執(zhí)行的實際內(nèi)核初始化函數(shù)指針放入R7 寄存器中,即將svcRtxKernelInitialize函數(shù)地址給R7;②使線程棧指針PSP 中的值為觸發(fā)SVC 中斷后的棧頂;③觸發(fā)SVC 中斷;④將調(diào)用R7中函數(shù)得到的返回值存放在PSP棧中。其宏定義為SVC0_0M(KernelInitialize,osStatus_t),展開后如下:

        #define SVC0_0M(f,t) //宏定義

        __attribute__((always_inline)) //強制內(nèi)聯(lián)

        //定義為靜態(tài)內(nèi)聯(lián)函數(shù)

        __STATIC_INLINE t __svc##f(void){

        SVC_ArgN(0); //定義r0作為通用寄存器

        //保存svcRtxKernelInitialize函數(shù)地址到R7中

        SVC_ArgF(svcRtx##f);

        //用于觸發(fā)SVC中斷服務程序

        SVC_Call0M(SVC_In0,SVC_Out1,SVC_CL1);

        return(t)__r0; } //函數(shù)返回值由r0傳回

        (2)SVC中斷服務程序

        SVC中斷服務程序執(zhí)行流程如圖2所示,分為兩部分:前一部分為調(diào)用內(nèi)核初始化實際函數(shù)svcRtxKernel-Initialize 前的流程,主要完成對SVC 調(diào)用號的判斷、讀出準備調(diào)用函數(shù)的入口地址等工作;后一部分為調(diào)用內(nèi)核初始化實際函數(shù)svcRtxKernelInitialize 函數(shù)(R7 寄存器存放該函數(shù)的地址)后的流程,主要完成恢復調(diào)用前的堆棧指針、函數(shù)調(diào)用后的返回值入棧、判斷是否進行上下文切換、退出SVC中斷等工作。

        圖2 SVC中斷處理程序執(zhí)行流程

        3.3 創(chuàng)建主線程

        內(nèi)核初始化之后,需要創(chuàng)建一個自啟動線程,以便內(nèi)核啟動后執(zhí)行它,由它創(chuàng)建其他用戶線程,這個自啟動線程稱為“主線程(thd_main)”。創(chuàng)建主線程的過程主要由變量定義、創(chuàng)建線程函數(shù)osThreadNew、帶上下文創(chuàng)建線程函數(shù)osThreadContextNew、SVC觸發(fā)封裝函數(shù)__svcThreadNew、實際創(chuàng)建線程函數(shù)svcRtxThreadNew以及中斷服務程序SVC_Handler構成。

        其調(diào)用順序為osThreadNew→osThreadContextNew→__svcThreadNew→觸發(fā)SVC中斷服務程序SVC_Handler→svcRtxThreadNew。

        (1)創(chuàng)建主線程的準備工作

        在mbedOS內(nèi)核中,使用線程控制塊TCB指針來表示一個線程。因此,創(chuàng)建主線程前要給TCB 和棧分配空間,并對屬性結構體main_attr進行初始化。

        main_attr.stack_mem=main_stack;//棧指針

        main_attr.stack_size=sizeof(main_stack);//棧大小

        main_attr.cb_mem=&main_obj;//控制塊指針

        main_attr.cb_size=sizeof(main_obj);//控制塊大小

        main_attr.priority=osPriorityNormal;//優(yōu)先級為 24

        main_attr.name="main_thread";//名稱

        (2)主線程的創(chuàng)建

        主線程的創(chuàng)建最終是通過觸發(fā)SVC中斷服務程序調(diào)用svcRtxThreadNew 函數(shù)來完成的,該函數(shù)的主要任務包括定義臨時變量、判斷參數(shù)及內(nèi)存空間的合法性、初始化主線程TCB和線程棧、調(diào)用線程提交服務程序、設置主線程狀態(tài)并放入就緒隊列中等方面,其執(zhí)行流程如圖3所示。

        圖3 主線程創(chuàng)建執(zhí)行流程

        3.4 內(nèi)核啟動

        在主線程創(chuàng)建成功后,mbedOS 會把主線程加入到就緒隊列中等待調(diào)用,接著將進行內(nèi)核的啟動,為操作系統(tǒng)的運行做最后的準備工作。啟動內(nèi)核主要由內(nèi)核啟動函數(shù)osKernelStart、SVC觸發(fā)封裝函數(shù)__svcKernelStart、實際內(nèi)核啟動函數(shù)svcRtxKernelStart 及中斷服務程序SVC_Handler 組成。其調(diào)用順序為osKernelStart→__svcKernelStart→觸發(fā)SVC中斷服務程序SVC_Handler→svcRtxKernelStart。

        (1)內(nèi)核啟動的實際執(zhí)行函數(shù)

        最終實現(xiàn)內(nèi)核啟動的是svcRtxKernelStart 函數(shù),其主要任務包括為線程的調(diào)度做好所有必要的準備、創(chuàng)建必要的功能線程、設置時間嘀嗒、使能定時器中斷、線程調(diào)度、切換棧指針、修改內(nèi)核狀態(tài)等方面,其執(zhí)行流程如圖4所示。

        圖4 內(nèi)核啟動執(zhí)行流程

        (2)運行到主線程

        在mbedOS 啟動過程中,通過調(diào)用svcRtxKernel-Start函數(shù)來啟動內(nèi)核。在內(nèi)核啟動期間,先后建立了主線程main_thread(優(yōu)先級為24)、空閑線程osRtxInfo.thread.idle(優(yōu)先級為1)和定時器線程osRtxInfo.timer.thread(優(yōu)先級為40),這三個線程的狀態(tài)都為就緒態(tài),都被放到就緒隊列中,并按優(yōu)先級高低排列就緒,即定時器線程、主線程和空閑線程。當svcRtxKernelStart 函數(shù)執(zhí)行完成后返回到SVC 中斷時,會在SVC 中斷中進行上下文切換,此時由于有一個優(yōu)先級最高的線程(即定時器線程)處于激活態(tài),它的線程控制塊指針被放在了osRtxInfo.thread.run.next 中,當前線程與下一線程是不同的(即osRtxInfo.thread.run.curr≠osRtxInfo.thread.run.next),這時就會進行上下文切換,將定時器線程切換為當前線程,當從SVC 中斷返回時就會轉到定時器線程中執(zhí)行。在定時器線程osRtxInfo.timer.thread 啟動后,先創(chuàng)建一個消息隊列,再從消息隊列取消息,由于此時消息隊列是空的,定時器線程被阻塞。之后mbedOS會進行線程調(diào)度,從就緒隊列中選擇優(yōu)先級最高的線程(此時為主線程main_thread),將其狀態(tài)設置為激活態(tài),準備運行。至此,CPU的控制權轉交給主線程,接著將由主線程執(zhí)行函數(shù)app_init(定義在08_mbedOsPrgapp_init.cpp 文件中)負責創(chuàng)建用戶線程。圖5 展示了從定時器線程切換到主線程運行這一過程中的函數(shù)調(diào)用關系,從中可以看出最終轉到app_init函數(shù)執(zhí)行。

        4 存儲器使用情況分析

        在mbedOS 啟動過程中,涉及到中斷向量表、程序代碼、常量、變量、堆、棧等空間分配問題,下面先給出KL36 微控制器結構,然后分析mbedOS 啟動過程中Flash和RAM空間的使用情況。

        圖5 從定時器線程切換到主線程運行的函數(shù)調(diào)用關系

        4.1 KL36微控制器結構

        KL36 微控制器包括ARM Cortex-M0+內(nèi)核、存儲器模塊、外設模塊及相關總線等,存儲器模塊與32位的高性能系統(tǒng)總線相連,外設模塊與32位外設總線相連,還提供擴展總線連接其他外圍設備,其結構如圖6所示。

        圖6 KL36微控制器結構

        4.2 Flash使用情況分析

        KL36 片內(nèi) Flash 大 小 為 64 KB,地址范圍為0x00000000~0x0000FFFF,一般用來存放中斷向量、程序代碼、常數(shù)等。mbedOS啟動后Flash中各個區(qū)的地址范圍、大小及作用如表1 所示(表中數(shù)據(jù)采用十六進制表示,下同)。

        4.3 RAM使用情況分析

        (1)mbedOS啟動后RAM使用情況分析

        KL36片內(nèi)RAM為靜態(tài)隨機存儲器SRAM,大小為8 KB,地址范圍為0x1FFFF800~0x200017FF,一般用來存儲全局變量、靜態(tài)變量、臨時變量(堆棧空間)等。該芯片??臻g的使用方向是從大地址向小地址方向進行的。因此,??臻g的棧頂設置在RAM 地址的最大值+1處。而堆空間的使用方向是從小地址向大地址方向進行的,這樣可以減少重疊錯誤。mbedOS啟動后RAM中各個段的地址范圍、大小及作用如表2所示。

        (2)各線程RAM分配情況分析

        在mbedOS 的啟動過程中,先后建立了主線程main_thread、空閑線程osRtxInfo.thread.idle、定時器線程osRtxInfo.timer.thread,并啟動定時器SysTick 中斷。在切換到主線程函數(shù)app_init 執(zhí)行之前,這三個線程的RAM 分配情況如表3 所示,在鏈表中的關系如圖7 所示。表中的成員名來源于線程控制塊結構體和線程屬性結構體,sp的值等于stack_mem+stack_size-64(這個64 Byte 的固定區(qū)域是用于在線程進行上下文切換時,保存線程的上下文,即R0~R12、R14、R15、xPSR等16個寄存器),0x1FFFF8E0地址表示就緒隊列頭指針。

        當定時器線程啟動之后就被阻塞,轉由主線程控制CPU 的使用權,在主線程函數(shù)app_init 中分別建立紅燈線程thd_redlight、藍燈線程thd_bluelight 和綠燈線程thd_greenlight三個用戶線程,當這三個用戶線程啟動完后,主線程進入阻塞狀態(tài)。此時,系統(tǒng)中有四個線程,分別是空閑線程、紅燈線程、藍燈線程和綠燈線程,這四個線程的RAM分配如表4所示,在鏈表中的關系如圖8所示。

        表1 Flash中的各區(qū)地址范圍、大小及作用

        表2 RAM中的各段地址范圍、大小及作用

        表3 執(zhí)行app_init之前系統(tǒng)線程的RAM分配情況表

        圖7 系統(tǒng)線程之間的關系

        表4 執(zhí)行app_init之后線程的RAM分配情況表

        圖8 用戶線程之間的關系

        5 結束語

        mbedOS 的啟動過程是一個極其復雜的過程,涉及到操作系統(tǒng)運行時所需的棧空間、堆空間、線程控制塊等資源的初始化,系統(tǒng)時鐘的設置,就緒隊列、延時隊列和等待隊列等的管理,以及對線程的調(diào)度,涉及到函數(shù)調(diào)用關系也極為復雜。本文通過對SD-mbedOS工程框架啟動流程的分析,簡要地給出了芯片上電啟動過程,通過源碼、宏定義函數(shù)、SVC中斷、流程圖等方式來著重剖析mbedOS 的啟動過程,最后分析了mbedOS 的存儲器使用情況。通過剖析,有助于讀者快速理解mbedOS的啟動過程、調(diào)度機制和整體架構,為簡化啟動流程、優(yōu)化執(zhí)行過程、提升啟動速度等進一步研究工作提供研究基礎,也為mbedOS在不同微控制器上的移植提供了技術基礎。本文涉及到的工程可到蘇州大學嵌入式學習社區(qū)網(wǎng)站(http://sumcu.suda.edu.cn)的“教學培訓-教學資料-mbedOS”位置,下載“SD_mbedOS_Start(KL36)”查看。

        欧洲-级毛片内射| 包皮上有一点一点白色的| 国产高清在线精品一区二区三区| 亚洲熟女熟妇另类中文| 内射中出日韩无国产剧情 | 国产精品一区二区资源| 国产精品一级黄色大片| 日韩一区三区av在线| 久久国产成人精品av| 97se亚洲国产综合自在线| 亚洲精品成人av观看| 亚洲中文字幕第一页免费 | 亚洲av无码不卡| 亚洲av成人一区二区三区网址| 中文字幕人妻少妇美臀| 手机久草视频福利在线观看| 丰满少妇高潮惨叫久久久一| 精品人妻少妇一区二区不卡| 国产成人精品曰本亚洲| 青青草视频网站免费看| 国产亚洲精品90在线视频| 国产又色又爽又黄的| 国内精品一区视频在线播放 | av在线色| 亚洲免费看三级黄网站| 91丝袜美腿亚洲一区二区| 丰满熟女高潮毛茸茸欧洲视频| 久久久久久成人毛片免费看| 在线无码免费看黄网站| 国产成人av三级三级三级在线| 国产老熟妇精品观看| 国产成人精品综合在线观看| 波多野结衣免费一区视频| 国产精品女同久久久久久| 日本a级黄片免费观看| 狠狠噜天天噜日日噜无码| 欧美国产成人精品一区二区三区| 日日噜噜夜夜狠狠久久av| 美腿丝袜视频在线观看| 情爱偷拍视频一区二区| 欧洲人妻丰满av无码久久不卡 |