ARM嵌入式学习(三)---汇编应用:LED点亮

目录

一、硬件原理分析

[二、GPIO 配置步骤(核心)](#二、GPIO 配置步骤(核心))

三、裸机代码结构

四、编译、链接、烧写代码等

[(1)整体流程(4 步走)](#(1)整体流程(4 步走))

(2)逐步骤详细说明

[1. 编译:生成 .o 文件](#1. 编译:生成 .o 文件)

[2. 链接:生成 .elf 文件](#2. 链接:生成 .elf 文件)

[3. 格式转换:生成 .bin 文件](#3. 格式转换:生成 .bin 文件)

[4. 反汇编:生成 .dis 文件(调试用)](#4. 反汇编:生成 .dis 文件(调试用))

(3)总结整个流程

[(4)最关键的 3 个知识点](#(4)最关键的 3 个知识点)

(5)烧写到SD卡中

六、注意事项

七、学习总结

一、硬件原理分析

学习采用IMX6ULL核心板:

  1. 查看开发板原理图

    • 确定 LED 对应的 GPIO 引脚(如 GPIO1_IO03 等,依底板实际电路)。
    • 确认驱动逻辑:高电平点亮 / 低电平点亮,是否有上拉 / 下拉,在GPIO_IO03中,低电平(0)点亮,高电平(1)灭。
    • 明确 GPIO 属于哪个模块,方便后续配置时钟与寄存器。
  2. 控制逻辑

    • 配置引脚为 GPIO 功能。
    • 设置为输出模式。
    • 输出高低电平实现亮灭。

二、GPIO 配置步骤(核心)

i.MX6ULL 配置一个通用 GPIO 输出共四步:选择引脚功能(MUXIO_SW)、配置引脚电气属性(PAD_SW)、配置引脚方向(DIR)、输出高低电平(DR)

  1. 选择引脚功能(MUX)

    代码:

    cs 复制代码
     ldr 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引脚进行配置。
  2. 配置引脚电气特性(PAD)

    代码:

    cs 复制代码
        ldr r0, =0x20e02f4
        ldr r1, [r0]        /*unuse*/
        ldr r1, =0x10b0
        str r1, [r0]
    • 设置上下拉、速度、驱动能力、开漏等。

    • 配置 IOMUXC_PAD_REG,一般设置为普通推挽输出,将IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03寄存器的低4位设置为0x10b0

  3. 配置引脚方向(DIR)

    代码

    cs 复制代码
        ldr 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,引脚方向为输出,反之则为输入模式
  4. 输出高低电平(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 个知识点

  1. 编译:生成机器码
  2. 链接 :指定代码在内存中的运行地址
  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卡中。

六、注意事项

  1. 必须先使能时钟,否则 GPIO 无法工作。
  2. 引脚 MUX 配置必须正确,否则不是 GPIO 模式。
  3. 链接地址必须与实际运行地址一致,否则跑飞。
  4. 裸机无操作系统,不能使用标准库函数,需自己实现操作。
  5. 电平逻辑要与硬件一致,避免配置相反导致不亮。
  6. 烧写时注意 SD 卡设备号,避免误烧硬盘。

七、学习总结

本次实验完成 i.MX6ULL 裸机开发完整流程:看原理图 → 分析 GPIO → 配置寄存器 → 编写 S 代码 → 编译链接 → 制作镜像 → SD 卡烧写 → 运行验证。理解了 Cortex‑A7 下裸机驱动的基本思想,掌握了 GPIO 输出配置方法,为后续按键、UART、I2C、SPI 等外设裸机驱动打下基础。

相关推荐
fffzd3 分钟前
STM32:OLED原理
stm32·单片机·嵌入式硬件·iic·oled·嵌入式软件
清风66666610 小时前
基于单片机与DAC0832的双路波形信号发生系统设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
azwsm11 小时前
电路元器件和GPIO控制器
单片机·嵌入式硬件
kebidaixu15 小时前
FreeRTOS 移植到 STM32F407VETX 记录(一)
stm32·单片机·嵌入式硬件
CSDN官方博客15 小时前
「谁说嵌入式只是调包和焊板子?」—— 2026嵌入式全栈技术征锋令
嵌入式硬件·物联网·embedding
点灯小铭16 小时前
基于单片机的数码管定时插座设计与定时开关功能实现
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
云栖梦泽16 小时前
玩转RK3506SDK
linux·嵌入式硬件
数智工坊18 小时前
机器人四大主控板系统分层选型指南:树莓派、ESP32、STM32与Arduino的能力边界与实战定位
stm32·嵌入式硬件·机器人
进击的小头18 小时前
第8篇:IGBT 从零到精通:核心原理、关键参数、选型指南与工业级应用要点
经验分享·嵌入式硬件·学习
点灯小铭18 小时前
基于单片机的多模式智能洗衣机设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业