NVIC中斷


 中斷寄存器

                1)ISER[8](Interrupt Set-Enable Registers):中斷使能寄存器--void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);。其

 

中斷使能寄存器共有8個,ISER[0]設置0~31號中斷的使能,ISER[1]設置32~63號中斷的使能,如此類推。以下以ISER[0]為例:

[31:0] SETENA中斷設置使能位。
寫:
0 =無影響
1 =使能中斷。
讀:
0 =中斷是禁止的
1=中斷已經被使能

如果要使能0號中斷,就向該寄存器的0位寫1,如果要使能38號中斷,就向NVIC_ISER[1]的6位寫1,如此類推,至於哪個中斷對應哪個中斷號


               2)ICER[8](Interrupt Clear-Enable Registers):中斷移除寄存器--void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);。該寄存器的作用於ISER相反。這里專門設置一個ICER來清除中斷位,而不是向ISER位寫0,是因為NVIC的寄存器寫1有效,寫0無效。
                3)ISPR[8](Interrupt Set-Pending Registers):中斷掛起控制寄存器--static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn);。通過置1可以將正在進行的中斷掛起,執行同級或者更高級別的中斷。寫0無效。
                4)ICPR[8](Interrupt Clear-Pending Registers):中斷解掛控制寄存器--static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn);。通過置1可以將正在掛起的中斷解掛。寫0無效。
                5)IABR[8](Interrupt Active-Bit Registers):中斷激活標志位寄存器--static __INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn);。這是一個只讀寄存器,可以知道當前在執行的中斷是哪一個(為1),在中斷執行完后硬件自動清零。
                6)IP[240](Interrupt Priority Registers):中斷優先級控制的寄存器--void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);。這是用來控制每個中斷的優先級。由於STM32F10x系列一共60個可屏蔽中斷,故使用IP[59]~IP[0]。其中每個IP寄存器的高4位[7:4]用來設置搶占和響應優先級(根據分組),低4位沒有用到。而兩個優先級各占幾個位又要由上面講到的中斷優先級分組決定。
 

STM32F0xx 實現中斷向量表重定義

在STM32F103等cortex-m3/m4內核的單片機上可以通過設置SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;該寄存器的值來實現中斷向量表的重定義。

在Coretext-M3與M4核中,在System Control Block中存在一個向量表偏移量寄存器 VTOR(0xE000ED08),系統產生中斷后,內核通過這個寄存器的值來找到中斷向量表的地址,進而執行中斷例程代碼。

當然,此寄存器的值是可以修改的,它的默認值為0。實際上在大部分的M3和M4的工程中,一般都是在SystemInit函數中對此寄存器的值進行設置。

由於STM32F0XX采用的是M0核,它是沒有這個VTOR寄存器的,那么它又是怎么找到中斷向量表的地址的呢?

如何將中斷向量表的尋找位置從0x0800 0000修改到0x0800 3000(假設為APP的地址)? 我們重新回顧之前的分析,可以得出有2種方法:

  • 修改寄存器VTOR的值(M3/M4 使用
  • 內存重映射(M0使用)

通過將SRAM重映射到地址0x0000 0000,那么,M0系統產生中斷后,CPU還是從地址0x0000 0000尋找中斷入口,但是,實際上不再是尋址0x0800 0000,而是尋址0x2000 0000,這么一來,接下來我們就只需要將中斷向量表整個拷貝到SRAM上,也就是0x2000 0000上,就這樣,CPU就可以正常尋址中斷向量表了。

 

 

/* Memory mapping of Cortex-M3 Hardware */
#define SCS_BASE            (0xE000E000)                              /*!< System Control Space Base Address */
#define ITM_BASE            (0xE0000000)                              /*!< ITM Base Address                  */
#define CoreDebug_BASE      (0xE000EDF0)                              /*!< Core Debug Base Address           */
#define SysTick_BASE        (SCS_BASE +  0x0010)                      /*!< SysTick Base Address              */
#define NVIC_BASE           (SCS_BASE +  0x0100)                      /*!< NVIC Base Address                 */
#define SCB_BASE            (SCS_BASE +  0x0D00)                      /*!< System Control Block Base Address */

#define InterruptType       ((InterruptType_Type *) SCS_BASE)         /*!< Interrupt Type Register           */
#define SCB                 ((SCB_Type *)           SCB_BASE)         /*!< SCB configuration struct          */
#define SysTick             ((SysTick_Type *)       SysTick_BASE)     /*!< SysTick configuration struct      */
#define NVIC                ((NVIC_Type *)          NVIC_BASE)        /*!< NVIC configuration struct         */
#define ITM                 ((ITM_Type *)           ITM_BASE)         /*!< ITM configuration struct          */
#define CoreDebug           ((CoreDebug_Type *)     CoreDebug_BASE)   /*!< Core Debug configuration struct   *

 

 

 

1. 中斷分組

分組函數:void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

假設,要使中斷分組為2

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

 

#define AIRCR_VECTKEY_MASK    ((uint32_t)0x05FA0000)
#define NVIC_PriorityGroup_2         ((uint32_t)0x500) /*!< 2 bits for pre-emption priority

 

 

/**
  * @brief  Configures the priority grouping: pre-emption priority and subpriority.
  * @param  NVIC_PriorityGroup: specifies the priority grouping bits length.
  *   This parameter can be one of the following values:
  *     @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority
  *                                4 bits for subpriority
  *     @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority
  *                                3 bits for subpriority
  *     @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority
  *                                2 bits for subpriority
  *     @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority
  *                                1 bits for subpriority
  *     @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority
  *                                0 bits for subpriority
  * @retval None
  */
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;
}

 

    分組配置是在寄存器SCB->AIRCR中配置,具體的分配關系如下所示: 

 

 

 STM32有16個級別(4-bit)優先級可使用:

 

 

 

        其中AIRCR寄存器來確定是用哪種分組,IP寄存器是相對應於那種分組搶占優先級和響應優先級的分配比例。例如組設置成3,那么此時所有的60個中斷優先寄存器高4位中的最高3位是搶占優先級,低1位為響應優先級CM3中定義了8個Bit用於設置中斷源的優先級,而STM32只選用其中的4個Bit。

        搶占優先級的級別高於響應優先級,而數值越小所代表的的優先級越高。 
        介紹一下搶占優先級、響應優先級的區別:
                1)高優先級的搶占優先級是可以打斷正在進行的低搶占優先級中斷的;
                2)搶占優先級相同的中斷,高響應優先級不可以打斷低響應優先級的中斷;
                3)搶占優先級相同的中斷,當兩個中斷同時發生的情況下,哪個響應優先級高,哪個先執行;
                4)如果兩個中斷的搶占優先級和響應優先級都是一樣的話,則看哪個中斷先發生就先執行;
        除此之外有兩點需要注意:
                1)打斷的情況只會與搶占優先級有關, 和響應優先級無關!
                2)一般情況下,系統代碼執行過程中,只設置一次中斷優先級分組,比如分組2,設置好分組之后一般不會再改變分組。隨意改變分組會導致中斷管理混亂,程序出現意想不到的執行結果。
        優先級舉例說明:假定設置中斷優先級組為2,然后設置中斷3(RTC中斷)的搶占優先級為2,響應優先級為1。中斷6(外部中斷0)的搶占優先級為3,響應優先級為0。中斷7(外部中斷1)的搶占優先級為2,響應優先級為0。那么這3個中斷的優先級順序為:中斷7>中斷3>中斷6
 

2.設置中斷的優先級別(搶占優先級和子優先級)

中斷初始化函數:void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

假設,要設置串口1的中斷,同時設置搶占優先級為1,子優先級為2

復制代碼
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口 1 中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 搶占優先級為 1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子優先級位 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure);  //根據上面指定的參數初始化 NVIC 寄存器
復制代碼

 

NVIC_Type為:

復制代碼
/** @addtogroup CMSIS_CM3_NVIC CMSIS CM3 NVIC
  memory mapped structure for Nested Vectored Interrupt Controller (NVIC)
  @{
 */
typedef struct
{
  __IO uint32_t ISER[8];                      /*!< Offset: 0x000  Interrupt Set Enable Register           */
       uint32_t RESERVED0[24];                                   
  __IO uint32_t ICER[8];                      /*!< Offset: 0x080  Interrupt Clear Enable Register         */
       uint32_t RSERVED1[24];                                    
  __IO uint32_t ISPR[8];                      /*!< Offset: 0x100  Interrupt Set Pending Register          */
       uint32_t RESERVED2[24];                                   
  __IO uint32_t ICPR[8];                      /*!< Offset: 0x180  Interrupt Clear Pending Register        */
       uint32_t RESERVED3[24];                                   
  __IO uint32_t IABR[8];                      /*!< Offset: 0x200  Interrupt Active bit Register           */
       uint32_t RESERVED4[56];                                   
  __IO uint8_t  IP[240];                      /*!< Offset: 0x300  Interrupt Priority Register (8Bit wide) */
       uint32_t RESERVED5[644];                                  
  __O  uint32_t STIR;                         /*!< Offset: 0xE00  Software Trigger Interrupt Register     */
}  NVIC_Type;                                               
/*@}*/ /* end of group CMSIS_CM3_NVIC */
復制代碼

NVIC基址 

#define SCS_BASE            (0xE000E000)                              /*!< System Control Space Base Address */
#define NVIC_BASE           (SCS_BASE +  0x0100)                      /*!< NVIC Base Address                 */
#define SCB_BASE            (SCS_BASE +  0x0D00)                      /*!< System Control Block Base Address */


#define NVIC                ((NVIC_Type *)          NVIC_BASE)        /*!< NVIC configuration struct         */

 

NVIC_Init()這個函數:

復制代碼
/**
  * @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);
  }
}
復制代碼

可以看到,它會去設置幾個寄存器:NVIC的IP,ISER,ICER等等,

 

 

STM32 學習:IAP 簡單的IAP例子

 

 

stm32中關於NVIC_SetVectorTable函數使用的疑惑與理解

 


免責聲明!

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



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