在线问答
直播中

h1654155865.6393

10年用户 301经验值
擅长:可编程逻辑 测量仪表 嵌入式技术 模拟技术 处理器/DSP 控制/MCU
私信 关注

【OK210试用体验】裸机篇 -- DDR重定位

【OK210试用体验】裸机篇 -- DDR重定位


      在S5PV210的启动流程中我们知道,S5PV210上电之后先从iROM中启动,iROM中的代码初始化完硬件之后会将外设储存器中的BL1段代码拷贝到iRAM中运行,再将BL2拷贝到iRAM中运行,最后跳转到OS的起始地址上运行。整个过程中代码不断在储存器中跳转,其中涉及到很重要的概念就是重定位。

      对于S5PV210而言,启动时只会从NAND Flash/SD等启动设备中拷贝前16K的代码到iRAM中,那么当我们的程序超过16K怎么办?那就需要我们在前16K的代码中将整个程序完完整整地拷贝到DRAM等其他更大存储空间,然后再跳转到DRAM中继续运行我们的代码,这个拷贝然后跳转的过程就叫重定位。

      本帖将学习将代码重定位到大容量的内存中运行,即DRAM。



S5PV210中的DRAM控制器


S5PV210中的DRAM部分的官方详细资料可以看S5PV210_UM_REV1.1中的 sections 05_memory 1. DRAM CONTROLLER。

      在S5PV210中有两个独立的DRAM控制器和端口(引脚):DMC0、DMC1。。DMC0支持最大512M的DRAM,DMC1支持最大1G的DRAM。它们都支持DDR/DDR2,支持128Mb、256Mb、512Mb、1Gb、2Gb、4Gb的内存设备,支持16/32bit的位宽。

      我们通过内存地址映射图来更好地认识这块: 2.png DRAM0对应的地址是0x2000_0000~0x3FFF_FFF共512M,DRAM1对应的地址是0x4000_000~0x7FFF_FFFF共1G。

      在OK210开发板中,搭载了4片K4T1G164QE,每片128 MByte,共512 MByte。 1.png

      S5PV210官方手册中还提供了芯片的接线配置方案: 6.png

      S5PV210中DRAM控制器块的框架图: 3.png



K4T1G164QE芯片


K4T1G164QE芯片资料:
K4T1G164q.pdf (1.06 MB)
(下载次数: 0, 2015-8-14 14:23 上传)
7.png ,芯片引脚作用: 8.png 9.png

      芯片手册提供了多种接线配置方案: 10.png (其中一部分)。



程序编写


      首先先创建两个文件夹来区别是BL1和BL2,在BL1中先编写start.S,可以起到引导作用,在这里我们要关闭看门狗、设置栈、初始化时钟、初始化串口、初始化DDR、跳转到main函数、重新设置栈、跳转到DDR的起始地址执行。

      整个过程中的前部分我们在前面已经学习过怎么编写,这里只需要将代码拷贝到相应的位置下即可。

      在初始化DDR中,官方手册给我们提供的方案,我们依照这个思路来配置寄存器。 4.png 5.png 。这个配置方案位于sections 05中的1.2.1.3.


      示例代码 ddr.c:
  1. #define MP1_0DRV (*(volatile unsigned long*)0xE02003CC)
  2. #define MP1_1DRV (*(volatile unsigned long*)0xE02003EC)
  3. #define MP1_2DRV (*(volatile unsigned long*)0xE020040C)
  4. #define MP1_3DRV (*(volatile unsigned long*)0xE020042C)
  5. #define MP1_4DRV (*(volatile unsigned long*)0xE020044C)
  6. #define MP1_5DRV (*(volatile unsigned long*)0xE020046C)
  7. #define MP1_6DRV (*(volatile unsigned long*)0xE020048C)
  8. #define MP1_7DRV (*(volatile unsigned long*)0xE02004AC)
  9. #define MP1_8DRV (*(volatile unsigned long*)0xE02004CC)

  10. #define DMC0_BASE                        0xF0000000
  11. #define DMC1_BASE                        0xF1400000

  12. #define DMC0_CONCONTROL                *((volatile unsigned int *)(DMC0_BASE + 0x00))
  13. #define DMC0_MEMCONTROL                *((volatile unsigned int *)(DMC0_BASE + 0x04))
  14. #define DMC0_MEMCONFIG0                *((volatile unsigned int *)(DMC0_BASE + 0x08))
  15. #define DMC0_MEMCONFIG1                *((volatile unsigned int *)(DMC0_BASE + 0x0C))
  16. #define DMC0_DIRECTCMD                *((volatile unsigned int *)(DMC0_BASE + 0x10))
  17. #define DMC0_PRECHCONFIG        *((volatile unsigned int *)(DMC0_BASE + 0x14))
  18. #define DMC0_PHYCONTROL0         *((volatile unsigned int *)(DMC0_BASE + 0x18))
  19. #define DMC0_PHYCONTROL1         *((volatile unsigned int *)(DMC0_BASE + 0x1C))
  20. #define DMC0_PWRDNCONFIG         *((volatile unsigned int *)(DMC0_BASE + 0x28))
  21. #define DMC0_TIMINGAREF         *((volatile unsigned int *)(DMC0_BASE + 0x30))
  22. #define DMC0_TIMINGROW                 *((volatile unsigned int *)(DMC0_BASE + 0x34))
  23. #define DMC0_TIMINGDATA         *((volatile unsigned int *)(DMC0_BASE + 0x38))
  24. #define DMC0_TIMINGPOWER         *((volatile unsigned int *)(DMC0_BASE + 0x3C))
  25. #define DMC0_PHYSTATUS                 *((volatile unsigned int *)(DMC0_BASE + 0x40))
  26. #define DMC0_CHIP0STATUS         *((volatile unsigned int *)(DMC0_BASE + 0x48))
  27. #define DMC0_CHIP1STATUS         *((volatile unsigned int *)(DMC0_BASE + 0x4C))
  28. #define DMC0_AREFSTATUS         *((volatile unsigned int *)(DMC0_BASE + 0x50))
  29. #define DMC0_MRSTATUS                 *((volatile unsigned int *)(DMC0_BASE + 0x54))

  30. #define DMC1_CONCONTROL                *((volatile unsigned int *)(DMC1_BASE + 0x00))
  31. #define DMC1_MEMCONTROL                *((volatile unsigned int *)(DMC1_BASE + 0x04))
  32. #define DMC1_MEMCONFIG0                *((volatile unsigned int *)(DMC1_BASE + 0x08))
  33. #define DMC1_MEMCONFIG1                *((volatile unsigned int *)(DMC1_BASE + 0x0C))
  34. #define DMC1_DIRECTCMD                *((volatile unsigned int *)(DMC1_BASE + 0x10))
  35. #define DMC1_PRECHCONFIG        *((volatile unsigned int *)(DMC1_BASE + 0x14))
  36. #define DMC1_PHYCONTROL0         *((volatile unsigned int *)(DMC1_BASE + 0x18))
  37. #define DMC1_PHYCONTROL1         *((volatile unsigned int *)(DMC1_BASE + 0x1C))
  38. #define DMC1_PWRDNCONFIG         *((volatile unsigned int *)(DMC1_BASE + 0x28))
  39. #define DMC1_TIMINGAREF         *((volatile unsigned int *)(DMC1_BASE + 0x30))
  40. #define DMC1_TIMINGROW                 *((volatile unsigned int *)(DMC1_BASE + 0x34))
  41. #define DMC1_TIMINGDATA         *((volatile unsigned int *)(DMC1_BASE + 0x38))
  42. #define DMC1_TIMINGPOWER         *((volatile unsigned int *)(DMC1_BASE + 0x3C))
  43. #define DMC1_PHYSTATUS                 *((volatile unsigned int *)(DMC1_BASE + 0x40))
  44. #define DMC1_CHIP0STATUS         *((volatile unsigned int *)(DMC1_BASE + 0x48))
  45. #define DMC1_CHIP1STATUS         *((volatile unsigned int *)(DMC1_BASE + 0x4C))
  46. #define DMC1_AREFSTATUS         *((volatile unsigned int *)(DMC1_BASE + 0x50))
  47. #define DMC1_MRSTATUS                 *((volatile unsigned int *)(DMC1_BASE + 0x54))

  48. void ddr_init()
  49. {
  50.         /* DMC0 */
  51.         DMC0_PHYCONTROL0 = 0x00101000;
  52.         DMC0_PHYCONTROL0 = 0x00101002;                        /* DLL on */
  53.         DMC0_PHYCONTROL1 = 0x00000086;
  54.         DMC0_PHYCONTROL0 = 0x00101003;                        /* DLL start */

  55.         while ((DMC0_PHYSTATUS & 0x7) != 0x7);        /* wait DLL locked */

  56.         DMC0_CONCONTROL = 0x0FFF2350;                        /* Auto Refresh Counter should be off */
  57.         DMC0_MEMCONTROL = 0x00202430;                        /* Dynamic power down should be off */
  58.         DMC0_MEMCONFIG0 = 0x20E01323;

  59.         DMC0_PRECHCONFIG = 0xFF000000;
  60.         DMC0_PWRDNCONFIG = 0xFFFF00FF;

  61.         DMC0_TIMINGAREF = 0x00000618;                        /* 7.8us * 200MHz = 1560 = 0x618  */
  62.         DMC0_TIMINGROW = 0x19233309;
  63.         DMC0_TIMINGDATA = 0x23240204;
  64.         DMC0_TIMINGPOWER = 0x09C80232;

  65.         DMC0_DIRECTCMD = 0x07000000;                        /* NOP */
  66.         DMC0_DIRECTCMD = 0x01000000;                        /* PALL */
  67.         DMC0_DIRECTCMD = 0x00020000;                        /* EMRS2 */
  68.         DMC0_DIRECTCMD = 0x00030000;                        /* EMRS3 */
  69.         DMC0_DIRECTCMD = 0x00010400;                        /* EMRS enable DLL */
  70.         DMC0_DIRECTCMD = 0x00000542;                        /* DLL reset */
  71.         DMC0_DIRECTCMD = 0x01000000;                         /* PALL */
  72.         DMC0_DIRECTCMD = 0x05000000;                        /* auto refresh */
  73.         DMC0_DIRECTCMD = 0x05000000;                        /* auto refresh */
  74.         DMC0_DIRECTCMD = 0x00000442;                        /* DLL unreset */
  75.         DMC0_DIRECTCMD = 0x00010780;                        /* OCD default */
  76.         DMC0_DIRECTCMD = 0x00010400;                        /* OCD exit */

  77.         DMC0_CONCONTROL = 0x0FF02030;                        /* auto refresh on */
  78.         DMC0_PWRDNCONFIG = 0xFFFF00FF;
  79.         DMC0_MEMCONTROL = 0x00202400;

  80.         /* DMC1 */
  81.         DMC1_PHYCONTROL0 = 0x00101000;
  82.         DMC1_PHYCONTROL0 = 0x00101002;
  83.         DMC1_PHYCONTROL1 = 0x86;
  84.         DMC1_PHYCONTROL0 = 0x00101003;

  85.         while((DMC0_PHYSTATUS&0x7) != 0x7);

  86.         DMC1_CONCONTROL = 0x0FFF2350;                        /* Auto Refresh Counter should be off */
  87.         DMC1_MEMCONTROL = 0x00202430;                        /* Dynamic power down should be off */
  88.         DMC1_MEMCONFIG0 = 0x40E01323;

  89.         DMC1_PRECHCONFIG = 0xFF000000;
  90.         DMC1_PWRDNCONFIG = 0xFFFF00FF;

  91.         DMC1_TIMINGAREF = 0x00000618;                        /* 7.8us * 200MHz = 1560 = 0x618  */
  92.         DMC1_TIMINGROW = 0x19233309;
  93.         DMC1_TIMINGDATA = 0x23240204;
  94.         DMC1_TIMINGPOWER = 0x09C80232;

  95.         DMC1_DIRECTCMD = 0x07000000;
  96.         DMC1_DIRECTCMD = 0x01000000;
  97.         DMC1_DIRECTCMD = 0x00020000;
  98.         DMC1_DIRECTCMD = 0x00030000;
  99.         DMC1_DIRECTCMD = 0x00010400;
  100.         DMC1_DIRECTCMD = 0x00000542;
  101.         DMC1_DIRECTCMD = 0x01000000;
  102.         DMC1_DIRECTCMD = 0x05000000;
  103.         DMC1_DIRECTCMD = 0x05000000;
  104.         DMC1_DIRECTCMD = 0x00000442;
  105.         DMC1_DIRECTCMD = 0x00010780;
  106.         DMC1_DIRECTCMD = 0x00010400;

  107.         DMC1_CONCONTROL = 0x0FF02030;
  108.         DMC1_PWRDNCONFIG = 0xFFFF00FF;
  109.         DMC1_MEMCONTROL = 0x00202400;
  110. }


      将代码从一个储存器拷贝到另一个储存器,我们用C语言的方式来实现,在 S5PV210_iROM_ApplicationNote_Preliminary_20091126中有提供相应的方案: 11.png 。因为我们是在SD卡中启动,所以需要看一下手册中的SD/MMC部分,在sections 08中的7. SD/MMC CONTROLLER中有详细的讲解,这里需要SD卡的控制器的寄存器的映射地址,看这部分的7.9.1。



     在BL2中我们只需跳转到main函数中执行,点亮LED和将在这个阶段运行的信息打印到PC上。

实验现象


将 bl1.bin 烧写到SD卡的第一扇区,bl2.bin 烧写到SD卡的第20扇区(这个可以自定义,修改相关代码),将SD卡从PC接口取出插入开发板上,调节到SD卡启动,上电后可以看到PC端打印出: 12.png 。在开发板上,四个LED灯交替闪烁: 13.jpg 14.jpg



回帖(2)

3guoyangyang7

2015-9-5 14:41:25
楼主能给我发一份完整的代码吗,万分感谢 qq 838239071
举报

h1654155865.6393

2015-9-5 22:03:54
引用: 3guoyangyang7 发表于 2015-9-5 14:41
楼主能给我发一份完整的代码吗,万分感谢 qq 838239071

今天比较晚上elecfans,没有及时回复,抱歉,希望代码对你有用。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分