LED汇编实验
1.原理分析:
为什么要学习Cortex-A汇编?
①需要利用汇编来初始化一些Soc外设;
②需要利用汇编语言来初始化DDR(但我们这里的IMX.6U不需要);
③设置sp指针,一般指向DDR(sp是CPU内部寄存器,用于保存栈顶指针,栈顶指针指向的是RAM,因此要么是内部RAM要么是外部RAM。对于跑linux的Cortex-A芯片而言,一般内部RAM比较小,所以实际使用中都指向外部 RAM,DDR就是外部RAM。),设置好C语言环境。
2.Mini开发板LED硬件原理分析:
回顾:STM32 IO初始化为GPIO:
①、使能指定 GPIO 的时钟。
②、初始化 GPIO,比如输出功能、上拉、速度等等。
③、STM32 有的 IO 可以作为其它外设引脚,也就是 IO 复用,如果要将 IO 作为其它外设引脚使用的话就需要设置 IO 的复用功能。
④、最后设置 GPIO 输出高电平或者低电平。
IMX.6U IO初始化为GPIO的一般步骤:
①、使能 GPIO 对应的时钟。
②、设置寄存器 IOMUXC_SW_MUX_CTL_PAD_XX_XX,设置 IO 的复用功能,使其复用
为 GPIO 功能。
③、设置寄存器 IOMUXC_SW_PAD_CTL_PAD_XX_XX,设置 IO 的上下拉、速度等等。
④、第②步已经将 IO 复用为了 GPIO 功能,所以需要配置 GPIO,设置输入/输出、是否使
用中断、默认输出电平等。
此处LED的GPIO初始化设置为:
I.MX6ULL IO初始化:
①、使能时钟,CCGR0~CCGR6这7个寄存器控制着6ULL所有外设时钟的使能。为了简单,设置CCGR0~CCGR6这7个寄存器全部为0XFFFFFFFF,相当于使能所有外设时钟。
②、IO复用,将寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的bit3~0设置为0101=5,这样GPIO1_IO03就复用为GPIO。
③、寄存器IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03是设置GPIO1_IO03的电气属性。包括压摆率、速度、驱动能力、开漏、上下拉等。
④、配置GPIO功能,设置输入输出。设置GPIO1_GDIR寄存器bit3为1,也就是设置为输出模式。设置GPIO1_DR寄存器的bit3,为1表示输出高电平,为0表示输出低电平。
3.汇编基本语法:
汇编由一条一条指令构成,指令就涉及到汇编指令。
例如:C语言的赋值如下:
Int a,b;
a=b;
汇编实现:
假设a地址为0X20,b地址为0x30
LDR R0, =0X30
LDR R1, [R0]
LDR R0, =0X20
STR R1, [R0]
我们在使用汇编编写驱动的时候最常用的就是LDR和STR这两个指令。
4.驱动编写:
leds.s:
1 .global _start /* 全局标号 */ 2 3 /* 4 * 描述:_start函数,程序从此函数开始执行此函数完成时钟使能、 5 * GPIO初始化、最终控制GPIO输出低电平来点亮LED灯。 6 */ 7 _start: 8 /* 例程代码 */ 9 /* 1、使能所有时钟 */ 10 ldr r0, =0X020C4068 /* CCGR0 */ 11 ldr r1, =0XFFFFFFFF 12 str r1, [r0] 13 14 ldr r0, =0X020C406C /* CCGR1 */ 15 str r1, [r0] 16 17 ldr r0, =0X020C4070 /* CCGR2 */ 18 str r1, [r0] 19 20 ldr r0, =0X020C4074 /* CCGR3 */ 21 str r1, [r0] 22 23 ldr r0, =0X020C4078 /* CCGR4 */ 24 str r1, [r0] 25 26 ldr r0, =0X020C407C /* CCGR5 */ 27 str r1, [r0] 28 29 ldr r0, =0X020C4080 /* CCGR6 */ 30 str r1, [r0] 31 32 /* 2、设置GPIO1_IO03复用为GPIO1_IO03 */ 33 ldr r0, =0X020E0068 /* 将寄存器SW_MUX_GPIO1_IO03_BASE加载到r0中 */ 34 ldr r1, =0X5 /* 设置寄存器SW_MUX_GPIO1_IO03_BASE的MUX_MODE为5 */ 35 str r1,[r0] 36 37 /* 3、配置GPIO1_IO03的IO属性 38 *bit 16:0 HYS关闭 39 *bit [15:14]: 00 默认下拉 40 *bit [13]: 0 kepper功能 41 *bit [12]: 1 pull/keeper使能 42 *bit [11]: 0 关闭开路输出 43 *bit [7:6]: 10 速度100Mhz 44 *bit [5:3]: 110 R0/6驱动能力 45 *bit [0]: 0 低转换率 46 */ 47 ldr r0, =0X020E02F4 /*寄存器SW_PAD_GPIO1_IO03_BASE */ 48 ldr r1, =0X10B0 49 str r1,[r0] 50 51 /* 4、设置GPIO1_IO03为输出 */ 52 ldr r0, =0X0209C004 /*寄存器GPIO1_GDIR */ 53 ldr r1, =0X8 54 str r1,[r0] 55 56 /* 5、打开LED0 57 * 设置GPIO1_IO03输出低电平 58 */ 59 ldr r0, =0X0209C000 /*寄存器GPIO1_DR */ 60 ldr r1, =0 61 str r1,[r0] 62 63 /* 64 * 描述: loop死循环 65 */ 66 loop: 67 b loop
5.程序编译:编译出bin文件即可烧写
①、使用arm-linux-gnueabihf-gcc,将.c .s文件变为.o
②、将所有的.o文件链接为elf格式的可执行文件。
③、将elf文件转为bin文件。
④、将elf文件转为汇编,反汇编。
链接:
链接就是将所有.o文件链接在一起,并且链接到指定的地方。本实验链接的时候要指定链接起始地址。链接起始地址就是代码运行的起始地址。
对于6ULL来说,链接起始地址应该指向RAM地址。RAM分为内部RAM和外部RAM,也就是 DDR。6ULL内部RAM地址范围0X900000~0X91FFFF。也可以放到外部DDR中,对于I.MX6U-ALPHA开发板,512MB字节DDR版本的核心板,DDR范围就是0X80000000~0X9FFFFFFF。对于256MB的DDR来说,那就是0X80000000~0X8FFFFFFF(Mini板和Alpha板子一样)。
但我们默认裸机代码的链接起始地址为0X87800000。要使用DDR,那么必须要初始化DDR,对于I.MX来说bin文件不能直接运行(严格来说,应该是bin文件不能直接烧写到SD卡,EMMC,NAND等外置存储中启动运行,而不是bin文件不能直接运行,使用JLINK将bin文件直接下载到内部RAM中还是可以运行的),需要添加一个头部,这个头部信息包含了DDR的初始化参数,I.MX系列SOC内部boot rom会从SD卡,EMMC等外置存储中读取头部信息,然后初始化DDR,并且将bin文件拷贝到指定的地方。
Bin的运行地址一定要和链接起始地址一致。位置无关代码除外。
1 cd linux/IMX6ULL/Board_Drivers/1_leds 2 arm-linux-gnueabihf-gcc -g -c leds.s -o led.o 3 arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf 4 arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin 5 arm-linux-gnueabihf-objdump -D led.elf > led.dis
6.bin文件烧写:
STM32烧写到内部FLASH。
6ULL支持SD卡、EMMC、NAND、nor、SPI flash等等启动。裸机例程选择烧写到SD卡里面。
在ubuntu下向SD卡烧写裸机bin文件。烧写不是将bin文件拷贝到SD卡中,而是将bin文件烧写到SD卡绝对地址上。而且对于I.MX而言,不能直接烧写bin文件,必须先在bin文件前面添加头部(之后讲解)。完成这个工作,需要使用正点原子提供的imxdownload软件(使用前先把它复制到1_leds下边)。
Imxdownload使用方法,确定要烧写的SD卡文件,我的是/dev/sdb。
给予imxdownload可执行权限:
Chmod 777 imxdownload
烧写:
1.将tf卡插到读卡器上插到电脑,连接到ubuntu虚拟机;
2.到1_leds文件夹下执行./imxdownload led.bin /dev/sdf(当然,你的SD卡是哪个需要修改)
3.Imxdownlaod会向led.bin添加一个头部,生成新的load.imx文件,这个load.imx文件就是最终烧写到SD卡里面去的文件。
1 ./imxdownload led.bin /dev/sdb
4.烧录好之后,拔下来tf卡插到开发板,将拨码开关拨至10000010(SD卡启动模式)。
注意:在将bin文件烧录到SD卡时一定要注意确认好自己的SD卡是哪个,否则即使烧录成功实验现象也可能不对。比如因为我的SD卡插到电脑上出来两个名称(/dev/sdb和/dev/sdb1,出来两个名称的原因是sdb表示我整个的SD卡磁盘,而sdb1是这个SD的一个分区,如果还有其他分区可能会有sdb2之类的),我烧录到sdb1成功了但实验现象不正确,sdb也烧录成功了现象正确。
5.上电之后就可以看到用户灯先不亮后面就亮了(程序执行需要一些时间)。
问题:JLINK能不能给IMX6ULL烧写程序呢?
①6ULL支持JTAG,但是因为没有烧写算法所以无法烧写;
②但是我们可以用JTAG把bin文件下载到内部RAM;
③奇葩问题:6ULL的JTAG口竟然和SAI复用,SAI连接了WM8960的音频DAC,如果使用还得拆了喇叭,得不偿失,所以我们一般不用;
④对于普通开发者,在嵌入式Linux开发中基本不使用JLINK;
⑤我们可以使用点灯,串口来调试程序。
本篇完!!!