目录
[二、GPIO 配置步骤(核心)](#二、GPIO 配置步骤(核心))
[(1)整体流程(4 步走)](#(1)整体流程(4 步走))
[1. 编译:生成 .o 文件](#1. 编译:生成 .o 文件)
[2. 链接:生成 .elf 文件](#2. 链接:生成 .elf 文件)
[3. 格式转换:生成 .bin 文件](#3. 格式转换:生成 .bin 文件)
[4. 反汇编:生成 .dis 文件(调试用)](#4. 反汇编:生成 .dis 文件(调试用))
[(4)最关键的 3 个知识点](#(4)最关键的 3 个知识点)
一、硬件原理分析
学习采用IMX6ULL核心板:

-
查看开发板原理图
- 确定 LED 对应的 GPIO 引脚(如 GPIO1_IO03 等,依底板实际电路)。

- 确认驱动逻辑:高电平点亮 / 低电平点亮,是否有上拉 / 下拉,在GPIO_IO03中,低电平(0)点亮,高电平(1)灭。

- 明确 GPIO 属于哪个模块,方便后续配置时钟与寄存器。
- 确定 LED 对应的 GPIO 引脚(如 GPIO1_IO03 等,依底板实际电路)。
-
控制逻辑
- 配置引脚为 GPIO 功能。
- 设置为输出模式。
- 输出高低电平实现亮灭。
二、GPIO 配置步骤(核心)
i.MX6ULL 配置一个通用 GPIO 输出共四步:选择引脚功能(MUXIO_SW)、配置引脚电气属性(PAD_SW)、配置引脚方向(DIR)、输出高低电平(DR)

-
选择引脚功能(MUX)
代码:
csldr r0, =0x20e0068 ldr r1, [r0] bic r1, r1, #0x1f orr r1, r1, #0x05 str r1, [r0]- 通过 IOMUXC 控制器,将引脚复用为 GPIO 模式。
- 配置 IOMUXC_MUX_REG,设置为 ALT5 等 GPIO 模式。
- 具体操作:查看IMX6ULL手册,找到GPIO_IO03引脚进行配置。

-
配置引脚电气特性(PAD)
代码:
csldr r0, =0x20e02f4 ldr r1, [r0] /*unuse*/ ldr r1, =0x10b0 str r1, [r0]-
设置上下拉、速度、驱动能力、开漏等。
-
配置 IOMUXC_PAD_REG,一般设置为普通推挽输出,将IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03寄存器的低4位设置为0x10b0 。

-
-
配置引脚方向(DIR)
代码
csldr r0, =0x209c004 ldr r1, [r0] orr r1, r1, #(1 << 3) str r1, [r0]- 配置 GPIOx_GDIR 寄存器。
- 对应位写 1 为输出模式,写 0 为输入模式。
- 具体操作:根据手册找到GPIO_DR和GPIO_GDIR,GPIO1_DR 第3位(GPIO1_IO3)置0(低电平)或置1(高电平),GPIO1_DIR 第3位(GPIO1_IO3)设置位1,引脚方向为输出,反之则为输入模式


-
输出高低电平(DR)
代码:
cs;置为1 ldr r0, =0x209c000 ldr r1, [r0] bic r1, r1, #(1 << 3) str r1, [r0] ;置为0 ldr r0, =0x209c000 ldr r1, [r0] orr r1, r1, #(1 << 3) str r1, [r0] bx lr
三、裸机代码结构
在GNU中可以直接用**.global _start**
具体代码:
cs
.global _start
_start:
ldr pc, =_reset_handler
ldr pc, =_software_handler
ldr pc, =_undef_handler
ldr pc, =_prefetch_abort_handler
ldr pc, =_data_abort_handler
nop
ldr pc, =_irq_handler
ldr pc, =_fiq_handler
_software_handler:
b _software_handler
_undef_handler:
b _undef_handler
_prefetch_abort_handler:
b _prefetch_abort_handler
_data_abort_handler:
b _data_abort_handler
_irq_handler:
b _irq_handler
_fiq_handler:
b _fiq_handler
_reset_handler:
/*DDR 0x80000000 ~ 0X9FFFFFFF*/
cpsid i /*disable irq*/
ldr sp, =0x81000000 /*init system mode stack 16M */
cps #0x12 /*change to irq mode */
/*
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0x12
msr cpsr_c, r0
*/
ldr sp, =0x82000000 /*init irq mode stack 16M */
cps #0x1f /* change to system mode */
/*
mrs r0, cpsr
orr r0, r0, #0x1f
msr cpsr_c, r0
*/
cpsie i /* enable irq */
bl led_init
led:
bl led_on
bl led_delay
bl led_off
bl led_delay
b led
code_end:
b code_end
led_init:
ldr r0, =0x20e0068
ldr r1, [r0]
bic r1, r1, #0x1f
orr r1, r1, #0x05
str r1, [r0]
ldr r0, =0x20e02f4
ldr r1, [r0] /*unuse*/
ldr r1, =0x10b0
str r1, [r0]
ldr r0, =0x209c004
ldr r1, [r0]
orr r1, r1, #(1 << 3)
str r1, [r0]
ldr r0, =0x209c000
ldr r1, [r0]
orr r1, r1, #(1 << 3)
str r1, [r0]
bx lr
led_on:
ldr r0, =0x209c000
ldr r1, [r0]
bic r1, r1, #(1 << 3)
str r1, [r0]
bx lr
led_off:
ldr r0, =0x209c000
ldr r1, [r0]
orr r1, r1, #(1 << 3)
str r1, [r0]
bx lr
led_delay:
ldr r0, =0x80001
loop_delay:
sub r0, r0, #1
cmp r0, #0
bge loop_delay
bx lr
四、编译、链接、烧写代码等
(1)整体流程(4 步走)
汇编/源码文件 (.s/.c)
↓ 编译
目标文件 (.o)
↓ 链接
可执行文件 (.elf)
↓ 格式转换
二进制文件 (.bin) 【烧写到开发板】
↓ 反汇编
反汇编文件 (.dis) 【调试用】
(2)逐步骤详细说明
1. 编译:生成 .o 文件
工具 :arm-linux-gnueabihf-gcc
作用 :把汇编 / C 源码 → 生成机器码目标文件,但不进行链接。
命令:
arm-linux-gnueabihf-gcc -g -c led.s -o led.o
参数说明
-g:生成调试信息,给 GDB 调试用-c:只编译,不链接-o led.o:指定输出文件名为led.o
结果 生成 led.o 文件(二进制机器码,但还不能直接运行)
2. 链接:生成 .elf 文件
工具 :arm-linux-gnueabihf-ld
作用 :给代码指定运行地址(链接地址),把多个 .o 文件合并成一个可执行文件。
重要概念
- 存储地址:代码放在 SD 卡、Flash 中的地址
- 运行地址:代码真正执行时所在的地址(必须在链接时指定)
- i.MX6ULL 启动:bootrom 会自动把 SD 卡代码复制到运行地址(DDR)
链接地址 0X87800000(DDR 地址,与 U-Boot 统一,方便学习)
命令:
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
参数说明
-Ttext 地址:指定代码段运行地址-o led.elf:输出为 elf 文件
结果 生成 led.elf(带地址信息的可执行文件)
3. 格式转换:生成 .bin 文件
工具 :arm-linux-gnueabihf-objcopy
作用 :把 .elf 转成纯二进制文件 .bin,用于烧写到开发板。
命令:
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
参数说明
-O binary:输出纯二进制格式-S:不要重定位信息-g:不要调试信息
结果 生成 led.bin这就是最终烧写到 SD 卡的文件!
4. 反汇编:生成 .dis 文件(调试用)
工具 :arm-linux-gnueabihf-objdump
作用 :把 .elf 转回汇编代码,方便查看地址、调试程序。
命令:
arm-linux-gnueabihf-objdump -D led.elf > led.dis
参数说明
-D:反汇编所有段> led.dis:输出到文件
结果 生成 led.dis可以看到代码被链接到 0X87800000 开始的地址。
(3)总结整个流程
• arm-linux-gnueabihf-gcc-g-c led.s -o led.o
• arm-linux-gnueabihf-ld -Ttext 0x87800000 led.o -o led.elf
• arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
• arm-linux-gnueabihf-objdump -D led.elf > led.dis
led.s
→ 编译成 led.o
→ 链接成 led.elf(指定运行地址)
→ 转成 led.bin(烧写到开发板)
→ 反汇编成 led.dis(调试)
(4)最关键的 3 个知识点
- 编译:生成机器码
- 链接 :指定代码在内存中的运行地址
- bin 文件:真正能在芯片上运行的纯二进制代码
很明显,如果一步步编译,则会很麻烦,这里写一个makefile可是更便捷
cs
TARGET=start
CC=arm-linux-gnueabihf-
LD=$(CC)ld
OBJCOPY=$(CC)objcopy
OBJDUMP=$(CC)objdump
OBJ=start.o main.o
$(TARGET).bin:$(OBJ)
$(LD) -Ttext 0x87800000 $(OBJ) -o $(TARGET).elf
$(OBJCOPY) -O binary -S -g $(TARGET).elf $@
$(OBJDUMP) -D $(TARGET).elf > $(TARGET).dis
%.o:%.S
$(CC)gcc -c -g $^ -o $@
%.o:%.c
$(CC)gcc -c -g $^ -o $@
clean:
rm $(TARGET).bin $(TARGET).elf $(TARGET).dis *.o
load:
./imxdownload $(TARGET).bin /dev/sdb
(5)烧写到SD卡中
.bin文件准备就绪后,插入sd卡连接到ubuntu;把imxdownload放入当前文件夹,然后写入bin文件,然后make load下载代码到SD卡中。
六、注意事项
- 必须先使能时钟,否则 GPIO 无法工作。
- 引脚 MUX 配置必须正确,否则不是 GPIO 模式。
- 链接地址必须与实际运行地址一致,否则跑飞。
- 裸机无操作系统,不能使用标准库函数,需自己实现操作。
- 电平逻辑要与硬件一致,避免配置相反导致不亮。
- 烧写时注意 SD 卡设备号,避免误烧硬盘。
七、学习总结
本次实验完成 i.MX6ULL 裸机开发完整流程:看原理图 → 分析 GPIO → 配置寄存器 → 编写 S 代码 → 编译链接 → 制作镜像 → SD 卡烧写 → 运行验证。理解了 Cortex‑A7 下裸机驱动的基本思想,掌握了 GPIO 输出配置方法,为后续按键、UART、I2C、SPI 等外设裸机驱动打下基础。