ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-08-02 20:32:50  阅读:230  来源: 互联网

标签:卡刷机 int 16KB BL1 unsigned BL2 裸机 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有