CMSIS_RTOS_Tutorial自譯中文版

来源:http://www.cnblogs.com/horal/archive/2017/11/16/7841148.html
-Advertisement-
Play Games

一.序言 本資料是Trevor Martin編寫的《The Designers Guide to the Cortex-M Processor Family》的摘要,並得到Elsevier的再版許可。查詢更多細節,請到本資料尾部進階章節。 本資料著力於介紹RTX,RTX可運行在基於Cortex-M構 ...


 

一.序言

 

本資料是Trevor Martin編寫的《The Designers Guide to the Cortex-M Processor Family》的摘要,並得到Elsevier的再版許可。查詢更多細節,請到本資料尾部進階章節。

本資料著力於介紹RTX,RTX可運行在基於Cortex-M構架的微控制器上。尤其,RTX符合CMSIS標準。CMSIS全稱"Cortex Microcontroller Interface Standard",定義了基於Cortex-M構架的微控制器標準的RTOS Api。CMSIS RTOS Api提供基於RTOS開發的介面,掌握後可跨多系列微控制器使用。另外,CMSIS RTOS Api也為高級應用(如Java虛擬機,UML)等提供標準介面。同時,CMSIS RTOS Api也是不依賴於硬體層的標準介面,支持代碼重覆使用。

作為新手,適應RTOS需要大量的練習,但RTOS的便利性會使使用者再也不想回到裸板程式。

1.1.起步-安裝工具

 

要運行本資料中的示例代碼,必須安裝MDK-ARM工具鏈。可在如下地址下載最新版本,並運行安裝程式。

http://www.keil.com/mdk5/install

該安裝程式是MDK-ARM的核心,包括IDE,編譯/鏈接工具和基本調試模塊。不包括對基於Cortex-M構架微控制器的具體型號支持,要支持具體的型號需要下載"Device Family Pack"(集合了啟動文件,Flash編程演算法和調試支持)。

本資料中的練習,均基於STM32F103RB微控制器,所以需要安裝對應的"Device Family Pack"。

初次安裝完畢,Pack Installer會自動啟動。也可通過工具欄啟動,如圖所示:

在Pack Installer選擇相應的模塊安裝,Pack Installer自動下載並安裝。

1.2.安裝常式

 

本資料中涉及到的常式也被做成CMSIS pack下載。在Pack Installer中雙擊Hitex.CMSIS_RTOS_Turorial.xxxx.pack file即可自動安裝。

安裝完成後界面如圖:

1.3.硬體需求

 

不需要硬體支持!

Keil工具鏈包含基於Cortex-M構架微控制器的模擬器,並可完全模擬其模型(包括CPU和外設)。這就意味著可以在debug模式下模擬運行。

 

二.綜述

 

學習本資料,分三個步驟:

  1. 首先建立一個基於Cortex-M構架微控制器的RTOS工程,並運行起來;
  2. 進一步深入RTOS每個細節,體驗RTOS對應用程式的貢獻和閃光點;
  3. 對RTOS有個整體認識後,深入探討如何配置RTOS選項;
對於沒有接觸過RTOS的新手來說,以下兩點需要剋服:

 

  1. 進程(或者叫任務),重點在理解進程的運行原理;
  2. 進程見通訊,重點是理解進程間的同步通訊;

2.1.進入RTOS的第一步

 

  1. RTOS的核心是調度器(支持輪換、搶占和協同多任務),時間和記憶體管理服務。進程間通訊由額外模塊如信號、信號量、互斥量、消息隊列、消息郵箱等支持完成。而,中斷則通過特權進程由內核調度。

2.2導入CMSIS-RTOS Api

 

  1. 添加頭文件 <cmsis_os.h>即可調用CMSIS_RTOS Api,如下:

    #include <cmsis_os.h>

    該頭文件作為CMSIS-RTOS標準文件。對於符合CMSIS-RTOS標準的Keil 內置RTX是預設的Api。其他RTOS應該會包含其特有Api,但只要支持CMSIS_RTOS,即可通過此方式引入。

2.3進程

 

  1. 標準C語言的最小程式塊是函數(函數被其他代碼並完成某些特定的運算)。在CMSIS-RTOS中,基本代碼單元是進程。進程與函數類似,但也有一些不同。

    函數示例: 進程示例:

    Unsigned int fun(void) void thread(void)

    { {

    .... ......

    Return(ch); while(1){........}

    } }

    最大的區別是,函數總歸要返回到被調用處,而進程則是無限迴圈,不會主動結束。

    RTOS程式有一定數量的進程組成,在調度器控制下運行。調度器使用Systick中斷生成時間片,並以時間片為單位分配各個進程的運行時間。如,進程1運行5ms,而後調度器將CPU分配給進程2一個相似的時間段,然後將cpu分別給進程3,......。巨集觀來看,好像各個進程同步運行。

    在概念層面,程式包含數個同步運行的進程,而每個進程則是完成特定功能的獨立代碼段。進程代碼的獨立性,使設計代碼、測試可限制在進程內進行,進而組合各個進程完成程式設計,這就使進程利於面向對象程式設計。同樣道理,進程可將調試局限在進程內,也更利於調試。後續可發現,進程對提高代碼復用性同樣有利。

    進程在創建時,系統自動分配進程ID,用作進程的標識,如下:

    osThreadId    id1,id2,id3

    完成進程切換,需要制定硬體定時器作為RTOS時間片參考,並消耗一定的代碼開銷。當進程切換時,系統需要保存正在運行的進程信息,同時載入將要運行的進程的信息,統稱為"任務切換時間",它是評估RTOS的重要指標。進程信息保存在進程式控制制塊中。

2.4創建進程

 

  1. 一個創建進程的示例:

    Void thread1(void const *parm);

    osThreadDef(thread1,osPriorityNormal, 1, 0);

    優先順序 實例數 stacksize(0預設size)

    osThreadId thread1_id = osThreadCreate(osThread(thread1),NULL);

    Void thread1(void const *parm)

    {

    //init code

    While(1) //thread body

    {

    ......

    }

    }

2.5進程優先順序和進程管理

 

  1. 一經創建,系統分配進程ID,進程ID是管理進程的標識。

    進程有優先順序特性,如圖:

    管理進程包括設置優先順序,讀取優先順序,進程消亡等,Api如下:

    osStatus osThreadSetPriority(threadID,priority);

    osPriority osThreadGetPriority(threadID);

    osStatus osThreadTerminate(threadID);

2.6多實例進程

 

  1. 進程支持多實例,如Ex4 Multiple Instance,代碼摘錄:

    void Led_Switch(void const *argument)

    {

    LED_ON((uint32_t)argument);

    Delay(500);

    LED_OFF((uint32_t)argument);

    Delay(500);

    }

    osThreadDef(osThread(Led_Swtich),osPriorityNormal,2,0);

    osThreadId id1 = osThreadCreate(osThread(Led_Swtich),(void *)1);

    osThreadId id2 = osThreadCreate(osThread(Led_Swtich),(void *)2);

2.7開始RTOS

 

預設,RTOS自main函數起接管系統調度,所以main函數是第一個運行中進程。一旦進入main函數,首先調用osKernelInitialize()停用調度,以爭取時間完成硬體初始化(如GPIO配置,USART配置等)和創建需要的進程或其他RTOS組件,而後調用osKernelStart()將系統控制權交還給RTOS,如下代碼示例:

Void main(void)

{

osKernelInitialize();

//user code

Init_thread();

osKernelStart();

}

上例中,main進程在完成進程創建後運行到"}"時消亡,這在RTOS中是不推薦的。Main函數也可作為一個進程,並通過ID管理,如下:

osThreadId main_id;

Void main(void)

{

osKernelInitialize();

//user code

main_id = osThreadGetId(); //返回當前進程ID

Init_thread();

osKernelStart();

While(1) //thread body

{

}

}

三.時間管理

RTOS提供基本的時間管理組件。

3.1延時函數

事件組件中最基本的服務就是延時函數,在應用程式中可直接調用延時函數,非常方便。

插曲:儘管RTOS內核約5K左右,相比於非RTOS系統中延時迴圈的無用代碼消耗,RTOS還是優勢明顯,這就是RTOS出現的原因。

函數原型:void osDelay(uint32_t millisec)

調用延時函數的進程會進入WAIT_DELAY狀態並持續延時函數制定的時間(millisec),調度器轉向其他READY狀態進程。延時結束,進程進入READY狀態,等待調度器調度。

3.2等待事件

除了等待制定的時間,osWait也可中斷進程並使進程進入等待狀態直至被重新觸發(觸發時間可以是信號、信號量、消息等),並且osWait同樣支持指定延時的周期。

函數原型:osStatus osWait(uint32_t millisec)

註意:keil RTX不支持此節內容。

3.3虛擬定時器

CMSIS-RTOS支持虛擬定時器,虛擬定時器向下計數,溢出時運行用戶定義的call-back函數。虛擬定時器可以定位為單次和迴圈模式,步驟如下:

  1. 定義回調函數(call-back);
  2. 定義定時器結構體;
  3. 創建定時器;
  4. 啟動定時器;

如Ex 6 Virtual Timers代碼摘錄:

void callback(void const *pram)

{

Switch((uint32_t) pram)

{

case 0:

GPIOB->ODR ^= 0x8;

Break;

case 1:

GPIOB->ODR ^= 0x4;

Break;

case 2:

GPIOB->ODR ^= 0x2;

Break;

case 3:

Break;

}

}

osTimerDef(osTimer(Timer0_handle),callback);

osTimerDef(osTimer(Timer1_handle),callback);

osTimerDef(osTimer(Timer2_handle),callback);

osTimerDef(osTimer(Timer3_handle),callback);

osTimerId timer0 = osTimerCreate(osTimer(Timer0_hanlder),osTimerPeriodic,(void *)0);

osTimerId timer1 = osTimerCreate(osTimer(Timer1_hanlder),osTimerPeriodic,(void *)1);

osTimerId timer2 = osTimerCreate(osTimer(Timer2_hanlder),osTimerPeriodic,(void *)2);

osTimerId timer3 = osTimerCreate(osTimer(Timer3_hanlder),osTimerPeriodic,(void *)3);

osTimerStart(timer0_handle,0x100);

osTimerStart(timer1_handle,0x100);

osTimerStart(timer2_handle,0x100);

osTimerStart(timer3_handle,0x100);

3.4微秒延時

借用系統中的Systick原始計數值可實現微妙延時。微妙延時不觸發調度,它僅僅暫停執行指定時間段,遵循如下步驟:

  1. 獲取Systick原始計數值;
  2. 定義延時時間段;
  3. 等待延時結束;

示例代碼如下:

Uint32_t tick,delayPeriod;

tick = osKernelSysTick(); //1

delayPeriod = osKernelTickMicroSec(100); //2

do{

....

}while((osKernelSysTick()-tick) < delayPeriod); //3

3.5空閑進程

空閑進程在系統沒有可用進程時被調用,以防止系統沒有進程可用。

空閑進程定義在RTX_Conf_CM.c中,並允許用戶自定義代碼。通常情況下,空閑進程中配置CPU進入低功耗狀態。如此一來,當Systick中斷或其他中斷時喚醒調度,如有可運行進程則運行進程,否則繼續進入低功耗狀態。

示例代碼:Ex 7 Idle

四.信號

 

4.1功能描述

 

CMSIS-RTOS keil RTX的進程支持多達16個信號,信號保存在進程式控制制塊中。當進程中存在等待信號時(不管是單個等待信號還是多個等待信號),進程暫停執行直至其他進程發出了被等待的信號。

調用信號等待函數,將觸發當前進程中止運行併進入等待狀態。處於等待狀態的進程滿足以下兩個條件時退出等待,進入可被調度狀態:

  1. 等待的信號被置位;
  2. 等待的時間溢出;

信號等待函數原型:osEvent osSignalWait(uint32_t signals,uint32_t millisec)

等待時間設置為0fffff,表示始終不溢出;

等待時間設置為0時,表示任一信號置位即可引起中止等待;

其他進程可置位或清除等待信號:

Uint32_t osSignalSet(osThreadId thread_id,uint32_t signals)

Uint32_t osSignalClear(osThreadId thread_id,uint32_t signals)

另,調用osEvent.value.signals,返回值指示當前被置位信號。

4.2常式

 

"Ex8 Signals"

4.3中斷進程

 

CMSIS-RTOS使用Systick中斷作為系統時鐘。因Systick中斷的服務等級設定為最低級,當中斷服務程式(ISR)的運行時間超出一個Systick中斷時,系統中斷將受到影響。

於是,在CMSIS-RTOS中,正確的處理方式是將中斷服務定義為一個進程,進程中等待信號。而在中斷服務中,僅僅給中斷進程發送信號。從而極大縮短中斷服務程式的長度,轉而線上程中執行。

示例代碼:

osThreadDef(osThread(isr_thread),osPriorityNormal,1,0);

osThreadId Isr_thread_id = osThreadCreate(osThread(isr_thread),NULL);

中斷線程:void isr_thread(void const *pram)

{

....

While(1)

{

osSignalWait(isrSignal,waitForever);

.....

}

}

中斷服務程式:void IRQ_Handler(void)

{

osSignalSet(Isr_thread_id,isrSignal);

}

4.4內核許可權調用SVC

 

CMSIS-RTOS運行在unprivilege模式下,當需要在進程中訪問privilege資源時,有兩種方式:

  1. 在配置文件中提升進程的許可權至privilege狀態(如下圖所示),但會造成所有的進程運行在privilege模式下,影響系統安全。

參考常式"Ex9 interrupt signal"

  1. 在需要privilege許可權時運行"系統級"代碼。

4.4.1SVC

 

遵循如下步驟:

  1. 新建"系統級"代碼列表(.s彙編文件),如下圖:

    SVC_Tables.s代碼如下:
        

    AREA SVC_TABLE, CODE, READONLY

    EXPORT SVC_Count

    SVC_Cnt EQU (SVC_End-SVC_Table)/4

    SVC_Count DCD SVC_Cnt

    ; Import user SVC functions here.

    IMPORT __SVC_1 //第一個"系統級"代碼

    EXPORT SVC_Table

    SVC_Table

    ; Insert user SVC functions here. SVC 0 used by RTL Kernel.

    DCD __SVC_1 ; user SVC function

    SVC_End

    END

    其中__SVC_1就是"系統級"用戶代碼函數。

  2. 建立"系統級"代碼與"進程級"代碼介面,示例:

    void __svc(1) init_ADC (void);

    __svc(1)代表SVC_Tables.s中第一個"系統級"代碼,同樣如果有多個應用,依次遞增即可。

  3. 編寫"系統級"代碼,如下圖:

    Void __SVC_1 (void)

    {

    ......

    }

    在完成定義後,進程中調用init_ADC()將自動執行__SVC_1()中的代碼。

五.信號量

 

5.1功能描述

與信號類似,信號量是兩個或多個進程同步的方法。

信號量項是一個包含多個信號的容器。當進程執行到需要信號量的代碼段(進程申請信號量),如果信號量中有信號可用(包含不少於一個的信號),則進程繼續執行,並且信號量中的信號數自減一。相反,如信號量中無信號可用(包含0個信號),則進程中止執行並等待信號量中的信號可用。

同時,進程中可向信號量添加信號數目,從而引起信號量中的可用信號數增一。

如上圖。假定信號量初始化為只有一個可用信號,當任務1提出申請時,信號量中含有1個可用信號,則任務1繼續執行並引起信號量中的可用信號為0。此時任務2若提出申請因信號量中無可用信號,任務2進入信號量等待狀態,直至任務1釋放信號量。

可見,進程可以釋放信號給信號量。

5.2創建信號量

示例代碼:

osSemaphoreId sem1;

osSemaphoreDef(sem1);

sem1 = osSemaphoreCreate(osSemaphore(sem1),SIX_TOKENS);

定義了一個含有6個可用信號的信號量sem1。

信號量初始化後,進程中即可申請信號量,使用函數:

osSemaphoreWait(osSemaphoreId sem_id,uint_32 millisec)

Millisec = 0xffff wait for ever

信號量使用結束後,釋放信號量,使用函數:

osSemaphoreRelease(osSemaphoreId sem_id);

5.3常式

Ex11 Interrupt Signals

5.4使用場景

5.4.1信號

兩個線程間同步執行是信號量最基本的應用。示例代碼:

osSemaphoreId sem_id;

osSemaphoreDef(sem_id);

void task1(void)

{

Sem_id = osSemaphoreCreate(osSemaphore(sem1),0);

While(1)

{

Fun(A);

osSemaphoreRelease(sem1);

}

}

Void task2(void)

{

While(1)

{

osSemaphoreWait(sem1,osWaitForever);

Fun(B);

}

}

在這個案例中,Fun(A)始終先於Fun(B)執行。

5.4.2限額

限額用於限制某些資源的配額。例如,某個指定的記憶體塊只運行指定數目的應用訪問。

如下常式,信號量初始化為5個信號,每個申請信號量的線程造成信號自減,當獲取信號量的進程為5個時,後續申請信號量的進程進入等待狀態,直至已獲取配額的進程釋放信號量,代碼常式:

osThreadId sem_id;

osThreadDef(sem1);

Void task1(void)

{

Sem_id = osThreadCreate(osThread(sem1),5);

While(1)

{

osSemaphoreWait(sem1,osWaitForever);

ProcessBuffer();

osSemaphoreRelease(sem1);

}

}

Void task2(void)

{

While(1)

{

osSemaphoreWait(sem1,osWaitForever);

ProcessBuffer();

osSemaphoreRelease(sem1);

}

}

......

常式"Ex12 Multiplex"。

5.4.3互鎖(2個線程同步)

互鎖是兩個線程同步的另一種通用模式。互鎖確保兩個線程得到同一互鎖點。如下常式:

osSemaphoreId arrival1,arrival2;

osSemaphoreDef(sem1);

osSemaphoreDef(sem2);

Void task1(void)

{

arrival1 = osSemaphore(osSemephore(sem1),0);

arrival2= osSemaphore(osSemephore(sem2),0);

While(1)

{

FunA1();

osSemaphoreRelease(arrival2);

osSemaphoreWait(arrival1);

FunA2();

}

}

Void task2(void)

{

While(1)

{

FunB1();

osSemaphoreRelease(arrival1);

osSemaphoreWait(arrival2);

FunB2();

}

}

此常式中,確保FunA2()、FunB2()同步執行。

5.4.4屏障(多個線程同步)

屏障是多個進程同步的有效模式,它的總體思路:設置一個初始化為0的信號量作為屏障,併在所有進程達到同步點時依次釋放屏障中的信號量,達到同步執行的目的。

常式"Ex14 Barrier"

5.5註意事項

信號量是RTOS中極端有效的模式。然而,因信號量可在進程中增減甚至銷毀,信號量中可用配額數比較難把控,使用時必須實時把控可用配額數。

六.互斥量

6.1功能描述

單從功能來講,互斥量可以看做只含有一個可用配額且不可被創建和銷毀的特殊信號量。互斥量主要用於防止對硬體的訪問衝突,比如同一時刻只能有一個應用訪問串口,否則將造成數據混亂。

申請互斥量的進程,必須等待互斥量中存在有效配額,否則進入等待狀態。

6.2創建互斥量

創建互斥量與創建信號量類似,示例代碼如下:

osMutexId    uart_mutex;

osMutexDef(Mutex1);

進程中創建互斥量:uart_mutex = osMutexCreate(osMutex(Mutex1));

其他進程申請互斥量:osMutexWait(uart_mutex);

使用完畢釋放互斥量:osMutexRelease(uart_mutex);

6.3常式

常式"Ex15 Mutex"

6.4註意事項

互斥量的使用限制多,也更安全,但扔要註意以下內容:

  1. 使用完畢必須及時釋放互斥量,否則將造成後續進程無法使用該資源;
  2. 調用ThreadTerminate()函數消亡進程時,必須確保該進程沒有占用互斥量,否則將造成後續進程無法使用該資源;

七.數據交換

信號、信號量、互斥量只用於進程之間的觸發,但對進程間的數據交換無能為力。進程間數據交換最簡單的方式是全局變數,但即使在簡單的系統中,把握和靈活應用全局變數也是不小的挑戰,因為全局變數會引起一系列不可預知錯誤。

在RTOS中,消息隊列郵箱隊列是進程間數據交互最為有效、安全的方式。

消息隊列和郵箱隊列的工作方式基本一樣,唯一的區別是消息隊列中傳輸的是待交換數據,而郵箱隊列中傳輸是指向待交換數據的指針,如下圖所示:

使用消息隊列和郵箱隊列進行數據交換有如下好處:

  1. 規範進程間數據交換的介面和緩存,為設計子系統提供可能;
  2. 規範進程的輸入、輸出,使進程獨立測試、調試成為可能;

7.1消息隊列

7.1.1創建消息隊列

創建消息隊列,遵循如下步驟:

  1. 聲明消息隊列ID,示例:osMessageQId Q_id;
  2. 定義消息隊列結構體,示例:osMessageQDef(Q1,16_Message_Slots,unsigned int);其中16_Message_Slots指示空間大小為16,unsigned int指示空間類型;
  3. 在進程中創建消息隊列,示例:Q_id = osMessageQCreate(osMessageQ(Q1),NULL);
  4. 聲明解析消息隊列數據的osEvent類型數據,示例:osEvent result;
  5. 在進程中發送數據到消息隊列,常式:osMessagePut(Q_id,Data,osWaitForever);
  6. 在另一進程中獲取消息隊列數據,常式:result = osMessageGet(Q_id,osWaitForever);result.value.xxx;

其中,osEvent是個union結構體,如下所示:

Union{

Uint32_t v;

Void *p;

Uint32_t signals;

}value

7.1.2常式

"Ex16 Message queue"

7.2記憶體鏈

7.2.1功能描述

消息隊列中的數據類型可以是數據本身,也可以是指向數據的指針。

消息隊列中存儲的數據是指向特定記憶體區域的指針,這樣的進程間交換數據的方式成為記憶體鏈。

結構體可以達到規範化特定記憶體區域的目的。

7.2.2創建記憶體鏈

創建記憶體鏈,遵循如下步驟:

  1.定義結構體,用於規範記憶體塊及初始化指針,示例:

Typedef    struct {

Uint8_t led1;

Uint8_t led2;

Uint8_t led3;

Uint8_t led4;

}memory_block_t;

  2.初始化記憶體鏈,示例:

osPoolId pool_id;

osPoolDef(pool_t,ten_blocks,memory_block_t);

在進程中創建pool_id = osPoolCreate(osPool(pool_t));

  3.初始化消息隊列,示例:

osMessageQDef(q1,ten_blocks,memory_block_t);

osMessageQid q_id;

在進程中創建:q_id = osMessageQCreate(osMessageQ(q1),NULL);

  4.發送消息隊列,示例:

memory_block_t *led = (memory_block_t *)osPoolAlloc(pool_id);

led->led1 = xx;....

osMessagePut(q_id,led,osWaitForever);

  5.讀取消息隊列,示例:

osEvent evt;

evt = osMessageGet(q_id,osWaitForever);

memory_block_t *temp = (memory_block_t *)evt.value.p;

  6.使用完畢釋放記憶體鏈:示例:

osPoolFree(pool_id,temp);

7.2.3常式

"Ex16 MemoryPool"

7.3郵箱隊列

 

7.3.1功能描述

 

郵箱隊列是將記憶體鏈融合到消息隊列中而成,郵箱隊列中存儲的同樣是指向特定記憶體區域的指針。

7.3.2創建郵箱隊列

 

同樣採用7.2.2中的結構體作為數據基礎,Typedef    struct {

Uint8_t led1;

Uint8_t led2;

Uint8_t led3;

Uint8_t led4;

}memory_block_t;

創建郵箱隊列遵循如下步驟:

1.創建郵箱隊列,常式:

 

osMailQDef(MQ_1,ten_blocks,memory_block_t);

osMailQId mq_id;

進程中創建,mq_id = osMailQCreate(osMailQ(MQ_1),NULL);

2.發送數據,常式:

 

Memory_block_t *led = (memory_block_t *)osMailAlloc(mq_id);

led->led1 = xx;....

osMailQPut(mq_id,led);

3.讀取數據,常式:

 

osEvent evt;

evt = osMailGet(mq_id,osWaitForever);

Memory_block_t *temp = (memory_block_t *)evt.value.p;

4.使用完畢釋放郵箱隊列,示例:

 

osMailFree(mq_id,temp);

7.3.3常式

 

"Ex17 MailQueue"

八.系統配置

 

掌握前面的內容,對CMSIS-RTOS有了總體的認識。CMSIS-RTOS包括進程管理、時間管理、進程間通訊等。

本章著力於討論如何配置系統。CMSIS-RTOS針對基於Cortex-M構架的處理器,提供一個統一的配置文件,RTX_Conf_CM.c,如下圖:

8.1進程參數

 

在討論進程的相關章節中一經接受了創建進程的基礎知識。

每個進程,系統分配一塊記憶體空間用作進程棧(預設200bytes),棧空間在進程創建時指定。

應用中最多允許運行的進程數可配置。

由於進程棧空間、進程數可配置,應用中的記憶體需求也可很容易的計算出來。

8.2內核調試支持

內核可配置項,包括:

8.2.1追蹤溢出

選擇該項"stack overflow checking",出現進程棧溢出RTOS內核調用os_error函數併進入死迴圈。該項主要用於調試階段的問題追蹤,當然也可自定義os_error函數用於最終的應用中列印錯誤信息,os_error代碼在RTX_CONF_CM.C文件中,源碼:

/* OS Error Codes */

#define OS_ERROR_STACK_OVF 1

#define OS_ERROR_FIFO_OVF 2

#define OS_ERROR_MBX_OVF 3

#define OS_ERROR_TIMER_OVF 4

extern osThreadId svcThreadGetId (void);

/// \brief Called when a runtime error is detected

/// \param[in] error_code actual error code that has been detected

void os_error (uint32_t error_code) {

/* HERE: include optional code to be executed on runtime error. */

switch (error_code) {

case OS_ERROR_STACK_OVF:

/* Stack overflow detected for the currently running task. */

/* Thread can be identified by calling svcThreadGetId(). */

break;

case OS_ERROR_FIFO_OVF:

/* ISR FIFO Queue buffer overflow detected. */

break;

case OS_ERROR_MBX_OVF:

/* Mailbox overflow detected. */

break;

case OS_ERROR_TIMER_OVF:

/* User Timer Callback Queue overflow detected. */

break;

default:

break;

}

for (;;);

}

8.2.2監控棧使用率

選擇"stack usage watermark"項,oxcc樣式自動寫入進程棧。運行時,watermark用於計算最大棧記憶體使用率,併在"system and Event viewer"視窗報告,如下圖所示:

8.2.3用戶定時器數

如用戶定時器數量與應用中使用的虛擬定時器不符,會造成os_timer()函數失效。

8.2.4進程運行許可權選擇

如"Ex9 interruter signal",進程運行許可權可配置。

8.3系統時基

預設的系統時基是Cortex-M中的SysTick定時器。但,也支持自定義使用其他定時器作為系統時基。

8.4時間片

預設的時間片是5ms。

8.5調度選項

調度器支持如下三種調度模式:

1.搶占式

此模式下,系統中進程擁有不同的優先順序,當擁有高優先順序的進程進入"ready"狀態,調度器轉入高優先順序進程運行。

2.輪詢式

此模式下,系統根據時間片為每個進程分配運行時間,處於運行態的進程在時間片到來時觸發調度(註意,即使高優先順序的進程進入"ready"狀態也要等時間片結束)。

3.輪詢、搶占式(預設狀態)

此模式下,系統根據時間片為每個進程分配運行時間,處於運行態的進程在時間片到來時或高優先順序的進程進入"ready"態觸發調度(註意,高優先順序的進程進入"ready"狀態將馬上觸發調度)。

4.協同式

此模式下,進程擁有相同的優先順序,有且僅有運行態的進程主動申請系統調度才會引起調度。

8.6源碼調試

如果用戶需要源碼級別的調試,遵循如下步驟:

  1. 新建文本文件,命名為"xxx.ini";
  2. "xxx.ini"中添加,SET SRC = <PATH>,其中<PATH>是RTX源碼的文件夾,預設是C:\Keil\ARM\pack\arm\cmsis\<version>\cmsis\rots\rtx。
  3. 在調試文件中導入"xxx.ini",如下圖所示:

註:"xxx.ini"中xxx代表任意長度滿足PC操作系統命名規格的字元串。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前提 安裝linux系統中遇到一個問題,設置ip以後則ping不通,簡單總結幾步: 1、設置ip 進入 /etc/sysconfig/network-scripts目錄下,修改文件名為ifcfg-eno16777736(或eth0文件) 2、關閉防火牆,臨時關閉service iptables st ...
  • 一、解析Linux應用軟體安裝包通常Linux應用軟體的安裝包有三種:1) tar包,如software-1.2.3-1.tar.gz。它是使用UNIX系統的打包工具tar打包的。2) rpm包,如software-1.2.3-1.i386.rpm。它是RedHat Linux提供的一種包封裝格式。 ...
  • 1. yum install squid2. vi /etc/squid/squid.conf 將http_access deny all 中deny 改為allow,http_port後面的是埠號,預設為3128。可改可不改。3. service squid restart4. 如果有防火牆, ...
  • 1.1.1 chrony簡介 Chrony是一個開源的自由軟體,它能保持系統時鐘與時鐘伺服器(NTP)同步,讓時間保持精確。 它由兩個程式組成:chronyd和chronyc。 chronyd是一個後臺運行的守護進程,用於調整內核中運行的系統時鐘和時鐘伺服器同步。它確定電腦增減時間的比率,並對此進 ...
  • 1、安裝Office2007以上版本。(如安裝的是Office2007需安裝SaveAsPDFandXPS.exe組件) 2、確認網站在IIS內使用的登錄用戶。(如圖所示用戶為IUSR,下麵操作以此用戶為例) 3、打開運行視窗,執行comexp.msc -32 ,打開32位的組件服務。 4、分別設置 ...
  • arch/x86/boot/header.S --> _start --> calll main arch/x86/boot/main.c --> main -- > go_to_protected_mode arch/x86/boot/pm.c --> go_to_protected_mode - ...
  • [20171115]ZEROCONF ROUTE.txt--//如果你檢查linux伺服器的網路配置,就可以發現如下一條路由:# route -n | egrep "169.254|Destination"Destination Gateway Genmask Flags Metric Ref Us ...
  • 總項目流程圖,詳見http://www.cnblogs.com/along21/p/7435612.html 實驗一:實現反向代理負載均衡且動靜分離 1、環境準備: 機器名稱 IP配置 服務角色 備註 nginx VIP:172.17.11.11 反向代理伺服器 開啟代理功能 設置監控,調度 rs0 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...