I.MX裸机点灯过程
Posted stmplayer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了I.MX裸机点灯过程相关的知识,希望对你有一定的参考价值。
刚开始学习I.MX6Ull的裸机开发,这里来记录一下今天的学习,本文章适合想要开始学习Linux驱动开发的朋友,内容简单,利用的是正点原子的视频与开发板,只是讲了开发步骤,对细节感兴趣的也可以去看看正点原子的视频。
一、ARM汇编基础
与STM32单片机不同,stm32开发板的启动文件中已经将SP指针初始化、DDR初始化。正点原子的Linux开发板并没有初始化这些,所以C语言环境还没准备好,不能直接运行C语言代码,我们利用汇编语言将C语言环境搭建好后就可以执行C语言代码了。这里刚开始只介绍了两个常用并且十分重要的指令,LDR、STR。他们是存储器访问指令,由于ARM不能直接的访问存储器,所以一般是我们将需要配置的值先保存到寄存器中,然后借助存储器访问指令将通用寄存器的的配置数据写入到I.MX6LL寄存器中。
1、LDR指令
1 LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
2 LDR R1, [R0] @读取地址 0X0209C004 中的数据到 R1 寄存器中
2、STR指令
1 LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
2 LDR R1, =0X20000002 @R1 保存要写入到寄存器的值,即 R1=0X20000002
3 STR R1, [R0] @将 R1 中的值写入到 R0 中所保存的地址中
需要注意的是这两个指令都是操控32位数据。如果需要按照字节与半字进行操作的话需要给LDR、STR后面分别加上B或者H。LDRB、LDRH。
二、汇编LED灯实验
点灯是单片机的灵魂,就如各种编程的hello world一样,下面就是正点原子提供给我们的点灯代码。
利用STM32点灯的时候我们是先进行初始化,初始化就包括了使能端口时钟、端口配置、设置高低电平控制灯的开关。Linux开发板也是如此,只不过用汇编控制寄存器的方式来实现。首先我们先看他和STM32GPIO口的命名有什么不同,STM32 中的 IO 都是 PA0~15、PB0~15 这样命名的,而I.MX6ULL 的 IO 命名规则是IOMUXC_SW_MUX_CTL_PAD_xx_IOxx。根据这两个xx也可以判断出引脚是什么功能,如GPIO1_IO01、UART1_TX_DATA、JTAG_MOD。之后我们再看I.MX6ULL的点灯过程。由于板上的LED内部已经连接了GPIO1_IO03,所以我们直接对GPIO1_IO03进行配置即可:1、使能 GPIO1 时钟 2、设置 GPIO1_IO03 的复用功能 3、配置 GPIO1_IO03 4、设置 GPIO。与STM32的初始化并没有太大的区别。下面就是具体初始化的代码,都是通过控制寄存器上每个位来实现初始化。
.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, =0X0000008
str r1,[r0]
/* 5、打开 LED0
* 设置 GPIO1_IO03 输出低电平
*/
ldr r0, =0X0209C000 /*寄存器 GPIO1_DR */
ldr r1, =0
str r1,[r0]
/*
* 描述: loop 死循环
*/
loop:
b loop
以上代码就是I.MX6ULL的点灯程序,只使用的LDR、STR两个指令,对没有汇编基础的小新也是很友好的。第 2 行定义了一个全局标号_start,_start相当于内存地址,代码就是从_start 这个标号开始顺序往下执行的,很像C语言的函数。
三、编译下载代码验证
这里就利用到了交叉编译工具。
1、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 文件。
2、arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
链接文件,就是将所有.o文件链接到一个指定的链接位置。上述命令中-Ttext 就是指定链接地址,“-o”选项指定链接生成的 elf 文件名,这里我们命名 为 led.elf。上述命令执行完以后就会在工程目录下多一个 led.elf 文件。
3、arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
格式准换,由于led.elf 文件也不是我们最终烧写到 SD 卡中的可执行文件,我们要烧写的.bin 文件,因此还需要将 led.elf 文件转换为.bin 文件。就是上述命令。上述命令中,“-O”选项指定以什么格式输出,后面的“binary”表示以二进制格式输出, 选项“-S”表示不要复制源文件中的重定位信息和符号信息,“-g”表示不复制源文件中的调试信息。
以上的步骤其实可以写成一个Makefile文件,make一下就可以执行完,很方便。以后会写一个关于Makefile的博客,这里就不提了。
4、此时的.bin文件并不能直接的烧入到I.MX6U,因为其内部没有flash,96K的ROM我们用户也不可以调用。所以我们可以从外置的存储介质来烧入代码。我使用的是SD卡。这个步骤需要使用正点原子提供的imxdownload裸机烧写软件。将他copy到工程根目录下与led.bin在一起,之后还要修改imxdownload的文件权限,利用Linux的一个命令chmod给文件可执行的权限。最后执行./imxdownload led.bin /dev/sdd 执行后文件夹多了一个load.imx文件,他其实就是imxdownload给led.bin文件加了一些数据头以后生成的。这里有些是Linux的基础知识,不懂得话一定要先学会使用Linux在开始Linux驱动的学习。
下来就可以在裸机上验证了,记得把BOOT_CFG调成以下状态:
设置好后按下复位键,等初始化完成后就可以看到灯亮了。
这里只是记录了点灯的过程,让新人们有个大概的思路,细节还是要看正点原子的文档,讲的很好。
以上是关于I.MX裸机点灯过程的主要内容,如果未能解决你的问题,请参考以下文章