其他分享
首页 > 其他分享> > ARM裸机 - SD卡刷机启动原理详解

ARM裸机 - SD卡刷机启动原理详解

作者:互联网

1.内存和外存的区别:

内存:RAM(random access memory,随机访问存储器,特点是任意字节读写,掉电丢失)。

外存:ROM(read only memory,只读存储器,类似于Flash SD卡之类的,用来存储东西,掉电不丢失,不能随机地址访问,只能以块为单位来访问)。

2.SD卡的编程接口

SD卡由9个针脚与外界进行物理连接,这9个脚中有2个地,1个电源,6个信号线。

在这里插入图片描述

3.SD协议与SPI协议

SD卡需要按照一定的接口协议(时序)来访问。

-> SPI协议:

SD卡支持SPI协议,是单片机中广泛使用的一种通信协议,并不是为SD卡专门发明的,SPI协议相对SD协议来说速度比较低

-> SD协议:

SD协议是专门用来和SD卡通信的,SD协议要求SoC中有SD控制器,运行在高速率下,要求SoC的主频不能太低

4.SD/MMC控制器

SD卡内部除了存储单元Flash外,还有SD卡管理模块,我们SoC和SD卡通信时,通过9针引脚以SD协议/SPI协议向SD卡管理模块发送命令、时钟、数据等信息,然后从SD卡返回信息给SoC来交互。工作时每一个任务(譬如初始化SD卡、譬如读一个块、譬如写、譬如擦除····)都需要一定的时序来完成。

5.S5PV210的SD卡启动详解

在这里插入图片描述
第一:CPU上电后先从内部IROM中读取预先设置的代码(BL0),首先做了一些基本的初始化(CPU时钟、关看门狗···);然后(BL0)会判断我们选择的启动模式,然后从相应的外部存储器去读取第一部分启动代码(BL1,大小为16KB)到内部SRAM。
第二:运行刚上一步读取来的BL1(16KB),然后执行。BL1负责初始化NandFlash,然后将BL2读取到IRAM(剩余的80KB)然后运行。
第三:从IRAM运行BL2,BL2初始化DRAM,然后将OS读取到DRAM中,然后启动OS,启动过程结束。

210内置了一块96KB大小的SRAM(叫iRAM),同时还有一块内置的64KB大小的NorFlash(叫iROM)

6.SD卡启动流程(bin文件小于16KB时和大于16KB时)

启动的第一种情况:整个镜像大小小于16KB。这时候相当于我的整个镜像作为BL1被steppingstone直接硬件加载执行了而已。

启动的第二种情况:整个镜像大小大于16KB。(只要大于16KB,哪怕是17KB,或者是700MB都是一样的)这时候就要把整个镜像分为2部分:第一部分16KB大小,第二部分是剩下的大小。然后第一部分作为BL1启动,负责去初始化DRAM并且将第二部分加载到DRAM中去执行(uboot就是这样做的)。

7.用函数指针方式调用device copy function

三星在iROM中事先内置了一些代码去初始化外部SD卡/NandFlash,并且内置了读取各种SD卡/NandFlash的代码在iROM中。BL0执行时就是通过调用这些device copy function来读取外部SD卡/NandFlash中的BL1的。

-> 宏定义方式来调用。

// 第一种方法:宏定义
#define CopySDMMCtoMem(z,a,b,c,e) (((bool(*)(int, unsigned int, unsigned short, unsigned int*, bool))(*((unsigned int *)0xD0037F98)))(z,a,b,c,e))

->  函数指针方式来调用。

typedef unsigned int bool;
// 第二种方法:用函数指针方式调用
typedef bool(*pCopySDMMC2Mem)(int, unsigned int, unsigned short, unsigned int*, bool);


// 实际使用时
pCopySDMMC2Mem p1 = (pCopySDMMC2Mem)0xD0037F98;
p1(x, x, x, x, x);		// 第一种调用方法
(*p1)(x, x, x, x, x);	// 第二种调用方法
*p1(x, x, x, x, x);		// 错误,因为p1先和()结合,而不是先和*结合。

8.S5PV210的SD卡启动实战

我们的代码分为2部分第一部分BL1小于等于16KB第二部分为任意大小,iROM代码执行完成后从SD卡启动会自动读取BL1到SRAM中执行BL1执行时负责初始化DDR,然后手动将BL2从SD卡copy到DDR中正确位置,然后BL1远跳转到BL2中执行BL2.

-> 先处理BL1

BL1中要完成:关看门狗、设置栈、开iCache、初始化DDR、从SD卡复制BL2到DDR中特定位置,跳转执行BL2.

start.s:

在这里插入图片描述

sd_relocate.c:

在这里插入图片描述

 -> 再处理BL2

进入BL2文件夹:

在这里插入图片描述

start.S:


.global _start					// 把_start链接属性改为外部,这样其他文件就可以看见_start了
_start:

	ldr pc, =main				// ldr指令实现长跳转
	
	
// 汇编最后的这个死循环不能丢
	b .

 led.c:单纯用来测试SD卡启动的

#define GPJ0CON		0xE0200240
#define GPJ0DAT		0xE0200244

#define rGPJ0CON	*((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT	*((volatile unsigned int *)GPJ0DAT)

void delay(void);

void led1(void)
{
	rGPJ0CON = 0x11111111;
	rGPJ0DAT = ((0<<3) | (1<<4) | (1<<5));
}

void led2(void)
{
	rGPJ0CON = 0x11111111;
	rGPJ0DAT = ((0<<3) | (0<<4) | (1<<5));
}

void led3(void)
{
	rGPJ0CON = 0x11111111;
	rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
}

// 该函数要实现led闪烁效果
void main(void)
{
	// led初始化,也就是把GPJ0CON中设置为输出模式
	//volatile unsigned int *p = (unsigned int *)GPJ0CON;
	//volatile unsigned int *p1 = (unsigned int *)GPJ0DAT;
	rGPJ0CON = 0x11111111;
	
	while (1)
	{
		// led亮
		rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
		// 延时
		delay();
		// led灭
		rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
		// 延时
		delay();
	}
}


void delay(void)
{
	volatile unsigned int i = 900000;		// volatile 让编译器不要优化,这样才能真正的减
	while (i--);							// 才能消耗时间,实现delay
}

标签:卡刷机,int,16KB,BL1,unsigned,BL2,裸机,ARM,SD
来源: https://blog.csdn.net/weixin_49303682/article/details/119331710