汇编led
一、原理图
原理图部分:
可以看出DS0是一个发光二极管,当LED0为低时,DS0亮起。
LED0接GPIO1_IO3
GPIO IO初始化流程:
1. 使能GPIO时钟,根据imx6ull数据手册可看出CCGR0-CCGR7使能了所有的外设的时钟,可设置这7个寄存器全部为0xffffffff,相当于使能所有的外设,CCM_CCRG:clock controll module_clock gating register
2. 设置IO服用,将寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03其复用为GPIO,bit0-bit3设置为0101
3. 配置GPIO的电气属性,IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03设置电气属性
包括压摆率、速度、驱动能力、开漏、上下拉等
4.配置GPIO功能,设置输入输出。设置GPIO1_DR寄存器bit3为1,也就是设置为输出模式,bit3为1表示高电平,为0表示输出低电平
二、GNU汇编语法
汇编程序的默认入口标号是_start,不过我们也可以在链接脚本中使用 ENTRY 来指明其它
的入口点,下面的代码就是使用_start 作为入口标号:
.global _start // 全局标号
_start:
ldr r0, =0x12 @r0=0x12
1、LDR 指令
LDR 主要用于从存储加载数据到寄存器 Rx 中,
LDR 也可以将一个立即数加载到寄存器 Rx
中,LDR 加载立即数的时候要使用“=”,而不是“#”。在嵌入式开发中,LDR 最常用的就是读
取 CPU 的寄存器值,比如 I.MX6UL 有个寄存器 GPIO1_GDIR,其地址为 0X0209C004,我们
现在要读取这个寄存器中的数据,示例代码如下:
示例代码 7.2.2.1 LDR 指令使用
LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004 LDR R1, [R0] @读取地址 0X0209C004 中的数据到 R1 寄存器中
上述代码就是读取寄存器 GPIO1_GDIR 中的值,读取到的寄存器值保存在 R1 寄存器中,
上面代码中 offset 是 0,也就是没有用到 offset。
R0-R7:因为ARM指令不能直接读取RAM里面的数据,所以要借助R0等寄存器
2、STR 指令
LDR 是从存储器读取数据,STR 就是将数据写入到存储器中,同样以 I.MX6UL 寄存器
GPIO1_GDIR 为例,现在我们要配置寄存器 GPIO1_GDIR 的值为 0X20000002,示例代码如下:
示例代码 7.2.2.2 STR 指令使用
LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, =0X20000002 @R1 保存要写入到寄存器的值,即 R1=0X20000002
STR R1, [R0] @将 R1 中的值写入到 R0 中所保存的地址中
LDR 和 STR 都是按照字进行读取和写入的,也就是操作的 32 位数据,如果要按照字节、
半字进行操作的话可以在指令“LDR”后面加上 B 或 H,比如按字节操作的指令就是 LDRB 和
STRB,按半字操作的指令就是 LDRH 和 STRH。
三、汇编代码
.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
四、编译程序
-
使用arm-linux-gnueabihf-gcc将.c .s文件变成.o文件
-
将所有的.o文件链接为elf格式的可执行文件,链接就是将所有的.o文件链接在一起,并且链接到指定的地方
-
将elf文件转成bin文件便于烧录
链接的时候要指定链接起始地址 ,链接起始地址就是代码运行的起始地址
对于imx6ull来说,链接起始地址应该指向RAM地址。RAM分为内部RAM和外部RAM,也就是DDR,imx6ull内部RAM地址为0x900000-0x91ffff,也可以放在外部DDR中,对于alpha512字节开发板而言,DDR范围就是0x80000000-0x9fffffff。要使用DDR,那么必须初始化DDR,对于IMX来说bin文件不能直接运行,需要添加一个头部,这个头部信息包含了DDR的初始化参数,IMX系列SOC内部boot rom会从SD卡,EMMC等外置存储中读取头部信息,然后初始化DDR,并且将bin文件拷贝到链接地址处。
bin文件的运行地址一定要和链接起始地址一致,位置无关代码除外
四、烧写bin文件
imx6ull支持SD卡,EMMC、NAND、nor、spi flash等等启动。裸机例程选择烧写到sd卡中
在ubuntu下向SD卡烧写裸机bin文件。烧写不是将bin文件拷贝到SD卡中,而是将bin文件烧写到SD卡绝对路径,需要借助imxdownload工具
imxdownload会向led.bin添加一个头部,生成新的load.imx文件,这个load.imx文件就是最终烧写到SD卡里面去的