向量中断控制器
向量的意思是有值有方向。向量中断的意思是,发生中断后按照指定的地址值跳转到中断服务函数执行(默认stm32f4xx_it)。
中断控制器顾名思义,控制中断
向量
中断向量表
在一张表上记录各种中断和它的中断处理函数跳转地址。
有点像一本书的目录,ARM 把目录设计好,发生中断的时候跳转到什么地方执行什么样的处理,由开发者设计。
所以在Cortex M3内核设计阶段,这张表就已经确定下来,它有一个默认的位置。
按照顺序逐一排序。
当中断或者异常发生的时候,硬件就会自动的跳转到对应的地址上,然后取出跳转地址。这些都是硬件动作。
这部分的初始化动作,一般是放在处理器s文件上startup code
列举一下s文件的向量标初始化动作
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD WWDG_IRQHandler ; Window Watchdog
DCD PVD_IRQHandler ; PVD through EXTI Line detect
DCD TAMPER_IRQHandler ; Tamper
DCD RTC_IRQHandler ; RTC
DCD FLASH_IRQHandler ; Flash
DCD RCC_IRQHandler ; RCC
DCD EXTI0_IRQHandler ; EXTI Line 0
DCD EXTI1_IRQHandler ; EXTI Line 1
DCD EXTI2_IRQHandler ; EXTI Line 2
这里已经定义好中断函数的函数名称,也就是入口。
这是默认的向量地址,cortexM3提供了一个向量偏移寄存器。就是说除了默认的向量表可用还可以自己去编辑。
移寄存器 就是这套新表的首地址。
使能,除能
每一个中断对应一个使能位
挂起,pend
如果中断发生时,正在处理同级或高优先级异常,或者被掩蔽,则中断不能立即得到响
应。此时中断被悬起。中断的悬起状态可以通过“中断设置悬起寄存器(SETPEND)”和“中
断悬起清除寄存器(CLRPEND)”来读取,还可以写它们来手工悬起中断。
优先级
没有什么好说的,8Bit变成3BIt的高低对齐
活动
每个外部中断都有一个活动状态位。在处理器执行了其 ISR 的第一条指令后,它的活动
位就被置 1,并且直到 ISR 返回时才硬件清零。由于支持嵌套,允许高优先级异常抢占某个
ISR。然而,哪怕一个中断被抢占,其活动状态也依然为 1
core_CM3.h
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;
NVIC结构体和NVIC寄存器对应。
typedef struct
{
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
This parameter can be an enumerator of @ref IRQn_Type
enumeration (For the complete STM32 Devices IRQ Channels
list, please refer to stm32f4xx.h file) */
uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
specified in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
A lower priority value indicates a higher priority */
uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
A lower priority value indicates a higher priority */
FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
will be enabled or disabled.
This parameter can be set either to ENABLE or DISABLE */
} NVIC_InitTypeDef;
NVIC配置结构体
NVIC_IRQChannel 也就是中断向量索引,代表需要去配置哪个中断
Priority有抢占优先级,和子优先级
NVIC_IRQChannelCmd ENABLE/DISABLE
外部事件管理器
输入线一般是GPIO,经过边沿检测可以探知输入线发生了变化,可以是上边沿检测也可以是下边沿检测。
软件中断事件寄存器和检测边沿的信号取或运算,说明软件中断可以和外部电平变化一样产生事件源。
脉冲发生器的作用是探知事件,他的输出作为MCU的内部信号可以链接到其他模块上。事件源通过中断屏蔽寄存器,挂起
请求寄存器输入到NVIC中,产生中断请求
对应的中断为EXTI系列
EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */
EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */
EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */
EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */
EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */
EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts
EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts
所有的外部事件,只能通过上面的中断索引得到相应。
GPIOx 对应EXTIx (x = 1,2,3…15)
另外七根 EXTI 线连接方式如下:
● EXTI 线 16 连接到 PVD 输出
● EXTI 线 17 连接到 RTC 闹钟事件
● EXTI 线 18 连接到 USB OTG FS 唤醒事件
● EXTI 线 19 连接到以太网唤醒事件
● EXTI 线 20 连接到 USB OTG HS(在 FS 中配置)唤醒事件
● EXTI 线 21 连接到 RTC 入侵和时间戳事件
● EXTI 线 22 连接到 RTC 唤醒事件
所以GPIOx是固定链接到EXTIx上。
需要配置GPIOyx y= A,B,C… x= 1,2,3…
也就是说要明确是哪组的GPIO链接到了EXTI line上。
例如EXTI15 ,是PC15还是PD15还是Px15接着
EXTI Line
接着配置边沿检测,和通路选择,是中断还是产生脉冲
以PE1 为例
所谓配置就是打通这条路 。
void EXTI_config(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
/* Configure PE2 pin as input floating */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/* Connect EXTI Line0 to PE2 pin */
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);
/* Configure EXTI Line2 */
EXTI_InitStructure.EXTI_Line = EXTI_Line2;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* Enable and set EXTI Line2 Interrupt to the lowest priority */
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
请求中断悬起寄存器的代表Input Line信号已经发生事件,如果INterrupt MASK也是1 的话,那么这路信号就会进入NVIC
通过这个办法可以判断具体是哪一路信号发生悬起。