嵌入式硬件IMX6ULL-裸机LED点亮实验
嵌入式硬件——IMX6ULL 裸机LED点亮实验
一. 实验准备
基于正点原子 IMX6ULL-Mini 开发板,实现 LED 周期性闪烁功能,需完成环境搭建与硬件原理确认两大核心准备工作。
1.1 开发环境搭建
需在Windows和Ubuntu中安装工具,确保文件传输、交叉编译、代码编辑功能正常。
1.1.1 跨系统文件传输工具(FileZilla + Ubuntu FTP服务)
用于Windows与Ubuntu之间传输代码、工具链等文件:
1. Windows端安装FileZilla
下载地址: ,默认安装即可。
2. Ubuntu端配置FTP服务(vsftpd)
打开Ubuntu终端,执行以下命令:
# 配置vsftpd.conf文件 sudo vi /etc/vsftpd.conf ``` 在配置文件中确保以下两行**无注释(删除开头的#)** : ```ini local_enable=YES # 允许本地用户登录 write_enable=YES # 允许写入操作 ``` 保存退出后,重启FTP服务:`sudo /etc/init.d/vsftpd restart`。
##### 3. 连接测试
打开FileZilla,点击「文件→站点管理器」,输入Ubuntu的IP地址、用户名、密码,连接成功后即可互传文件。
#### **1.1.2 交叉编译工具链安装(Linaro GCC)**
由于PC(x86架构)需编译ARM架构(I.MX6ULL)的程序,需安装**交叉编译工具链**:
1. 下载工具 选择适配64位Ubuntu的版本,下载地址: [https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/](https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/) 文件名:`gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz`。
2. 解压工具链到Ubuntu 用FileZilla将工具链压缩包上传到Ubuntu家目录,执行以下命令: ```bash # 创建安装目录 sudo mkdir /usr/local/arm # 拷贝压缩包到安装目录 sudo cp ~/工具链文件名 /usr/local/arm/ -f # 解压 sudo tar -vxf /usr/local/arm/工具链文件名 ```
3. 配置环境变量 编辑`~/.bashrc`文件,在末尾添加工具链路径: ```bash export PATH=$PATH:/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin ``` 保存后执行`source ~/.bashrc`使环境变量生效。
4. 验证安装 终端输入`arm-linux-gnueabihf-gcc -v`,若显示`4.9.4`版本信息,则安装成功。
5. 安装依赖库 执行`sudo apt-get install lsb-core lib32stdc++6`,解决64位Ubuntu运行32位工具链的依赖问题。
1.1.3 代码编辑器(VSCode) 可选Windows或Ubuntu版本,用于编写汇编、C代码,推荐安装`C/C++`、`ARM`插件以支持语法高亮。
### **1.2 开发板硬件原理确认**
1.2.1 开发板结构 IMX6ULL-Mini开发板分为**核心板**和**底板**:
- 核心板:包含IMX6ULL芯片、DDR(内存)、eMMC(存储)等核心器件;
- 底板:包含LED、按键等外设。
1.2.2 LED核心控制逻辑
当GPIO1_IO03输出**低电平(0)** 时,LED导通点亮;输出**高电平(1)** 时,LED熄灭。
## **二. 代码编写**
实验代码分为「汇编初始化代码」和「C语言功能代码」,汇编负责初始化C环境(时钟、GPIO复用),C语言实现LED闪烁逻辑。
### **2.1 汇编代码(start.s)**
**LED**
作用:初始化系统时钟、配置GPIO1_IO03引脚复用和电气属性、设置GPIO方向和初始电平,最终跳转到C语言`main`函数。
.global _start
_start: ldr pc, =_reset_handler ldr pc, =_undefine_handler ldr pc, =_svc_handler ldr pc, =_prefetch_abort_handler ldr pc, =_data_abort_handler ldr pc, =_reserved_handler ldr pc, =_irq_handler ldr pc, =_fiq_handler
_undefine_handler: ldr pc, =_undefine_handler
_svc_handler: ldr pc, = _svc_handler
_prefetch_abort_handler: ldr pc, =_prefetch_abort_handler
_data_abort_handler: ldr pc, =_data_abort_handler
_reserved_handler: ldr pc, =_reserved_handler
_irq_handler: ldr pc, =_irq_handler
_fiq_handler: ldr pc, =_fiq_handler
_reset_handler: mrs r0, cpsr bic r0, r0, #0x1F orr r0, r0, #0x12 // irq 模式 msr cpsr, r0
ldr sp, =0x86000000
mrs r0, cpsr
bic r0, r0, #0x1F
orr r0, r0, #0x1F // sys 模式
msr cpsr, r0
ldr sp, =0x84000000
bl _bss_clear
b main
_bss_clear: ldr r0, = __bss_start ldr r2, = __bss_end loop: mov r1, #0 str r1, [r0] add r0, r0, #4 cmp r0, r2 blt loop bx lr
finished: b finished
说明:代码中寄存器地址与配置逻辑参考`imx6ull裸机(v1.2).pdf`中GPIO配置流程(使能时钟→复用配置→电气属性→方向/电平设置)。
### **2.2 C语言功能代码**
#### **2.2.1 头文件(led.h)**
声明LED控制函数,依赖NXP SDK的寄存器定义(如`MCIMX6Y2.h`):
#ifndef LED_H
#define LED_H
#include “MCIMX6Y2.h”
/* LED初始化函数:配置GPIO1_IO03 */
void init_led(void);
/* LED点亮:GPIO1_IO03输出低电平 */
void led_on(void);
/* LED熄灭:GPIO1_IO03输出高电平 */
void led_off(void);
/* LED翻转:GPIO1_IO03电平取反 */
void led_nor(void);
#endif
#### 2.2.2 LED功能实现(led.c)
封装GPIO配置与LED控制逻辑,调用`fsl_iomuxc.h`中的IO复用函数:
#include “led.h” #include “fsl_iomuxc.h”
void init_led(void) {
/* 1. 配置GPIO1_IO03复用为GPIO */
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0);
/* 2. 配置电气属性:关闭HYS、上拉、200M速度 */
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0x10B0);
/* 3. 设置为输出模式 */
GPIO1->GDIR |= (1 « 3);
}
void led_on(void) {
GPIO1->DR &= ~(1 « 3); /* 低电平点亮 */
}
void led_off(void) {
GPIO1->DR |= (1 « 3); /* 高电平熄灭 */
}
void led_nor(void) {
GPIO1->DR ^= (1 « 3); /* 电平取反 */
}
说明:`IOMUXC_SetPinMux`和`IOMUXC_SetPinConfig`是SDK封装的IO配置函数,用于简化寄存器操作。
**2.2.3 主函数(main.c)**
实现LED周期性闪烁(软件延时):
#include “MCIMX6Y2.h”
#include “led.h”
/* 软件延时函数:参数越大,延时越长 */
void delay(unsigned int n) {
while(n–);
}
int main(void) {
/* 1. 使能所有外设时钟 */
CCM->CCGR0 = 0xFFFFFFFF;
CCM->CCGR1 = 0xFFFFFFFF;
CCM->CCGR2 = 0xFFFFFFFF;
CCM->CCGR3 = 0xFFFFFFFF;
CCM->CCGR4 = 0xFFFFFFFF;
CCM->CCGR5 = 0xFFFFFFFF;
CCM->CCGR6 = 0xFFFFFFFF;
/* 2. 初始化LED */
init_led();
/* 3. 循环翻转LED(周期约500ms) */
while(1) {
led_nor();
delay(0xFFFFF);
}
return 0;
}
## **三. 编译配置(Makefile)**
编写Makefile实现自动化编译,避免手动输入繁琐命令,支持汇编、C文件的编译与链接:
target = led
cross_compiler = arm-linux-gnueabihf-
cc = $(cross_compiler)gcc ld = $(cross_compiler)ld objcopy = $(cross_compiler)objcopy objdump = $(cross_compiler)objdump
incdirs = bsp imx6ull srcdirs = bsp project
include = $(patsubst %, -I%, $(incdirs))
cfiles = $(foreach dir, $(srcdirs), $(wildcard $(dir)/.c)) sfiles = $(foreach dir, $(srcdirs), $(wildcard $(dir)/.S))
cfilenodir = $(notdir $(cfiles)) sfilenodir = $(notdir $(sfiles))
cobjs = $(patsubst %, obj/%, $(cfilenodir:.c=.o)) sobjs = $(patsubst %, obj/%, $(sfilenodir:.S=.o))
objs = $(cobjs) $(sobjs)
VPATH = $(srcdirs)
$(target).bin : $(objs) $(ld) -Timx6ull.lds -o$(target).elf $^ $(objcopy) -O binary -S -g $(target).elf $@ $(objdump) -D $(target).elf > $(target).dis
$(sobjs) : obj/%.o : %.S @mkdir -p obj $(cc) -Wall -nostdlib -c $(include) -o $@ $<
$(cobjs) : obj/%.o : %.c @mkdir -p obj $(cc) -Wall -nostdlib -c $(include) -o $@ $<
.PHONY : clean clean: rm -rf $(objs) $(target).elf $(target).bin $(target).dis
说明: - 链接地址`0x87800000`:选择DDR中的地址,与Uboot链接地址一致,避免地址冲突;
- `-Ttext`:指定.text段(代码段)的起始地址; - `objcopy -O binary`:将ELF格式文件转换为裸机可执行的bin文件。
## **四. 程序编译与烧写**
### **4.1 编译步骤**
#### **1. 执行编译**
终端进入实验目录,执行`make`命令,编译成功后生成`led.bin`(最终烧写文件)。
### **4.2 程序烧写(SD卡启动)**
IMX6ULL无内部Flash,需将程序烧写到SD卡,通过SD卡启动。
#### 4.2.1 准备工具与SD卡
1. 下载imxdownload工具 NXP提供的SD卡烧写工具,拷贝到实验目录并添加执行权限: ``` chmod +x imxdownload ```
2. SD卡准备 - 使用空白SD卡(建议4GB以上),备份数据; - 通过读卡器连接Ubuntu,确保SD卡被Ubuntu识别。
#### **4.2.2 确认SD卡设备名**
终端执行`ls /dev/sd*`,识别SD卡设备文件:
- 未插SD卡时:显示`/dev/sda /dev/sda1`(系统磁盘);
- 插入SD卡后:新增`/dev/sdb /dev/sdb1`(SD卡,`sdb`为设备名)。
**注意:务必确认设备名为`/dev/sdb`,避免烧写到系统磁盘(`sda`)。**
#### **4.2.3 执行烧写**
在实验目录执行烧写命令: ```./imxdownload led.bin /dev/sdb ``` -
**烧写验证**:终端显示烧写大小(如3.2KB)、速度(正常几百KB/s以内);
- 生成`load.imx`文件:imxdownload在bin文件前添加启动头,适配IMX6ULL启动协议。
## **五. 实验验证**
### **5.1 开发板启动配置**
1. 设置BOOT拨码开关 需将开发板BOOT拨码开关设置为 SD卡启动 ,参考拨码表:
| | | |
| --- | --- | --- |
| ****拨码位**** | ****状态**** | ****说明**** |
| 1 | OFF | BOOT_MODE1=0 |
| 2 | ON | BOOT_MODE0=1 |
| 3~8 | OFF | 选择 SD 卡通道 |
2. 连接硬件- 插入烧写好程序的SD卡; - 打开开发板电源。
### 5.2 上电运行
打开开发板电源开关,观察用户LED(LED0):
- 正常现象:LED周期性闪烁(约1秒1次);
- 异常排查:若LED不亮,检查BOOT拨码、SD卡烧写、GPIO配置是否正确。
## 六. 常见问题排查
| | | |
| --- | --- | --- |
| ****问题现象**** | ****可能原因**** | ****解决方案**** |
| 交叉编译工具链未找到(command not found) | 环境变量配置错误 | 重新执行source ~/.bashrc,或检查~/.bashrc中工具链路径 |
| 烧写速度异常(>100MB/s) | SD 卡未被正确识别 | 重新插拔 SD 卡,重启 Ubuntu 后重试 |
| LED 不亮但烧写成功 | GPIO 配置错误 / BOOT 拨码错误 | 1. 检查start.s中 GPIO1_IO03 的复用与电气属性; 2. 确认 BOOT 拨码为 SD 卡启动 |
| 编译报错(undefined reference) | 源文件缺失或 Makefile 中未添加目标文件 | 1. 确认objs变量包含所有.o 文件; 2. 检查源文件是否存在 |