stm32 NVIC中斷管理實現[直接操作寄存器]


本文轉自:http://www.ichanging.org/stm32_NVIC.html

 
    cortex-m3支持256個中端,其中包含了16個內核中斷,240個外部中斷。stm32只有84個中斷,包括16個內核中斷和68個可屏蔽中斷。stm32f103上只有60個中斷,f107上才有68個中斷。
 
    中斷是stm32很基礎的一個功能,學會使用中斷,才可以更好的使用其他的外設。理解stm32的中斷,必須要先從stm32的 中斷優先級分組是怎么回事。要理解優先級分組,就要先理解什么是 先占優先級,和 次占優先級。  
 
     先占優先級的概念等同於51單片機中的中斷。假設有兩中斷先后觸發,已經在執行的中斷先占優先級如果沒有后觸發的中斷 先占優先級更高,就會先處理先占優先級高的中斷。也就是說又有較高的先占優先級的中斷可以打斷先占優先級較低的中斷。這是實現中斷嵌套的基礎。
 
     次占優先級只在同一先占優先級的中斷同時觸發時起作用,先占優先級相同,則優先執行次占優先級較高的中斷。次占優先級不會造成中斷嵌套。 如果中斷的兩個優先級都一致,則優先執行位於中斷向量表中位置較高的中斷。
 
還需要注意的一點是 這里的中斷優先級 高是指  是指是否更接近0級,0級優先級是最高的。
 
那么最低的優先級可以是多少?這就涉及了優先級分組的概念。 stm32 通過一個中斷向量控制器(NVIC),來分配先占優先級和次占優先級的數量。
 
arm cortex-m3 內核中擁有一個3位寬度的的PRIGROUP數據區,用來指示一個8位數據序列中的小數點的位置從而表示中斷優先級的分組。
 
舉個例子可以更好的理解: 如果PRIGROUP 數據位000  即為0  說明8位數據序列中小數位置在第1位的左邊  為xxxxxxx.y   用於表示中斷優先級的分組的含義就是   用7位的數據寬度來表示  先占優先級的數量 即為128  用1位的數據寬度來表示 次占優先級數量 即為 2 

 

 
所以arm cortex-m3中有2的三次方 即為8個優先級分組 。 
 
但是stm32中只有5個優先級分組,表示方法略有不同,參照下表:
 
NVIC_table.png
 
    MDK中定義的中斷相關的寄存器結構體為:

 

typedef struct
{
  vu32 ISER[2];
  u32  RESERVED0[30];
  vu32 ICER[2];
  u32  RSERVED1[30];
  vu32 ISPR[2];
  u32  RESERVED2[30];
  vu32 ICPR[2];
  u32  RESERVED3[30];
  vu32 IABR[2];
  u32  RESERVED4[62];
  vu32 IPR[15];
} NVIC_TypeDef;
 
ISER[2]:中斷使能寄存器組
 
stm32可屏蔽中斷共有60個,這里用了兩個32位的寄存器,可以表示64個中斷。stm32只用了前60位。 若要使能某個中斷,則必須設置相應的ISER位為1。
具體每一位對應的中斷關系如下:(參見 MDK下的 stm32f10x_nvic.h)

#ifdef STM32F10X_HD
ADC1_2_IRQn = 18, /*!< ADC1 and ADC2 global Interrupt */
USB_HP_CAN1_TX_IRQn = 19, /*!< USB Device High Priority or CAN1 TX Interrupts */
USB_LP_CAN1_RX0_IRQn = 20, /*!< USB Device Low Priority or CAN1 RX0 Interrupts */
CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */
CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */
EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */
TIM1_BRK_IRQn = 24, /*!< TIM1 Break Interrupt */
TIM1_UP_IRQn = 25, /*!< TIM1 Update Interrupt */
TIM1_TRG_COM_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt */
TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */
TIM2_IRQn = 28, /*!< TIM2 global Interrupt */
TIM3_IRQn = 29, /*!< TIM3 global Interrupt */
TIM4_IRQn = 30, /*!< TIM4 global Interrupt */
I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */
I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */
I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */
I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */
SPI1_IRQn = 35, /*!< SPI1 global Interrupt */
SPI2_IRQn = 36, /*!< SPI2 global Interrupt */
USART1_IRQn = 37, /*!< USART1 global Interrupt */
USART2_IRQn = 38, /*!< USART2 global Interrupt */
USART3_IRQn = 39, /*!< USART3 global Interrupt */
EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
RTCAlarm_IRQn = 41, /*!< RTC Alarm through EXTI Line Interrupt */
USBWakeUp_IRQn = 42, /*!< USB Device WakeUp from suspend through EXTI Line Interrupt */
TIM8_BRK_IRQn = 43, /*!< TIM8 Break Interrupt */
TIM8_UP_IRQn = 44, /*!< TIM8 Update Interrupt */
TIM8_TRG_COM_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt */
TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare Interrupt */
ADC3_IRQn = 47, /*!< ADC3 global Interrupt */
FSMC_IRQn = 48, /*!< FSMC global Interrupt */
SDIO_IRQn = 49, /*!< SDIO global Interrupt */
TIM5_IRQn = 50, /*!< TIM5 global Interrupt */
SPI3_IRQn = 51, /*!< SPI3 global Interrupt */
UART4_IRQn = 52, /*!< UART4 global Interrupt */
UART5_IRQn = 53, /*!< UART5 global Interrupt */
TIM6_IRQn = 54, /*!< TIM6 global Interrupt */
TIM7_IRQn = 55, /*!< TIM7 global Interrupt */
DMA2_Channel1_IRQn = 56, /*!< DMA2 Channel 1 global Interrupt */
DMA2_Channel2_IRQn = 57, /*!< DMA2 Channel 2 global Interrupt */
DMA2_Channel3_IRQn = 58, /*!< DMA2 Channel 3 global Interrupt */
DMA2_Channel4_5_IRQn = 59 /*!< DMA2 Channel 4 and Channel 5 global Interrupt */
#endif /* STM32F10X_HD */

系統中斷這里沒有申明,所以導致一些系統中斷無法使用,比如 systick的中斷 這個在  stm32上最方便的定時器Systick[操作寄存器+庫函數] 已經做了分析 
 
ICER[2]:中斷清除寄存器組
結構同 ISER[2],但是作用相反。 中斷的清楚不是通過向ISER[2]中對應位寫0實現的,而是在ICER[2]對應位寫1清除的。
 
ISPR[2]:中斷掛起控制寄存器組
每一位對應的中斷和ISER是一樣的。通過置1來掛起正在進行的中斷,而執行同級或者更高級別的中斷。
 
ICPR[2]:中斷解掛寄存器組
結構和ISPR[2]相同,作用相反。置1將相應中斷解掛。
 
IABR[2]:中斷激活標志位寄存器組
中斷和ISER[2]對應,如果為1,則表示該位所對應的中斷正在執行。這是只讀寄存器,由硬件自動清零。
 
IPR[15]:中斷優先級控制的寄存器組
IPR寄存器組由15個32位寄存器組成。每個可屏蔽的中斷占用8位,這樣可以表示的可屏蔽中斷為 15*4 =60個。而每個可屏蔽中斷占用的8位並沒有全部使用,而是只使用了高4位。這4位又分為搶占優先級和子優先級。搶占優先級在前,子優先級在后。而這兩個優先級各占幾位又要根據SCB->AIRCR中中斷分組的設置來決定。
 
IPR寄存器描述:
EXTICR1.png
 
 
stm32將中斷分為5組,組0~4. 該分組由SCB->AIRCR寄存器的[10:8]三位來定義。具體關系如下:
 
AIRCR[10:8] 分配情況 分配結果
0 111 .xxxx0000 0位 表示  搶占優先級,4位  表示  相應優先級
1 110 y.xxx0000 1位 表示  搶占優先級,3位 表示  相應優先級
2 101 yy.xx0000 2為 表示  搶占優先級,2位 表示  相應優先級
3 100 yyy.x0000 3位 表示  搶占優先級,1位 表示  相應優先級
4 011 yyyy.0000 4位 表示  搶占優先級,0位 表示  相應優先級
 
中斷管理實現如下:

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));

/* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}

/**
* @brief Initializes the NVIC peripheral according to the specified
* parameters in the NVIC_InitStruct.
* @param NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
* the configuration information for the specified NVIC peripheral.
* @retval None
*/
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{
uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;

/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));
assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));

if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
{
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;

tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;

NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;

/* Enable the Selected IRQ Channels --------------------------------------*/
NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
else
{
/* Disable the Selected IRQ Channels -------------------------------------*/
NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
}

/**
* @brief Sets the vector table location and Offset.
* @param NVIC_VectTab: specifies if the vector table is in RAM or FLASH memory.
* This parameter can be one of the following values:
* @arg NVIC_VectTab_RAM
* @arg NVIC_VectTab_FLASH
* @param Offset: Vector Table base offset field. This value must be a multiple
* of 0x200.
* @retval None
*/
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset)
{
/* Check the parameters */
assert_param(IS_NVIC_VECTTAB(NVIC_VectTab));
assert_param(IS_NVIC_OFFSET(Offset));

SCB->VTOR = NVIC_VectTab | (Offset & (uint32_t)0x1FFFFF80);
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM