代码改变世界

实用指南:20250924的学习笔记

2025-09-27 21:49  tlnshuju  阅读(9)  评论(0)    收藏  举报

i.MX6ULL 按键构建速查笔记(轮询 vs 中断)

一、轮询方式(Polling)

1. 初始化 4 大步
① 复用 IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B
MUX_MODE = ALT5 (0101b) → GPIO1_IO18
代码:IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);

② 电气 IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B
HYS=0 PUS=11b(22 kΩ上拉) PUE=1 PKE=1 ODE=0 SPEED=10b(100 MHz) DSE=000(输出禁用) SRE=0
代码:IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0xF080);

③ 方向 GPIO1->GDIR &= ~(1<<18); // 输入

④ 时钟 CCM_CCGR1 |= 0x3<<26; // 打开 GPIO1 门控(也可直接 CCM->CCGR1 = 0xFFFFFFFF)

2. 运行时
读 GPIO1->DR:
1 = 松开,0 = 按下(上拉 + 按键接地)

3. 缺陷
主循环若被大量耗时任务占用(如 delay(0x7FFFFF)),会漏采样 → 实时性丧失(“汽车刹车”场景不可用)


二、中断方式(GPIO 外部中断 → GIC)

1. 中断路径
外设 GPIO → GIC(SPI) → CPU interface → Core-A7 → 向量表 → 用户 ISR

2. GIC 中断号
IMX6ULL 外设中断 0–159(MCIMX6Y2.h 的 IRQn_Type)
GPIO1_IO16–31 合并为 SPI:GPIO1_Combined_16_31_IRQn(查表 53 号)

3. 关键寄存器
• Distributor:使能、优先级、分组
• CPU interface:应答、优先级屏蔽、EOI
• CP15:
VBAR = 0x87800000 (__set_VBAR)
CBAR 保存 GIC 物理基址(0x00A00000)

4. 中断调整步骤(GPIO1_IO18 例程)

① 初始化同上(复用、电气、方向、时钟)
② 边沿触发 GPIO1->ICR2 |= 3<<4; // 双边沿
③ 取消屏蔽 GPIO1->IMR |= 1<<18;
④ GIC 使能 GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);
⑤ 优先级 GIC_SetPriority(GPIO1_Combined_16_31_IRQn, 0);
⑥ 注册 system_interrupt_register(GPIO1_Combined_16_31_IRQn, key_irq_handler);
⑦ 向量表 system_interrupt_init(); // 设置 VBAR + GIC_Init()

5. ISR 注意事项
• 清 GPIO 中断标志:GPIO1->ISR = 1<<18;
• 清 GIC 挂起:GIC_ClearPendingIRQ(...)
• 简短迅速,可追加消抖(简单延时或定时器)


三、速记口诀

“轮询四步:复用-电气-方向-时钟;
中断加四:边沿-屏蔽-GIC-向量;
标志清俩:GPIO ISR + GIC pending;
实时用中断,轮询只教学。”

四、按照中断流程编写代码

(1)中断源:

1.中断配置寄存器(触发方式)

GPI01_ICR2:

GPIO1->1CR2|=(3<<4);

2.中断屏蔽寄存器(解除屏蔽)

GPI01_IMR:

GPI01->IMR|=(1<<18);

3.中断状态寄存器(判断中断)

GPI01_ISR:

if((GPI01->|SR&(1<<18))!=0)

{

led_norO;

GPIO1->ISRI=(1<<18);

}

(2)GIC:

1.GIC的初始化

GIC_Init();

2.使能irq中断

GIC_EnableIRQ(99);

3.中断优先级设置

GIC_SetPriority(99,0);

4.获取GIC寄存器组基地址

mrc p15, 4, r0, c15, c0,0

5.中断通知寄存器

C_IAR:base+offect(0x200C)

add r0,r0,#0x2000

ldr, r1,[r0,#0x0C]

6.中断结束寄存器

C_E0IR:base+offect(0x2010)

str,r1,[r0,#0x10]

(3)Kernal:

1.异常向量表基地址重映射(顺便打开icache)

mrc p15, 0,r0,c1, c0, 0

bic r0,r0, #(1 <<13)

orr r0,r0,#(1<<12)

mcr p15, 0,r0, c1, c0, 0

__set_VBAR(0x87800000)

2.异常向量的处理函数

_irq_handler_:

sub lr, lr, #4

stmfd sp!, {r0-r12, lr}

mrc p15, 4, r1, c15, c0, 0

add r1, r1, #0x2000

ldr r0, [r1, #0x0C]

stmfd sp!, {r0, r1}

cps #0x1F

stmfd sp!, {lr}

bl system_interrupt_handler

ldmfd sp!, {lr}

cps #0x12

ldmfd sp!, {r0, r1}

str r0,[r1, #0x10]

ldmfd sp!, {r0-r12, pc}^

3.中断处理函数

void system_interrupt_handler(IRQn_Type irq)

{

if (irq == GPIO1_Combined_16_31_IRQn)

{

if ((GPIO1->ISR & (1 << 18)) != 0)

{

GPIO1->ISR = (1 << 18);

}

}

}