FREERTOS—Cortex_NVIC詳解

NVIC

NVIC是中斷控制器, 共支持 1 至 240 個外部中斷輸入(通常外部中斷寫作 IRQs)。 具體的數值由芯片廠商在設計芯片時決定。此外,NVIC 還支持一個不可屏蔽中斷(NMI)輸入。NMI 的實際功能亦由芯片製造商決定。在某些情況下, NMI 無法由外部中斷源控制。NVIC 的訪問地址是 0xE000_E000
即:NVIC支持的外部中斷數值在1 - 240之間,有一個無法被軟件禁止的不可屏蔽中斷“NMI”,NMI 的實際功能由芯片製造商決定,NVIC 的訪問地址是 0xE000_E000

異常:編號爲 1-15 的對應系統異常大於等於 16 的則全是外部中斷。除了個別異常的優先級被定死外, 其它異常的優先級都是可編程的

系統異常列表
在這裏插入圖片描述
在啓動文件中的對應
在這裏插入圖片描述

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;      

#define SCS_BASE            (0xE000E000) 
#define NVIC                ((NVIC_Type *)          NVIC_BASE)
#define NVIC_BASE           (SCS_BASE +  0x0100)

由此得到 NVIC 的地址 = 0xE000E100,NVIC是一個NVIC_Type類型的指針
CM3 中可以有 240 對使能位/除能位,每個中斷擁有一對。這 240 個對子分佈在 8 對 32 位寄存器中(最後一對沒有用完)。欲使能一箇中斷,你需要寫 1 到對應 SETENA 的位中;欲除能一箇中斷,你需要寫 1 到對應的 CLRENA 位中;如果往它們中寫 0,不會有任何效果
在這裏插入圖片描述
由此可見:配置NVIC->ISER[0] 到 NVIC->ISER[8]寄存器可以使能中斷
ISER 到 ICER偏移了 0X80 個地址,計算方法 (24 + 8) x 4 = 128 = 0X80;爲什麼 x 4,因爲每一個地址只能存放 8 bit 的數據,u32 要佔用 4 個地址空間

**NVIC->IP:優先級配置寄存器,**因爲IP是u8型數據,所以最多支持256級的主優先級,支持最多128級子優先級,由於芯片精簡設計可能設置IP的高4位爲搶佔,低4位爲子優先級

PendSV(0XE000 ED22,系統異常14),SysTick(0XE000 ED23,系統異常14),優先級設置,要將這兩個優先級設置爲最低優先級
STM32中將 0 - 15 共16個系統異常,分組成 4 組,每4個一組,所以將最後四個分在一個組freeRTOS設置PendSV,SysTick優先級的函數包含在在port.c文件中 xPortStartScheduler(void);//開啓任務調度器

/* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
#define portNVIC_SYSPRI2_REG				( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
#define portNVIC_PENDSV_PRI					( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI				( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )

#ifdef __NVIC_PRIO_BITS
	#define configPRIO_BITS       		__NVIC_PRIO_BITS
#else
	#define configPRIO_BITS       		4                  
#endif
//此處就是定義使用了幾位作爲主優先級

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			15                      //中斷最低優先級
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5                       //可管理的最高優先級
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
首先將0xe000ed20轉爲指向u32地址,再加*,就是指向0xe000ed20這個地址,0xe000ed20中存放的是u32的數據

中斷屏蔽寄存器
PRIMASK:可關閉或者打開除NMI和fault之外的所有中斷,代碼如下

在這裏插入圖片描述
FAULTMASK:它把當前優先級改爲‐1。這麼一來,連硬fault都被掩蔽了。使用方案與PRIMASK的相似。但要注意的是, FAULTMASK會在異常退出時自動清零。
BASEPRI
更精巧的設計中,需要對中斷掩蔽進行更細膩的控制——只掩蔽優先級低於某一閾值的中斷——它們的優先級在數字上大於等於某個數。那麼這個數存儲在哪裏?就存儲在BASEPRI中。不過,如果往BASEPRI中寫0,則另當別論——BASEPRI將停止掩蔽任何中斷。例如,如果你需要掩蔽所有優先級不高於0x60的中斷,則可以如下編程:
MOV R0, #0x60
MSR BASEPRI, R0
如果需要取消 BASEPRI 對中斷的掩蔽,則示例代碼如下:
MOV R0, #0
MSR BASEPRI, R0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章