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