⑤這兩個函數(shù)都用于任務(wù)切換,它們的本質(zhì)都是觸發(fā)PendSV中斷,具體切換過程在PendSV的中斷函數(shù)中進行,其中OSCtxSw是任務(wù)級切換,OSIntCtxSw是中斷級切換,是從中斷退出時切換到一個任務(wù)中,從中斷切換到任務(wù)的過程中,CPU的寄存器入棧工作已經(jīng)完成。
OSCtxSw
PUSH {R4, R5}
LDR R4, =NVIC_INT_CTRL ;觸發(fā)PendSV異常
LDR R5, =NVIC_PENDSVSET
STR R5, [R4] ;向NVIC_INT_CTRL寫入NVIC_PENDSVSET觸發(fā)PendSV中斷
POP {R4, R5}
BX LR
OSIntCtxSw
PUSH {R4, R5}
LDR R4, =NVIC_INT_CTRL ;觸發(fā)PendSV異常
LDR R5, =NVIC_PENDSVSET
STR R5, [R4] ;向NVIC_INT_CTRL寫入NVIC_PENDSVSET觸發(fā)PendSV中斷
POP {R4, R5}
BX LR
NOP
⑥這部分代碼才是真正的任務(wù)切換函數(shù),通過觸發(fā)PendSV中斷來進入該函數(shù)內(nèi)進行任務(wù)切換
PendSV_Handler
CPSID I ;任務(wù)切換過程中必須關(guān)閉所有中斷
MRS R0, PSP ;如果在用PSP堆棧,則可以忽略保存寄存器
CBZ R0, PendSV_Handler_Nosave ;如果PSP為0就轉(zhuǎn)移到PendSV_Handler_Nosave
SUBS R0, R0, #0x20 ;R0-=20H
STM R0, {R4-R11}
LDR R1, =OSTCBCur
LDR R1, [R1]
STR R0, [R1]
PendSV_Handler_Nosave
PUSH {R14} ;保存R14的值
LDR R0, =OSTaskSwHook ;調(diào)用OSTaskSwHook()
BLX R0
POP {R14}
LDR R0, =OSPrioCur
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
LDR R0, =OSTCBCur
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0]
LDR R0, [R2] ;R0作為新任務(wù)的SP
LDM R0, {R4-R11} ;從堆棧中恢復(fù)R4-R11
ADDS R0, R0, #0x20
MSR PSP, R0 ;用新任務(wù)的SP加載PSP
ORR LR, LR, #0x04 ;確保LR的bit2為1,返回后使用進程堆棧
CPSIE I ;開啟所有中斷
BX LR ;中斷返回
end
(2)os_cpu.h文件詳解
①這部分主要用于定義一些數(shù)據(jù)類型,其中重點關(guān)注OS_STK這個數(shù)據(jù)類型,我們在定義任務(wù)堆棧的時候就是該類型數(shù)據(jù),這是一個32位的數(shù)據(jù)類型,按字節(jié)算的話實際堆棧大小是我們定義的4倍。
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U;
typedef signed char INT8S;
typedef unsigned short INT16U;
typedef signed short INT16S;
typedef unsigned int INT32U;
typedef signed int INT32S;
typedef float FP32;
typedef double FP64;
typedef unsigned int OS_STK;
typedef unsigned int OS_CPU_SR;
②這部分代碼定義了堆棧的增長方向,任務(wù)機切換的宏定義OS_TASK_SW,如果OS_CRITICAL_METHOD被定義為3的話那么進出臨界段的宏定義分別為OS_ENTER_CRITICAL和OS_EXIT_CRITICAL,這兩個函數(shù)都是用匯編語言編寫的
//OS_CRITICAL_METHOD = 1 :直接使用處理器的開關(guān)中斷指令來實現(xiàn)宏
//OS_CRITICAL_METHOD = 2 :利用堆棧保存和恢復(fù)CPU的狀態(tài)
//OS_CRITICAL_METHOD = 3 :利用編譯器擴展功能獲得程序狀態(tài)字,保存在局部變量cpu_sr
#define OS_CRITICAL_METHOD 3 //進入臨界段的方法
#if OS_CRITICAL_METHOD == 3
#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}
#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}
#endif
void OSCtxSw(void);
void OSIntCtxSw(void);
void OSStartHighRdy(void);
void OSPendSV(void);
#if OS_CRITICAL_METHOD == 3u
OS_CPU_SR OS_CPU_SR_Save(void);
void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
#endif
OS_CPU_EXT INT32U OSInterrputSum;
(3)sys.h文件修改
添加關(guān)于條件編譯的定義,在文件中添加以下代碼即可。
#define SYSTEM_SUPPORT_OS 1
當(dāng)宏定義為1的時候,編譯器在編譯的時候會只編譯滿足條件的代碼,當(dāng)為0時,這部分代碼不會被編譯。
(4)delay.c文件修改
①添加Sys_Tick中斷服務(wù)函數(shù)與函數(shù)定義
#include "includes.h"
//支持UCOSII
#ifdef OS_CRITICAL_METHOD
#define delay_osrunning OSRunning //OS是否運行標(biāo)記,0,不運行;1,在運行
#define delay_ostickspersec OS_TICKS_PER_SEC //OS時鐘節(jié)拍,即每秒調(diào)度次數(shù)
#define delay_osintnesting OSIntNesting //中斷嵌套級別,即中斷嵌套次數(shù)
#endif
//systick中斷服務(wù)函數(shù),使用OS時用到
void SysTick_Handler()
{
//OS開始跑了,才執(zhí)行正常的調(diào)度處理
if( delay_osrunning==1 )
{
OSIntEnter() ; //進入中斷
OSTimeTick() ; //調(diào)用ucos的時鐘服務(wù)程序
OSIntExit() ; //觸發(fā)任務(wù)切換軟中斷
}
}
②時鐘初始化函數(shù)修改
void SysTick_Init( u8 SYSCLK )
{
#if SYSTEM_SUPPORT_OS
u32 reload;
#endif
SysTick->CTRL &= ~( 1<<2 ) ; //SYSTICK使用外部時鐘源
fac_us = SYSCLK/8 ; //fac_us都需要使用
#if SYSTEM_SUPPORT_OS
reload = SYSCLK/8 ; //每秒鐘的計數(shù)次數(shù),單位為K
reload *= 1000000/delay_ostickspersec ; //根據(jù)delay_ostickspersec設(shè)定溢出時間
fac_ms = 1000/delay_ostickspersec ; //代表OS可以延時的最少單位
SysTick->CTRL |= 1<<1 ; //開啟SYSTICK中斷
SysTick->LOAD = reload ; //每1/delay_ostickspersec秒中斷一次
SysTick->CTRL |= 1<<0 ; //開啟SYSTICK
#else
fac_ms = ( u16 )fac_us*1000 ; //代表每個ms需要的systick時鐘數(shù)
#endif
}
-
單片機
+關(guān)注
關(guān)注
6032文章
44521瀏覽量
633129 -
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
6742瀏覽量
123194 -
uCOS-Ⅱ
+關(guān)注
關(guān)注
0文章
9瀏覽量
8585
發(fā)布評論請先 登錄
相關(guān)推薦
評論