嵌入式——ARM——汇编2

【嵌入式ARM入门】IMX6ULL 汇编启动代码 + LED点灯实战

开发板:正点原子IMX6ULL-mini,Cortex-A7 ARMv7,裸机开发

今日学习:ARM交叉编译工具链完整编译流程、汇编启动代码编写、栈设置、IOMUXC引脚复用、GPIO寄存器配置,最终实现LED点亮

一、学习概述

今天学习IMX6ULL裸机开发,使用ARM汇编编写启动代码,从交叉编译工具链4大编译阶段入手,理解预处理、编译、汇编、链接完整流程;掌握IOMUXC引脚复用原理,配置GPIO寄存器,汇编中设置不同模式栈,编写启动汇编代码,最终编译链接生成bin文件,完成裸机LED点灯。

二、核心知识点

2.1 ARM交叉编译工具链全流程

交叉编译:在x86 PC上编译生成能在ARM平台运行的程序,整套工具链arm-linux-gnueabihf-,分为4个阶段:

阶段 工具命令 输入文件 输出文件 功能说明
预处理 arm-linux-gnueabihf-cpp main.c -o main.i main.c main.i 处理#include#define宏、注释,只做文本替换,独立阶段
编译 arm-linux-gnueabihf-gcc -S main.i -o main.s main.i / start.S main.s C语言翻译成ARM汇编代码,独立阶段
汇编 arm-linux-gnueabihf-as main.s -o main.o main.s / start.S main.o / start.o 汇编语言转为目标文件(.o),二进制机器码+段信息
链接 arm-linux-gnueabihf-ld main.o start.o -o program.elf 多个.o目标文件 led.elf 合并所有目标文件,按lds链接脚本分配内存地址,生成elf可执行文件
工具链辅助组件
  1. arm-linux-gnueabihf-objcopy:elf转bin,objcopy -O binary led.elf led.binbin只有纯二进制指令,无elf头信息,裸机烧录用bin
  2. arm-linux-gnueabihf-objdump:反汇编,objdump -D led.elf > led.dis,查看elf对应的汇编代码,调试分析
  3. arm-linux-gnueabihf-gdb:GNU调试器,用于ARM代码单步调试

2.2 IMX6ULL 内存与ARM栈设置

IMX6ULL Cortex-A7,ARMv7架构,ARM有多种运行模式,每种模式拥有独立栈指针SP:

  • svc(管理模式,裸机常用)、irq中断模式、sys系统模式,不同模式需要单独设置SP栈地址
  • IRAM内部RAM地址范围:0x80000000 ~ 0xA0000000(512M)
  • 栈从高地址向低地址增长:
    • SVC栈:0x82000000
    • IRQ栈:0x87800000

裸机汇编启动第一步:切换处理器模式,给每种模式设置SP栈,没有栈,C语言无法运行(C函数需要栈保存局部变量、返回地址)

2.3 IOMUXC 引脚复用(核心重点)

IMX6ULL的PAD引脚是单刀多复用开关,一个物理PAD引脚可以复用为:GPIO、UART_TX/RXD、Timer等多种外设功能。

  • IOMUXC寄存器组两大作用:
    1. 复用功能选择:选择引脚映射到哪个外设(GPIO / UART / Timer)
    2. 电气特性配置:上下拉、速率、驱动能力、压摆率
  • 点灯流程:配置IOMUXC,把PAD引脚复用为GPIO功能 → 配置GPIO方向寄存器(输出) → 配置GPIO数据寄存器,输出高低电平,控制LED亮灭

2.4 汇编启动代码核心逻辑

裸机上电,芯片首先执行汇编启动文件start.S,C语言不能直接运行,需要汇编做初始化:

  1. 关闭看门狗(防止上电自动复位)
  2. 切换ARM处理器工作模式,分别设置SVC、IRQ等模式栈指针SP
  3. 初始化时钟(可选,本例简单点灯可省略)
  4. 配置IOMUXC引脚复用,设置GPIO为输出
  5. 操作GPIO数据寄存器输出电平,点亮LED
  6. 跳转到C语言main函数(如果有C代码)

本次实战:纯汇编实现LED点灯,直接操作寄存器地址,控制引脚电平。

三、完整汇编示例 start.S(IMX6ULL LED)

asm 复制代码
.global _start
_start:
    /* 1. 设置SVC模式栈 */
    mrs r0, cpsr
    bic r0, r0, #0x1f
    orr r0, r0, #0x13   @ SVC模式
    msr cpsr, r0
    ldr sp, =0x82000000 @ SVC栈地址

    /* 2. 设置IRQ模式栈 */
    mrs r0, cpsr
    bic r0, r0, #0x1f
    orr r0, r0, #0x12   @ IRQ模式
    msr cpsr, r0
    ldr sp, =0x87800000 @ IRQ栈地址

    /* 3. IOMUXC + GPIO寄存器配置,LED引脚初始化 */
    ldr r0, =0x20E0068  @ IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03
    ldr r1, =0x5        @ 设置复用为GPIO1_IO03
    str r1, [r0]

    ldr r0, =0x20E0254  @ IOMUXC_PAD 电气属性
    ldr r1, =0x10B0
    str r1, [r0]

    ldr r0, =0x209C000  @ GPIO1方向寄存器,设为输出
    ldr r1, =(1<<3)
    str r1, [r0]

    /* 4. 点亮LED,输出低电平(LED低电平点亮) */
    ldr r0, =0x209C004  @ GPIO1数据寄存器
    ldr r1, =0
    str r1, [r0]

loop:
    b loop  @ 死循环,防止跑飞

编译命令

bash 复制代码
# 汇编:start.S 编译成目标文件
arm-linux-gnueabihf-as start.S -o start.o
# 链接:使用ld + 链接脚本,生成elf
arm-linux-gnueabihf-ld start.o -o led.elf -T imx6ull.lds
# 转bin,裸机烧录文件
arm-linux-gnueabihf-objcopy -O binary led.elf led.bin
# 反汇编查看代码
arm-linux-gnueabihf-objdump -D led.elf > led.dis

四、学习重点

  1. 裸机上电先跑汇编:C语言依赖栈,必须汇编提前设置SP,才能调用C代码。
  2. 交叉编译四阶段区分:预处理只文本替换;编译生成汇编;汇编生成机器码.o;链接合并段、分配地址。
  3. IOMUXC是IMX6ULL核心:引脚不是默认GPIO,必须配置复用寄存器,否则引脚不工作。
  4. ARM不同模式拥有独立栈,SVC模式是裸机开发最常用模式。
  5. elf和bin区别:elf带段、符号、调试信息;bin只有原始机器指令,是裸机烧写到SD卡的文件。

五、易错点(踩坑总结)

  1. ❌ 忘记设置栈直接调用C代码:程序直接崩溃,C函数运行必须栈。
  2. ❌ 混淆IOMUX复用寄存器地址,地址写错,引脚功能不生效,LED不亮。
  3. ❌ 混淆bin与elf,直接烧录elf文件到SD卡,裸机无法识别,必须objcopy转bin。
  4. ❌ 栈地址设置错误:栈是从高地址向下生长,SP必须指向合法IRAM区间,不能越界。
  5. ❌ 电平逻辑搞错:开发板LED是低电平点亮,写1是熄灭,写0点亮,容易写反。
  6. ❌ 链接时缺少lds链接脚本,内存地址分配错误,程序运行地址错乱。
  7. ❌ 交叉编译工具选错:用x86 gcc编译,生成x86机器码,ARM芯片无法识别。

六、学习小结

今天完成IMX6ULL裸机汇编启动代码,打通了源码 -> 交叉编译工具链 -> elf -> bin -> 烧录开发板 -> LED点亮完整链路。理解ARMv7处理器模式、栈的作用、SOC引脚复用机制。裸机开发核心就是直接操作寄存器,没有操作系统,所有硬件初始化都需要手动写汇编/ C代码,为后面嵌入式Linux驱动打下基础。

相关推荐
指尖的爷1 小时前
【地狱级难度】ubuntu系统GOCV编译安装
linux·运维·ubuntu
智购科技自动贩卖机1 小时前
自动售货机嵌入式系统时钟同步与时间管理实战:从RTC校准到断网时间保持的工程实践
大数据·linux·数据库·人工智能·yolo
BizzZ_1 小时前
Linux(2)——权限
linux
j7~1 小时前
【C++微服务项目开发脚手架】(环境篇)虚拟机 + Docker + MySQL/Redis/RabbitMQ/ES/etcd/FastDFS 全套配齐
linux·c++·ubuntu·docker·vmware·项目开发·微服务脚手架
Biomamba生信基地1 小时前
安全访问:FutureTerminal之Jupyter配置及Linux终端、Python与R环境访问
linux·远程连接·生物信息学
M78佐菲1 小时前
ARM学习笔记(三)
linux·arm开发·笔记·嵌入式硬件·学习
邪修king1 小时前
Re:Linux 系统篇(三十一):库的制作与原理Chapter2:静态链接与程序加载 —— 从磁盘 ELF 到运行中进程的完整旅程
android·linux·运维·开发语言
云计算练习生2 小时前
什么是内核?操作系统内核到底管哪些事
linux·windows·操作系统·内核·shell
可涵不会debug2 小时前
公司外怎么连接管家婆?从 SQL Server 安装到 cpolar 固定 TCP 远程登录
linux·运维·ubuntu