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 等外设裸机驱动打下基础。

相关推荐
Hello_Embed2 小时前
嵌入式上位机开发入门(五):UDP 编程 —— Server 端实现
笔记·单片机·网络协议·udp·嵌入式
凌盛羽2 小时前
在MDK-ARM编译后用python解析map文件在编译窗口输出Flash和RAM使用及剩余情况
arm开发·python·stm32·单片机·mysql·链表·esp32
项目題供诗3 小时前
51单片机入门-红外遥控(十七)
单片机·嵌入式硬件·51单片机
蓝天星空4 小时前
STM32 的 USART(通用同步异步收发器)
stm32·单片机·嵌入式硬件
炎爆的土豆翔4 小时前
NEON 入门:把它理解成 ARM 平台上的 SSE / AVX
arm开发
Redemption4 小时前
嵌软面试每日一阅----单片机知识简述(以stm32为列)
c语言·stm32·单片机·嵌入式硬件·面试·嵌入式
v先v关v住v获v取4 小时前
高空作业平台调平机构结构设计7张cad+设计说明书
科技·单片机·51单片机
恒森宇电子有限公司4 小时前
芯晞微CSM2221 低压差线性LDO稳压器芯片 多种封装形式
单片机
三万棵雪松4 小时前
【Linux 物联网网关主控系统-感知层部分(一)】
linux·单片机·物联网·嵌入式linux