UCOSIII(1)——SVC與PenSV實現任務切換
本文基於STM32F407ZGT6
——————————————
SVC異常:
SVC(系統服務呼叫,亦簡稱系統呼叫)用於產生系統函式的呼叫請求。
SVC 異常是必須立即得到響應的應用程式執行 SVC 時都是希望所需的請求立即得到響應。
在 UCOS 中並未使用 SVC 這個功能,瞭解一下即可。
在 UCOS 中並未使用 SVC 這個功能,瞭解一下即可。
在 UCOS 中並未使用 SVC 這個功能,瞭解一下即可。
PendSv異常:
- 由於SVC異常是必須立即得到響應的(若因優先順序不比當前正處理的高,或是其它原因使之無法立即響應,將上訪成硬 fault),應用程式執行SVC 時都是希望所需的請求立即得到響應。
- PendSV 則不同,它是可以像普通的中斷一樣被懸起的(不像 SVC 那樣會上訪)。OS
可以利用它“緩期執行”一個異常——直到其它重要的任務完成後才執行動作。
1、懸 起 PendSV 的方法是:手工往 NVIC 的 PendSV 懸起暫存器中寫 1。懸起後,如果優先順序不夠高,則將緩期等待執行。
2、PendSV 的典型使用場合是在上下文切換時(在不同任務之間切換)。異常會自動延遲上下文切換的請求,直到其它的 ISR 都完成了處理後才放行。為實現這個機制,需要把 PendSV 程式設計為最低優先順序的異常。如果 OS 檢測到某 IRQ 正在活動並且被 SysTick 搶佔,它將懸起一個 PendSV異常,以便緩期執行上下文切換。
可以看到uCOS作業系統裡(其實實時作業系統都一樣)各類異常/中斷的優先順序關係:
SYSTICK異常>中斷>PendSv異常
PendSV 異常會自動延遲上下文切換的請求,直到其它的 ISR 都完成了處理後才放行。這樣保證了中斷的快速響應性又保證了作業系統的正常輪轉。
一、將PendSV 異常設定為最低優先順序(這兩段程式碼在os_cpu_a.asm中定義)。
NVIC_INT_CTRL EQU 0xE000ED04 ; 中斷控制暫存器 ; Interrupt control state register.
NVIC_SYSPRI14 EQU 0xE000ED22 ; 系統優先順序暫存器(2) ; System priority register (priority 14).
NVIC_PENDSV_PRI EQU 0xFFFF ; PendSV 中斷優先順序為最低 ; PendSV priority value (lowest).
NVIC_PENDSVSET EQU 0x10000000 ; 觸發軟體中斷的值 ; Value to trigger PendSV exception.
NVIC_PENDSV_PRI EQU 0xFFFF ;這個語句把PendSV 中斷優先順序為了最低0xFFFF 。
OSStartHighRdy彙編函式:
OSStartHighRdy
LDR R0, =NVIC_SYSPRI14 ; 設定 PendSV 的優先順序為最低 ; Set the PendSV exception priority
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0]
MOVS R0, #0 ; Set the PSP to 0 for initial context switch call
MSR PSP, R0
LDR R0, =OS_CPU_ExceptStkBase ; Initialize the MSP to the OS_CPU_ExceptStkBase
LDR R1, [R0]
MSR MSP, R1
LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET
STR R1, [R0] ;觸發PenSv中斷
CPSIE I ;開中斷 ; Enable interrupts at processor level
OSStartHang
B OSStartHang ;死迴圈,應該不會到這裡的 ; Should never get here
- LDR R1, =NVIC_PENDSV_PRI;這個語句把PendSV 中斷優先順序設定位0xFFFF,也就是最低。
- LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
;這兩個語句實現了觸發PendSv異常,也就是說進入OSStartHighRdy函式會觸發PendSv異常,然後會進入PendSv異常服務函式進行任務切換。
OSStartHighRdy 是由 OSStart()呼叫,OSStart()用來開啟多工的,如果多工開啟正常則進入OSStartHighRdy 函式觸發PendSv異常並馬上進行任務切換;如果多工開啟失敗的話就會進 入 OSStartHang函式(這裡沒有貼出來)。
二、OSStart()函式:
OSStart()函式在我們的main函式裡建立第一個任務的時候發生呼叫。(好像也只是呼叫一次,用於啟動系統)
void OSStart (OS_ERR *p_err)
{
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
if (OSRunning == OS_STATE_OS_STOPPED) {
OSPrioHighRdy = OS_PrioGetHighest(); //找出目前最高優先順序的函式 /* Find the highest priority */
OSPrioCur = OSPrioHighRdy;
OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
OSTCBCurPtr = OSTCBHighRdyPtr;
OSRunning = OS_STATE_OS_RUNNING; /*OSRunning變為1所以退出OSStart函式以後,系統開始跑*/
OSStartHighRdy(); //呼叫 OSStartHighRdy彙編函式 /* Execute target specific code to start task */
*p_err = OS_ERR_FATAL_RETURN; /* OSStart() is not supposed to return */
} else {
*p_err = OS_ERR_OS_RUNNING; /* OS is already running */
}
}
呼叫這個函式一般是在建立第一個任務時,那時系統還沒開始跑;在程式裡面OSRunning = OS_STATE_OS_RUNNING;把系統開始的標誌位OSRunning設定為1。這個函式正常執行結束以後代表著作業系統真正開始跑起來了。
三、PendSV 異常服務函式:
PendSV 異常服務要完成兩個工作:1、儲存上文;2、切換下文
任務之間的切換就是發生在PendSV 異常服務函式裡面。
可以理解為——觸發了PendSV 異常->函式自動跳轉到PendSV 異常服務函式->執行異常服務函式->實現任務的切換。
觸發PendSV 異常的函式:(在os_cpu_a.asm中定義)
- OSStartHighRdy;用得很少,只是在任務開啟時在OSStart()函式裡呼叫
- OSCtxSw :實現任務級的任務切換
- OSIntCtxSw :實現中斷級的任務切換
PendSV_Handler
CPSID I ;關中斷 ; Prevent interruption during context switch
MRS R0, PSP ; 將 psp 的值載入到 R0 ; PSP is process stack pointer
; CBZ判0轉移,判斷 R0如果值為 0 ,則跳轉到 OS_CPU_PendSVHandler_nosave
; 進行第一次任務切換的時候,R0 肯定為 0
CBZ R0, PendSVHandler_nosave ; Skip register save the first time
;判讀是否使用FPU
;Is the task using the FPU context? If so, push high vfp registers.
TST R14, #0X10
IT EQ
VSTMDBEQ R0!,{S16-S31}
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
;————————————儲存上下文————————————————————
; 手動儲存 CPU 暫存器 R4-R11 的值到當前任務的堆疊
STM R0, {R4-R11}
; 載入 OSTCBCurPtr 指標的地址到 R1
LDR R1, =OSTCBCurPtr ; OSTCBCurPtr->OSTCBStkPtr = SP;
LDR R1, [R1]
STR R0, [R1] ; R0 is SP of process being switched out
;—————————切換上下文—————————————
; 實現 OSTCBCurPtr = OSTCBHighRdyPtr
; 把下一個要執行的任務的堆疊OSPrioHighRdy載入到 CPU 暫存器中 ; At this point, entire context of process has been saved
PendSVHandler_nosave
PUSH {R14} ; Save LR exc_return value
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
BLX R0
POP {R14}
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
LDR R0, =OSTCBCurPtr ; OSTCBCurPtr = OSTCBHighRdyPtr;
LDR R1, =OSTCBHighRdyPtr
LDR R2, [R1]
STR R2, [R0]
; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;
LDM R0, {R4-R11} ; Restore r4-11 from new process stack
ADDS R0, R0, #0x20
;Is the task using the FPU context? If so, push high vfp registers.
TST R14, #0x10
IT EQ
VLDMIAEQ R0!, {S16-S31}
MSR PSP, R0 ; Load PSP with new process SP
ORR LR, LR, #0x04 ; Ensure exception return uses process stack
CPSIE I
BX LR ; Exception return will restore remaining context
END
相關文章
- 【freertos】006-任務切換實現細節
- Spring Boot整合quartz實現定時任務並支援切換任務資料來源Spring Bootquartz
- 用CSS實現tab切換CSS
- 使用Broker實現DG切換
- so-vits-svc實現歌聲轉換的一些提醒
- 系統呼叫時為什麼發生任務切換?
- 雙buffer實現無鎖切換
- 用純css實現Tab切換CSS
- celery 與 flask 實現非同步任務排程Flask非同步
- ucosiii(1): 時鐘節拍函式函式
- 任務1
- 任務。1
- [原始碼分析] 定時任務排程框架 Quartz 之 故障切換原始碼框架quartz
- 實現一個切換配方的功能
- WPF手動實現切換頁面
- Sass應用之實現主題切換
- 實現Vue專案主題切換Vue
- 純CSS實現Tab欄的切換CSS
- jquery中點選切換的實現jQuery
- 用CSS實現Tab頁切換效果CSS
- Label和input實現純CSS切換CSS
- 任務佇列,巨集任務與微任務佇列
- Android 實現APP可切換多語言AndroidAPP
- javascript實現tab切換的四種方法JavaScript
- Flutter UI使用Provide實現主題切換FlutterUIIDE
- Android——Activity切換炫酷動畫實現Android動畫
- 利用ViewPager和Fragment實現頁卡切換ViewpagerFragment
- 每日任務1
- win10快捷鍵任務視角怎麼用_win10怎麼快捷鍵切換任務檢視Win10
- SpringBoot如何實現定時任務Spring Boot
- Java如何實現定時任務?Java
- 用CompletableFuture實現非同步任務非同步
- 【freertos】004-任務建立與刪除及其實現細節
- git建立與切換分支Git
- nacos實現對minio的動態版本切換
- BGP線路,完美實現三網相互切換
- Flutter仿頭條頂部tab切換實現Flutter
- flutter 暗黑模式切換過渡動畫實現Flutter模式動畫