1 汇编LED原理分析
为什么要写汇编
需要用汇编初始化一些SOC外设
使用汇编初始化DDR、I.MX6U不需要
设置sp指针,一般指向DDR,设置好C语言运行环境
1.1 LED硬件分析
可以看到LED灯一端接高电平,一端连接了GPIO_3上面,GPIO_3如果为低电平,LED灯亮,为高则LED灯灭。
STM32的IO初始化流程
使能GPIO时钟
设置IO复用,将其复用为GPIO
配置GPIO的电气属性
使用GPIO,输出高低电平
I.MX6U的IO初始化
使能时钟CCGR0~CCGR6这七个寄存器控制着所有外设时钟,为了简单设置所有的寄存器全部为1,相当于使能所有外设时钟
设置IO复用,将寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的bit3~0设置为0101,即复用为GPIO模式
将寄存器IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03是设置GPIO的电气属性。包括压摆率、速度、驱动能力、开漏、上下拉等。
配置GPIO功能,设置输入输出。设置GPIO1_DR寄存器bit3,设置为输出模式。
2 编写驱动
2.1 手册解读
2.2 驱动代码
.global _start @全局标号
_start:
/*使能所有外设时钟 */
ldr r0, =0x020c4068 @CCGR0
ldr r1, =0xffffffff @要向CCGR0写入的数据
str r1, [r0] @将0xffffffff写入CCGR0中
ldr r0, =0x020c406c @CCGR1
str r1, [r0] @将0xffffffff写入CCGR1中
ldr r0, =0x020c4070 @CCGR2
str r1, [r0] @将0xffffffff写入CCGR2中
ldr r0, =0x020c4074 @CCGR3
str r1, [r0] @将0xffffffff写入CCGR3中
ldr r0, =0x020c4078 @CCGR4
str r1, [r0] @将0xffffffff写入CCGR4中
ldr r0, =0x020c407c @CCGR5
str r1, [r0] @将0xffffffff写入CCGR5中
ldr r0, =0x020c4080 @CCGR6
str r1, [r0] @将0xffffffff写入CCGR6中
ldr r0, =0x020c4084 @CCGR7
str r1, [r0] @将0xffffffff写入CCGR7中
/*配置GPIO1_IO03 PIN的复用为GPIO,也就是设置
*IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03=5
*IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的寄存器地址为0x020E0068
*/
ldr r0, =0x020E0068 @IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03
ldr r1, =0x5 @写入的数据
str r1, [r0] @写入
/*配置GPIO1_IO03的电气属性 也就是寄存器
*IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03
*IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03的寄存器地址为0x020e02f4
*
*bit0: 0低速率
*bit[5:3]: 110 R0/6驱动能力
*bit[7:6]: 10 100MHz速度
*bit11 : 0 关闭开路输出
*bit12 : 1 使能pull/kepper
*bit13 : 0 kepper
*bit15:14: 00 默认100K下拉
*bit16 : 0 关闭hys
*/
ldr r0, =0x020e02f4 @IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03
ldr r1, =0x10b0 @写入的数据
str r1, [r0] @写入
/*设置GPIO功能
*设置GPIO1_GDIR寄存器,设置GPIO1_GPIO03为输出
*GPIO1_GDIR寄存器地址为0x0209c004,设置GPIO1_GDIR寄存器bit3为1,
*也就是设置GPIO1_IO03为输出
*/
ldr r0, =0x0209c004
ldr r1, =0x8
str r1, [r0]
/*打开LED 也就是设置GPIO1_IO03为0
*GPIO1_DR寄存器地址为0x0209c000
*/
ldr r0, =0x0209c000
ldr r1, =0
str r1, [r0]
loop:
b loop
2.3 编译程序
将.c .s文件变为 .o
arm-linux-gnueabihf-gcc -c leds.s -o led.o
arm-linux-gnueabihf-ld连接文件,用来将 众多的.o文件连接到一个指定的链接位置,就是将所有.o文件链接在一起,并且链接到指定地方。所以就要指定一个起始地址,本实验指定的链接起始地址就是代码开始运行的地址。对于6ULL来说,链接起始地址应该指向RAM地址。RAM分为外部RAM和内部RAM,外部RAM也就是DDR,内部RAM地址范围是0x900000~0x91FFFF,也可以放在外部DDR中,对于I.MX6U-ALPHA开发板,512MB字节DDR版本的核心板,DDR范围就是0x80000000到0xA0000000
本系列视频,裸机代码的链接起始地址为0x87800000,因为后面uboot的链接起始地址也是0x87800000。要使用DDR,那么 必须要初始化DDR,这个头部信息包含了DDR的初始化参数,I.MX系列SOC内部boot rom会从SD卡、EMMC等外置存储中读取头部,然后初始化DDR,并且将bin文件拷贝到指定地方。
Bin的运行地址一定要和链接地址一致。位置无关代码除外。
2.4 烧写bin文件
STM32烧写到内部FLAHS
6ULL支持SD卡、EMMC、NAND、nor、SPI flash等启动,裸机例程选择烧写到SD卡里面。
在ubuntu下向SD卡烧写裸机bin文件。烧写不是将bin文件拷贝到SD卡中,而是将bin文件烧写到SD卡的指定绝对地址上,。而且对于I.MX而言,不能直接烧写bin文件,必须先在bin文件前面添加头部。完成这个工作,需要使用正点原子提供的imxdownload软件。
6ULL支持JTAG,因为没有烧写算法,所以无法烧写
但是可以通过JTAG将bin文件下载到内部ram
6ULL的JTAG口竟然和SAI复用,SAI连接了WM8960音频DAC,为啥不用跳线帽,不懂
在嵌入式Linux开发中基本不使用JLINK,普通开发者。
调试代码一般点灯、串口来调试程序。