一、关于DRAM
上一章我们讲解了如何对代码进行重定位,但是将代码重定位到只有256K IRAM中作用不大。
正确的做法是将代码重定位到容量更大的主存中,即DRAM。Exynos4412中有两个独立的DRAM控制器,分别叫DMC0和DMC1。DMC0和DMC1分别支持最大1.5G的DRAM,它们都支持DDR2/DDR3和LPDDR2等,512 Mb, 1 Gb, 2 Gb, 4 Gb and 8 Gbit的内存设备,支持16/32bit的位宽。DRAM0 对应的地址是0x4000_0000~0xAFFF_FFF共1.5GB,DRAM1 对应的地址是0xA000_000~0x0000_0000共1.5GB。
图7-1、DRAM控制地址图
查阅Tiny4412的原理图:
图7-2、DRAM电路原理样图
Tiny4412的512M的DRAM是由4片大小为128M的DDR3芯片组合而成(上图仅为其中一片),观察片选引脚可知4片DRAM芯片都是挂接到DMC0处。
如何才能使用DRAM?对应Tiny4412而言,由于它只用到了DMC0,所有我们只需要初始化DMC0和DDR3 DRAM芯片即可,本实验所有的初始化代码全部来自于U-BOOT程序。需要说明一点的,我在写这个裸机程序文档之前,已经看了一段时间U-BOOT程序,U-BOOT程序中对DRAM也做了相应的初始化工作,我就直接拿来用了,在参考学习U-BOOT过程中,我也记录了一份学习文档,里面有比较详细的DRAM初始化说明,等我U-BOOT实验成功后,我会整理一份相应文档。
Linux平台下Mini210S裸机程序开发指南》文档从我现有资料中找到他所说的类似的芯片说明。我只能参考着他的说明,从U-BOOT中找到一个函数,从他那里COPY了一些代码,来实现这个函数。大家先来一遍《linux平台下Mini210S裸机程序开发指南》文档关于此函数的说明 ,我在说一下我是怎么写的这个函数的。
经过mem_init函数对DRAM的初始化后,我们就可以拷贝代码到DRAM中然后跳转到DRAM中继续运行了,由BL1目录下的mmc_relocate.c来实现这部分功能,mmc_relocate.c的代码如下:
void copy_code_to_dram(void)
{
unsigned long ch;
void (*BL2)(void);
ch = *(volatile unsigned int *)(0xD0037488);
copy_sd_sd_to_mem copy_bl2 =(copy_sd_sd_to_mem) (*(unsigned int *) (0xD0037F98));
unsigned int ret;
// 通道0
if (ch == 0xEB000000)
{
// 0:channel 0
// 49:源,代码位于扇区49,1 sector = 512 bytes
// 32:长度,拷贝32 sector,既16K
// 0x23E00000:目的,链接地址0x23E00000
ret = copy_bl2(0, 49, 32,(unsigned int*)0x23E00000, 0);
}
// 通道2
else if (ch == 0xEB200000)
{
ret = copy_bl2(2, 49, 32,(unsigned int*)0x23E00000, 0);
}
else
return;
// 跳转到DRAM中
BL2 = (void *)0x23E00000;
(*BL2)();
}
首先我们定义了一个函数指针copy_bl2,将其赋值为0xD0037F98。为什么要这么做,是因为IROM内部固化的代码已经帮我们实现了一类拷贝函数,其中就包括从sd卡拷贝内容到DRAM的函数,这类函数所位于的地址见下图:
由上图可知,External Copy Function位于0xD0037F80~0xD0038000处,其中sd卡拷贝内容到DRAM的函数就位于地址0xD0037F98,其函数原型如下:
其中:
StartBlkAddress:从第几个扇区开始拷贝,一个扇区为512byte
blockSize:拷贝多少个扇区
memoryPtr:拷贝到DRAM的哪个地址上
with_init:是否需要初始化sd卡
有了上面这些知识,也就很容易看懂copy_code_to_dram 函数了。通过读地址0xD0037488上的值来确定是使用通道0还是通道1,芯片手册上明确指出“sd/MMC/eMMC boot – MMC Channel 0 is used for first boot. And Channel 2 is used forSecond boot”,我们的BL1.bin就是first boot,所以会使用通道0,调用CopysdMMCtoMem函数将BL2.bin从sd卡的扇区49拷贝到DRAM的0x23E00000处,拷贝的长度是16K。最后给BL2这个函数指针赋值0x23E0000,然后调用BL2函数即可跳转到0x23E0000处运行BL2.bin里的代码了。
大家看明白了,一句话三星的芯片内部已经有一个函数是用为从外部存储COPY东西内部iRAM或者DRAM中了,但是我在现有三星手册上没有找到类似的函数说明,没办法,我们这些学习者,是很难拿全芯片厂商的资料的。但也不是就没有办法实现这个实验了,U-BOOT中总会干这么个事吧,里面肯定有相关代码,所以我只能去分析U-BOOT的代码了,里面有一个文件叫/arch/arm/cpu/armv7/exynos/irom_copy.c的文件,里面的一个函数movi_uboot_copy(),就是将U-BOOT复制到DRAM中的,好了从这里复制必要代码实现自己的函数吧,我们的函数主要内容如下:
下面内容是定义了我们将要使用的COPY函数,这个函数就是实现了Mini210S中的copy_bl2的功能。
#defineISRAM_ADDRESS 0x02020000
#defineSECURE_CONTEXT_BASE 0x02023000
#defineEXTERNAL_FUNC_ADDRESS (ISRAM_ADDRESS +0x0030)
#defineEXT_eMMC43_BL2_ByCPU_ADDRESS (EXTERNAL_FUNC_ADDRESS+ 0x4)
#defineMSH_ReadFromFIFO_eMMC_ADDRESS (EXTERNAL_FUNC_ADDRESS+ 0x14)
#defineMSH_EndBootOp_eMMC_ADDRESS (EXTERNAL_FUNC_ADDRESS+ 0x18)
#defineLoadImageFromUsb_ADDRESS (EXTERNAL_FUNC_ADDRESS+ 0x40)
#defineSDMMC_ReadBlocks(uStartBlk, uNumOfBlks, uDstAddr)
\定义COPY函数的原型。
(((void(*)(unsigned int, unsigned int,unsigned int*))(*((unsigned int *)EXTERNAL_FUNC_ADDRESS)))(uStartBlk,uNumOfBlks, uDstAddr))
下面开始复制代码到DRAM中,首先声明了两个串口输出函数,实现这两个函数是为了调试用的。因为我说过,我现在程序不一定能执行成功,有时LED灯闪烁了,有时又没有。所以我打出了必要东西来调试用,大家也当学习嘛。
externvoid uart_asm_putc(int c);
externvoid uart_asm_putx(int x);
voidcopy_code_to_dram(void)
{
void (*user_bin)(void);
//这里怕DRAM没有初始化完成,等待了一会
volatile unsigned long count=0x100000;
while(count>0){
count--;}
uart_asm_putc('C');
uart_asm_putc('O');
uart_asm_putc('P');
uart_asm_putc('Y');
uart_asm_putc('r');
uart_asm_putc('n');
//从SD卡扇区49处复制32个扇区的内容到内存地址0x43e00000处
上一篇:tiny4412 裸机程序 六、重定位代码到IRAM+0x8000【转】
下一篇:tiny4412 裸机程序 九、串口排查驱动原因及字符图片显示
推荐阅读最新更新时间:2024-11-20 12:42