1.LED 模块硬件设计
- 用户可控 LED:红色 LED,阳极通过 510Ω 限流电阻连接到
GPIO1_IO03引脚,阴极接地(GND); - 电源指示灯:蓝色 LED,直接接电源,上电即亮(无需软件控制,仅用于判断供电)
- 控制逻辑:GPIO_IO03输出低电平时,LED 两端形成电压差(VCC → 电阻 → LED → GND),电流流过点亮;输出高电平时,两端无压差,LED 熄灭。
2.LED模块软件设计
1.内核初始化:启动代码框架与关键指令
1.异常向量表
.global _start ; 声明入口符号,链接器需识别
_start: ; 异常向量表(地址 0x00000000 开始,对应复位后 PC 初始值)
ldr pc, =_start_handler //复位异常(唯一会执行的异常入口)
ldr pc, =_undef_handler //未定义指令异常
ldr pc, =_svc_handler //SVC 异常(软中断)
ldr pc, =_prefetch_handler //预取指异常
ldr pc, =_data_handler//数据异常
ldr pc, =_reserved_handler //预留异常
ldr pc, =_irq_handler //IRQ 中断(外设常用)
ldr pc, =_fiq_handler//FIQ 中断 ; 复位异常处理函数
_undefined_hander:
b _undefined_hander
_supervisor_hander:
b _supervisor_hander
_prefetch_hander:
b _prefetch_hander
_data_hander:
b _data_hander
_not_use_hander:
b _not_use_hander
_irq_hander:
b _irq_hander
_fiq_hander:
b _fiq_hander
2.系统初始化:复位异常处理函数
重点指令:cps
CPS<effect> <iflags>{, #<mode>}
CPS #<mode>
<effect>:
| 参数值 | 含义 | 说明 |
|---|---|---|
ie | Interrupt Enable(使能) | 允许指定类型的中断触发(仅对 IRQ/FIQ 生效) |
id | Interrupt Disable(禁止) | 禁止指定类型的中断触发 |
<iflags>:
| 参数值 | 对应中断类型 | 说明 |
|---|---|---|
i | IRQ 中断 | 普通外设中断(如 GPIO 中断、UART 中断、定时器中断),优先级较低 |
f | FIQ 中断 | 快速中断(如高速 ADC、紧急硬件故障),优先级较高,响应速度更快 |
a | All(所有) | 同时控制 IRQ 和 FIQ 中断(禁止 a 即禁止所有可屏蔽中断) |
<mode>:目标 CPU 工作模式(M 域编码)7种工作模式
_start_hander: //上电触发
cpsid i //关闭普通中断,在模式转换过程中不被打扰
cps #0x12 //irq
ldr sp, =0x82000000 //分配irq栈地址
cps #0x1F //sys
ldr sp, =0x84000000 //分配sys栈地址
cpsie i //打开普通中断
2.外设操作核心:GPIO 寄存器配置
1.确定需要配置值
| 寄存器名称 | 基地址 | 偏移地址 | 完整地址 | 核心功能 |
|---|---|---|---|---|
| PAD_GPIO1_IO03 | 0x020E0000 | 0x0068 | 0x020E0068 | 配置引脚复用功能(切换为 GPIO) |
| PAD_GPIO1_IO03 | 0x020E0000 | 0x02F4 | 0x020E02F4 | 配置引脚电气特性 |
| GPIO1_GDIR(方向寄存器) | 0x0209C000 | 0x0004 | 0x0209C0004 | 配置 GPIO 为输入 / 输出 |
| GPIO1_DR(数据寄存器) | 0x0209C000 | 0x0000 | 0x0209C0000 | 控制 GPIO 输出 |
2.LED 初始化函数
led_init:
//配置复用功能
GPIO ldr r0, =0x020E0068 /加载复用控制寄存器地址
ldr r1, =0x05 //配置值
str r1, [r0] //将配置值写入寄存器
//配置引脚电气特性为默认值
ldr r0, =0x020E02F4 // 加载电气特性寄存器地址
ldr r1, =0x10B0 //配置值
str r1, [r0] //将配置值写入寄存器
//配置 GPIO 方向:设为输出模式
ldr r0, =0x0209C004//加载 GPIO1 方向寄存器地址
ldr r1, [r0] //先读取当前配置(避免覆盖其他引脚设置)
orr r1, r1, #(1 << 3)// 将 bit3 置 1(GPIO1_IO03 对应 bit3,1=输出)
str r1, [r0] // 写入生效
bx lr
3.LED控制函数
//点亮 LED:GPIO1_IO03 输出低电平
led_on:
ldr r0, =0x0209C000 ; 加载 GPIO1 数据寄存器地址
ldr r1, [r0] ; 读取当前电平(避免覆盖其他引脚)
bic r1, r1, #(1 << 3); 将 bit3 清 0(低电平,点亮 LED)
str r1, [r0] ; 写入生效
bx lr ;
//熄灭 LED:GPIO1_IO03 输出高电平
led_off:
ldr r0, =0x0209C000 ; 加载 GPIO1 数据寄存器地址
ldr r1, [r0] ; 读取当前电平
orr r1, r1, #(1 << 3); 将 bit3 置 1(高电平,熄灭 LED)
str r1, [r0] ; 写入生效
bx lr ;
// 延时函数
led_delay:
ldr r0, =0x7FFFFF ; 延时计数(528MHz 主频下,约 500ms)
loop: sub r0, r0, #1 ; 计数器减 1
cmp r0, #0 ; 比较是否为 0
bgt loop_delay ; 大于 0 则继续循环
bx lr ; 主循环:实现 LED 闪烁
主函数:
bl led_init //初始化
b finish
finish: //进行led亮暗变化
bl led_on
bl led_delay
bl led_off
bl led_delay
b finish
3.编译、烧录与测试
1.编译
1.汇编(.S → .o)
将汇编代码转为目标文件
arm-linux-gnueabihf-gcc -c start.S -o start.o -g //-c 只汇编不链接,-g 保留调试信息
2.链接(.o → .elf)
将目标文件链接到指定地址(i.MX6ULL 从 SD 卡启动时,代码加载地址为 0x87800000)
arm-linux-gnueabihf-ld -Ttext 0x87800000 start.o -o start.elf //-Ttext 指定代码段起始地址
3.格式转换(.elf → .bin)
ELF 文件包含调试信息,需转为纯二进制文件(开发板才能识别)
arm-linux-gnueabihf-objcopy -O binary -S -g start.elf start.bin
//-O binary 指定输出格式,-S/-g 去除符号/调试信息
4.反汇编(.elf → .dis)
将 ELF 文件转为汇编代码(可选)
arm-linux-gnueabihf-objdump -D start.elf > start.dis // -D 反汇编所有段
2.烧录
1.连接SD卡到Ubuntu
2.拷贝下载工具imxdownload到Ubuntu工程目录下
3.修改权限:改为可执行文件
chmod +777 imxdownload
4.烧写程序到SD卡
./imxdownload start.bin /dev/sdb
注:注意烧写速率,如果上M的速度是不成功的,必须拔掉USB读卡器,重启Ubuntu
编译和烧录可用makefile改写:
COPLITE=arm-linux-gnueabihf-
CC=$(COPLITE)gcc
LD=$(COPLITE)ld
OBJCOPY=$(COPLITE)objcopy
OBJDUMP=$(COPLITE)objdump
TAGRET=start
$(TAGRET).bin:$(TAGRET).S
$(CC) -c -g $(TAGRET).S -o $(TAGRET).o
$(LD) -Ttext 0x87800000 $(TAGRET).o -o $(TAGRET).elf
$(OBJCOPY) -O binary -S -g $(TAGRET).elf $(TAGRET).bin
$(OBJDUMP) -D $(TAGRET).elf > $(TAGRET).dis
clean:
rm $(TAGRET).o $(TAGRET).elf $(TAGRET).bin $(TAGRET).dis -f
load:
./imxdownload $(TAGRET).bin /dev/sdb
3.测试
1.启动方式选择SD卡,如图

2.插入SD卡
3.开发板上电
4.观察红色LED灯
1405

被折叠的 条评论
为什么被折叠?



