此笔记由个人整理
塞上苍鹰_fly
课程来自:正点原子_手把手教你学Linux
一、汇编简介
- 为什么要是用汇编
- 需要汇编去初始化一些SOC外设
- 使用汇编去初始化DDR(I.MX6U不用)
- 设置sp指针,一般指向DDR,设置好c语言环境
- 汇编由一条一条汇编指令构成
- 格式
函数名:
函数体
返回语句
- LDR
- 从存储器中读取数据
LDR R0,=0X0209C004@将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1,[R0] @读取地址 0X0209C004 中的数据到 R1 寄存器中
- SDR
- 往存储器中写入数据
LDR R0,=0X0209C004@将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1,=0X20000002@R1 保存要写入到寄存器的值,即 R1=0X20000002
STR R1,[R0] @将 R1 中的值写入到 R0 中所保存的地址中
- 假设a地址为0X20,b地址为0x30,a=b
LDR R0,=0X30
LDR R1,[R0]
LDR R0,=0X20
SDR R1,[R0]
二、硬件分析
- 原理图
-
stm32 IO初始化
- 使能GPIO时钟
- 设置IO复用,将其复用为GPIO
- 配置GPIO的电气属性
- 使用GPIO输出高低电平
-
I.MX6ULL IO初始化
- 使能时钟CCGR0-CCGR6,这七个寄存器控制着6ull外设的所有时钟使能。为了简单,设置CCGR0-CCGR6这7个寄存器全部为0XFFFFFFFF,相当于使能所有外设时钟。(第十八章)
寄存器 | 地址 |
---|---|
CCGR0 | 0X020C_4068h |
CCGR1 | 0X020C_406Ch |
CCGR2 | 0X020C_4070h |
CCGR3 | 0X020C_4074h |
CCGR4 | 0X020C_4078h |
CCGR5 | 0X020C_407Ch |
CCGR6 | 0X020C_4080h |
- IO复用,将寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 的bit3-0设置为0101=5,复用为gpio
- 电气属性设置,将寄存器IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 ,HYS(迟滞比较器),PUS(上下拉电阻),PUE(设置IO使用上下拉或者状态保持器),PKE(控制PUE功能是否开启),ODE(开路输出),SPEED(IO速度),DSE(设置驱动能力),SRW(压摆率)
- 配置GPIO功能,设置输入输出,设置GPIO1_DR寄存器bit3为1,也就是设置为输出模式。设置GPIO1_DR寄存器的bit3,为1表示输出高电平,为0表示输出低电平。
三、编写驱动
- 使能时钟
- 设置复用
- 设置电气属性
- 设置GPIO
- 循环
.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
/*IO复用*/
ldr r0,=0x020e0068
ldr r1,=0x5 @GPIO功能
str r1,[r0]
/*电气属性设置
*bit0: 0
*bit5:3 110
*bit7:6 10
*bit11 0
*bit12 1
*bit13 0
*bit15:14 00
*bit16 0
*/
ldr r0,=0x020e02f4
ldr r1,=0x10b0
str r1,[r0]
/*设置GPIO_GDIR*/
ldr r0,=0x0209c004
ldr r1,=0x8
str r1,[r0]
/*打开led
*GPIO_DIR
*/
ldr r0,=0x0209c000
ldr r1,=0
str r1,[r0]
loop:
b loop
四、编译程序
- 将.c.s文件编译为.o(arm-linux-gnueabihf-gcc)
arm-linux-gnueabihf-gcc -g -c leds.s -o led.o
- 将所有的.o文件连接为elf格式的可执行文件(arm-linux-gnueabihf-ld)
- 链接就是将所有.o文件链接在一起,并且链接到指定的地方。本实验链接的时候要指定链接起始地址。链接起始地址就是代码运行的起始地址
- 对于6ULL来说,链接起始地址应该指向RAM地址。RAM分为内部RAM和外部RAM,也就是 DDR。6ULL内部RAM地址范围0X900000-0X91FFFF
- 裸机代码的链接起始地址为0X87800000。要使用DDR,那么必须要初始化DDR,对于I.MX来说bin文件不能直接运行,需要添加一个头部,这个头部信息包含了DDR的初始化参数,I.MX系列SOC内部boot rom会从SD卡,EMMC等外置存储中读取头部信息,然后初始化DDR,并且将bin文件拷贝到指定的地方
- Bin的运行地址一定要和链接起始地址一致。位置无关代码除外
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
- 将elf文件转为bin文件(arm-linux-gnueabihf-objcopy)
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
- 将elf文件转为汇编,反汇编(arm-linux-gnueabihf-objdump)
arm-linux-gnueabihf-objdump -D led.elf > led.dis
五、烧录bin文件
-
STM32烧写到内部FLASH。
-
6ULL支持SD卡、EMMC、NAND、nor、SPI flash等等启动,裸机例程选择烧写到SD卡里面
-
在ubuntu下向SD卡烧写裸机bin文件。烧写不是将bin文件拷贝到SD卡中,而是将bin文件烧写到SD卡绝对地址上
- 使用方法
chmod 777 imxdownload
./imxdownload led.bin /dev/sdc1(自己sd卡的驱动文件)
- Imxdownlaod会向led.bin添加一个头部,生成新的load.imx文件,这个load.imx文件就是最终烧写到SD卡里面去的