目录
1、硬件原理图
从图可以看出,LED0 接到了 GPIO_3 上,GPIO_3 就是 GPIO1_IO03,当 GPIO1_IO03输出低电平(0)的时候发光二极管 LED0 就会导通点亮,当 GPIO1_IO03 输出高电平(1)的时候发光二极管 LED0 不会导通,因此 LED0 也就不会点亮。所以 LED0 的亮灭取决于 GPIO1_IO03的输出电平,输出 0 就亮,输出 1 就灭。
2、实验程序编写
led.s汇编程序如下所示:
/**************************************************************
文件名 :led.s
作者 :hanhui
版本 :V1.0
描述 :裸机实验 1 汇编点灯
其他 :无
日志 :初版V1.0 2020/8/31 hanhui创建
**************************************************************/
.global _start /* 全局变量 */
/*
* 描述: _start 函数,程序从此函数开始执行,此函数完成时钟使能、
* GPIO 初始化、最终控制 GPIO 输出低电平来点亮 LED 灯。
*/
_start:
/* 1、使能所有时钟 */
ldr r0, =0x020c4068 /* 寄存器 CCGR0 */
ldr r1, =0xffffffff
str r1, [r0]
ldr r0, =0x020c406c /* 寄存器 CCGR1 */
str r1, [r0]
ldr r0, =0x020c4070 /* 寄存器 CCGR2 */
str r1, [r0]
ldr r0, =0x020c4074 /* 寄存器 CCGR3 */
str r1, [r0]
ldr r0, =0x020c4078 /* 寄存器 CCGR4 */
str r1, [r0]
ldr r0, =0x020c407c /* 寄存器 CCGR5 */
str r1, [r0]
ldr r0, =0x020c4080 /* 寄存器 CCGR6 */
str r1, [r0]
/* 2、设置 GPIO1_IO03 复用为 GPIO1_IO03 */
ldr r0, =0x020e0068 /* 将寄存器 SW_MUX_GPIO1_IO03_BASE 加载到 r0 中 */
ldr r1, =0x5 /* 设置寄存器 SW_MUX_GPIO1_IO03_BASE 的 MUX_MODE 为 5 */
str r1, [r0]
/* 3、配置 GPIO1_IO03 的 IO 属性
*bit 16:0 HYS 关闭
*bit [15:14]: 00 默认下拉
*bit [13]: 0 kepper 功能
*bit [12]: 1 pull/keeper 使能
*bit [11]: 0 关闭开路输出
*bit [7:6]: 10 速度 100Mhz
*bit [5:3]: 110 R0/6 驱动能力
*bit [0]: 0 低转换率
*/
ldr r0, =0x020e02f4 /*寄存器 SW_PAD_GPIO1_IO03_BASE */
ldr r1, =0x10b0
str r1, [r0]
/* 4、设置 GPIO1_IO03 为输出 */
ldr r0, =0x0209c004 /* 寄存器 GPIO1_GDIR */
ldr r1, =0x00000008
str r1, [r0]
/* 5、打开 LED0
* 设置 GPIO1_IO03 输出低电平
*/
ldr r0, =0x0209c000 /*寄存器 GPIO1_DR */
ldr r1, =0
str r1, [r0]
/*
* 描述 :loop 死循环
*/
loop:
b loop
3、编译代码
3.1、arm-linux-gnueabihf-gcc 编译文件
arm-linux-gnueabihf-gcc -g -c led.s -o led.o
上述命令就是将 led.s 编译为 led.o,其中“-g”选项是产生调试信息,GDB 能够使用这些调试信息进行代码调试。“-c”选项是编译源文件,但是不链接。“-o”选项是指定编译产生的文件名字,这里我们指定 led.s 编译完成以后的文件名字为 led.o。执行上述命令以后就会编译生成一个 led.o 文件。
3.2、arm-linux-gnueabihf-ld 链接文件
使用 arm-linux-gnueabihf-ld 来将前面编译出来的 led.o 文件链接到 0X87800000 这个地址,使用如下命令:
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
上述命令中-Ttext 就是指定链接地址,“-o”选项指定链接生成的 elf 文件名,这里我们命名为 led.elf。上述命令执行完以后就会在工程目录下多一个 led.elf 文件。
led.elf 文件也不是我们最终烧写到 SD 卡中的可执行文件,我们要烧写的.bin 文件,因此还需要将 led.elf 文件转换为.bin 文件,这里我们就需要用到 arm-linux-gnueabihf-objcopy 这个工具了。
3.3、arm-linux-gnueabihf-objcopy 格式转换
arm-linux-gnueabihf-objcopy 更像一个格式转换工具,我们需要用它将 led.elf 文件转换为led.bin 文件,命令如下:
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
上述命令中,“-O”选项指定以什么格式输出,后面的“binary”表示以二进制格式输出,选项“-S”表示不要复制源文件中的重定位信息和符号信息,“-g”表示不复制源文件中的调试信息。
3.4、arm-linux-gnueabihf-objdump 反汇编
大多数情况下我们都是用 C 语言写试验例程的,有时候需要查看其汇编代码来调试代码,因此就需要进行反汇编,一般可以将 elf 文件反汇编,比如如下命令:
arm-linux-gnueabihf-objdump -D led.elf > led.dis
总结一下我们为了编译 ARM 开发板上运行的 led.o 这个文件使用了如下命令:
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
4、创建 Makefile 文件
led.bin:led.s
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
clean:
rm -rf *.o led.bin led.elf led.dis
创建好 Makefile 以后我们就只需要执行一次“make”命令即可完成编译
如果我们要清理工程的话执行“make clean”即可
5、代码烧写
专门编写了一个软件来将编译出来的.bin 文件烧写到 SD 卡中,这个软件叫做“imxdownload”。
将 imxdownload 拷贝到工程根目录下,也就是和 led.bin 处于同一个文件夹下,要不然烧写会失败的。
准备一张新的 SD(TF)卡,确保 SD 卡里面没有数据,因为我们在烧写代码的时候可能会格式化 SD 卡!!!
在输入命令“ls /dev/sd*”来查看当前 Ubuutu 下的存储设备,确定好SD 卡以后我们就可以使用软件 imxdownload 向 SD 卡烧写 led.bin 文件了。
使用 imxdownload 向 SD 卡烧写 led.bin 文件,命令格式如下:
./imxdownload <.bin file> <SD Card>
其中.bin 就是要烧写的.bin 文件,SD Card 就是你要烧写的 SD 卡,比如我的电脑使用如下命令烧写 led.bin 到/dev/sdb 中:
./imxdownload led.bin /dev/sdb
烧写的最后一行会显示烧写大小、用时和速度,比如 led.bin 烧写到 SD 卡中的大小是 3.2KB,用时 0.0130468s,烧写速度是 248KB/s。注意这个烧写速度,如果这个烧写速度在几百 KB/s 以下那么就是正常烧写。
注:如果这个烧写速度大于几十 MB/s、甚至几百 MB/s 那么肯定是烧写失败了!
解决方法就是重新插拔 SD 卡,一般出现这种情况,重新插拔 SD 卡基本没啥用,只有重启Ubuntu。
烧写完成以后会在当前工程目录下生成一个 load.imx 的文件,load.imx 这个文件就是软件 imxdownload 根据 NXP 官方启动方式介绍的内容,在 led.bin 文件前面添加了一些数据头以后生成的。最终烧写到 SD 卡里面的就是这个 load.imx 文件,而led.bin。
6、代码验证
代码已经烧写到了 SD 卡中了,接下来就是将 SD 卡插到开发板的 SD 卡槽中,然后设置拨码开关为 SD 卡启动,拨码开关设置如图所示:
设置好以后按一下开发板的复位键,如果代码运行正常的话 LED0 就会被点亮,如图所示: