STM32F4 HAL库开发 -- NVIC 中断优先级管理
一、中斷寄存器
STM32F429xx的96個中斷里面,包括10個內核中斷和91個可屏蔽中斷,具有16級可編程的中斷優先級,而我們常用的就是這91個可屏蔽中斷。在MDK內,與NVIC相關的寄存器,MDK為其定義了如下的結構體。
/**\brief Structure type to access the Nested Vectored Interrupt Controller (NVIC).*/ typedef struct {__IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */uint32_t RESERVED0[24U];__IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */uint32_t RSERVED1[24U];__IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */uint32_t RESERVED2[24U];__IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */uint32_t RESERVED3[24U];__IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */uint32_t RESERVED4[56U];__IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */uint32_t RESERVED5[644U];__OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ } NVIC_Type;下面重點介紹這幾個寄存器:
ISER[8]:
ISER全稱是:Interrupt Set-Enable Registers,這是一個中斷使能寄存器組。
CM4內核支持256個中斷,這里用8個32位寄存器來控制,每個位控制一個中斷。但是STM32F429的可屏蔽中斷最多只有91個,所以對我們來說,有用的就是三個(ISER[0~2]),總共可以表達96個中斷。而STM32F429只用了其中的91個。
ISER[0]的bit0 ~ 31分別對應中斷0 ~ 31;ISER[1]的bit0 ~ 32對應中斷32 ~ 63;ISER[2]的bit0 ~ 26對應中斷64 ~ 90;這樣總共91個中斷就分別對應上了。你要使能某個中斷,必須設置對應的ISER位為1,使該中斷被使能(這里僅僅是使能,還要配合中斷分組、屏蔽、IO口映射等設置才算是一個完整的中斷設置)。
ICER[8]:
ICER全稱是:Interrupt Clear-Enable Registers,是一個中斷除能寄存器組。該寄存器組與ISER的作用恰恰相反,是用來清除某個中斷的使能的。其對應位的功能,也和ISER一樣。
這里要專門設置一個ICER來清除中斷位,而不是向ISER寫0來清除,是因為NVIC的這些寄存器都是寫1有效,寫0無效的。
ISPR[8]:
ISPR全稱是:Interrupt Set-Pending Registers,是一個中斷掛起控制寄存器組。每個位對應的中斷和ISER是一樣的。通過置1,可以將正在進行的中斷掛起,而執行同級或更高級別的中斷。寫0是無效的。
ICPR[8]:
ICPR全稱是:Interrupt Clear-Pending Registers,是一個中斷解掛控制器組。其作用于ISPR相反,對應位也和ISER是一樣的。通過設置1,可以將掛起的中斷解掛。寫0無效。
IABR[8]:
IABR全稱是:Interrupt Active Bit Registers,是一個中斷激活標志位寄存器組。對應位所代表的中斷和ISER一樣,如果為1,則表示該位所對應的中斷正在被執行。這是一個只讀寄存器,通過它可以知道當前在執行的中斷是哪一個。在中斷執行完了由硬件自動清零。
IP[240]:
IP全稱是:Interrupt Priority Registers,是一個中斷優先級控制的寄存器組。
這個寄存器相當重要。STM32F429的中斷分組與這個寄存器組密切相關。IP寄存器組有240個8bit的寄存器組成,每個可屏蔽中斷占用8bit,這樣總共 可以表示240個可屏蔽中斷。而STM32F429只用到了其中的91個。IP[90]~IP[0]分別對應中斷90 ~ 0。而每個可屏蔽中斷占用的8bit并沒有全部使用,而是只用了高4位。這4位,又分為搶占優先級和子優先級。搶占優先級在前,子優先級在后。而這兩個優先級各占幾位又要根據SCB->AIRCR中的中斷分組設置來決定。
STM32F429的中斷分組:STM32F429將中斷分為5個組,組0 ~ 4。該分組的設置是由SCR->AIRCR寄存器的bit0 ~ 8來定義的。具體分配關系如下圖:
通過這個表,我們就可以清楚的看到組0 ~ 4對應的配置關系,例如組設置為3,那么此時所有的91個中斷,每個中斷的中斷優先級寄存器的高四位中的最高3位是搶占優先級,低1位是響應優先級。每個中斷,你可以設置搶占優先級為0 ~ 7,響應優先級為1或0.搶占優先級的級別高于響應優先級的。而數值越小所代表的優先級就越高。
這里需要注意兩點:第一,如果兩個中斷的搶占優先級和響應優先級都是一樣的話,則看哪個中斷先發生就先執行;第二,高優先級的搶占優先級是可以打斷正在進行的低搶占優先級中斷的。而搶占優先級相同的中斷,高優先級的響應優先級不可以打斷低響應優先級的中斷。
結合實例說明一下:假定設置中斷優先級組為2,然后設置中斷3(RTC_WKUP中斷)的搶占優先級為2,響應優先級為1.中斷6(外部中斷0)的搶占優先級為3,響應優先級為0。中斷7(外部中斷1)的搶占優先級為2,響應優先級為0。那么這3個中斷的優先級順序為:中斷7>中斷3>中斷6。
上面例子中的中斷3和中斷7都可以打斷中斷6的中斷。而中斷7和中斷3卻不可以相互中斷。
二、HAL 庫實現以上中斷分組設置以及中斷優先級管理
NVIC中斷管理相關函數主要在HAL庫關鍵文件stm32f4xx_hal_cortex.c 中定義。
1、中斷優先級分組函數HAL_NVIC_SetPriorityGrouping
函數聲明:void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup);
函數定義:
這個函數的作用是對中斷的優先級進行分組,這個函數在系統中只需要被調用一次,一旦分組確定就最好不要更改,否則容易造成程序分組混亂。
從函數體以及注釋可以看出,這個函數是通過調用函數NVIC_SetPriorityGrouping來進行中斷優先級分組設置。再查看NVIC_SetPriorityGrouping:
/**\brief Set Priority Grouping\details Sets the priority grouping field using the required unlock sequence.The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field.Only values from 0..7 are used.In case of a conflict between priority grouping and availablepriority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set.\param [in] PriorityGroup Priority grouping field.*/ __STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) {uint32_t reg_value;uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */reg_value = SCB->AIRCR; /* read old register configuration */reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */reg_value = (reg_value |((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |(PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */SCB->AIRCR = reg_value; }可以看到,函數的最開頭有這樣一行函數:
assert_param(IS_NVIC_PRIORITY_GROUP(PriorityGroup));
其中函數 assert_param是斷言函數,它的作用主要是對入口參數的有效性進行判斷。也就是說我們可以通過這個函數知道入口參數在哪些范圍內是有效的。
查看IS_NVIC_PRIORITY_GROUP:
#define IS_NVIC_PRIORITY_GROUP(GROUP) (((GROUP) == NVIC_PRIORITYGROUP_0) || \((GROUP) == NVIC_PRIORITYGROUP_1) || \((GROUP) == NVIC_PRIORITYGROUP_2) || \((GROUP) == NVIC_PRIORITYGROUP_3) || \((GROUP) == NVIC_PRIORITYGROUP_4))從這個內容可以看出,當GROUP的值為NVIC_PRIORITYGROUP_0 ~ NVIC_PRIORITYGROUP_4的時候,IS_NVIC_PRIORITY_GROUP的值才為真。這也就是我們上面講的,分組范圍為0~4,對應的入口參數為宏定義值NVIC_PRIORITYGROUP_0 ~ NVIC_PRIORITYGROUP_4。比如我們設置整個系統的中斷優先級分組值為2,那么方法是:
HAL_NVIC_SetPriorityGroupin(NVIC_PRIORITYGROUP_2);
這樣就確定了中斷優先級分組為2,也就是2位搶占優先級,2位響應優先級,搶占優先級和響應優先級的值得范圍均為0 ~ 3。
打開stm32f4xx_hal.c 文件可以看到,文件內部定義了HAL庫初始化函數HAL_Init,這個函數非常重要,其作用主要是對中斷優先級分組,FLASH以及硬件層進行初始化。在HAL_Init內部,有如下一行代碼:
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
這行代碼的作用是把系統中斷優先級分組設置為分組4,也就是說,在主函數中調用HAL_Init函數之后,在HAL_Init函數內部會通過調用HAL_NVIC_SetPriorityGrouping 函數來進行系統中斷優先級分組設置。所以,我們要進行中斷分組設置,只需要修改HAL_Init函數內部的這行代碼即可。
2、設置搶占優先級和響應優先級
官方 HAL 庫文件 stm32f4xx_hal_cortex.c 中定義了三個單個中斷優先級設置
函數。函數如下:
這里大家還需要注意,中斷優先級分組和中斷優先級設置是兩個不同的概念。
中斷優先級分組是用來設置整個系統對于中斷分組設置為哪個分組,分組號為0 ~ 4,設置函數為HAL_NVIC_SetPriorityGrouping,確定了中斷優先級分組號,也就確定了系統對于單個中斷的搶占優先級和響應優先級設置各占幾個位。(NVIC_PRIORITYGROUP_4 為4個搶占優先級,0位響應優先級)。設置好中斷優先級分組,確定過了分組號之后,接下來我們就是要對單個優先級進行中斷優先級設置。
最后總結一下中斷優先級設置的步驟:
(1)系統運行開始的時候設置中斷分組。確定組號,也就是確定搶占優先級和響應優先級的分配位數。設置函數為HAL_NVIC_SetPriorityGrouping。對于HAL庫,在文件 stm32f4xx_hal.c內部定義函數 HAL_Init 中有調用 HAL_NVIC_PriorityGroupConfig 函數進行相關設置,所以我們只需要修改HAL_Init內部對中斷優先級分組設置即可。
(2)設置單個中斷的中斷優先級別和使能響應中斷通道,使用到的函數主要為:
HAL_NVIC_SetPriority 和HAL_NVIC_EnableIRQ。
總結
以上是生活随笔為你收集整理的STM32F4 HAL库开发 -- NVIC 中断优先级管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据库发展研究报告(2021年)
- 下一篇: 2021年中国药店创新趋势报告