cortex - A7核中断实验——基于STM32MP157A

一:按键中断原理

异常中断处理流程

分为保存现场和恢复现场两部分

1:保存现场

        CPSR寄存器:当前程序状态寄存器

        此步骤由电脑自动完成,分为四大步三小步

        1:保存CPSR寄存器中的值到SPSR_<mode>寄存器中(mode为对应的异常模式寄存器)

        2:修改CPSR寄存器中的值

                1> 修改CPSR寄存器的T位(状态位),修改为ARM状态

                2> 根据需要,禁止相应的中断位 I位/F位(分别对应IRQ、FIQ)

                3> 修改CPSR寄存器的模式位,切换到对应的异常模式

        3:保存函数返回地址到LR_<mode>寄存器中

        4:PC指针指向异常向量表

CPSR寄存器部分位功能图

T[5]:状态位
    T=0:ARM状态,执行arm指令集
    T=1:thumb状态,执行thumb指令集
M[4:0]:模式位
    10000 User mode;    
    10001 FIQ mode;         
    10011 SVC mode;
    10111 Abort mode;  
    11011 Undef mode;  
    11111 System mode;     
    10110 Monitor mode;   
    10010 IRQ mode; 

 2:恢复现场

        1:把SPSR_<mode>寄存器中值重新给到CPSR寄存器中

        2:LR_<mode>寄存器中的值重新给PC寄存器
 

分析电路图

 再去主板上找它们是什么引脚,以KEY1为例

KEY1为 PF9引脚,所以是GPIO控制器

至此我们可以确定,我们需要的是:

        GIC控制器:通用的全局中断控制器

        EXTI控制器:外部中断事件控制器

        GPIO控制器:输入输出控制器,控制引脚

1.通过框图分析可知:RCC章节/GPIOF章节/EXTI章节/GIC章节

2.需要分析GPIOF章节:设置引脚为输入模式

3.需要分析EXTI章节:检测中断的触发方式

4.需要分析GIC章节:设置GPIOF引脚对应的中断号

二:分析芯片手册

1.RCC章节分析

寻找对应总线

略过前几篇文章做一次找一次的GPIOF,它在AHB4总线

EXTI也在AHB4总线(下面还能看到GPIOF)

 GIC中断控制器在CA7总线

 

 意味着,该控制器(GIC、EXTI)系统会自动使能,不需要我们通过RCC手动使能

查找RCC_MP_AHB4ENSETR

0x50000A28地址的第5位置1,设置GPIOF控制器使能
RCC_MP_AHB4ENSETR[5] = 1 -------->设置GPIOF控制器使能工作

2.GPIO章节分析

这次GPIO章节比较简单,只需要设置为输入模式即可

GPIOF_MODER[19:18] = 00------>KEY1输入模式

3.EXTI章节分析

 

 

 由该图知,PF9引脚对应的控制器为:EXTI_EXTICR1.EXTI9

1)EXTI_EXTICR3寄存器

EXTI_EXTICRn寄存器每8位管理一个EXTI,一个寄存器32位,最多管理4个EXTI

因为KEY1引脚为PF9,所以,EXTICR寄存器编号为3(范围为8~11引脚)

 

分析可知:
key1------>PF9------>EXTI9--->9 / 4 = 2.....1--->EXTI_EXTICR3[15:8] = 0x05

由此(寻找过程)得出公式
EXTI编号 / 4 = 商 ...... 余数
商+1 :对应的哪一个寄存器
余数*8:对应寄存器8位中的最低位

2)EXTI_FTSR1寄存器

 

key1------>PF9------>EXTI9--->对应事件9--->EXTI_FTSR1[9] = 0x1

EXTI_IMR1寄存器

key1------>PF9------>EXTI9--->对应事件9--->EXTI_IMR1[9] = 0x1--->中断不屏蔽

 EXTI_FPR1寄存器

rc_w1: rc--->可读  w1--->写1清除中断挂起标志位
读0:中断没有发生
读1:中断发生
写0:表示没有清除中断挂起标志位
写1:表示清除中断挂起标志位

所以:
key1------>PF9------>EXTI9--->对应事件9--->EXTI_FPR1[9] = 0x1--->清除中断挂起标志位

4:GICD章节

GIC控制器分为GICC与GICD两个

 

Software generated interrupts (SGI):软件中断号(ID:0~15)
Private peripheral interrupts (PPI):私有的外设中断号(ID:16~31)
Shared peripheral interrupts (SPI):共享外设中断号(ID:32~287)

GICD_CTLR寄存器(GICD控制寄存器)

设置GICD层CPU0组使能
GICD_CTLR[0] = 1

GICD_ISENABLERx寄存器(中断使能寄存器)

GIC层一共管理288个中断号(16个SGI,16个PPI,256个SPI)
GICD_ISENABLERx每一位管理一个中断号,所以一个寄存器最多管理32个中断号
要想管理288个中断号,需要 288 / 32 = 9个这样的寄存器   

key1------>PF9------>EXTI9--->对应事件9--->中断号99--->GICD_ISENABLER3[3] = 1

因此判断,计算公式为:
中断号 / 32 = 商 ...... 余数
商:中断号对应要操作的寄存器
余数:中断号对应操作寄存器的位数

GICD_IPRIORITYRx寄存器(中断优先级设置寄存器)

公式: 中断号 / 4 = 商 ...... 余数
    商:中断号对应要操作的寄存器
    余数*8+3:中断号对应操作寄存器的位数
key1------>PF9------>EXTI9--->
对应事件9--->中断号99---> 99 / 4 = 24 .... 3--->GICD_IPRIORITYR24[31:27]

GICD_ITARGETSRx寄存器(中断处理目标寄存器)

公式: 中断号 / 4 = 商 ...... 余数
商:中断号对应要操作的寄存器
余数*8:中断号对应操作寄存器的位数
key1------>PF9------>EXTI9--->
对应事件9--->中断号99---> 99 / 4 = 24 .... 3--->GGICD_ITARGETSR24[25:24] = 0bx1

0bx1----->分配给CPU0
0b1x----->分配给CPU1
0b11----->分配给CPU0和CPU1

GICD_ICPENDRx寄存器(中断清除挂起寄存器)

公式: 中断号 / 32 = 商 ...... 余数
商:中断号对应要操作的寄存器
余数:中断号对应操作寄存器的位数

key1------>PF9------>EXTI9--->
对应事件9--->中断号99---> 99 / 32 = 3 .... 3--->GICD_ICPENDR3[3] = 1

 5.GICC章节

GICC_CTLR寄存器(GICC控制寄存器)

CTRL[0] = 1 cpu组0使能

GICC_PMR寄存器(中断优先级设置寄存器)

该寄存器的值随意设置,只需要比GICD层设计的中断优先级的值要大(GICD_IPRIORITYRx)

GICC_EOIR寄存器(GICC中断结束寄存器)

GICC_EOIR作用:清除中断号
GICC_EOIR[9:0]:清除按键的中断号

 三:代码实现

直接根据前文分析出来的内容,填写代码即可,头文件内采用现成的库、

key.c文件

RCC与EXTI初始化

//初始化EXTI层
void pf9_exti_init()
{
	/***********RCC初始化**************/
	//使能GPIOF
	RCC->MP_AHB4ENSETR = (0x1 << 5);
	
	/*****GPIO章节初始化*****/
	//设置PF9引脚为输入模式
	//GPIOF_MODER[19:18] = 0b00
	GPIOF->MODER &= (~(0x3 << 18));

	/*******EXTI章节初始化********/
	//1.设置PF9引脚和EXTI9控制器进行链接
	//EXIT_EXTICR3[15:8] = 0x05
	EXTI->EXTICR3 &= (~(0xff << 8));  //清零
	EXTI->EXTICR3 |= (0x05 << 8);   //置1

	//2.设置PF9引脚检测方式为下降沿
	//EXTI_FTSR1[9] = 0x01
	EXTI->FTSR1 |= (0x1 << 9);

	//3.设置PF9引脚中断不屏蔽
	//EXTI_IMR1[9] = 0x01
	EXTI->C1IMR1 |= (0x01 << 9);
}

GICD初始化

//初始化GICD层
void pf9_gicd_init()
{
	//设置GICD层全局中断使能寄存器
	GICD->CTRL |= (0X01 << 0);
	
	//设置GICD层中断使能寄存器
	//EXTI9-->99号-->GICD_ISENABLER[3][3] = 1
	GICD->ISENABLER[3] |= (0x1 << 3);

	//设置GICD层中断优先级寄存器
	//99号中断-->GICD_IPRIORITYR24[31:27] = 10 //数字随意
	GICD->IPRIORITYR[24] &= (~(0x1F << 27));  //清零
	GICD->IPRIORITYR[24] |= (0x1 << 27);

	//设置GICD层中断目标分配器
	//99号中断 --> 99/4 = 24....3 --> GICD_ITARGETSR24[25:24] = 0bx1(x代表0、1任意值)
	GICD->ITARGETSR[24] &= (~(0x3 << 24));
	GICD->ITARGETSR[24] |= (0x1 << 24);
}

GICC初始化

//初始化GICC
void pf9_gicc_init()
{
	//设置GICC层全局中断使能寄存器
	GICC->CTRL |= (0x1 << 0);

	//设置GICC层中断优先级寄存器
	GICC->PMR &= (~(0x1F << 3));
	GICC->PMR |= (0xF << 3);  //优先级设置为15
}

为了初始化方便,整合到一起

//包裹pf9
void PF9_init()
{
	pf9_exti_init();
	pf9_gicd_init();
	pf9_gicc_init();
}

还要编写中断文件

do_irq.c文件

#include "key.h"

extern void delay_ms(int ms);

extern void printf(const char *fmt, ...);

//unsigned int i = 0;
void do_irq(void) 
{
	unsigned int num = 0;
	//获取中断信号
	num = GICC->IAR;
	switch(num)
	{
/*    此处为省略的key2与key3的中断事件
	case 97:	
		delay_ms(500); //防按键抖动
		printf("key2######\n");
		//清除EXTI中断挂起标志位
		EXTI->FPR1 |= (0x1 << 7);
		//清除GICD层中断挂起标志位
		//key1-->PF9-->EXTI9-->事件9-->中断号99
		//97 / 32 = 3...1
		GICD->ICPENDR[3] |= (0x1 << 1);

		break;
	case 98:	
		delay_ms(500); //防按键抖动
		printf("key3######\n");
		//清除EXTI中断挂起标志位
		EXTI->FPR1 |= (0x1 << 8);
		//清除GICD层中断挂起标志位
		//key1-->PF9-->EXTI9-->事件9-->中断号99
		//98 / 32 = 3...2
		GICD->ICPENDR[3] |= (0x1 << 2);

		break;
*/
	case 99:
		delay_ms(500); //防按键抖动
		printf("key1######\n");
		//清除EXTI中断挂起标志位
		EXTI->FPR1 |= (0x1 << 9);
		//清除GICD层中断挂起标志位
		//key1-->PF9-->EXTI9-->事件9-->中断号99
		//99 / 32 = 3...3
		GICD->ICPENDR[3] |= (0x1 << 3);

		break;
	}
	//清除中断信号
	GICC->EOIR &= (~(0x3FF << 0));
	GICC->EOIR |= num;
}

key.h文件

#ifndef __KEY_H__
#define __KEY_H__

#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_exti.h"
#include "stm32mp1xx_rcc.h"
#include "stm32mp1xx_gic.h"

//初始化
/******KEY1----->PF9******/
//初始化EXTI层
void pf9_exti_init();

//初始化GICD层
void pf9_gicd_init();

//初始化GICC层
void pf9_gicc_init();

//包裹pf9
void PF9_init();


//此处本还有key2、key3的初始化,此处略
#endif

实验运行效果:

当按下开发板的对应按钮后,会在串口界面输出对应的按键号

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

老K殿下

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

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

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

打赏作者

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

抵扣说明:

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

余额充值