[017] [ARM-Cortex-M3/4] 中断的硬件框架

ARM
Contents
中断硬件框架
中断路径上的3个部件
中断状态
STM32F103的GPIO中断..
STM32MP157的GPIO中断...
IMX6ULL的GPIO中断..
GPIO中断编程.
GPIO配置
EXTI配置
NVIC配置
CPU配置
EXTI9_5中断服务例程

1 中断硬件框架

1.1 中断路径上的3个部件

  • 中断源
    • 引脚映射的外设,如GPIO/UART/DMA/TIMER等
    • 触发方式,如GPIO可以配置上升沿、下降沿等方式触发
    • 触发控制:使能中断、中断状态、中断类型等
  • 中断控制器
    • 各中断源发出的中断信号,汇聚到中断控制器
    • 可设置各中断优先级、使能/失能中断等操作
    • 中断控制器向CPU发送中断信号,CPU通过读取中断控制器的寄存器,判断当前处理的是哪个中断
    • 中断控制器有多种实现,比如:
      • STM32F103中被称为NVIC:Nested vectored interrupt controller(嵌套向量中断控制器)
      • ARM9中一般是芯片厂家自己实现的,没有统一标准
      • Cortex A7中使用GIC(Generic Interrupt Controller)
  • CPU
    • 每执行完一条指令,都会去判断是否有中断发生
    • 通过内部中断屏蔽寄存器组(primask、faultmask、basepri),可以设置它来使能/禁止中断(总开关)

image-20220321172502101

1.2 中断状态

中断可以有多种状态:

① 非活动状态(Inactive)–这意味着该中断未触发,或触发了但CPU并未去处理
② 挂起(Pending)–这意味着中断源已被触发,但正在等待CPU核处理。待处理的中断要通过转发到CPU接口单元,然后再由CPU接口单元转发到内核。
③ 活动(Active)–描述了一个已被内核接收并正在处理的中断。
④ 活动和挂起(Active and pending)–描述了一种情况,其中CPU核正在为中断服务,而 NVIC/GIC又收到来自同一源的中断。(ISR返回时活动状态才会被硬件清除)

1.3 STM32F103的GPIO中断

ST芯片每组引脚(PAx、PBx、PCx…)中同一时刻只有一个能触发外部中断,而NXP芯片每个引脚都可以触发外部中断

  • EXIT开关1:外部中断能否发送给NVIC
  • NVIC开关2:此中断能否发给CPU
  • CPU开关3:是否处理中断

image-20220321175123310

1.3.1 GPIO控制器

STM32F103的GPIO控制器中AFIO_EXTICR1~AFIO_EXTICR4寄存器(AFIO寄存器属于GPIO外设)选择外部中断(EXTI)的输入源:

image-20220321194653633

EXTI可以给NVIC提供16个中断信号:EXTI0~EXTI15

image-20220321175733720

GPIO引脚只有一个引脚可用于触发外部中断。

1.3.2 EXTI

在GPIO控制器中,可以设置某个GPIO引脚作为中断源,给EXTI提供中断信号,其触发方式及使能可用通过EXTI配置,NVIC硬件框图:

image-20220321195439435

  • EXTI线16连接到PVD输出
  • EXTI线17连接到RTC闹钟事件
  • EXTI线18连接到USB唤醒事件
  • EXTI线19连接到以太网唤醒事件(只适用于互联型产品)

产生中断请求,我们要设置:

  • Falling trigger selection register:是否选择下降沿触发
  • Rising trigger selection register:是否选择上升沿触发
  • Interrupt mask register:是否屏蔽中断(屏蔽事件用Event mask register)

当发生中断时,可以读取下列寄存器判断是否发生了中断、发生了哪个中断:

  • Pending reqeust register

注意:同一中断线上,可同时设置上升沿和下降沿触发。同时必须要清除pend位,否则会一直发起中断请求(硬件框图也可以看出来)

产生软件中断/事件可通过Software interrupt event register配置,向相应位写1即会触发相应EXTI线上的中断/事件。

1.3.3 NVIC

多个中断源汇聚到NVIC,NVIC从多个中断源中取出优先级最高的中断,向CPU发出中断信号。

image-20220321201916902

至多240个中断,从异常向量表第16项开始,因此:ISER(中断设置使能寄存器)、ICPR(中断清除挂起寄存器)等寄存器共8对(8*32=256,多余位保留)。

一般需要设置:

  • 优先级分组(默认0)
  • 中断源的优先级(默认0)
  • 使能中断源(默认失能)

1.3.4 CPU

  • PRIMASK(Priority mask register)

PRIMASK的bit0设置为1,就可以屏蔽所有优先级可配置的中断。

CPSID I 	;PRIMASK=1 关中断
CPSIE I 	;PRIMASK=0 开中断
// or:
MOV R0, #1
MSR PRIMASK, R0  ; 将1写入PRIMASK禁止所有中断
MOV R0, #0
MSR PRIMASK, R0  ; 将0写入PRIMASK使能所有中断
  • FAULTMASK(fault mask register)

bit0值1后屏蔽除NMI、RESET外所有的异常(与PRIMASK相比,连hard fault都屏蔽了)

CPSIE F  ; 开异常
CPSID F  ; 关异常
// or:
MOV R0, #1
MSR FAULTMASK, R0  ; 将1写入FAULTMASK禁止异常
MOV R0, #0
MSR FAULTMASK, R0  ; 将0写入FAULTMASK使能异常
  • BASEPRI(Base priority register)

image-20220321203024936

根据优先级来屏蔽中断,屏蔽所有优先级≥BASEPRI priority mask bits的中断。

MOVS RO, #0x60		; 禁止优先级在0x60~0xFF的中断
MSR BASEPRI, R0	
MRS R0, BASEPRI		; 读取BASEPRI
MOVS RO, #0			
MSR BASEPRI, R0		;取消屏蔽

1.4 STM32MP157的GPIO中断

STM32MP157的GPIO中断在硬件上的框架与STM32F103类似,但中断控制器不同,STM32MP157中使用的是GIC:

image-20220321203312275

GPIO/EXTI/NVIC与F103基本一致。其CPU的CPSR寄存器中有一位:I位,用来使能/禁止中断:

image-20220321203921161

可以使用以下汇编指令修改I位:

  CPSIE I  ; 清除I位,使能中断
  CPSID I  ; 设置I位,禁止中断

1.4.1 GIC

ARM体系结构定义了通用中断控制器(GIC),该控制器包括一组用于管理单核或多核系统中的中断的硬件资源。GIC提供了内存映射寄存器,可用于管理中断源和行为,以及(在多核系统中)用于将中断路由到各个CPU核。它使软件能够屏蔽,启用和禁用来自各个中断源的中断,以(在硬件中)对各个中断源进行优先级排序和生成软件触发中断。它还提供对TrustZone安全性扩展的支持。GIC接受系统级别中断的产生,并可以发信号通知给它所连接的每个内核,从而有可能导致IRQ或FIQ异常发生。

从软件角度来看,GIC具有两个主要功能模块,简单画图如下:

image-20220321204301033

① 分发器(Distributor)
系统中的所有中断源都连接到该单元。可以通过仲裁单元的寄存器来控制各个中断源的属性,例如优先级、状态、安全性、路由信息和使能状态。
分发器把中断输出到“CPU接口单元”,后者决定将哪个中断转发给CPU核。

② CPU接口单元(CPU Interface)
CPU核通过控制器的CPU接口单元接收中断。CPU接口单元寄存器用于屏蔽,识别和控制转发到CPU核的中断的状态。系统中的每个CPU核心都有一个单独的CPU接口。
中断在软件中由一个称为中断ID的数字标识。中断ID唯一对应于一个中断源。软件可以使用中断ID来识别中断源并调用相应的处理程序来处理中断。呈现给软件的中断ID由系统设计确定,一般在SOC的数据手册有记录。

中断可以有多种不同的类型:

① 软件触发中断(SGI,Software Generated Interrupt)
这是由软件通过写入专用仲裁单元的寄存器即软件触发中断寄存器(ICDSGIR)显式生成的。它最常用于CPU核间通信。SGI既可以发给所有的核,也可以发送给系统中选定的一组核心。中断号0-15保留用于SGI的中断号。用于通信的确切中断号由软件决定。

② 私有外设中断(PPI,Private Peripheral Interrupt)
这是由单个CPU核私有的外设生成的。PPI的中断号为16-31。它们标识CPU核私有的中断源,并且独立于另一个内核上的相同中断源,比如,每个核的计时器。

③ 共享外设中断(SPI,Shared Peripheral Interrupt)
这是由外设生成的,中断控制器可以将其路由到多个核。中断号为32-1020。SPI用于从整个系统可访问的各种外围设备发出中断信号。

​ 中断可以是边沿触发的(在中断控制器检测到相关输入的上升沿时认为中断触发,并且一直保持到清除为止)或电平触发(仅在中断控制器的相关输入为高时触发)

下图是GIC控制器的逻辑结构:

image-20220321204637877

1.5 IMX6ULL的GPIO中断

IMX6ULL的GPIO中断在硬件上的框架,跟STM32MP157是类似的:

image-20220321204727944

但是GPIO控制器与STM32不同,每组GPIO都有对应的GPIOx_ICR1、GPIOx_ICR2寄存器(interrupt configuration register )。每个引脚都可以配置为中断引脚,并配置它的触发方式

image-20220321204852299

2 GPIO中断编程

测试PC5按键引脚的双边沿外部中断

2.1 GPIO配置

  • 使能AFIO时钟和GPIOC时钟

  • 配置上拉输入模式

  • 选择PC5作为EXTI中断源

image-20220321234539827

void key_gpio_init(void){
    /*1. 使能GPIOC/AFIO, 配置输入模式 */
    unsigned int *pReg;
    pReg = (unsigned int *)(0x40021000 + 0x18);
	/* 使能GPIOC时钟 */
    *pReg |= 1 << 4;
	/* 使能AFIO时钟 */
    *pReg |= 1 << 0;
    /* 设置GPIOC5为上拉输入引脚 */
    // GPIOC->CRL配置为上/下拉模式
	pReg = (unsigned int *)(0x40011000 + 0x00);
	*pReg &= ~(0xf << 20);
    *pReg |= 0x8 << 20;
    // GPIOC->BSRR  控制ODR寄存器输出1 -> 上拉模式
	pReg = (unsigned int *)(0x40011000 + 0x10);
    *pReg |= 1 << 5;
    /*2. PC5作为EXTI9_5的中断源 */
    AFIO->EXTICR[1] |= 2 << 4; 	// 0:A, 1:B, 2:C...
}

2.2 EXTI配置

  • 触发方式:下降沿 + 上降沿

  • 使能exti5中断请求

image-20220321225502291

void key_exti_init(void){
    /*1. 中断触发方式 */
    EXTI->FTSR |= 1 << 5;  // 下降沿触发
    EXTI->RTSR |= 1 << 5;  // 上降沿也触发
    /*2. 使能中断请求 */
    EXTI->IMR |= 1 << 5;
}

2.3 NVIC配置

  • exti5中断向量编号为23

image-20220321233334921

  • 设置优先级分组为组2,即PRIGROUP[2:0] = 0b101 = 5

image-20220321224636283

STM32F1只实现位[7:4]

  • 设置EXIT9_5优先级

image-20220321224548224

Interrupt priority registers可以按字节访问,数组下标即对应中断编号

STM32F1只实现每个字段的位[7:4],位[3:0]读为0

  • 使能EXIT9_5中断请求

image-20220321224035673

▲ STM32F10XX NVIC寄存器

void key_nvic_init(void){
    /*1. 设置优先级分组 */
    SCB->AIRCR |= 5 << 8;       	// 优先级分组2: [7:6] 4 Group priorities, [5:4]4 Sub priorities 
    /*2. 设置EXTI9_5,的优先级 */
    NVIC->IP[23] |= 0x40;        	// 中断向量表第23位为EXTI9_5, [7:6]=0b01 = 1 Group priorities, [5:4]=0b00 = 0 Sub priorities 
    /*3. 使能EXTI9_5 */
    NVIC->ISER[0] |= 1 << 23;
}

2.4 CPU配置

清除primask

void cpu_irq_enable(void){
    __asm("CPSIE I\n\t");
}
void cpu_irq_disable(void){
    __asm("CPSID I\n\t");
}

当然,也可以通过汇编实现

cpu_interrupt_enable	PROC
						EXPORT	cpu_interrupt_enable
						MSR		PRIMASK, R0
						BX		LR
						ENDP

在C中调用cpu_interrupt_enable汇编函数:

void cpu_interrupt_enable(uint32_t r0);

参考:How do I access local C variable in arm inline assembly?

2.5 EXTI9_5中断服务例程

void EXTI9_5_IRQHandler(void)
{
    cpu_irq_disable();
    /* 清除EXTI悬起状态 */
	EXTI->PR |= 1 << 5;			    // 写1清除
	/* 清除NVIC悬起状态 */
	// NVIC->ICPR[0] |= 1 << 23;	// 写1清除  (进入esr后, 硬件清除悬起位)

    unsigned int *gpioc_idr = (unsigned int *)(0x40011000 + 0x08);
    if (*gpioc_idr & (1 << 5))
        send_str(usart1, "key release\r\n");
    else
        send_str(usart1, "key press\r\n");
    cpu_irq_enable();
}

串口打印结果:

image-20220322012355699

注意:必须向 pending request register写1清除悬起标志位,否则EXTI会一直向NVIC发送请求,不断进入EXTI ISR函数。但是NVIC的EXTI9_5中断的悬起位无需清除,因为当进入ISR时,硬件会清除其悬起位。


参考:

  • STM32F10xx Cortex-M3编程手册
  • STM32F1xx Reference manual
  • Cortex-M3权威指南
  • ARM Cortex-M3和Cortex-M4权威指南
  • ARM Application Note 179 Cortex-M3 Embedded Software Development

END

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柯西的彷徨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值