STM32之中断
在STM32(Cortex-M3)中没有显示的代码拷贝,只有启动代码进行了向量的初始化,一直以为是编译器在程序影像中自己完成了相关向量的拷贝,即,拷贝到固定的NVIC区,事实上并不是这样,cortex-m3并没有一块专门用于存放NVIC向量表的地方,这张表实际是存放在代码(程序映像)的开始,下面引用cortex-M3权威指南进行解释:
当发生了异常并且要响应它时,CM3需要定位其服务例程的入口地址。这些入口地址存储在所谓的“(异常)向量表”中。缺省情况下,CM3认为该表位于零地址处,且各向量占用4字节。因此每个表项占用4字节,如表7.6所示。
因为地址0处应该存储引导代码,所以它通常映射到Flash或者是ROM器件,并且它们的值不得在运行时改变。然而,为了支持动态重分发中断,CM3允许向量表重定位——从其它地址处开始定位各异常向量。这些地址对应的区域可以是代码区,但更多是在RAM区。在RAM区就可以修改向量的入口地址了。为了实现这个功能,NVIC中有一个寄存器,称为“向量表偏移量寄存器”(在地址0xE000_ED08处),通过修改它的值就能重定位向量表。但必须注意的是:向量表的起始地址是有要求的:必须先求出系统中共有多少个向量,再把这个数字向上“圆整”到2的整次幂,而起始地址必须对齐到后者的边界上。例如,如果一共有32个中断,则共有32+16(系统异常)=48个向量,向上圆整到2的整次幂后值为64,因此向量表重定位的地址必须能被64*4=256整除,从而合法的起始地址可以是:0x0, 0x100, 0x200等。向量表偏移量寄存器的定义如表7.7所示。
如果需要动态地更改向量表,则对于任何器件来说,向量表的起始处都必须包含以下向量:
主堆栈指针(MSP)的初始值
复位向量
NMI
硬fault服务例程
后两者也是必需的,因为有可能在引导过程中发生这两种异常。
可以在SRAM中开出一块空间用于存储向量表。在引导期间先填写好各向量,然后在引导完成后,就可以启用内存中的新向量表,从而实现向量可动态调整的能力。
向量表其实是一个word(32位)型数组,其中每一项代表一种异常的起始地址,当有异常发生时,相应的异常处理函数将被执行。向量表是可以重定位的,重定位由NVIC来控制。复位时,重定位控制寄存器初始值为0,所以在复位时,向量表必须存放在0地址处。向量表定义如下:
复位时序:
当处理器复位之后,会从存储器中读取两个word的数据。地址0x00000000数据为SP(栈寄存器)初始值,地址0x00000004数据为程序的起始地址,也就是说复位之后,程序将从该处开始执行。例如:
1、NVIC
Nested vectored interrupt controller :可嵌套向量中断控制器 (NVIC)
NVIC 特性
82个可屏蔽中断 ##不包括内核的16个中断 16个可编程优先级 ##适用于全部中断 低延迟异常和中断处理 电源管理控制 系统控制寄存器的实现
NVIC与处理器内核接口紧密耦合, 实现了高效快速的中断响应。所有的中断,包括内核异常都被 NVIC 所管理.
2、中断向量表
其实中断向量表在**STM32F4XX**启动文件里面就可以看出来,详情可看 :[STM32F4XX启动文件分析](https://blog.csdn.net/u013904227/article/details/51168546)
3、EXTI(External interrupt/event controller) 外部中断/事件控制器
主要特性
在每个中断/事件线都有独立的触发和屏蔽功能 每个中断线有专用的状态标志位 可产生高达 23 个软件事件/中断请求 以比APB2时钟周期更短的脉冲宽度检测外部信号
中断与事件配置
硬件中断选择
配置23线为中断源可参考以下配置步骤 :
配置 23 中断线的屏蔽位 (EXTI_IMR) 配置中断线的触发选择位 (EXTI_RTSR and EXTI_FTSR) 配置控制 NVIC IRQ 通道的使能与屏蔽位来使来自 23 线的一个中断可以被正确的应答,NVIC IRQ 被映射到外部中断控制器(EXTI)
硬件事件选择
配置23线为事件源可参考以下配置步骤 :
配置 23 事件线的屏蔽位 (EXTI_EMR) 配置事件线的触发选择位 (EXTI_RTSR and EXTI_FTSR)
软件 中断/事件 选择
23 线可以被配置为软件 中断/事件 线。下面的操作步骤可以产生一个软件中断.
配置 23 事件/中断 线的屏蔽位 (EXTI_IMR, EXTI_EMR) 设置软件中断寄存器的应答位 (EXTI_SWIER)
外部 中断/事件 映射
STM32F407ZG 的 140 个 GPIO 引脚都与一个外部中断线相连,具体如图所示:
上述一共用到了16根 EXTI 线,其余 7 根 EXTI 线的连接使用如下:
EXTI 16 连接到 PVD 输出(PVD:掉电检测) EXTI 17 连接到 RTC Alarm 事件 EXTI 18 连接到 USB OTG FS Wakeup 事件 EXTI 19 连接到 Ethernet Wakeup 事件 EXTI 20 连接到 USB OTG HS (configured in FS) Wakeup 事件 EXTI 21 连接到 RTC Tamper and TimeStamp 事件 EXTI 22 连接到 RTC Wakeup 事件
中断与事件的区别
一个硬件中断/事件的产生:
input line 输入外部信号 边缘检测电路检测电平变化(电平变化检测可以人为配置,并且上升沿检测与下降沿检测是独立的) 经过一个或门,此或门连接电平检测电路的输出与软件事件/中断寄存器。也因此任意一条线的值为真,那么输出就为真,所以可以产生软触发中断或者事件 或门输入信号分别经过两个与门,另个与门分别再与中断屏蔽寄存器与事件屏蔽寄存器连接,控制中断或者事件的产生。这两个也是独立的,所以可以同时产生中断以及事件 如果是中断的话,输出信号会再经过中断挂起请求寄存器,如果此时芯片正处于不可被中断打断的时候,可以配置中断挂起寄存器来暂时挂起一个中断。需要软件参与 如果是事件的话,输出信号直接输出到一个脉冲发生器里面,脉冲发生器可以产生一个脉冲,调动相应的硬件完成此次事件响应。无需软件参与
DMA传输的例子:<喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxibG9ja3F1b3RlPg0KCcjnufvF5NbDzqrW0LbPtcS7sKOs0OjSqtTa1tC2z7L6yfrWrrrzo6y9+Mjr1tC2z7SmwO26r8r9o6zU2tbQts+0psDtuq/K/dbQtKW3okRNQbLZ1/ejrMi7uvO9+NDQRE1BoaMgyOe5+8Xk1sPOqsrCvP61xLuwo6zWsb3T08nKwrz+1+7W1crks/bC9rPlwLS0pbeiRE1BstnX96OssrvQ6NKqvq25/dbQts+0psDtuq/K/b340NBETUG1xLSlt6KhozwvYmxvY2txdW90ZT4NCjxwPsrCvP6/ydLUvbW1zUNQVbXEuLq6yaOszOG438HLz+zTpsvZtsg8L3A+DQo8aDEgaWQ9"4内核最重要的两个模块scbsystem-controller-block-nvicnested-vectored-interrupt-controller">4、内核最重要的两个模块(SCB:System controller block NVIC:Nested vectored interrupt controller)
内核的外设
SCB
地址 | 寄存器名 | 读写权限 | 特权 | 复位值 | 作用描述 |
---|---|---|---|---|---|
0xE000E008 | ACTLR | RW | Privileged | 0x00000000 | 辅助控制寄存器 |
0xE000ED00 | CPUID | RO | Privileged | 0x410FC240 | CPU的ID号码 |
0xE000ED04 | ICSR | RW | Privileged | 0x00000000 | 中断控制与状态寄存器 |
0xE000ED08 | VTOR | RW | Privileged | 0x00000000 | 中断向量表偏移,一般只取两个值,第29位为1表示SRAM区,为0表示code区 |
0xE000ED0C | AIRCR | RW | Privileged | 0xFA050000 | 应用程序中断以及复位 |
0xE000ED10 | SCR | RW | Privileged | 0x00000000 | 系统控制 |
0xE000ED14 | CCR | RW | Privileged | 0x00000200 | 配置与控制 |
0xE000ED18 | SHPR1 | RW | Privileged | 0x00000000 | 系统中断处理函数优先级寄存器1 |
0xE000ED1C | SHPR2 | RW | Privileged | 0x00000000 | 系统中断处理函数优先级寄存器2 |
0xE000ED20 | SHPR3 | RW | Privileged | 0x00000000 | 系统中断处理函数优先级寄存器3 |
0xE000ED24 | SHCRS | RW | Privileged | 0x00000000 | 系统中断处理函数控制与状态 |
0xE000ED28 | CFSR | RW | Privileged | 0x00000000 | 配置异常状态寄存器 |
0xE000ED28 | MMSRb | RW | Privileged | 0x00 | 内存管理异常状态寄存器 |
0xE000ED29 | BFSRb | RW | Privileged | 0x00 | 总线异常状态寄存器 |
0xE000ED2A | UFSRb | RW | Privileged | 0x0000 | 使用异常状态寄存器 |
0xE000ED2C | HFSR | RW | Privileged | 0x00000000 | 硬件异常状态寄存器 |
0xE000ED34 | MMAR | RW | Privileged | Unknown | 内存管理异常地址寄存器 |
0xE000ED38 | BFAR | RW | Privileged | Unknown | 总线异常地址寄存器 |
0xE000ED3C | AFSR | RW | Privileged | 0x00000000 | 辅助异常状态寄存器 |
NVIC
地址 | 寄存器名 | 读写权限 | 特权 | 复位值 | 作用描述 |
---|---|---|---|---|---|
0xE000E100-0xE000E11C | NVIC_ISER0-NVIC_ISER7 | RW | Privileged | 0x00000000 | 中断使能 |
0XE000E180-0xE000E19C | NVIC_ICER0-NVIC_ICER7 | RW | Privileged | 0x00000000 | 中断禁止 |
0XE000E200-0xE000E21C | NVIC_ISPR0-NVIC_ISPR7 | RW | Privileged | 0x00000000 | 中断挂起 |
0XE000E280-0xE000E29C | NVIC_ICPR0-NVIC_ICPR7 | RW | Privileged | 0x00000000 | 中断恢复 |
0xE000E300-0xE000E31C | NVIC_IABR0-NVIC_IABR7 | RW | Privileged | 0x00000000 | 中断激活 |
0xE000E400-0xE000E4EF | NVIC_IPR0-NVIC_IPR59 | RW | Privileged | 0x00000000 | 中断优先级 |
0xE000EF00 | STIR | WO | Configurable | 0x00000000 | 软件触发中断 |
5、优先级分组的概念
Cortex M4 的优先级分组如下图所示
内核优先级的分组:
要注意的是,在 STM32F407ZG 只使用了 4bits 的位(高4位),也就是说分组情况如下
STM32组编号 | PRIGROUP | Binary point | Group priority bits | Subpriority bits | Group priorities | subpriorities |
---|---|---|---|---|---|---|
0 | 0b111 | b.yyyyyyyy | none | [7:4] | 1 | 16 |
1 | 0b110 | bx.yyyyyyy | [7] | [6:4] | 2 | 8 |
2 | 0b101 | bxx.yyyyyy | [7:6] | [5:4] | 4 | 4 |
3 | 0b100 | bxxx.yyyyy | [7:5] | [4] | 8 | 2 |
4 | 0b011 | bxxxx.yyyy | [7:4] | none | 16 | 1 |
在STM32中组编号恰好与内核手册中的是反的,这样设计的原因是为了兼容性,也就是说如果程序移植到了只支持3位优先级设置的系统中也能够运行。另外有三种设计方式分别是:使用高 4bits,组编号不反转;使用低 4bits,组编号不反转;使用低 4bits,组编号反转。这三种方法如果按照内核分组写出来之后会发现会有优先级完全一样的情况出现,所以不可取。
要了解优先级分组,就要明确两个概念:抢占优先级(组优先级)、响应优先级(子优先级)
抢占优先级:可以被中断嵌套。也就是在一个中断发生的时候,另一个抢占优先级比此中断级别高的中断可以打断正在进行的中断,直到更高优先级的中断执行完毕之后,才会返回来继续执行这个被打断的中断 响应优先级:不可以被中断嵌套。也就是说在多个中断同时发生的时候,只能够优先相应较高优先级的中断,并且如果在中断过程中有更高优先级中断发生的时候,正在进行的中断也不能够被打断。
抢占优先级与响应优先级的关系有点像 TCP/IP 协议中的网络号与子网号的区别,两个中断也是先比较抢占优先级然后才是比较响应优先级
6、程序编写
- <code class="hljs cs">#define SUM_NVIC_PRIOTITY_BITS 4 //一共用了4个位
- /* 中断优先级分组
- * group_num : 分组号,上面有列出各个分组对应的优先级
- */
- static void set_priority_group(u8 group_num)
- {
- u32 temp = , temp1 = ;
- group_num = group_num % (SUM_NVIC_PRIOTITY_BITS + ); //因为只有5个组,所以限制数量
- temp1 = (((~group_num) & 0x07) << ); //取反区低三位
- temp = SCB->AIRCR;
- temp &= 0x0000F8FF; //清除8-10位
- temp |= 0x05FA0000; //必须写5FA位,是作为钥匙的作用,不写的话写入的分组是无效的
- temp |= temp1;
- SCB->AIRCR = temp;
- }
- /* 设置优先级分组
- * g_priority :抢占优先级 sub_priority :响应优先级
- * irq_num :中断号 prioritygroup :优先级组
- */
- void NVIC_set_priority(u8 g_priority, u8 sub_priority, IRQn_Type irq_num, u8 prioritygroup)
- {
- int32_t sub_priority_bits = ;
- sub_priority_bits = SUM_NVIC_PRIOTITY_BITS - prioritygroup;
- ASSERT(sub_priority_bits >= ); //断言,如果小于0就报错
- /* 原型
- #define ASSERT(x) while(!(x)){ \
- printf("Assert failed!!! File:%s Function:%s Line:%d\r\n", __FILE__, __FUNCTION__, __LINE__); \
- delay_ms(1000); \
- }
- */
- set_priority_group(prioritygroup); //设置优先级分组
- /* 参考内核头文件写的 */
- if(irq_num < ) //要判断是否小于0原因是:内核头文件中把内核的中断设置为小于0的枚举类型,而其他的都是大于0的,参照内核头文件
- {
- /* 根据内核头文件中的 SCB 结构体对应内核手册部分推算 */
- SCB->SHP[((uint32_t)(irq_num) & 0xF)-] = ((g_priority << sub_priority_bits) | sub_priority) << ( - SUM_NVIC_PRIOTITY_BITS);
- }
- else
- {
- NVIC->IP[(uint32_t)(irq_num)] = ((g_priority << sub_priority_bits) | sub_priority) << ( - SUM_NVIC_PRIOTITY_BITS);
- }
- }
- /* 使能相应的中断,为必须的 */
- void NVIC_enable_irq(IRQn_Type irq)
- {
- NVIC->ISER[(uint32_t)((int32_t)irq) >> ] |= (uint32_t)( << ((uint32_t)((int32_t)irq) % ));
- }
- void EX_irq_config(GPIOx_SELECT gpiox,GPIOx_pn_SELECT gpiox_n,GPIO_IRQ_TRIGGER trigger)
- {
- RCC->APB2ENR |= ( << ); //使能SYSCFG模块,只有使能之后对SYSCFG寄存器的设置才会有效
- gpio_init(gpiox, gpiox_n, BYM_PULL_UP, BYM_GPI, BYM_HIGH_LEVEL, BYM_PUSH_PULL); //初始化GPIO为输入,内部上拉
- SYSCFG->EXTICR[gpiox_n/] &= ~(0xF << ((gpiox_n % ) * )); //
- SYSCFG->EXTICR[gpiox_n/] |= (gpiox << ((gpiox_n % ) * ));//映射 Px_n 到 EXTIn中断线
- EXTI->IMR |= ( << gpiox_n); //解除屏蔽
- EXTI->RTSR |= ((trigger & 0x01) << gpiox_n); //设置触发沿
- EXTI->FTSR |= ((trigger >> ) << gpiox_n);
- }
- /* 只支持外部中断的中断标志清除 */
- void EX_irq_clear(u8 irq)
- {
- EXTI->PR |= ( << irq);
- }</code>
7、测试
测试抢占优先级不同的情况
主程序
- <code class="hljs perl">NVIC_set_priority(, , EXTI3_IRQn, );
- NVIC_set_priority(, , EXTI2_IRQn, );
- EX_irq_config(BYM_GPIOE, BYM_Px3, IRQ_BOTHEDGE);
- EX_irq_config(BYM_GPIOE, BYM_Px2, IRQ_BOTHEDGE);
- NVIC_enable_irq(EXTI3_IRQn);
- NVIC_enable_irq(EXTI2_IRQn);</code>
中断服务程序
- <code class="hljs scss">void EXTI3_IRQHandler(void)
- {
- if( == gpio_get(BYM_GPIOE, BYM_Px3))
- {
- printf("Key 1 down \r\n");
- delay_ms();
- printf("Key 1 end \r\n");
- }
- EX_irq_clear();
- }
- void EXTI2_IRQHandler(void)
- {
- if( == gpio_get(BYM_GPIOE, BYM_Px2))
- {
- printf("Key 2 down \r\n");
- delay_ms();
- printf("Key 2 end \r\n");
- }
- EX_irq_clear();
- }</code>
先按下 GPE3(对应EXTI3),立马按下 GPE2(对应EXTI2),有下面的输出结果(不会被打断)
1
2
|
Key 1 down Key 1 end |
先按下 GPE2(对应EXTI2),立马按下 GPE3(对应EXTI3),有下面的输出结果(EXTI2的中断被EXTI3打断了)
1
2
3
4
|
Key 2 down Key 1 down Key 2 end Key 1 end |
测试抢占优先级相同而响应优先级不同的情况
主程序改变如下
1
2
3
4
5
6
|
<code class = "hljs perl" >NVIC_set_priority( 1 , 2 , EXTI3_IRQn, 2 ); NVIC_set_priority( 1 , 1 , EXTI2_IRQn, 2 ); EX_irq_config(BYM_GPIOE, BYM_Px3, IRQ_BOTHEDGE); EX_irq_config(BYM_GPIOE, BYM_Px2, IRQ_BOTHEDGE); NVIC_enable_irq(EXTI3_IRQn); NVIC_enable_irq(EXTI2_IRQn);</code> |
先按下 GPE3(对应EXTI3),立马按下 GPE2(对应EXTI2),有下面的输出结果(不会被打断)
1
2
|
Key 1 down Key 1 end |
先按下 GPE2(对应EXTI2),立马按下 GPE3(对应EXTI3),有下面的输出结果(不会被打断)
1
2
|
Key 2 down Key 2 end |
8、程序编写思路
设置优先级分组,使用 SCB 的 AIRCR 寄存器(重要的是写入钥匙,5FA) 具体规划分组内部抢占与响应优先级,如果中断是内核的,使用 SCB 3. 控制模块,如果是外部的,使用 NVIC 模块 使能 SYSCFG 模块时钟,映射相应的中断线,如果是IO口中断还要设置跳变沿以及初始化IO管脚 解除中断或者事件屏蔽(EXTI寄存器) NVIC使能相应的中断 编写中断服务程序
STM32之中断的更多相关文章
- (二)stm32之中断配置
一.stm32的中断和异常 Cortex拥有强大的异常响应系统,它能够打断当前代码执行流程事件分为异常和中断,它们用一个表管理起来,编号为0~15为内核异常,16以上的为外部中断,这个表就是中断向量表 ...
- 转载:STM32之中断与事件---中断与事件的区别
这张图是一条外部中断线或外部事件线的示意图,图中信号线上划有一条斜线,旁边标志19字样的注释,表示这样的线路共有19套.图中的蓝色虚线箭头,标出了外部中断信号的传输路径,首先外部信号从编号1的芯片管脚 ...
- STM32外部中断具体解释
一.基本概念 ARM Coetex-M3内核共支持256个中断,当中16个内部中断,240个外部中断和可编程的256级中断优先级的设置.STM32眼下支持的中断共84个(16个内部+68个外部), ...
- STM32之中断与事件---中断与事件的区别
STM32之中断与事件---中断与事件的区别 http://blog.csdn.net/flydream0/article/details/8208463 这张图是一条外部中断线或外部事件线的示意图 ...
- stm32之中断配置
一.stm32的中断和异常 Cortex拥有强大的异常响应系统,它能够打断当前代码执行流程事件分为异常和中断,它们用一个表管理起来,编号为0~15为内核异常,16以上的为外部中断,这个表就是中断向量表 ...
- STM32的中断系统
STM32的中断系统 STM32具有十分强大的中断系统,将中断分为了两个类型:内核异常和外部中断.并将所有中断通过一个表编排起来,下面是stm32中断向量表的部分内容: 上图-3到6这个区域被标黑了, ...
- stm32定时器中断类型分析
一直在用的stm32定时器的中断都是TIM_IT_Update更新中断,也没问为什么,直到碰到有人使用TIM_IT_CC1中断,才想到这定时器的中断类型究竟有什么区别,都怪当时学习stm32的时候不够 ...
- 转别人的 STM32外部中断使用注意事项
前言:这些问题都是我之前在工作中遇到的,后来觉得需要总结,自己记忆不好,所以在这个给自己打个mark. 一:触发方式 STM32 的外部中断是通过边沿来触发的,不支持电平触发: 二:外部中断分组 ST ...
- STM32外部中断初理解
PA0,PB0...PG0--->EXTI0 PA1,PB1...PG1--->EXTI1 ....... PA15,PB15...PG15--->EXTI15 以上为GPIO和中断 ...
- stm32之中断系统
概述: 提供中断控制器,用于总体管理异常,称之为“嵌套向量中断控制器:Nested Vectored Interrupt Controller (NVIC) VIC:中断管理器: NVIC:内嵌中断管 ...
随机推荐
- laravel中上传图片之后图片的处理
$file=Input::file('file'); if ($file->isValid()){ $entension=$file->getClientOriginalExtension ...
- PHP 中使用explode()函数切割字符串为数组
explode()函数的作用:使用一个字符串分割另一个字符串,打散为数组. 例如: 字符串 $pizza = "第1 第2 第3 第4 第5 第6"; 根据空格分割后:$piece ...
- APUE学习笔记——5缓冲Buffering、流、文件对象
缓冲的几个基本概念 缓冲的作用:减少系统read和write的次数. 全缓冲 系统标准I/O缓冲区被写满时才进行真正的I/O操作. 磁盘文件一般使用全缓冲 ...
- 剑指offer--48.机器人的运动范围
这道题不是要求走一趟最多走多少,而是最多走多少,WA几次才想通. ------------------------------------------------------------------- ...
- linux配置PHP环境!!(云服务器架设)
首先去阿里云或腾讯云购买主机(腾讯云现在有免费30天的云主机...) 购买好之后选择安装: 点登陆 就可以到linux的操作界面了 进入操作界面 输入root账号密码取得权限之后就可以开始配置环境了 ...
- @Qualifier注解详解
@Qualifier注解意味着可以在被标注bean的字段上可以自动装配.Qualifier注解可以用来取消Spring不能取消的bean应用. 下面的示例将会在Customer的person属性中自动 ...
- VS2010 快捷键 (空格显示 绿点, Tab 显示箭头)
转自http://www.cnblogs.com/xiaoyusmile/archive/2012/06/27/2566049.html VS2010 有用的快捷键 : Ctrl + r, ctrl ...
- .net MVC3 架构搭建描述
用visual studio创建.net MVC3 web项目时,默认情况下是将Views,Controllers,Models创建在一个项目中. 需要把Controllers和Models做为两个独 ...
- 几种常见的微服务架构方案——ZeroC IceGrid、Spring Cloud、基于消息队列、Docker Swarm
微服务架构是当前很热门的一个概念,它不是凭空产生的,是技术发展的必然结果.虽然微服务架构没有公认的技术标准和规范草案,但业界已经有一些很有影响力的开源微服务架构平台,架构师可以根据公司的技术实力并结合 ...
- Java8安装配置
方法1.命令行安装 -jdk 存在多个版本,自动配置: sudo update-alternatives --config java 方法2.下载安装 下载java8的jdk http://www.o ...