一、开发环境准备
1. 宿主机与工具链
-
Windows端:安装VS Code,装这几个必备扩展:
-
Chinese (Simplified):汉化包,看着舒服 -
C/C++ Extension Pack:C/C++语法支持 -
Arm Assembly:ARM汇编语法高亮、补全 -
Makefile Tools:Makefile工程管理
-
-
编译环境:Ubuntu系统(可以是WSL2或者虚拟机),用来交叉编译代码,毕竟最终跑在ARM架构的IMX6ULL上。
2. 核心硬件资源先搞懂
IMX6ULL的外设操作主要和三个模块打交道,先把这几个基础概念记牢:
| 模块 | 核心寄存器 | 作用 |
|---|---|---|
| IOMUXC(引脚复用) | IOMUXC_SW_MUX_CTL_PAD_xxx |
配置引脚复用功能,比如把某个IO设为GPIO模式 |
IOMUXC_SW_PAD_CTL_PAD_xxx |
配置引脚电气属性:上下拉、驱动能力、速度等 | |
| GPIO | GPIOx_DR |
GPIO数据寄存器,控制引脚输出高低电平 |
GPIOx_GDIR |
GPIO方向寄存器,配置引脚是输入还是输出 | |
| CCM(时钟控制) | CCM_CCGR0 ~ CCM_CCGR6 |
外设时钟门控,给对应位写0xFFFFFFFF就能打开所有外设时钟 |
另外要记住一个关键地址:IMX6ULL的DDR起始地址是0x80000000,后面链接脚本会用到。
二、汇编点灯实战(以GPIO1_IO03为例)
点灯是所有嵌入式开发的"Hello World",咱们先从最底层的汇编实现,搞清楚每一步硬件操作的原理。
1. 整体流程
汇编点灯一共4步:
-
开启GPIO外设时钟
-
配置引脚复用为GPIO功能
-
配置引脚电气属性
-
设置GPIO为输出模式,并输出低电平点亮LED
2. 完整汇编代码(start.S)
.global _start
_start:
/* 1. 开启GPIO1时钟(CCM_CCGR1控制GPIO1时钟,bit27:26置11即可) */
ldr r0, =0x20C406C /* CCM_CCGR1寄存器地址 */
ldr r1, =0xFFFFFFFF /* 打开所有外设时钟,偷懒直接全开 */
str r1, [r0]
/* 2. 配置引脚复用:将GPIO1_IO03复用为GPIO功能 */
ldr r0, =0x20E0068 /* IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03寄存器地址 */
ldr r1, =0x5 /* ALT5模式就是GPIO */
str r1, [r0]
/* 3. 配置引脚电气属性 */
ldr r0, =0x20E02F4 /* IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03寄存器地址 */
ldr r1, =0x10B0 /* 配置:下拉、100MHz速度、驱动能力R0/6等 */
str r1, [r0]
/* 4. 配置GPIO1_IO03为输出模式 */
ldr r0, =0x209C004 /* GPIO1_GDIR寄存器地址 */
ldr r1, =0x8 /* bit3置1,对应GPIO1_IO03为输出 */
str r1, [r0]
/* 5. 输出低电平,点亮LED(假设LED共阳极接法) */
ldr r0, =0x209C000 /* GPIO1_DR寄存器地址 */
ldr r1, =0x0 /* bit3清零,输出低电平 */
str r1, [r0]
loop:
b loop /* 死循环,防止程序跑飞 */
3. 配套Makefile
CROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET = led_asm
$(TARGET).bin: $(TARGET).elf
$(CROSS_COMPILE)objcopy -O binary -S $^ $@
$(TARGET).elf: start.o
$(CROSS_COMPILE)ld -Ttext 0x80000000 -o $@ $^
start.o: start.S
$(CROSS_COMPILE)gcc -Wall -nostdlib -c $^ -o $@
clean:
rm -rf *.o *.elf *.bin
注意链接地址
-Ttext 0x80000000,就是我们前面说的DDR起始地址,代码会被加载到这里运行。
4. 编译烧录
-
把代码放到Ubuntu里,执行
make生成led_asm.bin -
通过imxdownload工具把bin文件烧写到SD卡:
./imxdownload led_asm.bin /dev/sdb # 注意sdb是你的SD卡设备名,别写错! -
把SD卡插到开发板,拨码开关设为SD卡启动,上电就能看到LED亮起来~
三、后续进阶方向
这次只是最基础的汇编点灯,后面还会更新:
-
C语言点灯:用C封装寄存器操作,更符合工程习惯
-
NXP官方固件库点灯:学习工业级代码的写法
-
中断、定时器、串口等外设的裸机驱动
常见问题Q&A
-
LED不亮怎么办?
先检查LED的硬件接法(共阳/共阴),再核对寄存器地址是否正确,最后看SD卡烧录有没有报错。
-
为什么要用汇编开头?
裸机程序没有引导程序帮我们做初始化,汇编负责最底层的CPU初始化、栈设置等,后面C语言运行环境准备好了就可以跳转到C代码。
如果这篇博客对你有帮助,别忘了点赞收藏~ 有问题欢迎在评论区交流!