cortex A7核按键中断实验

news2024/11/25 16:30:53

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



实验现象

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ElasticSearch安装与介绍

目录 ElasticSearch安装与介绍Elastic Stack简介ElasticsearchLogstashKibanaBeats ElasticSearch快速入门简介下载单机版安装启动ElasticSearch 错误分析错误情况1错误情况2错误情况3 ElasticSearch-Head可视化工具通过Docker方式安装通过Chrome插件安装 ElasticSearch中的基本…

docker部署prometheus+grafana+alertmanager+dingtalk实现钉钉告警

目录 docker安装准备工作镜像拉取容器启动启动node-exporter启动prometheus启动grafana启动webhook-prometheus-dingtalk启动alertmanager所有容器启动成功如下 将prometheus和alertmanager进行关联在prometheus目录下新建一个rules.yml文件的告警规则修改prometheus.yml文件&a…

NLP学习笔记十二-skip-gram模型求解

NLP学习笔记十一-skip-gram模型求解 上一篇文章&#xff0c;我们见到了skip-gram模型的原理&#xff0c;这里我们在陈述一下skip-gram模型其实是基于分布相似性原理来设计的&#xff0c;在skip-gram模型中&#xff0c;他认为一个词的内涵可以由他的上下文文本信息来概括&#…

AcWing 837. 连通块中点的数量

题目如下&#xff1a; 给定一个包含 n个点&#xff08;编号为 1∼ n&#xff09;的无向图&#xff0c;初始时图中没有边。 现在要进行 m 个操作&#xff0c;操作共有三种&#xff1a; C a b&#xff0c;在点 a和点 b之间连一条边&#xff0c;a 和 b 可能相等&#xff1b;Q1 …

【iMessage苹果日历推真机群控】使用虚拟化平台创建一个 macOS 虚拟机

PC 虚拟机上部署群控推送并模拟苹果 iMessage 推送消息是比较复杂的任务。由于苹果的 iMessage 服务是基于苹果设备和操作系统的&#xff0c;模拟 iMessage 推送需要考虑苹果的生态系统和安全机制。 以下是一种可能的方法&#xff0c;但请注意这是一个高级设置&#xff0c;需要…

chatgpt赋能python:Python编程中的放大代码技巧

Python 编程中的放大代码技巧 Python 是一门广泛应用于各个领域的编程语言。由于它易学易用、可移植性好、开发效率高等特点&#xff0c;使其在人工智能、大数据分析、网站开发等领域被广泛应用。在实际编程中&#xff0c;随着代码量的增加&#xff0c;需要更好地组织和管理代…

BFS 广度优先搜索

广度优先搜索BFS&#xff08;Breadth First Search&#xff09;也称为宽度优先搜索&#xff0c;它是一种先生成的结点先扩展的策略&#xff0c;类似于树的层次遍历。 在广度优先搜索算法中&#xff0c;解答树上结点的扩展是按它们在树中的层次进行的。首先生成第一层结点&#…

TS系列之keyof详解,示例

文章目录 前言一、keyof是什么总结 前言 如果你用过TS的工具类型&#xff0c;Partial、Required、Pick、Record。那么你可能看过他们内部实现都有共同点就是keyof关键字。即使没有见过&#xff0c;那么下面就一起来了解一下&#xff0c;keyof关键字的详细作用吧。 一、keyof是…

Filebeat详细介绍,下载和启动,日志读取和模块设置等

目录 Filebeat介绍为什么要用Filebeat&#xff1f;架构下载启动读取文件自定义字段输出到ElasticSearch Filebeat工作原理harvesterprospectorinput启动命令参数说明 部署Nginx读取Nginx中的配置文件Modulenginx module 配置配置filebeat测试错误1错误2 Filebeat 介绍 Filebe…

Java开发中的常见问题和解决方法:如何解决常见的性能和bug问题

章节一&#xff1a;引言 在Java开发中&#xff0c;我们经常会面临各种各样的问题&#xff0c;包括性能问题和Bug。这些问题可能会导致应用程序的运行变慢、不稳定甚至崩溃。本文将介绍一些常见的Java开发问题&#xff0c;并提供解决这些问题的方法和技巧&#xff0c;帮助开发人…

ElasticSearch集群8.0版本搭建、故障转移

目录 ElasticSearch集群集群节点搭建集群分片和副本 故障转移将data节点停止将master节点停止 分布式文档路由文档的写操作 搜索文档全文搜索搜索&#xff08;query&#xff09;取回 fetch ElasticSearch集群 集群节点 ELasticsearch的集群是由多个节点组成的&#xff0c;通过…

SSM学习记录9:SpringBoot整合SSM(注解方式)

SSM学习记录9&#xff1a;SpringBoot整合SSM&#xff08;注解方式&#xff09; 1.首先创建新项目&#xff0c;选择Spring Initializr&#xff0c;type为Maven 2.接着依赖选择Spring Web 3.无需繁琐配置&#xff0c;即可运行编写的controller类 启动SpringBootDemoApplication↓…

利用人工智能模型学习Python爬虫

爬虫是一种按照一定的规则&#xff0c;自动地抓取万维网信息的程序或者脚本。 网络爬虫(又称为网页蜘蛛&#xff0c;网络机器人)是其中一种类型。 爬虫可以自动化浏览网络中的信息&#xff0c;当然浏览信息的时候需要按照我们制定的规则进行&#xff0c;这些规则我们称之为网络…

UE4/5样条线学习(一):基础的样条线使用

目录 效果展示&#xff1a; 制作&#xff1a; 组件 逻辑 效果展示&#xff1a; 注&#xff1a;按住alt拉轴可以拉出多一个点 制作&#xff1a; 第一步我们创建一个蓝图&#xff0c;命名为BP_Sline&#xff1a; 组件 之后我们开始找组件&#xff0c;输入bill&#xff0c;我…

使用 docker 创建 mongodb 副本集, 和调整副本集优先级

mongod 本地创建副本集 mongod --port 27017 --dbpath /srv/mongodb/db0 --replSet rs0 --bind_ip localhost,<hostname(s)|ip address(es)> –dbpath 指向数据存放地址 –replSet 后面为 副本集的名。 rs.initiate() 启动新的副本集 rs.conf() 查看副本集的配置 rs.stat…

chatgpt赋能python:Python实现多关键词搜索PDF文件

Python实现多关键词搜索PDF文件 概述 在今天的数字化社会中&#xff0c;很多信息都以数字化的形式存储在PDF文件中。这让我们在搜索特定信息时面临很多挑战&#xff0c;特别是当我们需要同时搜索多个PDF文件并集中检索这些文件时。 在这篇文章中&#xff0c;我们将介绍如何使…

HTTP协议,带你了解HTTP协议

目录 1、HTTP 协议介绍 2、HTTP 协议的工作过程 HTTP 协议的工作过程可以分为以下几个步骤&#xff1a; 3、Fiddler 抓包工具介绍 3.1 抓包工具的使用 3.2 抓包结果 3.3 抓包工具原理 4、HTTP 协议格式总览 5、HTTP 请求&#xff08;Request&#xff09; 5.1 认识 URL…

Seata分布式事务实现

docker方式搭建seata-server(推荐) 参考官方文档: 使用 Docker 部署 Seata Server docker run -d --name seata-server -p 8091:8091 -p 7091:7091 seataio/seata-server:1.6.1 根据版本情况使用不同版本的镜像: https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7…

算法拾遗三十三Morris遍历

算法拾遗三十三Morris遍历 常规二叉树遍历Morris遍历Morris遍历判断是否是搜索二叉树给定一颗二叉树的头节点head&#xff0c;求以head为头的树中&#xff0c;最小深度是多少&#xff1f; 常规二叉树遍历 public static class Node {public int value;Node left;Node right;pub…

UE4/5样条线学习(二):样条网格体组件的使用

目录 效果展示&#xff1a; 制作&#xff1a; 效果展示&#xff1a; 制作&#xff1a; 前面的步骤和之前的UE4/5样条线学习&#xff08;一&#xff09;&#xff1a;基础的样条线使用_多方通行8的博客-CSDN博客是一样的。 创建一个actor蓝图&#xff0c;然后一个公告板组件&…