Cotex-A系列需要自己写汇编。但是指令不是很多,只需要初始化一些外设。只需要1-2个重要的外设,看门狗,紧接着初始化DDR。设置好指针就能运行C语言了。
STM32的芯片不需要写汇编,是因为ST昌吉已经帮你写好了,就是那个.s文件。
/*
为什么要学习Cortex-A汇编
1.需要用汇编初始化一些SOC外设
2.使用汇编初始化DDR
但是6ULL芯片不需要,会在bin头中包含这些内容
3.设置SP指针一遍指向DDR,设置好C语言运行环境。
*/
STM32 的IO初始化流程
1.使能GPIO时钟
2.设置IO复用,复用为GPIO
3.配置GPIO的电气属性
4.使用GPIO输出高低电平
I.MX6ULL 的初始化流程
1.使能时钟(CCM的 CCGR0-CCGR6这七个寄存器)为了简单,设置CCGR0-CCGR6这七个寄存器全部为0xFFFFFFFF , 相当于使能全部的时钟。
2.IO复用,将寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的[3,0]位设置为0101,这样GPIO1_IO03就可以复用为GPIO模式了。
3.配置电气属性,将寄存器IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03的电气属性
设置的重点是压摆率,速度,驱动能力,开漏,上下拉等电阻。
4.配置GPIO功能,设置输入输出功能。
GPIOx_DR的读写寄存器,可以读取数据,也可以输入数据
GPIOx_GDIR的寄存器,代表输入输出0-input , 1-output
GPIOx_PS的状态寄存器
GPIOx_ICR的中断触发寄存器
GPIOx_ISR的中断掩码寄存器,控制中断时使能还是关闭
设置GPIO_DR=1为输出模式,就能点亮小灯了。
想要详细地去学习汇编,就要去参考《ARM Architecture Regerence Manual ARMx7-A and …-R edition》与《ARM Core Cotex-A(armV7)编程手册》
使用GNU汇编语法
@C代码示例
int a , b
a=b
@assembly示例
LDR R0 , =0X20
LDR R1 [R0] @将R0的数据写到R1中
LDR R0 , =0X30
STR R1 ,[R0] @将R1的数据写到R0地址中
@压栈出栈
PUSH {r0~R3,r5}
PUSH {LR}
POP {LR}
POP {r0~R3,r5}
我们需要知道的是User , SVC , System ,FIQ , RIQ , Abort
R0-R12 , SP , LR . PC ,CPSR (特殊寄存器),SPSR(异常备份寄存器)
.global _start /*全局标号*/
_start:
/*使能GPIO1_IO04 ---- RED LED */
/*CCGR1*/
ldr r0 , =0x020c406c
ldr r1 , =0xffffffff /*[27,26]*/
str r1 , [r0]
/*IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04寄存器复用GPIO*/
ldr r0 , =0x020e006c
ldr r1 , =0x5
str r1 , [r0]
/*IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04电气特性配置
*[0]bit : 0 低压摆率
*[5:3]bit :110 R0/6驱动能力
*[7:6]bit :10 速度100MHz
*[11]bit :0 关闭开路输出
*[12]bit :1 pull/keeper使能
*[13]bit :0 keeper功能
*[15:14]bit:00 默认下拉
*[16]bit :0 HYS关闭
*/
ldr r0 , =0x020e02f8
ldr r1 , =0x10b0
str r1 , [r0]
/*GPIO1_GDIR寄存器*/
ldr r0, =0x0209C004
ldr r1, =0x0000010
str r1,[r0]
/*GPIO1_IO4输出低电平*/
ldr r0 , =0x0209c000
ldr r1 , =0
str r1 , [r0]
/*进入死循环*/
loop:
b loop
用交叉编译工具链去编译程序
1.使用arm-none-linux-gnueabi-gcc将.s文件变为.o
2.将.o文件链接为.elf可执行文件,它比bin文件多了一些信息。链接是为了将.o文件添加到一个指定的起始地址,指向RAM,才能一行一行读取文件。RAM分为内部RAM128kb(0x900000-0x91ffff),与外部RAM512M(0x80000000-0x91ffffff)。我们选择链接起始地址为0x87800000。
3.将elf文件转为bin文件
4.将elf文件转为汇编,反汇编
我们的裸机程序并没有初始化DDR。要初始化DDR,需要添加一个头部信息。头部信息包含了DDR的初始化参数。I.MX系列SOC内部的boot room会从SD卡,EMMC等外部存储中读取头部信息,然后初始化DDR,并且将Bin文件拷贝到指定地方。
bin的运行地址一定要和链接其实地址一致,位置无关代码除外。
#编译为预编译文件
$: arm-none-linux-gnueabihf-gcc -g -c led.s -o led.o
#链接
$: arm-none-linux-gnueabihf-ld -Ttext 0x87800000 led.o -o led.elf
$: ls
led.s led.o led.elf
#转为bin文件
$: arm-none-linux-gnueabihf-objcopy -O binary -g -S led.elf led.bin
$: ls
led.s led.o led.elf led.bin
#还可以实现反汇编
arm-none-linux-gnueabihf-objdump -D led.elf > led.dis
IMX6ULL支持SD,EMMC,NAND,NOR FLASH,SPI Flash启动。
裸机例程那么使用SD卡吧。但是并不是直接把.bin文件直接扔到SD卡内存中。
将download二进制文件使用方法。
它其实是讲bin文件加入头部的.imx文件下载到了SD卡中去读取。
$: ./download led.bin /dev/sdb
这样插入SD卡就可以看到LED红灯被点亮了。
由于常常需要烧写,不断写那几个shell命令太麻烦了,写一个makefile吧
FILE=led
$(FILE).bin : $(FILE).s
arm-linux-gnueabihf-gcc -g -c $(FILE).s -o $(FILE).o
arm-linux-gnueabihf-ld -Ttext 0x87800000 $(FILE).o -o $(FILE).elf
arm-linux-gnueabihf-objcopy -O binary -g -S $(FILE).elf $(FILE).bin
#arm-linux-gnueabihf-objdump -D $(FILE).elf > $(FILE).dis
clean:
rm -rf *.o *.bin *.elf *.dis *.imx