1. 程式人生 > 其它 >Freertos—中斷+臨界區

Freertos—中斷+臨界區

一、學習資料

Freertos臨界區和開關中斷:

https://www.cnblogs.com/yangguang-it/p/7161486.html

https://blog.csdn.net/LiaRonBob/article/details/105083306

二、臨界區概念

臨界區其實就是一段在執行的時候不能被中斷的程式碼段

臨界區函式:進入臨界區taskENTER_CRITICAL(); 和退出臨界區taskEXIT_CRITICAL();

具體函式定義有兩種:

1、不帶版本保護,不能巢狀

進入臨界區:

 1 void vPortEnterCritical(void)
 2 {
 3 
 4     /*
Mask interrupts up to the max syscall interrupt priority. */ 5 6 ulPortSetInterruptMask(); 7 8 /* Now interrupts are disabled ulCriticalNesting can be accessed 9 10 directly. Increment ulCriticalNesting to keep a count of how many times 11 12 portENTER_CRITICAL() has been called.
*/ 13 14 ulCriticalNesting++; 15 16 /* This is not the interrupt safe version of the enter critical function so 17 18 assert() if it is being called from an interrupt context. Only API 19 20 functions that end in "FromISR" can be used in an interrupt. Only assert if 21 22 the critical nesting count is 1 to protect against recursive calls if the
23 24 assert function also uses a critical section. */ 25 26 if (ulCriticalNesting == 1) { 27 28 configASSERT(ulPortInterruptNesting == 0); 29 30 } 31 } 
View Code

退出臨界區:

 1 void vPortExitCritical(void)
 2 
 3 {
 4 
 5     if (ulCriticalNesting > portNO_CRITICAL_NESTING) {
 6 
 7         /* Decrement the nesting count as the critical section is being
 8 
 9         exited. */
10 
11         ulCriticalNesting--;
12 
13         /* If the nesting level has reached zero then all interrupt
14 
15         priorities must be re-enabled. */
16 
17         if (ulCriticalNesting == portNO_CRITICAL_NESTING) {
18 
19         /* Critical nesting has reached zero so all interrupt priorities
20 
21            should be unmasked. */
22 
23             portCLEAR_INTERRUPT_MASK();
24 
25        }
26 
27     }
28 
29 }
View Code

2、帶版本保護,可以巢狀

 1 #define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
 2 
 3 /* 在 portmacro.h 中定義 */
 4 
 5 #define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
 6 
 7 /* 在 portmacro.h 中定義 */
 8 
 9 static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
10 
11 {
12 
13 uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;       
14 
15 __asm
16 
17 {
18 
19 mrs ulReturn, basepri
20 
21 msr basepri, ulNewBASEPRI
22 
23 dsb
24 
25 isb
26 
27 }       
28 
29 return ulReturn;
30 
31 }
View Code

三、中斷

Freertos的臨界區被打斷的情況分兩種,一種是系統排程,另外一種是外部中斷。其實系統

排程最終也是通過中斷來實現的,也可以歸結為中斷。因此臨界區保護其實就是對中斷的開關控制。

FreeRTOS關中斷的函式在portmacro.h中定義,分不帶返回值和帶返回值兩種.

不帶返回值的關中斷函式

1、不帶返回值的關中斷函式,不能巢狀,不能在中斷裡面使用。不帶返回值的意思是:在往 BASEPRI寫入新的值的時候,不用先將BASEPRI的值儲存起來,即不用管當前的中斷狀態是怎麼樣的,既然不用管當前的中斷狀態,也就意味著這樣的函式不能在中斷裡面呼叫

2、configMAX_SYSCALL_INTERRUPT_PRIORITY是一個在FreeRtOSConfig.h中定義的巨集,即要寫入到BASEPRI暫存器的值。該巨集預設定義為191,高四位有效,即等於0xb0,或者是11,即優先順序大於等於11的中斷都會被遮蔽,11以內的中斷則不受FreeRTOS管理(數值越小,優先順序越高)。

3、將configMAX_SYSCALL_INTERRUPT_PRIORITY的值寫入BASEPRI暫存器,實現關中斷(準確來說是關部分中斷).

不帶返回值的關中斷函式

1、帶返回值的關中斷函式,可以巢狀,可以在中斷裡面使用。帶返回值的意思是:在往 BASEPRI寫入新的值的時候,先將BASEPRI的值儲存起來,在更新完BASEPRI的值的時候,將之前儲存好的

BASEPRI的值返回,返回的值作為形參傳入開中斷函式

2、configMAX_SYSCALL_INTERRUPT_PRIORITY是一個在FreeRTOSConfig.h中定義的巨集,即要寫入到BASEPRI暫存器的值。該巨集預設定義為191,高四位有效,即等於0xb0,或者是11,即優先順序大於等於11的中斷都會被遮蔽,11以內的中斷則不受FreeRTOS管理。

3、儲存BASEPRI的值,記錄當前哪些中斷被關閉

4、返回原來BASEPRI的值

3、開中斷

FreeRTOS開中斷的函式在portmacro.h中定義

2022-03-22