三 FreeRTOS 臨界段的保護

2021-10-23 12:12:43 字數 4597 閱讀 9303

3.4 開中斷

3.5 進入臨界段

3.6 退出臨界段

3.7 案例

[野火®]《freertos 核心實現與應用開發實戰—基於stm32》

臨界段用一句話概括就是一段在執行的時候不能被中斷的**段。

在 freertos 裡面,這個臨界段最常出現的就是對全域性變數的操作,全域性變數就好像是乙個槍把子,誰都可以對他開槍,但是我開槍的時候,你就不能開槍,否則就不知道是誰命中了靶子。

在進行系統排程和處理外部中斷時,臨界段會被打斷。系統排程,最終也是產生 pendsv 中斷,在 pendsv handler 裡面實現任務的切換,所以還是可以歸結為中斷。所以,freertos 對臨界段的保護可以理解為對中斷的開和關的控制。

為了快速地開關中斷, cortex-m 核心專門設定了一條 cps 指令,有 4 種用法。

cpsid   i    ;primask=

1;關中斷

cpsie i ;primask=

0;開中斷

cpsid f ;faultmask=

1;關異常

cpsie f ;faultmask=

0;開異常

cortex-m 核心 裡面三個中斷遮蔽暫存器描述如下。

暫存器名稱

描述primask

這是個只有單一位元的暫存器。 在它被置 1 後,就關掉所有可遮蔽的異常,只剩下 nmi 和硬 fault 可以響應。它的預設值是 0,表示沒有關中斷。

faultmask

這是個只有 1 個位的暫存器。當它置 1 時,只有 nmi 才能響應,所有其它的異常,甚至是硬 fault 也被關閉。它的預設值也是 0,表示沒有關異常。

basepri

這個暫存器最多有 9 位(由表達優先順序的位數決定)。它定義了被遮蔽優先順序的閾值。當它被設成某個值後,所有優先順序號大於等於此值的中斷都被關(優先順序號越大,優先順序越低)。但若被設成 0,則不關閉任何中斷, 0 也是預設值。

在 freertos 中,對中斷的開和關是通過操作 basepri 暫存器來實現的,即大於等於 basepri 的值的中斷會被遮蔽,小於 basepri 的值的中斷則不會被遮蔽,不受freertos 管理。

freertos 關中斷的函式在 portmacro.h 中定義,分無返回值和有返回值兩種。

在往 basepri 寫入新的值的時候,不用先將 basepri 的值儲存起來,即不用管當前的中斷狀態是怎麼樣的,既然不用管當前的中斷狀態,也就意味著這樣的函式不能在中斷裡面呼叫。

/* 不帶返回值的關中斷函式,不能巢狀,不能在中斷裡面使用;*/

#define portdisable_interrupts() vportraisebasepri()

static portforce_inline void

vportraisebasepri

(void

)}

在往 basepri 寫入新的值的時候,先將 basepri 的值儲存起來,在更新完 basepri 的值的時候,將之前儲存好的 basepri 的值返回,返回的值作為形參傳入開中斷函式。

/* 帶返回值的關中斷函式,可以巢狀,可以在中斷裡面使用;*/

#define portset_interrupt_mask_from_isr() ulportraisebasepri()

static portforce_inline uint32_t ulportraisebasepri

(void

)return ulreturn;

/* 返回原來 basepri 的值。*/

}

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

開中斷函式,具體是將傳進來的形參更新到 basepri 暫存器。

根據傳進來形參的不同,分為中斷保護版本與非中斷保護版本。

直接將 basepri 的值設定為 0,與 portdisable_interrupts() 成對使用。

/* 不帶中斷保護的開中斷函式 */

#define portenable_interrupts() vportsetbasepri( 0 )

將上一次關中斷時儲存的 basepri 的值作為形參,與 portset_interrupt_mask_from_isr() 成對使用。

/* 帶中斷保護的開中斷函式 */

#define portclear_interrupt_mask_from_isr(x) vportsetbasepri(x)

static portforce_inline void

vportsetbasepri

( uint32_t ulbasepri )

}

#define taskenter_critical() portenter_critical()

#define taskenter_critical_from_isr() portset_interrupt_mask_from_isr()

進入臨界段,無中斷保護版本,不能巢狀。

/* 在 task.h 中定義 */

#define taskenter_critical() portenter_critical()

/* 在 portmacro.h 中定義 */

#define portenter_critical() vportentercritical()

/* 在 port.c 中定義 */

void

vportentercritical

(void)}

/* 在 portmacro.h 中定義 */

#define portdisable_interrupts() vportraisebasepri()

/* 在 portmacro.h 中定義 */

static portforce_inline void

vportraisebasepri

(void

)}

進入臨界段,有中斷保護版本,可以巢狀。

/* 在 task.h 中定義 */

#define taskenter_critical_from_isr() portset_interrupt_mask_from_isr()

/* 在 portmacro.h 中定義 */

#define portset_interrupt_mask_from_isr() ulportraisebasepri()

/* 在 portmacro.h 中定義 */

static portforce_inline uint32_t ulportraisebasepri

(void

)return ulreturn;

}

#define taskexit_critical() portexit_critical()

#define taskexit_critical_from_isr( x ) portclear_interrupt_mask_from_isr( x )

退出臨界段,無中斷保護版本,不能巢狀。

/* 在 task.h 中定義 */

#define taskexit_critical() portexit_critical()

/* 在 portmacro.h 中定義 */

#define portexit_critical() vportexitcritical()

/* 在 port.c 中定義 */

void

vportexitcritical

(void)}

/* 在 portmacro.h 中定義 */

#define portenable_interrupts() vportsetbasepri( 0 )

static portforce_inline void

vportsetbasepri

( uint32_t ulbasepri )

}

退出臨界段,有中斷保護版本,可以巢狀。

/* 在 task.h 中定義 */

#define taskexit_critical_from_isr( x ) portclear_interrupt_mask_from_isr( x )

/* 在 portmacro.h 中定義 */

#define portclear_interrupt_mask_from_isr(x) vportsetbasepri(x)

static portforce_inline void

vportsetbasepri

( uint32_t ulbasepri )

}

在 freertos 中,對臨界段的保護出現在兩種場合,一種是在中斷場合一種是在非中斷場合。

/* 在中斷場,臨界段可以巢狀 */

/* 在非中斷場合,臨界段不能巢狀 */

FreeRTOS臨界資源保護(臨界區保護)

臨界區未保護出現的異常 今天我們說說其中之一的原因 臨界資源未保護。我們先看個例子,假如有乙個5個節點單向鍊錶,如下結構 head 1 2 3 4 5 null 有一任務a在乙個單向鍊錶的2 3節點之間插入乙個新的2a節點,已經將2 2a,還未將2a 3,此時,鍊錶變為兩個未完整的部分,如下結構 h...

FreeRTOS 中斷配置和臨界段

中斷遮蔽暫存器 primask faultmask和basepri 1.primask 這是個只有1個位的暫存器。當它置1時,就關掉所有可遮蔽的異常,只剩下 nmi和硬fault可以響應。它的預設值是0,表示沒有關中斷 2.faultmask 這是個只有1個位的暫存器。當它置1時,只有nmi才能響應...

四 FreeRTOS 中斷配置和臨界段

freertos 的中斷配置是乙個很重要的內容,我們需要根據所使用的 mcu 來具體配置。因此要先了解 mcu 架構中有關中斷的知識。中斷由硬體產生,當中斷產生以後 cpu 就會中斷當前的流程轉而去處理中斷服務,待中斷服務函式執行完後再回來執行之前被中斷的任務。cortex m 核心的 mcu 提供...