(嵌入式)关于arm中的存储控制器(三)终!

.equ:
.equ symbol, expression: 把某一个符号(symbol)定义成某一个值(expression),该指令并不分配空间,相当于C语言中的#define宏定义。

LR寄存器:
LR(link register)连接寄存器,在ARM体系结构中LR的特殊用途有两种:
1.用来保存子程序的返回地址。
2.当异常发生时,LR中保存的值等于异常发生时PC的值减4(或者减2),因此在各种异常模式下可以根据LR的值返回到异常发生前的位置继续执行。
当通过BL或者BLX指令调用子程序时,硬件自动将子程序返回地址保存在R14(LR)寄存器中,在子程序返回时,把LR的值赋值到程序计数器PC即可实现子程序返回(eg:MOV PC,LR)。


ADR指令:
这是一条小范围的地址读取伪指令,它将基于PC的相对偏移地址值读到目标寄存器中。
使用格式: ADR register,exper
在编译源程序时,编译器首先计算出当前PC到exper的偏移值#offset_to_exper,然后使用一条ADD或者SUB指令来替换这些伪指令,例如,ADD resister,PC,#offset_to_exper
注意标号exper与指令必须在统一代码段。
ADRL指令:
这是一条中等范围的地址读取伪指令,它将基于PC的相对偏移地址值读到目标寄存器中。
原理和ADR一样,不同的是它在编译的时候,会被用两条合适的指令来替换伪指令。
eg:ADD register,PC,offset1
       ADD register,register,offset2
所以上面adrl    r2, mem_cfg_val  意思是把下面那13个值的起始存储地址存入到r2寄存器。


.long:
定义一个4字节数据,并为它分配空间 

.align n:
它的作用是对指令或者数据存放的地址按 2^n 进行对齐。下面是指定按 2^4 对齐。


汇编语言head.S:(作用是将 RAM 程序复制到 SDRAM中,并在SDRAM 中执行)

.equ  MEM_CTL_BASE, 0x48000000  @ MEM_CTL_BASE 为芯片内存中的13个存储控制器中寄存器的起始地址
.equ  SDRAM_BASE,   0x30000000  @ SDRAM_BASE 为SDRAM在芯片中的内存地址

.text
.global _start
_start:
			bl disable_watch_dog    @ 关闭WATCHDOG,否则CPU会不断重启
			bl memsetup             @ 设置存储控制器(配置其相应的寄存器)
			bl copy_steppingstone_to_sdram  @ 复制代码到SDRAM中
			ldr pc,=on_sdram        @ 跳转到SDRAM中继续执行
on_sdram:
			ldr sp,=0x34000000      @ 设置堆栈
			bl main
halt_loop:
			b halt_loop						
			
disable_watch_dog:
			mov r1,  #0x53000000   @ WATCHDOG在芯片中的内存地址
			mov r2,  #0x0
			str r2, [r1]     @ 把WATCHDOG寄存器写0
			mov pc, lr       @ 把连接寄存器 lr 的值赋值给程序计数器 PC。用来子程序返回继续执行主程序

copy_steppingstone_to_sdram:
			@ 我们这里将steppingstonede 4K数据全部复制到SDRAM中去
			@ steppingstone的 起始地址为0x00000000, SDRAM中的起始地址为0x30000000
			
			mov r1,#0
			ldr r2,=SDRAM_BASE
			mov r3,#4*1024      @ 因为我们要复制4K的大小
1:
			ldr r4,[r1],#4    @ 从steppingstone 读取4字节的数据,然后让源地址加4
			str r4,[r2],#4    @ 将r4 里4字节的数据复制SDRAM中,然后目的地址加4
			
			cmp r1, r3        @ 参考我下面的解释
			bne 1b
			mov pc, lr
		
memsetup:
			mov r1, #MEM_CTL_BASE
			adrl r2, mem_cfg_val   @ 注意这里 adr 后面是L 而不是数字1,反正我开始就是傻傻分不清。
			                       @ 这个语句就是把 mem_cfg_val 段定义的几个数据的其实地址传递给 r2
			
			add r3, r1,#52         @ 把 r1+13*4 传递给r3,cpu是32bit的,即一个寄存器包含4个字节,所以13个就包含52个字节
			                       @ 那么,如果把13个寄存器全部赋值结束后地址就应该是 r1+13*4。
1:
			ldr r4, [r2],#4        @ 读取设置值,并让r2+4。
		        str r4, [r1],#4       @ 将此值写入寄存器,并让r1+4,以便下一个数据写入下一个寄存器
					  
                        cmp r1, r3             @ 关于 cmp 指令其实也就是计算r1-r3,但是它的结果并不改变其寄存器的值,只是改变程序状态寄存器 CPSR的标志位
		                               @ 然后下一条语句在指令后加上条件判断就能完成我们想要的循环。
                        bne 1b                 @ ne(如果不相等) 1b 这里的b(backwark),向后跳转到局部标签1处执行。
		  			       @ 相应的还有1f(foward),向前跳转到局部标签1处执行,注意理解这里的前和后,前代表地址增的方向,后代表地址减的方向
                        mov pc, lr

.align 4
mem_cfg_val:
				.long  0x22011110  @ BWSCON 寄存器要写入的值		  
				.long  0x00000700  @ BANKCON0 寄存器要写入的值
				.long  0x00000700  @ BANKCON1 寄存器要写入的值
				.long  0x00000700  @ BANKCON2 寄存器要写入的值
				.long  0x00000700  @ BANKCON3 寄存器要写入的值
				.long  0x00000700  @ BANKCON4 寄存器要写入的值
				.long  0x00000700  @ BANKCON5 寄存器要写入的值
				.long  0x00018005  @ BANKCON6 寄存器要写入的值
				.long  0x00018005  @ BANKCON7 寄存器要写入的值
				.long  0x008C07A3  @ REFRSH 寄存器要写入的值
				.long  0x000000B1  @ BANKSIZE 寄存器要写入的值
				.long  0x00000030  @ MRSRB6 寄存器要写入的值
				.long  0x00000030  @ MRSRB7 寄存器要写入的值

c语言main函数:

#define  GPFCON  (*(volatile unsigned long *)0x56000050)
#define  GPFDAT  (*(volatile unsigned long *)0x56000054)

#define  GPF4_out  (1<<(4*2))
#define  GPF5_out  (1<<(5*2))
#define  GPF6_out  (1<<(6*2))

void wait(volatile unsigned long dly)   // 简单的延时函数
{
	for(;dly>0;dly--);
}

int main(void)
{
	unsigned long i=0;
	
	GPFCON = CPF4_out | GPF5_out | GPF6_out; // 将LED对应的引脚设置为输出
	
	while(1)
	{
		wait(30000);
		GPFDAT = (~(1<<4)); // 根据i的值,点亮LED
		if(++1 == 8)
			i=0;
	}
	return 0;
}


Makefile:

sdram.bin : head.S leds.C
	arm-linux-gcc -c -o head.o head.S
	arm-linux-gcc -c -o leds.o leds.c
	arm-linux-ld -Ttext 0x30000000 head.o leds.o -o sdram_elf
	arm-linux-objcopy -O binary -S sdram_elf sdram.bin
	arm-linux-objdump -D -m arm sdram_elf > sdram.dis
clean:
	rm -f sdram.dis sdram_elf sdram.bin *.o	

注: objdump 命令是Linux下的反汇编目标文件或者可执行文件的命令

    -D 表示反汇编 (要反汇编的文件) 中的所有section
    -m 后面跟的cpu架构,arm就表示arm架构的cpu
    >  表示将这个程序的反汇编文件西写入到led1.dis这个文件中,在终端中不显示出来
       如果不加这个> ,那么你在终端上就可以看到输出的LED1_elf反汇编程序 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值