开发板——在X210开发板上进行裸机开发的细节

 以下内容是学习裸机开发过程中的一些细节内容的记录。

1、汇编语言函数细节

用汇编写的函数,末尾应该添加mov pc,lr语句。

2、裸机代码相关文件

3、关于链接地址

4、关于重定位的理解

(1)在sram内部重定位

这是在sram内部重定位,因此不需要初始化DDR。

根据S5PV210地址映射图,链接脚本(略)指定的链接地址0xd0024000是在SRAM中。

/** 描述:	演示重定位(在SRAM内部重定位)*/#define WTCON		0xE2700000
#define SVC_STACK	0xd0037d80.global _start	// 把_start链接属性改为外部,这样其他文件就可以看见_start了_start:// 第1步:关看门狗(向WTCON的bit5写入0即可)ldr r0, =WTCONldr r1, =0x0str r1, [r0]// 第2步:设置SVC栈ldr sp, =SVC_STACK// 第3步:开/关icachemrc p15,0,r0,c1,c0,0;			// 读出cp15的c1到r0中//bic r0, r0, #(1<<12)			// bit12 置0  关icacheorr r0, r0, #(1<<12)			// bit12 置1  开icachemcr p15,0,r0,c1,c0,0;// 第4步:重定位。(这里的代码细节说明adr是与运行相关的,ldr是与链接相关的。)adr r0, _start     // adr指令用于加载_start当前运行地址             // adr加载时就叫短加载	 			ldr r1, =_start    // ldr指令用于加载_start的链接地址:0xd0024000    // ldr加载时如果目标寄存器是pc就叫长跳转,如果目标寄存器是r1等就叫长加载// bss段的起始地址ldr r2, =bss_start	// 就是我们重定位代码的结束地址,重定位只需重定位代码段和数据段即可cmp r0, r1			// 比较_start的运行时地址和链接地址是否相等beq clean_bss		// 如果相等说明不需要重定位,所以跳过copy_loop,直接到clean_bss// 如果不相等说明需要重定位,那么直接执行下面的copy_loop进行重定位// 重定位完成后继续执行clean_bss。// 用汇编来实现的一个while循环
copy_loop:ldr r3, [r0], #4    // 源str r3, [r1], #4	// 目的   这两句代码就完成了4个字节内容的拷贝cmp r1, r2			// r1和r2都是用ldr加载的,都是链接地址,所以r1不断+4总能等于r2bne copy_loop// 清bss段,其实就是在链接地址处把bss段全部清零
clean_bss:ldr r0, =bss_start					ldr r1, =bss_endcmp r0, r1				// 如果r0等于r1,说明bss段为空(即不存在bss段),直接下去beq run_on_dram			// 清除bss完之后的地址mov r2, #0clear_loop:str r2, [r0], #4		// 先将r2中的值放入r0所指向的内存地址(r0中的值作为内存地址),cmp r0, r1				// 然后r0 = r0 + 4bne clear_looprun_on_dram:	// 长跳转到led_blink开始第二阶段ldr pc, =led_blink				// ldr指令实现长跳转//bl led_blink					// bl指令实现短跳转// 汇编最后的这个死循环不能丢b .

(2)重定位至DDR

这里重定位至DDR,因此需要初始化DDR。

根据S5PV210地址映射图,链接脚本(略)指定的链接地址0x2000 0000 在DDR中。

/** 文件名:	led.s	* 作者:	朱老师* 描述:	演示重定位*/#define WTCON		0xE2700000
#define SVC_STACK	0xd0037d80.global _start	
_start://..............// 第4步:初始化ddrbl sdram_asm_init //此函数末尾记得添加mov pc,lr// 第5步:重定位,后面的代码和之前的完全一样。故不写。

(3)总结

对比可知,两者没有什么区别,重定位至DDR只是多了一个内存初始化操作而已。

5、SRAM的地址0xd002_0010映射到0x0000_0000地址

Makefile用 -Ttext 0x0 指定链接地址为0x0。这意味着我们认为这个程序将来会放在0x0地址中运行,但实际上运行时的地址是0xd0020010(我们用dnw下载时指定的下载地址)。

这两个地址看似不同但实际相同,因为S5PV210内部把SRAM的地址0xd002_0010映射到地址0x0000_0000。把链接地址设为0x0000_0000,就等价于链接地址是0xd002_0010。

BL0执行完后会自动跳转到0xd0020010这个地址开始运行,这个地址是CPU设计决定的。

6、S5PV210内置的拷贝函数

关注下0xD0037F98这个地址,它是S5PV210内置的拷贝函数的入口地址。该函数的参数之一是从哪个通道拷贝(SD0还是SD2,对应着inand和SD卡),参数之二是从哪个扇区开始拷贝,参数之三是拷贝至哪里,参数之四是拷贝多少。

BL0内部利用这个函数,将16KB(由参数之四决定)的BL1,从SD卡或者inand(由参数之一决定)的第一个扇区(由参数之二决定),拷贝到 SRAM 的 0xd002_0010 地址(由参数之三决定)。由于BL0是写死在IROM中的,我们唯一能做的就是通过启动介质拨码开关来决定参数之一,参数之二、三、四是固定的。

BL1中如果需要拷贝SD卡中的某些内容,则还是使用S5PV210内置的拷贝函数,只不过因为BL1是我们编写的,我们可以自由设置参数一、二、三、四。

比如将一个大文件分成两个文件BL1和BL2,先将BL1烧写至SD卡第1扇区,BL2烧写至SD卡合适的扇区位置即可(假如烧录至第49扇区)。

上电后IROM中的BL0将利用拷贝函数,把BL1从SD卡第1扇区拷贝到 SRAM的 0xd002_0010地址。BL1在执行时也利用拷贝函数,将BL2从SD卡的第49扇区拷贝到一个合适的地址(这个地址可能位于IRAM或者DDR中,它是由链接脚本规定的,我们从链接脚本得知这个地址,然后作为参数传入拷贝函数),最后BL1代码末尾处执行跳转语句,跳转到这个地址,就可以接着执行BL2。

7、验证6中所讲述的内容

(1)BL1的相关内容

首先,BL1的链接脚本的链接地址是0xd0020010。这就很合理,这个地址就是BL1该呆在的地方,因为CPU设计时规定的一开始运行的地址就是0xd0020010。

SECTIONS
{. = 0xd0020010;.text : {start.osdram_init.o* (.text)}.data : {* (.data)}bss_start = .; .bss : {* (.bss)}bss_end  = .;	
}

其次,BL1的Makefile中,需要把BL1做16字节填充的,这也很合理。

接着,start.S中初始化DDR后,利用拷贝函数把存储在SD卡中的BL2,复制到DDR的某个位置,并跳转到该位置执行BL2。

#define WTCON		0xE2700000
#define SVC_STACK	0xd0037d80.global _start	// 把_start链接属性改为外部,这样其他文件就可以看见_start了
_start:// 第1步:关看门狗(向WTCON的bit5写入0即可)ldr r0, =WTCONldr r1, =0x0str r1, [r0]// 第2步:设置SVC栈ldr sp, =SVC_STACK// 第3步:开/关icachemrc p15,0,r0,c1,c0,0;			// 读出cp15的c1到r0中//bic r0, r0, #(1<<12)			// bit12 置0  关icacheorr r0, r0, #(1<<12)			// bit12 置1  开icachemcr p15,0,r0,c1,c0,0;// 第4步:初始化ddrbl sdram_asm_init// 第5步:重定位,从SD卡第45扇区开始,复制32个扇区内容到DDR的0x23E00000bl copy_bl2_2_ddr// 汇编最后的这个死循环不能丢b .
#define SD_START_BLOCK	45
#define SD_BLOCK_CNT	32
#define DDR_START_ADDR	0x23E00000 //这地址在DDR中,不在IRAM中typedef unsigned int bool;// 通道号:0或者2
// 开始扇区号:这里设为45
// 读取扇区个数:这里设备32
// 读取后放入的地址:这里设为0x23E00000
// with_init:0
typedef bool(*pCopySDMMC2Mem)(int, unsigned int, unsigned short, \unsigned int*, bool);
typedef void (*pBL2Type)(void);//从SD卡第45扇区开始,复制32个扇区内容到DDR的0x23E00000,然后跳转到23E00000去执行
void copy_bl2_2_ddr(void)
{// 第一步,读取SD卡扇区到DDR中//定义一个函数指针并指向拷贝函数pCopySDMMC2Mem p1 = (pCopySDMMC2Mem)0xD0037F98);//给(指向拷贝函数的)函数指针传入参数,开始读取SD卡到DDR中p1(2, SD_START_BLOCK, SD_BLOCK_CNT, (unsigned int *)DDR_START_ADDR, 0);	// 第二步,跳转到DDR中的BL2去执行//定义一个函数指针并指向BL2的下载地址pBL2Type p2 = (pBL2Type)DDR_START_ADDR;//通过函数指针这种方式跳转到DDR中的BL2的下载地址,去执行BL2数p2();
}

(2)BL2的相关内容

首先,链接地址应该由BL1的拷贝函数将BL2拷贝到哪里决定。由BL1代码可知BL2被拷贝到了0x23E00000,那么BL2的链接地址应该是0x23E00000。

另外,BL2有main函数文件、start.S文件等文件,怎么知道先执行start.S文件呢?这是由链接脚本中的.o文件的顺序决定的。

SECTIONS
{. = 0x23E00000;.text : {start.o* (.text)}.data : {* (.data)}bss_start = .; .bss : {* (.bss)}bss_end  = .;	
}

其次,BL2的makefile中不会再添加16字节填充的操作,经查验果真如此。

start.S文件内容如下,可知接下来会到main函数的文件中执行main函数。

#define WTCON		0xE2700000
#define SVC_STACK	0xd0037d80.global _start	_start:ldr pc, =main				// ldr指令实现长跳转// 汇编最后的这个死循环不能丢b .

(3)总结

BL1所使用的拷贝函数还是BL0所使用的拷贝函数,即S5PV210内置的拷贝函数。

BL2的入口地址,是BL2的链接脚本指定链接地址。该地址由BL1将BL2拷贝到哪里决定。

BL2链接脚本中.o的顺序,决定了BL2众多的程序文件中,先执行哪些文件。

8、将数据烧写至SD卡的方式

方式1:在linux中利用write2sd文件

write2sd文件内容如下,可知BL1和BL2分别烧录至第1扇区、第45扇区开始的地方。

#!/bin/sh
sudo dd iflag=dsync oflag=dsync if=./BL1/BL1.bin of=/dev/sdb seek=1
sudo dd iflag=dsync oflag=dsync if=./BL2/BL2.bin of=/dev/sdb seek=45

方式2:利用九鼎提供的烧写软件

它只能将一个文件(uboot.bin或者裸机镜像文件)烧写至SD卡的第1扇区开始的地方。

注意,它只能烧写一个文件,而且必须烧写至SD卡第1扇区。

方式3:利用三星提供的sd_fusing文件夹

具体见利用三星提供的sd_fusing.sh将uboot烧写到SD卡。

注意,这个文件夹是将uboot.bin烧写至sd的方法,特指烧写uboot镜像,而非其他的?错误的认识,可以烧写其他镜像,但得16字节的校验头。

补充说明

其实方式3最后也利用方式1作为方式3的最后一个步骤。方式3前面还包括将sd卡分区、截取uboot.bin前8k作为BL1(而整个uboot.bin作为BL2)等步骤。将sd卡分区的意义何在呢?sd卡不是本身就已经分区了吗?(待解决)

9、裸机代码中的前几个固定步骤

裸机代码的前几个步骤比较固定,都是一些初始化操作,而且有些操作在BL0中已经完成,这里重新再设置一遍也不会出错。另外,ddr的初始化和重定位这两个步骤看情况是否需要。

(0)开发板制锁

如果不进行这个步骤,得一直按着POWER键。

	// 第0步:开发板置锁ldr r0, =0xE010E81Cldr r1, [r0]ldr r2, =0x301orr r1, r1, r2str r1, [r0]

(1)关看门狗

开启看门狗是为了防止机器故障时自动复位。如果开启看门狗后,没有及时去喂狗,则系统会自动复位。没有操作系统前,喂狗这个操作需要编写代码完成,因此为了减少编码工作,这里选择直接把看门狗关闭。(其实BL0已经关了看门狗,这里重新设置一遍。)

    // WTCON(0xE2700000),其中bit5是看门狗的开关:0代表关,1代表开// 第1步:关看门狗(向WTCON的bit5写入0即可)ldr r0, =WTCONldr r1, =0x0str r1, [r0]

(2)初始化时钟

这一部分的内容,见博客:S5PV210的时钟系统_天糊土的博客-CSDN博客

	// 第2步:初始化时钟bl clock_init

(3)设置SVC栈

C语言的运行需要一定的条件,这些条件由汇编来提供。C语言运行时主要是需要栈。比如C语言中的局部变量都是用栈来实现的。如果汇编部分没有给C部分设置合理的栈地址,那么C代码中定义的局部变量就会落空,整个程序就死掉了。

我们现在要设置栈,不可能也没有必要去设置所有的栈,我们先要设置自己的模式,然后设置自己的模式下的栈到合理合法的位置即可。

我们如何访问SVC模式下的SP呢?很简单,先把模式设置为SVC,再直接操作SP。但是因为我们复位后就已经是SVC模式了,所以直接设置SP即可。

由于栈必须是当前一段可用的内存(这段内存必须已经初始化,而且这段内存只会被我们用作栈,不会被其他程序征用),当前CPU刚启动时,外部的SDRAM尚未初始化,目前可用的内存只有内部的SRAM(因为它不需初始化即可使用)。因此只能在SRAM中找一段内存来作为SVC的栈。结合iROM_application_note中的memory map,可知SVC栈应该设置为0xd0037D80。

	// 第3步:设置SVC栈ldr sp, =SVC_STACK //#define SVC_STACK	0xd0037d80

(4)开关icache

iROM中的BL0已经打开了icache,我们这里重新设置一遍也没有错。

	// 第4步:开/关icachemrc p15,0,r0,c1,c0,0;			// 读出cp15的c1到r0中//bic r0, r0, #(1<<12)			// bit12 置0  关icacheorr r0, r0, #(1<<12)			// bit12 置1  开icachemcr p15,0,r0,c1,c0,0;

寄存器和SDRAM之间的读取速度差异太大,SDRAM的读取速度远不能满足寄存器的需要,没有cache的话,会拉低系统的整体速度。210内部有32KB icache和32kb dcache,icache是用来缓存指令的;dcache是用来缓存数据的。

(5)DDR的初始化(可能需要)

见S5PV210——SDRAM的初始化_天糊土的博客-CSDN博客

(6)代码的重定位(可能需要)

见重定位的简介与操作(涉及位置无关码)_天糊土的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461034.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux上perl怎么传输参数,如何在perl子函数中传递参数?

慕村225694Perl 可以通过函数元型在编译期进行有限的参数类型检验。如果你声明sub mypush ()那么 mypush() 对参数的处理就同内置的 push() 完全一样了。函数声明必须要在编译相应函数调用之前告知编译器(编译器在编译函数调用时会对相应函数用 prototype来查询它的元型来进行参…

Struts2中ValueStack结构和总结

【ValueStack和ActionContext的关系】首先&#xff0c;从结构上来看ValueStack是ActionContext的一个组成部分&#xff0c;是对ActionContext功能的扩展。ActionContext是一个容器结构&#xff0c;是Struts2中用于数据存储的的场所&#xff0c;而ValueStack则是一个具备表达式引…

浅谈mysql数据库引擎

2019独角兽企业重金招聘Python工程师标准>>> 数据库是数据的集合&#xff0c;计算机中的数据库是存储器上一些文件的集合或者是内存数据的集合。Mysql,SQL server数据库都是可以存储数据&#xff0c;并提供数据查询&#xff0c;更新功能的数据库管理系统。Mysql数据…

linux ssh抓包,如何在SSH连接Linux系统的环境下使用wireshark抓包?

TSINGSEE青犀视频云边端架构EasyNVR、EasyDSS、EasyGBS等都是有两种操作系统的版本&#xff0c;一种是linux&#xff0c;一种是windows。而大多数开发者用户都会使用linux版本进行安装。对于安装部署出现的问题&#xff0c;TSINGSEE青犀视频团队研发的经常为客户远程调试&#…

ASP.NET后台调用前台JS函数的三种常见方法

为什么80%的码农都做不了架构师&#xff1f;>>> 第一种&#xff1a;使用普通的添加控件中的Attributes属性进行调用 例如&#xff0c;像一般的普通的按钮&#xff1a;Button1.Attributes.Add("onclick","MyFun();"); 此方法只能在Onload中或者…

嵌入式数据库sqlite在ARM上的的移植和使用

参考SQLite的编译、安装和使用_whz_zb的博客-CSDN博客&#xff0c;如有侵权&#xff0c;请告知删除。 参考&#xff1a;头文件路径问题 Linux下的头文件搜索路径 - 心哲 - 博客园 参考&#xff1a;进一步学习资源 SQlite - 标签 - likebeta - 博客园 一、源码获取 SQLite Do…

贪心法

贪心法的证明 —归纳证明&#xff1a; —贪心法使用的条件是&#xff1a;最优子结构和贪心选择正确性 —贪心算法是一步一步实现的&#xff0c; —在归纳证明的时候&#xff0c;贪心的第一步贪心选择策略的正确性就是归纳基础&#xff0c;因为以后都是一个子问题的选取&#xf…

第一季5:Hi3518EV200的环境搭建

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、内容总结 本文讲述如何安装交叉编译工具链&#xff0c;与编译源码得到uboot、kernel、rootfs镜像文件。 &#xff08;1&#xff09;安装交叉编译工具链&#xff0c;主要是通过执行osdrv/opensou…

Android动画的实现 上

在Android系统中也能经常见到动画&#xff0c;那么如何实现动画效果呢&#xff1f;本文就来为大家介绍动画的实现方式。 Android中动画的实现分两种方式&#xff0c;一种方式是补间动画Tween Animation&#xff0c;就是说你定义一个开始和结束&#xff0c;中间的部分由程序运算…

第一季2:HI3518EV200的初体验(检测板子是否正常工作)

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、检测步骤 1、设置PC主机有线网卡的ip地址设为192.168.1.10&#xff0c;关闭防火墙。 2、虚拟机桥接到有线网卡&#xff0c;并设置虚拟机的静态ip地址为192.168.1.141。 3、在uboot控制台设置ub…

第一季3:HI3518E方案整体架构介绍(硬件和软件支持)

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 1、硬件资源 &#xff08;1&#xff09;HI3518E单芯片提供&#xff1a;CPU DSP 内置64MB DDR ETHERNET MAC。 &#xff08;2&#xff09;外置16MB的SPI接口的Flash用来存放程序&#xff08;ubo…

(一)FlexViewer之整体框架解析

文章版权由作者李晓晖和博客园共有&#xff0c;若转载请于明显处标明出处&#xff1a;http://www.cnblogs.com/naaoveGIS/。 1.FlexViewer简介 FlexViewer框架为Esri提供的可以高效开发基于WEB的地理信息应用系统的一种完全免费的应用程序框架。目前有两种版本&#xff0c;一种…

三阶魔方复原操作方法

在女票的指导下&#xff0c;我花了一个晚上学习如何复原三阶魔方&#xff0c;虽然是知其然不知其所以然&#xff0c;但好歹也能把魔方复原了。下面都是一些傻瓜式的操作&#xff0c;里面涉及的理论我不清楚。魔方总共分三层&#xff0c;下面是每层复原方法。 第一层 1、先以“…

Phaser开源2d引擎 javascript/html5游戏框架

功能特点&#xff08;Features&#xff09; 易维护代码&#xff08;Easy Asset Loading&#xff09; Phaser可以加载图片&#xff0c;音频文件&#xff0c;数据文件&#xff0c;文本文件和自动解析精灵图和纹理地图集数据&#xff08;出口纹理封隔器或Flash CS6&#xf…

8大排序算法图文讲解转

本文链接&#xff1a;http://www.cricode.com/3212.html 作者&#xff1a;快课网——Jay13 转载请务必保留作者出处&#xff0c;谢谢&#xff01; 排序算法可以分为内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大…

Immutable Collections(3)Immutable List实现原理(中)变化中的不变

Immutable Collections(3)Immutable List实现原理(中)变化中的不变 文/玄魂 前言 在上一篇文章&#xff08;Immutable Collections&#xff08;2&#xff09;ImmutableList<T>实现原理.&#xff08;上&#xff09;&#xff09;,分析了&#xff09;ImmutableList<T>…

大话Fragment管理

大话Fragment管理 上一个项目遇到了一个Activity 管理30个Fragment的情况&#xff0c;刚开始的时候真的管理的焦头烂额&#xff0c;但是后来不停的研究api文档&#xff0c;渐渐的明白了android的Fragment管理 体系。下面用…

第一季4:Hi3518E_SDK_Vx.x.x.x的SDK目录结构

一、Hi3518E_SDK_V1.0.3.0.tgz的位置 “Hi3518E_SDK_V1.0.3.0.tgz”位于“Hi3518E V200R001C01SPC030”中&#xff0c;其目录包含关系如下。 Hi3518E_SDK_V1.0.3.0.tgz 解压后内部文件组织如下。 二、执行SDK展开脚本sdk.unpack后的目录关系 将Hi3518E_SDK_V1.0.3.0.tgz拷贝到…

第一季6:海思方案中uboot、kernel和rootfs的烧写方法

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、概述 因为所用的板子默认从SPI Flash启动&#xff0c;因此本文主要讲如何“使用tftp&#xff0c;烧写映像文件&#xff08;uboot、kernel、rootfs&#xff09;到SPI Flash”。另外海思还提供了“…