臨界段代碼也叫臨界區(qū),是指那些必須完整運行、不能被打斷的代碼段,比如有的外設(shè)的初始化需要嚴(yán)格的時序,初始化過程中不能被打斷。FreeRTOS在進入臨界段代碼的時候需要關(guān)閉中斷,處理完臨界段代碼以后再打開中斷。FreeRTOS系統(tǒng)本身就有很多的臨界段,這些代碼都加了臨界段代碼保護,寫自己用戶程序的時候有些地方也需要添加臨界段代碼保護。
FreeRTOS與臨界段代碼保護有關(guān)的函數(shù)有4個,在task.h中定義,分別是:taskENTER_CRITICAL()、taskEXIT_CRITICAL() 、taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR( x )。其中前2個是任務(wù)級的臨界段代碼保護,后2個是中斷級的臨界段代碼保護,無論哪種情況臨界段的代碼都要盡量短小,下面分別來看。
1. 任務(wù)級臨界段代碼保護
taskENTER_CRITICAL()和taskEXIT_CRITICAL()是任務(wù)級的臨界段代碼保護,一個是進入臨界段,一個是退出臨界段,這2個函數(shù)是成對使用的,這函數(shù)的定義如下:
而portENTER_CRITICAL()和portEXIT_CRITICAL()也是宏定義,在portmacro.h中有定義,如下:
函數(shù)vPortEnterCritical()和vPortExitCritical()在文件port.c中,函數(shù)如下:
可以看出,進入函數(shù)vPortEnterCritical()以后首先調(diào)用函數(shù)portDISABLE_INTERRUPTS()來關(guān)閉中斷,然后給變量uxCriticalNesting加1。uxCriticalNesting是一個全局變量,用來記錄臨界段嵌套次數(shù)。函數(shù)vPortExitCritical()是退出臨界段調(diào)用,函數(shù)每次將uxCriticalNesting 減1,只有當(dāng)uxCriticalNesting 減到0才會調(diào)用函數(shù)portENABLE_INTERRUPTS()來使能中斷。這樣保證了在有多個臨界段代碼的時候不會因為某一個臨界段代碼的退出而打亂其他臨界段的保護,只有所有的臨界段代碼都退出以后才會使能中斷。
2. 中斷級臨界段代碼保護
函數(shù)taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR( x )為中斷級臨界段代碼保護函數(shù),用在中斷服務(wù)程序中,而且這個中斷的優(yōu)先級一定要小于等于configMAX_SYSCALL_INTERRUPT_PRIORITY。這2個函數(shù)在task.h中有如下定義:
接下來看portSET_INTERRUPT_MASK_FROM_ISR()和portCLEAR_INTERRUPT_MASK_FROM_ISR( x ),這2個函數(shù)在文件portmacro.h中有如下定義:
函數(shù)usPortRaiseCpuIPL()和vPortSetCpuIPL( x )在文件port.c中,函數(shù)如下:
可以看出,進入函數(shù)usPortRaiseCpuIPL()實現(xiàn)的功能為首先保存當(dāng)前CPU的優(yōu)先級IPL[2:0] 到變量usOldIPL中,作為函數(shù)返回值用于vPortSetCpuIPL( x ) 的形參在退出臨界段時恢復(fù)IPL[2:0] 。另一個usPortRaiseCpuIPL() 的操作就是將CPU的優(yōu)先級IPL[2:0]賦值configMAX_SYSCALL_INTERRUPT_PRIORITY,使優(yōu)先級小于等于configMAX_SYSCALL_INTERRUPT_PRIORITY的中斷被屏蔽。