IMX6ULL 裸机开发实战:从汇编启动代码到 LED 闪烁(Ubuntu 篇)


一、 开发平台与硬件信息

1.1 核心参数

  • 开发板:正点原子 i.MX6ULL-Mini(核心板 + 底板模式)。
  • CPU:NXP i.MX6ULL (Cortex-A7),主频达 800MHz。
  • 内存/存储:512MB DDR3L + 8GB eMMC。
  • 启动方式:支持 SD 卡、eMMC、NAND 等多种模式。

1.2 LED 硬件电路

  • 控制目标:底板上的红色 LED 灯。

  • 引脚连接:GPIO1_IO03。

  • 控制逻辑:共阳极接法。

  • 寄存器输出 0(低电平):LED 点亮。

  • 寄存器输出 1(高电平):LED 熄灭。

  • 限流电阻:510 欧姆,防止电流过大。


二、 编写汇编启动代码(start.S)

启动代码是系统上电后运行的第一段程序,负责初始化处理器状态、设置堆栈和异常向量表。

2.1 完整汇编逻辑

在 VS Code 中创建 start.S,代码如下:

.global _start          @ 定义程序入口点

_start:
    /* 1. 配置异常向量表 */
    ldr pc, = _start_handler           @ 复位中断
    ldr pc, = _undefined_handler       @ 未定义指令
    ldr pc, = _supervisor_handler      @ 软件中断 SWI
    ldr pc, = _prefetch_handler        @ 指令预取中断
    ldr pc, = _data_abort_handler      @ 数据访问中断
    ldr pc, = _not_use_handler         @ 未使用
    ldr pc, = _irq_handler             @ IRQ 中断
    ldr pc, = _fiq_handler             @ FIQ 中断

/* 异常处理死循环 */
_undefined_handler:    b _undefined_handler
_supervisor_handler:   b _supervisor_handler
_prefetch_handler:     b _prefetch_handler
_data_abort_handler:   b _data_abort_handler
_not_use_handler:      b _not_use_handler
_irq_handler:          b _irq_handler
_fiq_handler:          b _fiq_handler

_start_handler:
    /* 2. 中断配置与模式切换 */
    cpsid i                     @ 关闭所有 IRQ 中断

    /* 切换到 IRQ 模式并设置栈指针 */
    cps #0x12                   
    ldr sp, = 0x82000000

    /* 切换到系统(SYS)/用户模式并设置栈指针 */
    cps #0x1F                   
    ldr sp, = 0x84000000        

    cpsie i                     @ 使能中断

    /* 3. 跳转到 LED 初始化逻辑 */
    bl led_init
    b finish

finish:
    bl led_on
    bl led_delay
    bl led_off
    bl led_delay
    b finish

/* --- LED 硬件操作函数 --- */

led_init:
    /* A. 配置引脚复用为 GPIO1_IO03 (MUX 寄存器地址: 0x020E0068) */
    ldr r0, = 0x020E0068
    ldr r1, = 0x05              @ 模式 5 即 GPIO 功能
    str r1, [r0] 

    /* B. 配置电气特性 (PAD 寄存器地址: 0x020E02F4) */
    ldr r0, = 0x020E02F4
    ldr r1, = 0x10B0            @ 设置上拉、驱动能力等
    str r1, [r0]    

    /* C. 配置 GPIO 方向为输出 (GDIR 寄存器) */
    ldr r0, = 0x0209C004
    ldr r1, [r0]
    orr r1, r1, #(1 << 3)       @ 第 3 位置 1
    str r1, [r0]
    bx lr

led_on:
    /* 操作数据寄存器 DR: 第 3 位写 0 */
    ldr r0, = 0x0209C000
    ldr r1, [r0]
    bic r1, r1, #(1 << 3)
    str r1, [r0]
    bx lr

led_off:
    /* 操作数据寄存器 DR: 第 3 位写 1 */
    ldr r0, = 0x0209C000
    ldr r1, [r0]
    orr r1, r1, #(1 << 3)
    str r1, [r0]
    bx lr

led_delay:
    ldr r0, =0x7FFFF
loop:    
    sub r0, r0, #1
    cmp r0, #0
    bgt loop
    bx lr


三、 硬件初始化原理详解

配置 i.MX6ULL 的外设通常遵循以下三个核心步骤:

  1. 复用功能配置 (IOMUX):芯片引脚很多,一个引脚可以做 GPIO,也可以做 UART 或 I2C。我们需要通过 IOMUXC_SW_MUX_CTL_PAD 寄存器将其选定为 GPIO。
  2. 电气特性配置 (PAD):通过 IOMUXC_SW_PAD_CTL_PAD 设置引脚的压摆率、驱动能力、开漏输出以及上下拉电阻。
  3. GPIO 控制器配置
  • GDIR:设置方向。1 为输出,0 为输入。
  • DR:数据寄存器。写 1 输出高电平,写 0 输出低电平。

四、 编译与烧录流程

在 Ubuntu 终端中,我们需要使用 ARM 交叉编译工具链(arm-linux-gnueabihf-)。

4.1 代码编译四部曲

步骤 指令 作用
1. 编译 arm-linux-gnueabihf-gcc -c start.S -o start.o -g 生成目标文件 .o
2. 链接 arm-linux-gnueabihf-ld -Ttext 0x87800000 start.o -o start.elf 链接并指定内存起始地址
3. 转换 arm-linux-gnueabihf-objcopy -O binary -S -g start.elf start.bin 提取可运行的纯二进制文件
4. 反汇编 arm-linux-gnueabihf-objdump -D start.elf > start.dis 生成反汇编文件用于调试

4.2 程序烧录(写入 SD 卡)

  1. 准备环境:将 SD 卡插入电脑,连接至虚拟机。
  2. 查找设备:使用 ls /dev/sd* 确认 SD 卡设备节点(通常为 /dev/sdb/dev/sdc)。
  3. 赋予工具权限chmod +777 imxdownload
  4. 执行烧录
./imxdownload start.bin /dev/sdb

注意:若烧录速度极快且显示“上M”,通常是卡未挂载成功或节点选错,需重新插拔。


五、 使用 Makefile 简化开发

手动输入命令非常繁琐,我们编写一个 Makefile 来自动化处理。

# 1. 定义变量
CROSS_COMPILE ?= arm-linux-gnueabihf-
CC            := $(CROSS_COMPILE)gcc
LD            := $(CROSS_COMPILE)ld
OBJCOPY       := $(CROSS_COMPILE)objcopy
OBJDUMP       := $(CROSS_COMPILE)objdump

# 2. 默认目标生成 start.bin
start.bin : start.S
	$(CC) -c start.S -o start.o -g
	$(LD) -Ttext 0x87800000 start.o -o start.elf
	$(OBJCOPY) -O binary -S -g start.elf start.bin
	$(OBJDUMP) -D start.elf > start.dis

# 3. 清理中间文件
clean:
	rm -f start.o start.elf start.bin start.dis

# 4. 烧录
load:
	./imxdownload start.bin /dev/sdb

使用方法:

  • 输入 make:自动完成编译。
  • 输入 make load:直接烧录到 SD 卡。
  • 输入 make clean:清除冗余文件。

六、 开发板测试

  1. 设置启动拨码:根据底板原理图,将拨码开关调整至 SD 卡启动模式(通常是 1-8 位有特定的上下组合)。
  2. 上电:插入 SD 卡,连接电源,按下蓝色电源开关。
  3. 结果:电源指示灯(蓝色)常量,用户指示灯(红色)开始按照设定的延时周期闪烁。
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐