嵌入式学习(2) - LED、BEEP、KEY及中断实验
目录
LED实验
LED初始化
LED点亮/熄灭
蜂鸣器实验
KEY & 中断
1.中断
2.中断处理的基本流程
3.通用中断控制器GIC (管理中断)
GIC核心组件
4.中断实验
开始记录具体的不同模块的裸机开发学习,以下实验都是基于C语言开发,同时要参考IMX6ULL的手册
LED实验
1.在原理图找到连接关系,确认寄存器引脚为GPIO1_IO03
2.引脚方向
GPIO1->GDIR置1为输出模式
IOMUXC_SetPinMux为实验板自带头文件里定义的函数,作用为定义复用功能
IOMUXC_SetPinConfig作用为定义电气特性
LED初始化
void led_init(void) { IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0); IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0x10b0); // IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 0x05; // IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 = 0x10b0; GPIO1->GDIR |= (1 << 3); GPIO1->DR |= (1 << 3); }LED点亮/熄灭
void led_on(void) { GPIO1->DR &= ~(1 << 3); } void led_off(void) { GPIO1->DR |= (1 << 3); }蜂鸣器实验
#include "MCIMX6Y2.h" #include "fsl_iomuxc.h" #include "beep.h" void beep_init(void) { IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01, 0); IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01, 0x10b0); //IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1 = 0x05; //IOMUXC_SNVS_SW_PAD_CTL_PAD_SNVS_TAMPER1 = 0x10b0; GPIO5->GDIR |= (1 << 1); GPIO5->DR |= (1 << 1); } void beep_on(void) { GPIO5->DR &= ~(1 << 1); } void beep_off(void) { GPIO5->DR |= (1 << 1); }KEY & 中断
1.中断
CPU打断当前正在进行的工作,去处理更为紧急的任务,并且在处理完中断任务后还能回到原先的地方进行工作。
2.中断处理的基本流程
(1)中断请求:由外设(中断源)主动向CPU发出请求。
(2)中断响应条件判断:CPU检查是否允许响应此中断,以及该中断是否被屏蔽。
(3)中断优先级裁决:若同时有多个中断请求,CPU根据预设优先级决定处理顺序。
(4)保护现场:将当前任务的执行环境(如寄存器值)保存起来,以便后续恢复。
(5)执行中断服务函数:执行处理该紧急事件的特定程序代码。
(6)恢复现场:将之前保存的执行环境恢复,使原任务得以继续执行。
3.通用中断控制器GIC (管理中断)
arm中,片内外设控制器给内核(A7)发送通知,此称之为中断,这个过程中间需要经历GIC。
GIC核心组件
分发器 (Distributor):
负责接收所有中断源(SGI, PPI, SPI)的信号。
对中断进行使能/禁用、优先级划分、路由分发(决定将中断发送给哪个CPU Interface)等全局管理。
CPU接口 (CPU Interface):
每个CPU核心都有一个独立的接口。
负责向连接的CPU核心提交中断请求。
接收CPU发出的中断响应确认和处理完成信号。
4.中断实验
main.c函数
void ccm_ccgr_enable(void) { CCM->CCGR0 = 0xffffffff; CCM->CCGR1 = 0xffffffff; CCM->CCGR2 = 0xffffffff; CCM->CCGR3 = 0xffffffff; CCM->CCGR4 = 0xffffffff; CCM->CCGR5 = 0xffffffff; CCM->CCGR6 = 0xffffffff; } static void delay(unsigned int num) { while (num--) ; } void gpio1_io18_handler(void) { led_on(); beep_on(); } int main(void) { system_irq_init(); ccm_ccgr_enable(); led_init(); beep_init(); key_irq_init(); while (1) { while (1) { if (key_get_status() == 0) { led_on(); beep_on(); } else { led_off(); beep_off(); } } delay(0x80000); } return 0; }如果是 GPIO1_Combined_16_31_IRQn(按键中断):
检查 GPIO1->ISR寄存器,确认是否是第18引脚触发。
若是,则从 irq_gpio_handler_array数组中取出并执行之前注册的 gpio1_io18_handler函数。
清除该引脚的中断标志(GPIO1->ISR |= (1 << 18))。
//初始化中断系统 void system_irq_init(void) { _set_VBAR(0x87800000); GIC_Init(); } //当GPIO1_IO18中断发生时 中断服务函数 void system_irq_handler(IRQn_Type irq_num) { switch (irq_num) { case GPI01_Combined_0_15_IRQn: case GPIO1_Combined_16_31_IRQn: { if (GPIO1->ISR & (1 << 18)) //判断是否是 GPIO1_IO18产生的中断。 { irq_gpio_handler_array[GPIO1_HANDLER_BASE + 18](); //向中断状态寄存器(ISR)的对应位写1,清除中断标志,告知硬件本次中断已处理完毕 GPIO1->ISR |= (1 << 18); } } break; default: if (irq_handler_array[irq_num]) { irq_handler_array[irq_num](); break; } } }中断注册阶段 (request_irq函数逻辑)
这是向系统注册中断的接口。main.c通过它“预约”中断服务。
int request_irq(int irq_num, irq_handler_t handler) { if ((irq_num < IOMUXC_IRQn) || (irq_num > GPIO_IRQ_MAX)) { return -1; } if (!handler) { return -1; } switch (irq_num) { // case IOMUXC_IRQn ... PMU_IRQ2_IRQn: case GPIO1_IO0_IRQ ... GPIO1_IO15_IRQ: GIC_EnableIRQ(GPIO1_Combined_0_15_IRQn); GIC_SetPriority(GPIO1_Combined_0_15_IRQn, 0); irq_gpio_handler_array[irq_num - GPIO_IRQ_BASE - 1] = handler; break; case GPIO1_IO16_IRQ ... GPIO1_IO31_IRQ: GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn); GIC_SetPriority(GPIO1_Combined_16_31_IRQn, 0); irq_gpio_handler_array[irq_num - GPIO_IRQ_BASE - 1] = handler; break; default: GIC_EnableIRQ(irq_num); GIC_SetPriority(irq_num, 0); irq_handler_array[irq_num] = handler; break; } return 0; }