环境配置
arm-linux-gnueabihf-gcc配置
首先下载arm-linux-gnueabihf-gcc,并且解压到任意路径(最好不要有中文)。
右键计算机,属性->高级系统设置->环境变量,找到Path路径,双击打开
添加刚才解压到的路径中的bin文件夹目录到Path路径中
接下来一路确定就ok,现在验证一下是否正确,win+r键输入cmd回车,在cmd界面输入arm-linux-gnueabihf-gcc.exe -v,如下图所示即配置成功
make安装
首先下载make安装包,解压到任意路径后打开make-3.81.exe进行安装(不能在压缩包打开,会生成dll文件)。
接下来设置环境变量Path,增加“C:\Program Files (x86)\GnuWin32\bin”:
验证make是否安装成功:打开cmd,输入make -v,如下图所示即为安装成功
安装mkimage.exe
mkimage工具的源码来自u-boot,它用来给bin文件添加一个头部信息,很多芯片的固件都需要根据这个头部信息把bin文件放到内存去执行。
我们已经事先把mkimage.exe放到GCC工具链的bin目录里,无需单独安装。
验证mkimage.exe:启动命令行,执行“mkimage -h”,如下图所示:
代码编写
led.h
声明两个枚举,一个为led编号的枚举,一个为led状态的枚举,声明两个函数,一个为led初始化,一个为led控制函数。
#ifndef __LED_H
#define __LED_H
typedef enum{
led1,
led2,
LED_NUM_MAX
}led_num_t;
typedef enum{
led_on = 1,
led_off = !led_on
}led_status_t;
void LED_Init(void);
void LED_Control(led_num_t ln,led_status_t ls);
#endif
led.c
通过指针变量访问imx6ull寄存器,volatile是防止编译器优化,
#include "./led.h"
void LED_Init(void){
volatile unsigned int* pReg;
/*gpio5_io3模式设置为普通gpio口*/
pReg = (volatile unsigned int*)(0x02290000 + 0x14);
*pReg |= 0x05;
/*gpio5_io3引脚设置为输出*/
pReg = (volatile unsigned int*)(0x020AC000 + 0x04);
*pReg |= (1 << 3);
}
void LED_Control(led_num_t ln,led_status_t ls){
/*没有此led*/
if(ln >= LED_NUM_MAX)
return;
/*左移位数*/
unsigned char lm_bit;
switch(ln){
case led1:
lm_bit = 3;
break;
/*目前只用到了led1*/
default:
return;
}
volatile unsigned int* pReg;
/*指向gpio5组dr寄存器*/
pReg = (volatile unsigned int*)(0x020AC000 + 0x00);
if(ls == led_on)
*pReg &= ~(1 << lm_bit);
else
*pReg |= (1 << lm_bit);
}
编写main.c
#include "./led/led.h"
void delay(unsigned long i){
while(i != 0){
i--;
}
}
void main(void){
volatile unsigned int* pReg;
LED_Init();
while(1){
/*gpio5_io3输出低电平*/
LED_Control(led1,led_on);
delay(1000000);
/*gpio5_io3输出高电平*/
LED_Control(led1,led_off);
delay(1000000);
}
}
编写start.s
//没什么好说的 死记硬背 头
.text
.global _start
_start:
//设置栈,1M
ldr sp,=0x80100000
//添加main函数
bl main
编写makefile
PREFIX=arm-linux-gnueabihf-
CC=$(PREFIX)gcc
LD=$(PREFIX)ld
AR=$(PREFIX)ar
OBJCOPY=$(PREFIX)objcopy
OBJDUMP=$(PREFIX)objdump
led.img : start.S led/led.c main.c
$(CC) -nostdlib -g -c -o start.o start.S
$(CC) -nostdlib -g -c -o led/led.o led/led.c
$(CC) -nostdlib -g -c -o main.o main.c
$(LD) -T imx6ull.lds -g start.o led/led.o main.o -o led.elf
$(OBJCOPY) -O binary -S led.elf led.bin
$(OBJDUMP) -D -m arm led.elf > led.dis
mkimage -n ./tools/imximage.cfg.cfgtmp -T imximage -e 0x80100000 -d led.bin led.imx
dd if=/dev/zero of=1k.bin bs=1024 count=1
cat 1k.bin led.imx > led.img
clean:
rm -f led.dis led.bin led.elf led.imx led.img *.o
makefile文件分析
PREFIX=arm-linux-gnueabihf-
CC=$(PREFIX)gcc
LD=$(PREFIX)ld
AR=$(PREFIX)ar
OBJCOPY=$(PREFIX)objcopy
OBJDUMP=$(PREFIX)objdump
设置一些常量名称,以便下面调用
led.img : start.S led/led.c main.c
声明生成led.img所需要用到的文件
$(CC) -nostdlib -g -c -o start.o start.S
$(CC) -nostdlib -g -c -o led/led.o led/led.c
$(CC) -nostdlib -g -c -o main.o main.c
使用gcc编译器将这些文件编译成.o文件
$(LD) -T imx6ull.lds -g start.o led/led.o main.o -o led.elf
将这些.o文件链接为elf文件
$(OBJCOPY) -O binary -S led.elf led.bin
$(OBJDUMP) -D -m arm led.elf > led.dis
将elf转换为二进制bin文件
反汇编为dis文件
mkimage -n ./tools/imximage.cfg.cfgtmp -T imximage -e 0x80100000 -d led.bin led.imx
使用mkimage将led.bin编译成imx文件(用于emmc烧录)
dd if=/dev/zero of=1k.bin bs=1024 count=1
cat 1k.bin led.imx > led.img
在imx文件头部加上1k大小的bin文件,并生成img文件(用于tf/sd卡烧录)
添加编译所需要的文件
首先下载编译所需的文件,直接添加到led工程文件夹就可以
编译并烧录代码
编译代码
在此led工程文件夹右键,选择git bash here,打开git窗口,输入make指令并回车,如下图所示即可完成编译
烧录代码
首先下载百问网提供的imx6ull烧录工具,将板子切换到usb启动,连接电源线和usb数据线,软件选择专业版,上电如下图所示
点击固件/裸机,选择imx文件,点击运行,即可看到led闪烁。
此时程序为运行在ram,并没有烧录进去,复位以后就会丢失。
PS:烧录程序时,如果是emmc要选择imx文件,sd/tf卡要选择img文件,这是因为emmc和sd卡的前1k字节是不可以写东西的,软件可以跳过emmc的前1k字节,但不可以跳过sd卡的前1k字节,所以在编译程序的时候在imx文件的头部加上了1k.bin这个文件,达到了跳过前1k字节的目的