cortex A7核按键中断实验

cortex A7核按键中断实验

一、分析电路图

实验目的:完成板子三个按键操作

1.1 电路图IO口

KEY1------>PF9
KEY2------>PF7
KEY3------>PF8
在这里插入图片描述
在这里插入图片描述

1.2 工作原理

KEY1 ------> PF9 ------> 按键触发方式:下降沿触发
KEY2 ------> PF7 ------> 按键触发方式:下降沿触发
KEY3 ------> PF8 ------> 按键触发方式:下降沿触发
在这里插入图片描述

二、分析框图

2.1 分析框图

在这里插入图片描述

2.2 总结

1、通过以上框图分析可知,需要分析芯片手册RCC章节 / GPIO章节 / EXTI章节 / GIC章节
2、RCC章节 : 使能对应组控制器
3、GPIO章节 : 设置引脚为输入模式
4、EXTI章节 :配置引脚触发方式为下降沿触发
5、GIC章节 :按键如何管理中断号,判断哪一个按键按下

三、分析RCC章节

3.1 确定总线连接

在这里插入图片描述

3.2 确定基地址

在这里插入图片描述
在这里插入图片描述

3.3 分析RCC_MP_AHB4ENSETR寄存器

在这里插入图片描述
1.RCC_MP_AHB4ENSETR寄存器作用
设置对应组控制器使能
2.如何确定RCC_MP_AHB4ENSETR基地址
通过2.5.2章节 1)确定总线名称 2)确定对应组寄存器基地址
3.如何确定RCC_MP_AHB4ENSETR地址
RCC_MP_AHB4ENSETR地址 = 基地址 + 偏移地址 = 0x50000000 + 0xA28 = 0x50000A28
4.如何通过RCC_MP_AHB4ENSETR寄存器,设置GPIOF组控制器使能
RCC_MP_AHB4ENSETR[5] = 1 --------> 0x50000A28地址空间中第5位写1,保证其他位不变

四、分析GPIO章节

4.1 分析GPIOx_MODER寄存器

在这里插入图片描述
1.GPIOF_MODER寄存器作用
设置GPIO引脚模式
2.如何确定GPIOF_MODER基地址
通过2.5.2章节 1)确定总线名称 2)确定对应组寄存器基地址
3.如何确定GPIOF_MODER地址
GPIOF_MODER地址 = 基地址 + 偏移地址 = 0x50007000 + 0x00 = 0x50007000
4.如何通过GPIOF_MODER寄存器,设置PF9/PF7/PF8引脚为输入模式
key1: GPIOF_MODER[19:18] = 00 --------> 0x50007000地址空间中第[19:18]位写00,保证其他位不变
key2: GPIOF_MODER[15:14] = 00 --------> 0x50007000地址空间中第[15:14]位写00,保证其他位不变
key3: GPIOF_MODER[17:16] = 00 --------> 0x50007000地址空间中第[17:16]位写00,保证其他位不变

五、分析EXTI章节

5.1 介绍

在这里插入图片描述

5.2 框图

在这里插入图片描述

5.3 找出寄存器

在这里插入图片描述

5.4 EXTI选择寄存器介绍

在这里插入图片描述

5.5 分析EXTI_EXTICR3寄存器

在这里插入图片描述
在这里插入图片描述
1.EXTI_EXTICR3(EXTI external interrupt selection register 3)寄存器
寄存器全称:外部中断选择寄存器
作用:GPIO选择和哪一个EXTI组控制器进行连接
2.为什么有4个EXTI_EXTICRn寄存器
1) 通过EXTI选择寄存器介绍可知,一共有16个EXTI(EXTI0 ~ EXTI15)
2)通过以上选择寄存器分析可知,每8位管理一个EXTI,一个寄存器32位,所以最多管理4个EXTI
3)要想管理16个EXTI,所以需要4个这样的寄存器
3.如何配置KEY1/KEY2/KEY3与EXTI控制器进行连接
KEY1 -----> PF9 -----> EXTI9 -------> EXTI_EXTICR3[15:8] = 0x05
KEY2 -----> PF7 -----> EXTI7 -------> EXTI_EXTICR2[31:24] = 0x05
KEY3 -----> PF8 -----> EXTI8 -------> EXTI_EXTICR3[7:0] = 0x05
4.有没有什么公式可以计算操作的是哪个寄存器的哪几位
EXTI编号 / 4 = 商 … 余数
商 + 1:控制哪个寄存器
余数 * 8:操作8位中的最低位
KEY1 -----> PF9 -----> EXTI9 -------> 9 / 4 = 2 … 1 -------> EXTI_EXTICR3[15:8] = 0x05
KEY2 -----> PF7 -----> EXTI7 -------> 7 / 4 = 1 … 3 -------> EXTI_EXTICR2[31:24] = 0x05
KEY3 -----> PF8 -----> EXTI8 -------> 8 / 4 = 2 … 0 -------> EXTI_EXTICR3[7:0] = 0x05
5.6 分析EXTI_FTSR1寄存器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
1.EXTI_FTSR1:EXTI falling trigger selection register
寄存器全称:EXTI下经验触发选择寄存器
作用:设置EXTI编号为下降沿触发
2.如何配置KEY1/KEY2/KEY3引脚为下降沿触发方式
KEY1 -----> PF9 -----> EXTI9 -------> EXTI_FTSR1[9] = 1 -------> 设置下降沿触发方式
KEY2 -----> PF7 -----> EXTI7 -------> EXTI_FTSR1[7] = 1 -------> 设置下降沿触发方式
KEY3 -----> PF8 -----> EXTI8 -------> EXTI_FTSR1[8] = 1 -------> 设置下降沿触发方式
5.7 分析EXTI_IMR1寄存器
在这里插入图片描述
1.EXTI_IMR1:EXTI CPU wakeup with interrupt mask register
寄存器全称:EXTI中断屏蔽寄存器
作用:设置EXTI信号是否转发到GIC层
2.如何配置KEY1/KEY2/KEY3引脚中断不屏蔽
KEY1 -----> PF9 -----> EXTI9 -------> EXTI_IMR1[9] = 1 -------> 设置中断不屏蔽,EXTI中断编号会被转发到GIC层
KEY2 -----> PF7 -----> EXTI7 -------> EXTI_IMR1[7] = 1 -------> 设置中断不屏蔽,EXTI中断编号会被转发到GIC层
KEY3 -----> PF8 -----> EXTI8 -------> EXTI_IMR1[8] = 1 -------> 设置中断不屏蔽,EXTI中断编号会被转发到GIC层
5.8 分析EXTI_FPR1寄存器
在这里插入图片描述
1.EXTI_FPR1:EXTI falling edge pending register
寄存器全称:EXTI下降沿触挂起寄存器
作用:清除EXTI层中断挂起标志

2.如何配置KEY1/KEY2/KEY3引脚清除EXTI层中断挂起标志
rc_w1:
读0:表示中断没有发生
读1:表示中断发生
写0:表示没有清除EXTI层中断挂起标志位
写1:表示清除EXTI层中断挂起标志位
KEY1 -----> PF9 -----> EXTI9 -------> EXTI_FPR1[9] = 1 -------> 清除EXTI层中断挂起标志位
KEY2 -----> PF7 -----> EXTI7 -------> EXTI_FPR1[7] = 1 -------> 清除EXTI层中断挂起标志位
KEY3 -----> PF8 -----> EXTI8 -------> EXTI_FPR1[8] = 1 -------> 清除EXTI层中断挂起标志位

六、中断整体框图

6.1 总结所以寄存器

EXTI章节总结:
1.中断选择寄存器 EXTI_EXTICR3
2.设置下降沿触发 EXTI_FTSR1
3.设置中断不屏蔽 EXTI_IMR1
4.清除EXTI层中断挂起标志位 EXTI_FPR1
GICD层
GICD interrupt set-enable register (GICD_ISENABLER0)
GICD interrupt priority register x (GICD_IPRIORITYRx)
GICD interrupt processor target register x (GICD_ITARGETSRx)
GICD control register (GICD_CTLR)
GICD interrupt clear-pending register x (GICD_ICPENDRx)
GICC input priority mask register (GICC_PMR)
GICC control register (GICC_CTLR)
GICC interrupt acknowledge register (GICC_IAR)
GICC end of interrupt register (GICC_EOIR)

6.2 框图

在这里插入图片描述

七、分析GICD章节

7.1 中断号如何管理

Software generated interrupts (SGI):软件产生中断 Interrupt ID:15-0
Private peripheral interrupts (PPI):私有外设中断,Interrupt ID:16-31
Shared peripheral interrupts (SPI):共享外设中断 Interrupt ID:32-287
GIC层一共管理288个中断号(0~287)
在这里插入图片描述

7.2 分析GICD_CTLR寄存器

在这里插入图片描述
在这里插入图片描述
1.GICD_CTLR:GICD control register
寄存器全称:GICD层控制寄存器
寄存器作用:使能对应组中断
2.使能GICD层组0中断:GICD_CTLR[0] = 1

7.3 分析GICD_ISENABLERx寄存器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
GICD_ISENABLERx:GICD interrupt set-enable register
寄存器全称:中断设置使能寄存器
作用:接收EXTI层转发的中断信号
2.思考:
1)为什么GICD层一共有9个GICD_ISENABLERx(x = 0 ~ 8)寄存器
i)GICD_ISENABLERx这个寄存器一共32位,每一位管理一个中断号,一个寄存器最多管理32个中断号
ii)GIC层一共管理288个中断号(16个SGIS,16个PPIS,256个SPIS)
iii)所以需要 288 / 32 = 9 个GICD_ISENABLERx(x = 0 ~ 8)寄存器,才可以管理完成
2)如何确定KEY1/KEY2/KEY3中断号是多少?
通过21.3章节表117确定中断号
key1 -----> EXTI9 -----> 99
key2 -----> EXTI7 -----> 97
key3 -----> EXTI8 -----> 98
3.如何通过GICD_ISENABLERx寄存器设置KEY1/KEY2/KEY3使能
KEY1 -----> PF9 -----> EXTI9 -------> GICD_ISENABLER3[3] = 1 -------> 设置99号中断使能
KEY2 -----> PF7 -----> EXTI7 -------> GICD_ISENABLER3[1] = 1-------> 设置97号中断使能
KEY3 -----> PF8 -----> EXTI8 -------> GICD_ISENABLER3[2] = 1 -------> 设置98号中断使能
4.有什么公式可以直接计算出,操作哪个寄存器的哪一位?
中断号 / 32 = 商 … 余数
商:操作哪个寄存器
余数:操作寄存器的位数
KEY1 -----> PF9 -----> EXTI9 -------> 99 / 32 = 3…3 ------->GICD_ISENABLER3[3] = 1 -------> 设置99号中断使能
KEY2 -----> PF7 -----> EXTI7 -------> 97 / 32 = 3…1 ------->GICD_ISENABLER3[1] = 1-------> 设置97号中断使能
KEY3 -----> PF8 -----> EXTI8 -------> 98 / 32 = 3…2 ------->GICD_ISENABLER3[2] = 1 -------> 设置98号中断使能

7.4 分析GICD_IPRIORITYRx寄存器

在这里插入图片描述
1.GICD_IPRIORITYRx:GICD interrupt priority register
寄存器全名:GICD层中断优先级寄存器
作用:设置GICD层中断优先级
2. 为什么GICD层一共有72个GICD_IPRIORITYRx(x = 0 ~ 71)寄存器
i)GICD_IPRIORITYRx这个寄存器一共32位,每八位管理一个中断号,一个寄存器最多管理4个中断号
ii)GIC层一共管理288个中断号(16个SGIS,16个PPIS,256个SPIS)
iii)所以需要 288 / 4 = 72个GICD_IPRIORITYRx(x = 0 ~ 71)寄存器,才可以管理完成
3.思考:有什么公式可以直接计算出,操作哪个寄存器的哪一位?
中断号 / 4 = 商 … 余数
商:操作哪个寄存器
余数*8+3:操作寄存器的位数
3.何通过GICD_IPRIORITYRx寄存器设置KEY1/KEY2/KEY3对应的中断优先级
KEY1 -----> PF9 -----> EXTI9 -------> 99 / 4 = 24…3 ------->GICD_IPRIORITYR24[31:27] -------> 设置99号中断优先级
KEY2 -----> PF7 -----> EXTI7 -------> 97 / 4 = 24…1 ------->GICD_IPRIORITYR24[15:11] -------> 设置97号中断优先级
KEY3 -----> PF8 -----> EXTI8 -------> 98 / 4 = 24…2 ------->GICD_IPRIORITYR24[23:19] -------> 设置98号中断优先级
注意:中断的值越小,代表中断的优先级越高,设置中断优先级值的范围 0 ~ 2^5-1

7.5 分析GICD_ITARGETSRx寄存器在这里插入图片描述

1.GICD_ITARGETSRx:GICD interrupt processor target register
寄存器全名:GICD层中断目标分配寄存器
作用:设置GICD层中断分配给哪个A7核,对于裸机开发中,只能给CPU0
2. 为什么GICD层一共有72个GICD_ITARGETSRx(x = 0 ~ 71)寄存器
i)GICD_ITARGETSRx这个寄存器一共32位,每八位管理一个中断号,一个寄存器最多管理4个中断号
ii)GIC层一共管理288个中断号(16个SGIS,16个PPIS,256个SPIS)
iii)所以需要 288 / 4 = 72个GICD_ITARGETSRx(x = 0 ~ 71)寄存器,才可以管理完成
3.思考:有什么公式可以直接计算出,操作哪个寄存器的哪一位?
中断号 / 4 = 商 … 余数
商:操作哪个寄存器
余数*8:操作寄存器的位数
4.何通过GICD_ITARGETSRx寄存器设置KEY1/KEY2/KEY3对应的中断分配给CPU0
KEY1 -----> PF9 -----> EXTI9 -------> 99 / 4 = 24…3 ------->GICD_ITARGETSR24[25:24] = 0bx1
KEY2 -----> PF7 -----> EXTI7 -------> 97 / 4 = 24…1 ------->GICD_ITARGETSR24[9:8] = 0bx1
KEY3 -----> PF8 -----> EXTI8 -------> 98 / 4 = 24…2 ------->GICD_ITARGETSR24[17:16] = 0bx1
5.这两位写什么样的值,分配给CPU0
0bx1:分配给CPU0 备注:x代表任意值
0b1x:分配给CPU1
0b11:分配给CPU1 和 CPU0

7.6 分析GICD_ICPENDRx寄存器在这里插入图片描述

1.GICD_ICPENDRx:GICD interrupt clear-pending register
寄存器全称:中断清除挂起寄存器
作用:清除GICD层中断挂起标志位
2.思考:
1)为什么GICD层一共有9个GICD_ICPENDRx(x = 0 ~ 8)寄存器
i)GICD_ISENABLERx这个寄存器一共32位,每一位管理一个中断号,一个寄存器最多管理32个中断号
ii)GIC层一共管理288个中断号(16个SGIS,16个PPIS,256个SPIS)
iii)所以需要 288 / 32 = 9 个GICD_ICPENDRx(x = 0 ~ 8)寄存器,才可以管理完成
2)如何确定KEY1/KEY2/KEY3中断号是多少?
通过21.3章节表117确定中断号
key1 -----> EXTI9 -----> 99
key2 -----> EXTI7 -----> 97
key3 -----> EXTI8 -----> 98
3.有什么公式可以直接计算出,操作哪个寄存器的哪一位?
中断号 / 32 = 商 … 余数
商:操作哪个寄存器
余数:操作寄存器的位数
KEY1 -----> PF9 -----> EXTI9 -------> 99 / 32 = 3…3 ------->GICD_ICPENDR3[3]= 1------->清除99号中断对应GICD层中断挂起标志位
KEY2 -----> PF7 -----> EXTI7 -------> 97 / 32 = 3…1 ------->GICD_ICPENDR[1] = 1------->清除97号中断对应GICD层中断挂起标志位
KEY3 -----> PF8 -----> EXTI8 -------> 98 / 32 = 3…2 ------->GICD_ICPENDR[2] = 1 ------->清除98号中断对应GICD层中断挂起标志位

八、分析GICC章节

8.1 分析GICC_CTLR寄存器在这里插入图片描述

1.GICC_PMR:GICC input priority mask register
GICC层中断优先级屏蔽寄存器
作用:设置GICC层中断优先级
2.如何设置GICC层中断优先级
GICC_PMR[7:3] = 中断优先级值
注意:GICD层中断优先级需要比GICC层中断优先级高,值越小代表优先级越高

8.2 分析GICC_PMR寄存器

在这里插入图片描述
1.GICC_PMR:GICC input priority mask register
GICC层中断优先级屏蔽寄存器
作用:设置GICC层中断优先级
2.如何设置GICC层中断优先级
GICC_PMR[7:3] = 中断优先级值
注意:GICD层中断优先级需要比GICC层中断优先级高,值越小代表优先级越高

8.3 分析GICC_IAR寄存器

在这里插入图片描述
GICC_IAR寄存器 作用:获取中断号
定义一个变量 = GICC_IAR[9:0]
8.4 分析GICC_EOIR寄存器在这里插入图片描述
GICC_EOIR寄存器:清除中断号
GICC_EOIR[9:0]寄存器的值 = IAR[9:0]寄存器中获取的值

main.c

#include "key.h"

extern void printf(const char *fmt, ...);
void delay_ms(int ms)
{
	int i,j;
	for(i = 0; i < ms;i++)
		for (j = 0; j < 1800; j++);
}

#define EXTI7_INPUT_EVENT 7
#define EXTI8_INPUT_EVENT 8
#define EXTI9_INPUT_EVENT 9
#define GPIOGROUP 0x05
#define KEY1_ID 99
#define KEY2_ID 97
#define KEY3_ID 98
#define IPR_EXTI7 7
#define IPR_EXTI8 8
#define IPR_EXTI9 9

void led_init()
{
	RCC->MP_AHB4ENSETR |= (0x1 << 4);
	RCC->MP_AHB4ENSETR |= (0x1 << 5);

	gpio_init_t init ={
		.moder = OUTPUT,
		.otyper = PP,
		.ospeedr = LOW,
		.pupdr = NO_PUPDR,
	};
	hal_gpio_init(GPIOE,&init,GPIO_PIN_10);
	hal_gpio_init(GPIOE,&init,GPIO_PIN_8);
	hal_gpio_init(GPIOF,&init,GPIO_PIN_10);
}

int main()
{
	led_init();
	key_gpio_rcc_init();

	//KEY1
	hal_exti_key_init(EXTI9_INPUT_EVENT,GPIOGROUP,Falling);
	hal_gic_key_init(KEY1_ID,IPR_EXTI9);
	//KEY2
	hal_exti_key_init(EXTI7_INPUT_EVENT,GPIOGROUP,Falling);
	hal_gic_key_init(KEY2_ID,IPR_EXTI7);
	//KEY3
	hal_exti_key_init(EXTI8_INPUT_EVENT,GPIOGROUP,Falling);
	hal_gic_key_init(KEY3_ID,IPR_EXTI8);
	while(1)
	{
	//当按键按下之后,触发irq异常源
	//执行中断处理函数
	}
	return 0;
}

do_irq.c

#include "key.h"
extern void delay_ms(int ms);
extern void printf(const char *fmt, ...);
//按键按下之后,打印一句话
void do_irq(void) 
{
	unsigned int num;
	//1.获取中断号 IAR[9:0]
	num = GICC->IAR & 0x3ff;
	//2.判断中断号
	switch(num)
	{
		case 97: // KEY2 ---->LED2---->PF10
			GPIOF->ODR ^= (0x1 << 10);
			printf("key2 interrupt id = %d\n",num);
			EXTI->FPR1 |= (0x1 << 7);
			GICD->ICPENDR[3] |= (0x1 << 1);
			break;
		case 98: //KEY3 ---->LED1---->PE10
			GPIOE->ODR ^= (0x1 << 10);
			printf("key3 interrupt id = %d\n",num);
			EXTI->FPR1 |= (0x1 << 8);
			GICD->ICPENDR[3] |= (0x1 << 2);
			break;
		case 99: //KEY1 ---->LED3---->PE8
			GPIOE->ODR ^= (0x1 << 8);
			delay_ms(500);
			printf("key1 interrupt id = %d\n",num);
		//3.清除EXTI层中断挂起标志位 FPR1[9] = 1
		EXTI->FPR1 |= (0x1 << 9);
		//4.清除GICD层中断挂起标志位 ICPENDR[3] 第3位写1
		GICD->ICPENDR[3] |= (0x1 << 3);
			break;
	}
	//5.清除中断号EOIR
	GICC->EOIR = num;
}

gpio.c

#include "gpio.h"

void hal_gpio_init(gpio_t* gpiox,gpio_init_t *init,unsigned int pin)
{
	gpiox->MODER &= (~(0x3 << (pin * 2)));
	gpiox->MODER |= (init->moder << (pin * 2));

	gpiox->OTYPER &= (~(0x1 << pin));
	gpiox->OTYPER |= (init->otyper << pin);

	gpiox->OSPEEDR &= (~(0x3 << (pin * 2)));
	gpiox->OSPEEDR |= (init->ospeedr << (pin * 2));

	gpiox->PUPDR &= (~(0x3 << (pin * 2)));
	gpiox->PUPDR |= (init->pupdr << (pin * 2));
}


void hal_gpio_write(gpio_t* gpiox,unsigned int pin,gpio_status_t status)
{
	if(status == OFF)
	{
		gpiox->ODR &= (~(0x1 << pin));
	}
	else
	{
		gpiox->ODR |= (0x1 << pin);
	}
}

key.c

#include "key.h"


//GPIO章节和RCC章节初始化
void key_gpio_rcc_init()
{
	//KEY1--->PF9
	//KEY2--->PF7
	//KEY3--->PF8
	//1.设置GPIOF组使能 MP_AHB4ENSETR[5] = 1
	RCC->MP_AHB4ENSETR |= (0x1 << 5);
	//2.设置PF9为输入模式 MODER[19:18] = 00
	GPIOF->MODER &= (~(0x3 << 18));
	//3.设置PF7为输入模式 MODER[15:14] = 00
	GPIOF->MODER &= (~(0x3 << 14));
	//4.设置PF8为输入模式 MODER[17:16] = 00
	GPIOF->MODER &= (~(0x3 << 16));
}

//EXTI章节初始化
void hal_exti_key_init(unsigned int input_event,
		unsigned int gpiogroup,triger_t trigger)
{
	//1.设置GPIO引脚和EXTI进行连接
	switch(input_event / 4)
	{
		case 1:
			EXTI->EXTICR2 &= (~(0xff << (input_event % 4 * 8)));
			EXTI->EXTICR2 |= (gpiogroup << (input_event % 4 * 8));
			break;
		case 2:
			EXTI->EXTICR3 &= (~(0xff << (input_event % 4 * 8)));
			EXTI->EXTICR3 |= (gpiogroup << (input_event % 4 * 8));
			break;
		case 3:
			break;
	}
	//2.设置中断触发方式
	if(trigger == Falling) 
	{
		//触发方式为下降沿触发
		EXTI->FTSR1 |= (0x1 << input_event);
	}
	else
	{
		//触发方式为上升沿触发
		EXTI->RTSR1 |= (0x1 << input_event);
	}
	//3.设置中断不屏蔽
	EXTI->C1IMR1 |= (0x1 << input_event);	
}

//GIC章节初始化
void hal_gic_key_init(unsigned int id,unsigned int ipr)
{
	//1.设置GICD层中断使能寄存器
	GICD->ISENABLER[id/32] &= (~(0x1 << (id % 32 )));
	GICD->ISENABLER[id/32] |= (0x1 << (id % 32));	
	//2.设置GICD层中断优先级寄存器
	GICD->IPRIORITYR[id/4] &= (~(0x1f << (id % 4 * 8 + 3)));
	GICD->IPRIORITYR[id/4] |= (ipr << (id % 4 * 8 + 3));
	//3.设置GICD层中断目标分配寄存器
	GICD->ITARGETSR[id/4] &= (~(0x3 << (id % 4 * 8)));
	GICD->ITARGETSR[id/4] |= (0x1 << (id % 4 * 8));
	//4.设置GICD层中断全局控制器
	GICD->CTRL |= (0x1 << 0);
	//5.设置GICC层中断优先级寄存器
	GICC->PMR |= (0x1f << 3);
	//6.设置GICC层中断全局控制器
	GICC->CTRL |= (0x1 << 0);
}

gpio.h

#ifndef __GPIO_H__
#define __GPIO_H__

typedef struct{
	volatile unsigned int MODER;
	volatile unsigned int OTYPER;
	volatile unsigned int OSPEEDR;
	volatile unsigned int PUPDR;
	volatile unsigned int IDR;
	volatile unsigned int ODR;
}gpio_t;

#define GPIOE ((gpio_t*)0x50006000)
#define GPIOF ((gpio_t*)0x50007000)

#define GPIO_PIN_0 0
#define GPIO_PIN_1 1
#define GPIO_PIN_2 2
#define GPIO_PIN_3 3
#define GPIO_PIN_4 4
#define GPIO_PIN_5 5
#define GPIO_PIN_6 6
#define GPIO_PIN_7 7
#define GPIO_PIN_8 8
#define GPIO_PIN_9 9
#define GPIO_PIN_10 10
#define GPIO_PIN_11 11
#define GPIO_PIN_12 12
#define GPIO_PIN_13 13
#define GPIO_PIN_14 14
#define GPIO_PIN_15 15

typedef enum{
	INPUT = 0,
	OUTPUT,
	ALT,
	ANALOG,
}gpio_moder_t;

typedef enum{
	PP = 0,
	PDR,
}gpio_otyper;

typedef enum{
	LOW = 0,
	MED,
	HIGH,
	VERY_HIGH,
}gpio_ospeedr;

typedef enum{
	NO_PUPDR = 0,
	PU,
	PD,
	RESERVE,
}gpio_pupdr;
typedef enum{
	OFF = 0,
	ON,
}gpio_status_t;

typedef struct{
	gpio_moder_t moder;
	gpio_otyper otyper;
	gpio_ospeedr ospeedr;
	gpio_pupdr pupdr;
}gpio_init_t;

void hal_gpio_init(gpio_t* gpiox,gpio_init_t *init,unsigned int pin);
void hal_gpio_write(gpio_t* gpiox,unsigned int pin,gpio_status_t status);

#endif


key.h

#ifndef __KEY_H__
#define __KEY_H__

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

typedef enum{
	Rising = 0,
	Falling,
}triger_t;

//GPIO章节和RCC章节初始化
void key_gpio_rcc_init();
//EXTI章节初始化
void hal_exti_key_init(unsigned int input_event,
		unsigned int gpiogroup,triger_t trigger);
//GIC章节初始化
void hal_gic_key_init(unsigned int id,unsigned int ipr);

#endif

start.s

/*
 * start.S
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

/*
 * Exception vector table
 */
.text

	.global	_start
_start:
@ 异常向量表
	b reset
	ldr pc, _undefined_instruction
	ldr pc, _software_interrupt
	ldr pc, _prefetch_abort
	ldr pc, _data_abort
	ldr pc, _not_used
	ldr pc, _irq
	ldr pc, _fiq

_undefined_instruction:
	.word undefined_instruction
_software_interrupt:
	.word software_interrupt
_prefetch_abort:
	.word prefetch_abort
_data_abort:
	.word data_abort
_not_used:
	.word not_used
_irq:
	.word irq
_fiq:
	.word fiq

 /* The actual reset code */
reset:
	@ 重新映射异常向量表的入口地址
	/* Set Vector Base Address Register */
	mrc p15, 0, r0, c1, c0, 0
	bic r0, #(1<<13)
	mcr p15, 0, r0, c1, c0, 0
	ldr	r0,=0xc0008000
	mcr	p15,0,r0,c12,c0,0		@ Vector Base Address Register

	/* Set the cpu to svc32 mode */
	mrs r0, cpsr
	bic r0, r0, #0x1f
	orr r0, r0, #0xd3
	msr cpsr, r0

	/* Enable NEON/VFP unit */
	mrc p15, #0, r1, c1, c0, #2
	orr r1, r1, #(0xf << 20)
	mcr p15, #0, r1, c1, c0, #2
	mov r1, #0
	mcr p15, #0, r1, c7, c5, #4
	mov r0, #0x40000000
	fmxr fpexc, r0

	/* Cache init */
	mrc	p15, 0, r0, c0, c0, 0
	and	r1, r0, #0x00f00000
	and	r2, r0, #0x0000000f
	orr r2, r2, r1, lsr #20-4
	cmp r2, #0x30
	mrceq p15, 0, r0, c1, c0, 1
	orreq r0, r0, #0x6
	mcreq p15, 0, r0, c1, c0, 1

	/* Invalidate L1 I/D */
	mov r0, #0
	mcr	p15, 0, r0, c8, c7, 0
	mcr	p15, 0, r0, c7, c5, 0

	/* Disable mmu stuff and caches */
	mrc p15, 0, r0, c1, c0, 0
	bic r0, r0, #0x00002000
	bic r0, r0, #0x00000007
	orr r0, r0, #0x00001000
	orr r0, r0, #0x00000002
	orr r0, r0, #0x00000800
	mcr p15, 0, r0, c1, c0, 0

	/* Initialize stacks */
	@ 初始化各种模式下的占空间
init_stack:
	ldr	r0, stacktop        /*get stack top pointer*/

	/********svc mode stack********/
	mov	sp, r0
	sub	r0, #128*4          /*512 byte  for irq mode of stack*/
	/********irq mode stack********/
	msr	cpsr, #0xd2
	mov	sp, r0
	sub	r0, #128*4          /*512 byte  for fiq mode of stack*/
	/********fiq mode stack********/
	msr	cpsr, #0xd1
	mov	sp, r0
	sub	r0, #0
	/********abort mode stack******/
	msr	cpsr, #0xd7
	mov	sp, r0
	sub	r0, #0
	/********undefine mode stack**/
	msr	cpsr, #0xdb
	mov	sp, r0
	sub	r0, #0
    /***sys mode and usr mode stack***/
	msr	cpsr, #0x10
	mov	sp, r0             /*1024 byte  for user mode of stack*/

    /******clear bss section********/
	@ 清除BSS段
	ldr	r0, =__bss_start	/* this is auto-relocated! */
	ldr	r1, =__bss_end__	/* this is auto-relocated! */
	mov	r2, #0x00000000		/* prepare zero to clear BSS */

clbss_l: cmp r0, r1			/* while not at end of BSS */
	strlo r2, [r0]			/* clear 32-bit BSS word */
	addlo r0, r0, #4		/* move to next */
	blo	clbss_l

	/* Call _main */
	ldr pc, =main     @ 汇编调用C  跳转到main.c文件的main函数中


/*
 * Exception handlers
 */
	.align 5  // 2的5次方,=32bit 也就是4字节对其
undefined_instruction:
	b	.

	.align 5
software_interrupt:
	b	.

	.align 5
prefetch_abort:
	b	.

	.align 5
data_abort:
	b	.

	.align 5
not_used:
	b	.

	.align 5
	.global irq
irq:
	sub  lr, lr, #4
	stmfd sp!, {r0-r12, lr}
	bl do_irq
	ldmfd sp!, {r0-r12, pc}^

	.align 5
	.global fiq
fiq:
	b .
stacktop:    .word 		stack + 4 * 512
.data

stack:	 .space  4 * 512



实验现象

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/28696.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS元服务端云一体化开发快速入门(上)

一、前提条件 您已使用已实名认证的华为开发者帐号登录DevEco Studio。 请确保您的华为开发者帐号余额充足&#xff0c;账户欠费将导致云存储服务开通失败。 二、选择云开发模板 1.选择以下任一种方式&#xff0c;打开工程创建向导界面。 如果当前未打开任何工程&#xff0c…

Question Log

Question Log 提示&#xff1a;记录一下平常遇到的坑 Question Log&#xff08;★ &#xff1e; &#xff09; Question LogⅠ、★ &#xff1e; 使用VsCode构建Unity开发环境1.环境配置2.遇到的相关问题★.The .NET Core SDK cannot be located: A valid dotnet installation …

JS + 浮动 + 递归实现图片瀑布流懒加载

思路 页面 pege 分成左浮动的数列 lineBox&#xff0c;每列中图片 sinImg 依次向下摆放每加载一张图片时&#xff0c;判断页面中哪列的高度最小&#xff0c;将当前图片放到最小的那列尾部监听当前图片 onload 事件&#xff0c;当前图片加载完成后&#xff0c;再加载下一张图片…

力扣题库刷题笔记5--最长回文子串

1、题目如下&#xff1a; 2、个人Python代码实现&#xff1a; 首先想到的是通过类似冒泡排序的方式进行切片&#xff0c;然后判断切片的子字符串是否为回文字符串&#xff0c;然后记录出最长的回文字符串&#xff0c;代码如下&#xff1a; 可以看到&#xff0c;通过切片的方式&…

剑指offer35 复杂链表的复制

复杂链表的复制 文章目录 复杂链表的复制方法一 回溯哈希表第二种解释 方法二&#xff1a;拼接拆分算法流程 参考文献 本题要求我们对一个复杂链表进行复制。在复杂链表中&#xff0c;每个节点除了有一个next指针指向下一个节点&#xff0c;还有一个random指针指向链表中的任意…

嵌入式容器源码解析

问题分析 不同于使用springmvc,在我们使用springboot时无需配置tomcat就可以直接使用&#xff0c;这就说明springboot已经在我们启动项目时将tomcat配置好了&#xff0c;接下来我们就来看看springboot底层是怎么实现的。 源码解析 ServletWebServerFactoryAutoConfiguratio…

Python 标准库 - 并发执行

Python 标准库 - 并发执行 1. 简单介绍2. 程序示例2.1 threading 编程示例2.2 multiprocessing 编程示例2.3 concurrent.futures 编程示例 1. 简单介绍 Python 标准库 非常庞大&#xff0c;所提供的组件涉及范围十分广泛&#xff0c;官方参考链接https://docs.python.org/zh-cn…

unity 3d实现下雨、雾气、萤火虫和火花四溅的粒子效果

文章目录 先看最终效果1. 下雨效果2. 雾气效果3. 萤火虫和火花四溅的效果 3d下雨粒子效果涟漪效果雨滴和涟漪效果结合水花效果雨滴涟漪水花结合问题雾气效果萤火虫火花效果萤火虫和火花效果结合完毕 先看最终效果 1. 下雨效果 2. 雾气效果 3. 萤火虫和火花四溅的效果 3d下雨粒…

函数栈帧的创建与销毁

函数栈帧的创建与销毁 前言认识相关寄存器认识相关汇编命令详解思路图 前言 函数栈帧的创建与销毁在不同编译器下&#xff0c;函数调用过程中栈帧的创建略有差异&#xff0c;具体细节取决于编译器的实现&#xff0c;但大体逻辑是一致的。&#xff08;在使用编译器时&#xff0…

某游戏登录密码加密,webpack

注意&#xff1a;文章内容仅用于学习和技术交流&#xff0c;切勿做出违法的事情&#xff0c;如有侵权请联系我删除。 网址&#xff08;今天的大冤种&#xff09;&#xff1a;aHR0cHM6Ly93d3cuZ205OS5jb20v 一&#xff0c;分析 从上面图片可以看到&#xff0c;他的密码是加密了…

桥接模式(十)

不管怎么样&#xff0c;都要继续充满着希望 上一章简单介绍了适配器模式(九), 如果没有看过, 请观看上一章 一. 桥接模式 引用 菜鸟教程里面的 桥接模式介绍: https://www.runoob.com/design-pattern/bridge-pattern.html 桥接&#xff08;Bridge&#xff09;是用于把抽象化…

谷粒商城p46-配置网关路由与路径重写

软件 &#xff1a; vscode idea 服务&#xff1a; renren-fast&#xff0c;gulimall-product&#xff0c;gulimall-gateway、nacos 前提条件&#xff1a; gateway、renren-fast已经注册到nacos 注意&#xff1a; 1、renren-fast单独注入nacos依赖&#xff0c;不要注入common…

#2023开放原子全球开源峰会之旅

#2023我在开源峰会 2023开放原子全球开源峰会参会指南 嗨咯&#xff0c;大家好&#xff01; 6月11号&#xff0c;是一年一度的开放原子大会&#xff0c;有幸参加&#xff0c;很开心&#xff01; 文章目录 1、逛展区&#xff08;领周边&#xff09;环节1.1 CSDN展区1.2 阿里云 …

ansible的部署和命令模块

一、 ansible 的概述 1、ansible简介 Ansible是一款为类Unix系统开发的自由开源的配置和自动化工具。 它用Python写成&#xff0c;类似于saltstack和Puppet&#xff0c;但是有一个不同和优点是我们不需要在节点中安装任何客户端。 它使用SSH来和节点进行通信。Ansible基于 …

(九)CSharp-数组

一、矩形数组 1、访问数组元素 class Program{static void Main(string[] args){int[] intArr1 new int[15];intArr1[2] 10;int var1 intArr1[2];int[,] intArr2 new int[5, 10];intArr2[2, 3] 7;int var2 intArr2[2, 3];int[] myIntArray new int[4];for (int i 0; i…

计算字母出现次数【存在括号计算】

计算字母出现次数【存在括号计算】 此代码考虑到了本问题的大多可能情况&#xff0c;闲话少述&#xff0c;代码中的注释很丰富。 代码绝对可以解决你的问题&#xff01; 不行你就评论&#xff0c;回复速度超快 作者时间YaoChongChong2023年6月14日10&#xff1a;40 Descript…

【gcc, cmake, eigen, opencv,ubuntu】五.CMakeLists.txt编写

文章目录 CMakeLists.txt编写1.CMakeLists.txt模板2.设置编程语言版本3.设置编译类型Debug&#xff0c;Release4.设置获取文件列表5.添加include目录6.配置编译选项 CMakeLists.txt编写 1.CMakeLists.txt模板 一个使用opencv 的 CMakeLists.txt # cmake最低版本要求 cmake_m…

该怎么学Python?自学Python的方法和资料整理!

导语 Python 作为一门简洁、易学且功能强大的编程语言&#xff0c;备受程序员和初学者的喜爱。如果你也想学习 Python&#xff0c;但不知从何入手&#xff0c;本文将为你整理一些自学 Python 的方法&#xff0c;助你快速入门并掌握这门语言。 为什么学习Python&#xff1f;&a…

requests库的使用

文章目录 get 请求post 请求get 请求和 post 请求的区别response1. res.headers2. status_code3. json get 请求 参数类型作用urlstr发起请求的地址params字典url为基准地址&#xff0c;不包含查询参数&#xff1b;使用此参数会自动对 params 字典编码&#xff0c;然后和url拼…

函数参数的拓展

函数参数的默认值 C 中可以在函数声明时为参数提供一个默认值 当函数调用时没有提供默认参数的值&#xff0c;则使用默认值 参数的默认值必须在函数声明中指定 当函数声明时没有出现参数的默认值&#xff0c;而定义的时候出现参数的默认值&#xff0c;编译器会报错 当函数声…