博客介绍
硬件:正点原子linux开发板IM6ULL
开发环境:Ubuntu下的VSCode
功能:仿照STM32寄存器格式进行对IMX6ULL的内存地址进行映射对应的寄存器。
参考:正点原子linux
声明:以下仅为个人学习认知。如有错误,希望提出建议。
学习步骤简介
文件编写步骤:
1.编写连接脚本文件
2.编写汇编初始化内存及跳转
3.编写寄存器映射内存头文件
4.编写初始化
5.编写Makefil
编写连接脚本文件
- 第2行为初始化定位计数器为0x87800000;
- 第3行为设置一个.test段名,在花括号内start.o必须写在前面,不然在连接的时候程序的启动顺序将会被改变,导致程序不能正常启动;
- 第8行中的.rodata 表示只读数据段名;ALIGN(4) 表示数据段以4字节对齐方式;
- 第9和12行表示为分别获取.bss段的起始地址和终止地址。__bss_start 和 __bss_end错不多就是给段地址起了个别名。在连接汇编的时候可以使用这两个名字进行对bss段内的数据进行初始化。
编写汇编初始化内存及跳转
start.S
.global _start /*定义全局标号*/
.global _bss_start /*定义全局标号 指向bss段的起始地址*/
_bss_start:
.word __bss_start /*__bss_start 在链接脚本文件中定义*/
.global _bss_end /*定义全局标号 指向bss段的终止地址*/
_bss_end:
.word __bss_end /*__bss_end 在链接脚本文件中定义*/
_start:
/*设置处理器进入VSC模式*/
/*-------------------------------------------------------------------------------------------------------------------------*/
MRS R0, CPSR /*读取CPSR到R0 */
BIC R0, R0, #0x1F /*清除CPSR的bit0-4 */
ORR R0, R0, #0x13 /*写CPSR的bit0-4 */
MSR CPSR, R0 /*将RO写入CPSR */
/*清除BSS段 */
/*-------------------------------------------------------------------------------------------------------------------------*/
LDR R0, _bss_start /*将bss段起始地址送入R0 */
LDR R1, _bss_end /*将bss段结束地址送入R1 */
MOV R2, #0 /*设置R2初始值 */
bss_loop: /*bss段数据初始化循环 */
STMIA R0!, {R2} /*将R2的值送如R0所在地址,并更新R0 */
CMP R0, R1 /*比较R0与R1,并设置CPSR的状态标志位 */
BLE bss_loop /*BLE=B+LE; LE:如果R0 <= R1 执行B:跳转命令 */
/*设置SP指针并跳转C语言main函数 */
/*-------------------------------------------------------------------------------------------------------------------------*/
LDR SP, =0x80200000
B main /*跳转到C语言main函数 */
编写寄存器映射内存头文件
以CCM寄存器为例:
#ifndef __IMX6ULL_H
#define __IMX6ULL_H
/*先进行初始化 CCM寄存器的基地址 */
#define CCM_BASE (0x020C4000) /*CCM的基地址*/
typedef struct
{
volatile unsigned int CCR;
volatile unsigned int CCDR;
volatile unsigned int CSR;
volatile unsigned int CCSR;
volatile unsigned int CACRR;
volatile unsigned int CBCDR;
volatile unsigned int CBCMR;
volatile unsigned int CBCMR1;
volatile unsigned int CBCMR2;
volatile unsigned int CSCDR1;
volatile unsigned int CS1CDR;
volatile unsigned int CS2CDR;
volatile unsigned int CDCDR;
volatile unsigned int CHSCCDR;
volatile unsigned int CSCDR2;
volatile unsigned int CSCDR3;
volatile unsigned int RESERVEC_1[2]; //中间出现跳跃地址,也就是不连续的内存地址,使用地址占位变量来填充
volatile unsigned int CDHIPR;
volatile unsigned int RESERVEC_2[2];
volatile unsigned int CLPCR;
volatile unsigned int CISR;
volatile unsigned int CIMR;
volatile unsigned int CCOSR;
volatile unsigned int CGPR;
volatile unsigned int CCGR0;
volatile unsigned int CCGR1;
volatile unsigned int CCGR2;
volatile unsigned int CCGR3;
volatile unsigned int CCGR4;
volatile unsigned int CCGR5;
volatile unsigned int CCGR6;
volatile unsigned int RESERVEC_3[1];
volatile unsigned int CMEOR;
}CCM_Type;
/*将CCM_BASE对应的地址设置为CCM_Type结构体类型*/
#define CCM ((CCM_Type*) CCM_BASE)
#endif
编写初始化
以CCM寄存器为例:
//使能外设时钟
void clock_init(void)
{
CCM->CCGR0 = 0xFFFFFFFF; //使用结构体指针方式对CCM_CCGR寄存器进行操作,就相当于与对0x020C4068H地址进行操作
CCM->CCGR1 = 0xFFFFFFFF;
CCM->CCGR2 = 0xFFFFFFFF;
CCM->CCGR3 = 0xFFFFFFFF;
CCM->CCGR4 = 0xFFFFFFFF;
CCM->CCGR5 = 0xFFFFFFFF;
CCM->CCGR6 = 0xFFFFFFFF;
}
编写Makefil
Makefile文件
objs := start.o main.o
gcc := arm-linux-gnueabihf-gcc
ld := arm-linux-gnueabihf-ld
objcopy := arm-linux-gnueabihf-objcopy
objdump := arm-linux-gnueabihf-objdump
ledc.bin : $(objs)
$(ld) -Timx6u.lds -o ledc.elf $^
$(objcopy) -O binary -S ledc.elf ledc.bin
$(objdump) -D -m arm ledc.elf > ledc.dis
%.o:%.c
$(gcc) -Wall -nostdlib -c -O2 $^ -o $@
%.o:%.s
$(gcc) -Wall -nostdlib -c -O2 $^ -o $@
%.o:%.S
$(gcc) -Wall -nostdlib -c -O2 $^ -o $@
clean:
rm -rf *.o ledc.bin ledc.elf ledc.dis
收获:
- 使用变量名赋值 := 代替 较长的编译命令
- 使用依赖集合符号: $^