S5PV210学习笔记——(2) 启动阶段的设置

5.2 启动阶段的设置

5.2.1 关开门狗

       启动阶段喂狗比较麻烦,而且启动阶段都是初始化,看门狗这时的作用不大。根据用户手册,可以找到关看门狗的寄存器,只需要对这个寄存器的第五位写0即可

S5PV210学习笔记——(2) 启动阶段的设置_第1张图片

S5PV210学习笔记——(2) 启动阶段的设置_第2张图片

5.2.2 设置栈调用C语言

       首先,C语言中的所有局部变量全都存在栈里,所以在调用C语言程序之前,必须把栈先初始化了。

       其次,在初始化栈的时候,因为每个模式下都有自己独立的SP寄存器(R13)所以必须先进入对应的模式下才行,系统在复位后默认是在SVC模式下,我们就不用再另外设置CPSR了。

       此外,要注意,手册里面为我们写出了栈的地址及大小,为0xD0037780-0xD0037D7F,此外,在ARM中,默认使用的是满减栈(存的时候先减再存),所以我们这里的栈指针要设置在0xD0037D80处,这样才往里存的时候才先减1移到0xD0037D7F处

S5PV210学习笔记——(2) 启动阶段的设置_第3张图片

5.2.3 cache高速缓存

       执行程序时,从 Flash先把程序读到内存里面,然后每执行一条程序,就会从PC指向的内存中把指令读到寄存器,然后再通过寄存器给到CPU去执行,这个时候,对于容量来说,CPU<寄存器<寄存器>>DDR,所以在工作时,CPU执行完程序后,需要等待DDR慢慢把指令传给寄存器,效率非常低

       所以就用一个cache缓存放在寄存器和DDR之间作为中介。容量上来看,CPU<寄存器寄存器>cache>DDR。当执行程序时,cache会把正在执行的指令的周围几条都拿过来缓存着,当CPU要执行下一条指令的时候,先检查cache里面有没有需要执行的指令,如果有就直接从cache传到寄存器,速度大大提高,如果没有的话就会从内存中重新读取,然后cache清缓存、存入新的一批指令。

       这里,我们的内部icache的动作是自动的,不用认为干预,我们只需要程序开启/关闭icache即可,这里就用到了前面汇编指令介绍的CP15协处理器的指令

S5PV210学习笔记——(2) 启动阶段的设置_第4张图片

5.2.4 重定义和链接脚本、位置有关码和位置无关码

       程序从源码到可执行程序主要经历以下几个步骤,其中前三个步骤是必须的,其他步骤根据需求可选

① 预编译:主要是去掉宏定义、注释等这些信息(像是洗菜削皮)

② 编译:编译器把.C、.S文件编译成.o文件。.o文件里面是由很多个函数一段一段构成,所以需要第三步(切菜)

③ 链接:把各个函数段链接起来(把菜按先后顺序下锅)

④ strip:把可执行程序中的符号信息去除,从而节省空间

⑤ objcopy:由可执行程序生成可烧录的bin文件

⑥ objdump:由可执行程序反汇编得到汇编程序

       了解链接前,先了解一个概念,位置无关码(PIC,position independent code)和位置有关码,就是,汇编源文件被编码成二进制可执行程序时,编码方式和位置(内存)地址是否相关。

       设计程序的时候,会给程序指定预期规划的运行地址,此时这个预先指定的地址叫链接地址,将来程序在执行时,必须把程序放在指定的链接地址下面执行,否则不行,这就是位置有关编码。

       链接地址:连接时,连接脚本指定的地址

       运行地址:程序运行时放的地址

       这两个地址必须相同

如果不相同,我们就要通过代码为这段程序重定义位置,让它能正常执行。

       这里在哈工大李治军老师的《计算机操作系统》课程中前面linux的启动过程也有提到过代码的重定义这个概念。

       而链接地址的决定,可以在makefile中连接到指定地址或者在makefile中指定连接脚本,然后根据链接脚本里面指定的链接地址地址来链接。

       使用makefile直接连接时,像下图,链接地址是由makefile中的-Ttext来决定。使用makefile直接规定链接地址时,指令arm-linux-ld -Ttext 0x0 -o led.elf $^中的-Ttext 0x0,就是把程序连接到0x0处

S5PV210学习笔记——(2) 启动阶段的设置_第5张图片

       使用连接脚本来链接时,先了解一下链接脚本。链接脚本就是通过段名和地址,为每一个段分配相应的地址和链接顺序,像这里,. = 0xd002400,就是让里的链接起始地址是0xd002400,然后.text表示这里是代码段(放函数编译后生成的东西),大括号指定了代码段开头必须让start.o,然后后面放其他代码段属性的文件,不限顺序;之后是.data数据段(用来放显示初始化为非0的全局变量);然后是. bss段,又叫ZI段即zero initial段(用来放显示初始化为0或者没有初始化的全局变量,这就可以知道为什么全局变量不初始化时默认大小就是0了)。然后他们中间有个bss_start = . 和bss_end = .,这两个变量分别记录了地址值,方便后面计算这个. bss段的大小,或者做其他的用途。另外,要在makefile中指定出使用的链接脚本,如指令arm-linux-ld -Tlink.lds -o led.elf $^中的-Tlink.lds就表示要使用link.lds这个链接脚本

S5PV210学习笔记——(2) 启动阶段的设置_第6张图片 S5PV210学习笔记——(2) 启动阶段的设置_第7张图片

     这里可能还不明白链接地址和运行地址这两个概念的作用是什么,可以看接下来的代码,实验中,我们把程序通过链接脚本链接到0xd002400处,然后把程序下载到0xd0020010,于是这里的链接地址就是0xd002400,运行地址就是0xd0020010。这两个地址不同,所以只能利用位置无关码在运行位置有关码之前把代码搬到0xd002400处运行。

       这里注意,Ldr是伪指令操作pc寄存器时,它是位置有关码,比如ldr pc,=_start,而Adr是位置无关码,比如adr r0,_start

S5PV210学习笔记——(2) 启动阶段的设置_第8张图片

       程序中,通过adr r0,_start获取当前运行地址(也就是0xd0020010),通过ldr r1,=_start获取链接地址(也就是0xd002400),然后通过ldr r2,=bss_start获取在链接脚本中定义的bss段起始地址,然后通过复制当前运行地址处的程序到链接地址处,这里我们复制到bss段前面即可,主要原因是:bss段存的全是值为0的全局变量,所以我们只需要把bss的空间长度里的内容全部清零就好了,并不需要再复制一遍了,麻烦。这里我们重定位来的程序bss是自己手动清零的,而下载到0xd0020010的程序中的bss段是在C语言编译器和连接器帮我们在程序前面添加的一段头程序,在main()之前自动清bss,就不需要我们关心了。

       接下来看反汇编程序,来分析ldr和adr,根据上面汇编程序的32行、34行、36行,一个adr两个ldr伪指令分别对应下面的15 16 17行。需要注意,这里的PC是当前正在执行指令向后两条的地址,所以应该是前面的值+8,但是!!我们的程序实际下载到的地方是0xd0020010,所以从原理上来说,板子里下载进去的程序是从0xd0020010开始的,每一条指令一条一条按照顺序从0xd0020010往后放,所以PC的地址是运行地址+8,这也就是运行地址的意义。

       接着看,第15行,是r0 = pc-36=pc-0x24,来计算一下,按照链接时的定义,pc此时相对于最开头的d0024000偏移量是0xd002401c+0x08-0xd0024000=0x24,所以pc的真实值应该是0xd0020010+0x24 = 0xd0020034,于是计算一下,r0=0xd0020010,就是我们之前下载进去的地址(运行地址),所以可以知道这里的adr反汇编过来的sub只是计算偏移量,是相对跳转

S5PV210学习笔记——(2) 启动阶段的设置_第9张图片

       接着看第16行,它的反汇编是由ldr r1,=_start得来,这里的pc+72取的是地址,而指令都是按照顺序排列在一起,所以不管运行地址链接地址如何,pc加上一个值指向的地址肯定是在这段代码里面的同一位置,不信可以计算一下来看看:pc的真实值是0xd0024020+0x08-0xd0024000+0xd0020010 = 0x28+0xd0020010 = 0xd0020038,然后再加上72,就是0xd0020080。然后0xd0020080-0xd0020010得到这个内存空间相对于下载进去的起始地址便宜0x70,所以就可以找到最终程序里对应位置0x70+0xd0024000 = 0xd0024070;这个地方他直接存着一个值,就是d0024000,

S5PV210学习笔记——(2) 启动阶段的设置_第10张图片

       分析到这里,我们知道可以看到ldr伪指令得到的数是一个绝对的数值,那么一旦ldr r1,_start里面的操作对象不是r1而是pc,即源程序中的63行,ldr pc,=led_blink,那程序不就直接跳到了实际内存存着不知道是什么东西的0xd0024000的链接地址后面的d0024060了吗,这时程序就会跑飞了,所以ldr伪指令操作PC跳转到某一函数是位置有关码,它对PC的赋值与程序的链接地址有关。

       这里,我们把ldr伪指令命令成为长跳转(操作PC)或者长加载(操作通用寄存器),adr命令成为短跳转(操作PC)或者短加载(操作通用寄存器)

5.2.5 外部拓展SDRAM

       SDRAM:同步动态随机存储器。SDRAM容量大、价格低、掉点易失、随机读写、总线式访问,使用前必须先初始化(这一点和NAND Flash一样)。DDR是DDR SDRAM,是SDRAM的升级版。(DDR:double rate,双倍速度的SDRAM),还有DDR1 DDR2 DDR3 DDR4 LPDDR等。

       我们板子上用的是K4T1G164QE,是DDR2,K表示三星产品,4表示是DRAM,T表示产品号码,1G表示容量(1Gb,等于128MB,我们开发板X210上一共用了4片相同的内存,所以总容量是128×4=512MB)16表示单芯片是16位宽的,4表示是4bank。

       在手册中,可以看到S5PV210这块芯片所指定的存储,

       DRAM0:内存地址范围:0x20000000~0x3FFFFFFF(512MB),对应引脚是Xm1xxxx

       DRAM1: 内存地址范围:0x40000000~0x7FFFFFFF(1024MB),对应引脚是Xm2xxxx

       S5PV210学习笔记——(2) 启动阶段的设置_第11张图片

S5PV210学习笔记——(2) 启动阶段的设置_第12张图片

 S5PV210学习笔记——(2) 启动阶段的设置_第13张图片

       看Port1口,有14根地址线,32根数据线,但是对于我们这块DDR芯片来说,只有16根数据线,我们在使用时,用两块128MB的DDR并联接入,从原理上来看,就和一整块256MB的一样。

S5PV210学习笔记——(2) 启动阶段的设置_第14张图片

       看数据手册《NT5TU64M16GG-DDR2-1G-G-R18-Consumer》第10页的block diagram。

210的DDR端口信号中有BA0~BA2,接在内存芯片的BA0~BA2上,这些引脚就是用来选择bank的。共8个bank,每个bank内部有128Mb,通过row address(14位) + column address(10位)的方式来综合寻址。一共能寻址的范围是:2的14次方+2的10次方 = 2的24次方。对应16MB(128Mbit)内存。

S5PV210学习笔记——(2) 启动阶段的设置_第15张图片

初始化SDRAM时,直接使用SOC内的DDR控制器控制即可。在S5PV210的数据手册里,有详细的初始化步骤。

S5PV210学习笔记——(2) 启动阶段的设置_第16张图片S5PV210学习笔记——(2) 启动阶段的设置_第17张图片

 对应的初始化程序:

S5PV210学习笔记——(2) 启动阶段的设置_第18张图片

S5PV210学习笔记——(2) 启动阶段的设置_第19张图片

S5PV210学习笔记——(2) 启动阶段的设置_第20张图片

S5PV210学习笔记——(2) 启动阶段的设置_第21张图片

S5PV210学习笔记——(2) 启动阶段的设置_第22张图片

你可能感兴趣的:(S5PV210嵌入式学习笔记,嵌入式)