freertos 的中斷配置是乙個很重要的內容,我們需要根據所使用的 mcu 來具體配置。因此要先了解 mcu 架構中有關中斷的知識。
中斷由硬體產生,當中斷產生以後 cpu 就會中斷當前的流程轉而去處理中斷服務,待中斷服務函式執行完後再回來執行之前被中斷的任務。cortex-m 核心的 mcu 提供了乙個用於中斷管理的巢狀向量中斷控制器(nvic)。
cotex-m3 和 m4 的 nvic 最多支援 240 個 irq(中斷請求)、1 個不可遮蔽中斷(nmi)、1 個systick(滴答定時器)定時器中斷和多個系統異常。
當多個中斷來臨的時候處理器應該響應哪乙個中斷是由中斷的優先順序來決定的,高優先順序的中斷(優先順序編號小)肯定是首先得到響應,而且高優先順序的中斷可以搶占低優先順序的中斷,這個就是中斷巢狀。cortex-m 處理器的有些中斷是具有固定的優先順序的,比如復位、nmi、hardfault,這些中斷的優先順序都是負數,優先順序也是最高的。
cortex-m 處理器有三個固定優先順序和 256 個可程式設計的優先順序,最多有 128 個搶占等級,但是實際的優先順序數量是由晶元廠商來決定的。但是,絕大多數的晶元都會精簡設計的,以致實際上支援的優先級數會更少,如 8 級、16 級、32 級等,比如 stm32 就只有 16 級優先順序。在設計晶元的時候會裁掉表達優先順序的幾個低端有效位,以減少優先級數,所以不管用多少位來表達優先順序,都是 msb 對齊的,如下圖就是使用三位來表達優先順序。
bit0~bit4 沒有實現,所以讀它們總是返回零,寫如它們的話則會忽略寫入的值。因此,對於 3 個位的情況,可是使用的優先順序就是 8 個:0x00(最高優先順序)、0x20、0x40、0x60、0x80、0xa0、0xc0 和 0xe0。注意,這個是晶元廠商來決定的!不是我們能決定的,比如 stm32 就選擇了 4 位作為優先順序!
為了使搶占機能變得更可控,cortex-m 處理器還把 256 個優先順序按位分為高低兩段:搶占優先順序(分組優先順序)和亞優先順序(子優先順序)。nvic 中有乙個暫存器是「應用程式中斷及復位控制暫存器(aircr)」,aircr 暫存器裡面有個位段名為「優先順序組」 prigroup,它把優先順序分為兩個位段:msb 所在的位段(左邊的)對應搶占優先順序,lsb 所在的位段(右邊的)對應亞優先順序
stm32 使用了 4 位,因此最多有 5 組優先順序分組設定,這 5 個分組在 msic.h 中有定義。注意,stm32 中定義的分組 0 對應的是分組位置7,因為它對應的值是0x700(=7)。因為freertos 的中斷配置沒有處理亞優先順序這種情況,所以我們只能配置中斷優先順序分組為 4,直接就 16 個主優先順序,使用起來也簡單!
#define nvic_prioritygroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
4 bits for subpriority */
#define nvic_prioritygroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
3 bits for subpriority */
#define nvic_prioritygroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
2 bits for subpriority */
#define nvic_prioritygroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
1 bits for subpriority */
#define nvic_prioritygroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
0 bits for subpriority */
在許多應用中,需要暫時遮蔽所有的中斷一執行一些對時序要求嚴格的任務,這個時候就可以使用 primask 暫存器,primask 用於禁止除 nmi 和 hard****t 外的所有異常和中斷,彙編程式設計的時候可以使用 cps(修改處理器狀態)指令修改 primask 暫存器的數值:
cpsie i; //清除 primask(使能中斷)
cpsid i; //設定 primask(禁止中斷)
primask 暫存器還可以通過 mrs 和 msr 指令訪問:
movs r0, #1
msr primask, r0 ;//將 1 寫入 primask 禁止所有中斷
movs r0, #0
msr primask, r0 ;//將 0 寫入 primask 以使能中斷
faultmask 比 primask 更狠,它可以連 hardfault 都遮蔽掉,使用方法和 primask 類似,faultmask 會在退出時自動清零。使用方法如下:
cpsie f ;清除 faultmask
cpsid f ;設定 faultmask
movs r0, #1
msr faultmask, r0 ;將 1 寫入 faultmask 禁止所有中斷
movs r0, #0
msr faultmask, r0 ;將 0 寫入 faultmask 使能中斷
basepri 暫存器用於設定某個閾值,只遮蔽優先順序低於這個閾值的中斷。比如,我們要遮蔽優先順序不高於0x60的中斷,則可以使用如下彙編程式設計:
mov r0, #0x60
msr basepri, r0
如果需要取消 basepri 對中斷的遮蔽,可以使用如下**:
mov r0, #0
msr basepri, r0
注意!freertos 的開關中斷就是操作 basepri 暫存器來實現的!它可以關閉低於某個閾值的中斷,高於這個閾值的中斷就不會被關閉!
freertos 開關中斷函式為 portenable_interrupts ()和 portdisable_interrupts()。利用他們可以開啟或遮蔽freertosconfig.h中指定優先順序的中斷。
臨界段**也叫做臨界區,是指那些必須完整執行,不能被打斷的**段,比如有的外設的初始化需要嚴格的時序,初始化過程中不能被打斷。freertos 在進入臨界段**的時候需要關閉中斷,當處理完臨界段**以後再開啟中斷。freertos 系統本身就有很多的臨界段**,這些**都加了臨界段**保護,我們在寫自己的使用者程式的時候有些地方也需要新增臨界段**保護。
freertos 與 臨 界 段 代 碼 保 護 有 關 的 函 數 有 4 個 : taskenter_critical() 、taskexit_critical() 、 taskenter_critical_from_isr() 和 taskexit_critical_from_isr()。他們在 task.h 檔案中有相應的巨集定義。
taskenter_critical()和 taskexit_critical()是任務級的臨界**保護,乙個是進入臨界段,乙個是退出臨界段,這兩個函式是成對使用的。任務級臨界**保護使用方法如下:
void taskcritical_test(void)
}
注意臨界區**一定要精簡!因為進入臨界區會關閉中斷,這樣會導致優先順序低於 configmax_syscall_interrupt_priority 的中斷得不到及時的響應!
taskenter_critical_from_isr()和 taskexit_critical_from_isr()中斷級別臨界段**保護,是用在中斷服務程式中的,而且這個中斷的優先順序一定要低於configmax_syscall_interrupt_priority,因為高於這個優先順序的中斷服務函式不能呼叫 freertos 的 api 函式。中斷級臨界**保護使用方法如下:
//定時器 3 中斷服務函式
void tim3_irqhandler(void)
tim_clearitpendingbit(tim3,tim_it_update); //清除中斷標誌位
}
FreeRTOS 中斷配置和臨界段
中斷遮蔽暫存器 primask faultmask和basepri 1.primask 這是個只有1個位的暫存器。當它置1時,就關掉所有可遮蔽的異常,只剩下 nmi和硬fault可以響應。它的預設值是0,表示沒有關中斷 2.faultmask 這是個只有1個位的暫存器。當它置1時,只有nmi才能響應...
001 FreeRTOS中斷配置
一 優先順序看 022 stm32中斷優先順序分組解析 二 freertos的中斷配置中沒有處理亞優先順序 響應優先順序 的情況,所以只能配置成組4,16個都為搶占優先順序 三 此巨集用來設定 mcu 使用幾位優先順序,stm32 使用的是 4 位,因此此巨集為 4!2 4 16,那麼就有16個優先...
FreeRTOS中斷優先順序配置(重要)
freertos中斷優先順序配置 重要 本章節為大家講解freertos中斷優先順序配置,此章節非常重要,初學者經常在這裡犯迷糊。對於初學者來說,本章節務必要整明白。12.1 nvic 基礎知識 使用freertos時如何配置外設nvic 12.3 freertos 配置選項中nvic相關配置 不受...