实验三——SDRAM

一。运行环境

  开发板:jz2440

  系统:  ubuntu12.04

  编译器:arm-linux-gcc

二、特殊寄存器

     sdram的操作无需按照时序图来设置,只要设置好相关的13个寄存器,arm处理器里面的存储管理器会自动输出控制信号

   

 1     .long   0x22011110      @ BWSCON
 2     .long   0x00000700      @ BANKCON0
 3     .long   0x00000700      @ BANKCON1
 4     .long   0x00000700      @ BANKCON2
 5     .long   0x00000700      @ BANKCON3  
 6     .long   0x00000700      @ BANKCON4
 7     .long   0x00000700      @ BANKCON5
 8     .long   0x00018005      @ BANKCON6
 9     .long   0x00018005      @ BANKCON7
10     .long   0x008C07A3      @ REFRESH
11     .long   0x000000B1      @ BANKSIZE
12     .long   0x00000030      @ MRSRB6
13     .long   0x00000030      @ MRSRB7

先看BWSCON:

每四位控制一个BKNK

对于SDRAM,ST7设置为0,SRAN则设置为1

WSx通常设置为0 

DBx设置为01b,这个一般按照实际情况来设置,还要参照具体开发板上面存储资源。

对于这六个寄存器,主要设置时序的,默认值就欧克

MT[16:15]设置SRAM   OR  SDRAM   ,这里设置0B11

如果是sdram,那么Trcd 设为推荐值0b10

SCAN 设置为9-bit

对于刷新寄存器,注意低11位会根据CLK不同而不同,也就是说使用PLL与否,会有不同的值

由此可算出

Refreh_count =2^12+1-12*64/8092=1955

REFRESF=0x008c0000+1955

  先看代码:这里主要有三个head.S  ,led.c ,Makefile,其中led的代码同流水灯一样,直接拷贝过来。

  此外外,代码参考韦东山先生的源码,经过烧写可验证没问题。

三。直接贴代码

先看Makefile:

1 sdram.bin:head.S led.c
2     arm-linux-gcc -Wall -O2 -c -g -o head.o head.S
3     arm-linux-gcc -Wall -O2 -c -g -o led.o led.c
4     arm-linux-ld -Ttext 0x30000000 head.o led.o -o sdram_elf
5     arm-linux-objcopy -O binary -S sdram_elf sdram.bin
6     arm-linux-objdump -D -m arm sdram_elf>sdram.dis
7 
8 clean:
9     rm -f sdram.bin sdram_elf*.o sdram.dis

再看head.h

 1 .equ MEM_BASE,0x48000000
 2 .equ SDRAM_BASE,0x30000000
 3 
 4 .text
 5 .global _start
 6 _start:
 7 
 8     bl close_watchdog       @关闭看门狗
 9     bl mem_set              @设置存储寄存器组
10     bl steppingstone_sdram  @复制代码到sdram
11 
12     ldr pc,=on_sdram
13 on_sdram:
14     ldr sp,=0x34000000
15     bl main
16 halt_loop:
17     b halt_loop
18 
19 
20 
21 close_watchdog:
22     mov r1,#0x53000000
23     mov r2,#0x0
24     str r2,[r1]
25 
26     mov pc,lr   @返回
27 
28 steppingstone_sdram:    @起始地址0x00000000,目标地址0x30000000
29     mov r1,#0
30     ldr r2,=SDRAM_BASE
31     mov r3,#1024*4
32 
33 
34 copy_loop:
35     ldr r4,[r1],#4
36     str r4,[r2],#4
37 
38     cmp r1,r3
39     bne copy_loop
40     mov pc,lr        @返回
41 
42 mem_set:
43     mov r1,#MEM_BASE
44 
45     adrl r2,JCQ
46     add r3,r1,#52      @4*13
47 
48 set_loop:
49     ldr r4,[r2],#4
50     str r4,[r1],#4
51     cmp r1,r3
52     bne set_loop
53 
54     mov pc,lr
55 
56 
57 .align 4
58 JCQ:
59     .long 0x22011110 @BWSCON
60     .long 0x00000700 @bankcon0
61     .long 0x00000700 @bankcon1
62     .long 0x00000700 @bankcon2
63     .long 0x00000700 @bankcon3
64     .long 0x00000700 @bankcon4
65     .long 0x00000700 @bankcon5
66     .long 0x00018005 @bankcon6
67     .long 0x00018005 @bankcon7
68     .long 0x008c07a3 @refresh
69     .long 0x000000b1 @banksize
70     .long 0x00000030 @mrsrb6
71     .long 0x00000030 @mrsrb7

其实没什么改动,换些名字而已,但是自己敲的话,当然会有一些细节上面会出错,不注意的地方。

以上启动文件是以汇编编写的,下面贴出c语言版的。

 head.S:

 1 .extern main
 2 .text
 3 .global _start
 4 _start:
 5     b reset
 6 
 7 reset:
 8     ldr sp,=4096         @
 9 
10     bl close_watchdog       @关闭看门狗
11     bl mem_set              @设置存储寄存器组
12     bl steppingstone_sdram  @复制代码到sdram
13 
14 
15     
16     ldr pc,=on_sdram
17 on_sdram:
18     ldr sp,=0x34000000
19     ldr pc,=0x30000000
20 halt_loop:
21     b halt_loop

init.c:

 1 /*************************************************************************
 2     > File Name: init.c
 3     > Author: hulig
 4     > Mail:  
 5     > Created Time: 2014年11月08日 星期六 15时52分55秒
 6     >function:init disable watchdog ,init mem .goto main and on
 7     >result:ok
 8  ************************************************************************/
 9 
10 #define WTCON    (*(volatile unsigned long *)0x53000000)
11 #define MEM_BASE (*(volatile unsigned long *)0x48000000)
12 
13 void close_watchdog()
14 {
15     WTCON =0;     //往看门狗寄存器里写0 就可以啦
16 }
17 
18 void mem_set()   //与sdram设置有关的13个寄存器写入对应的值就ok
19 {
20     unsigned long const mem_jcq[]={
21             0x22011110,
22             0x00000700,
23             0x00000700,
24             0x00000700,
25             0x00000700,
26             0x00000700,
27             0x00000700,
28             0x00018005,
29             0x00018005,
30             0x008c07a3,
31             0x000000b1,
32             0x00000030,
33             0x00000030,
34     };
35 
36     int i=0;
37     volatile unsigned long *p=(volatile unsigned long *)MEM_BASE;
38     for(;i<13;i++)
39         p[i]=mem_jcq[i];
40 }
41 
42 void steppingstone_sdram(void)
43 {
44     unsigned int *pSrc=(unsigned int *)0;        // 将steppingstone  0地址复制到sdram起始地址
45     unsigned int *pDes =(unsigned int *)0x30000000;//sdram起始地址
46 
47     while(pSrc<(unsigned int*)4096)
48     {
49     *pDes=*pSrc;
50     pDes++;
51     pSrc++;
52     }    
53 
54 
55 }

上面c代码并不能达到预期的效果,其主要问题点是sdram的初始化,也就是给13个寄存器赋值的时候:

 1 《一》。
 2 #define BWSCON (*(volatile unsigned long * )0x48000000)
 3 #define BANKCON0 (*(volatile unsigned long * )0x48000004)
 4 #define BANKCON1 (*(volatile unsigned long * )0x48000008)
 5 #define BANKCON2 (*(volatile unsigned long * )0x4800000c)
 6 #define BANKCON3  (*(volatile unsigned long * )0x48000010)
 7 #define BANKCON4 (*(volatile unsigned long * )0x48000014)
 8 #define BANKCON5 (*(volatile unsigned long * )0x48000018)
 9 #define BANKCON6 (*(volatile unsigned long * )0x4800001c)
10 #define BANKCON7 (*(volatile unsigned long * )0x48000020)
11 #define REFRESH (*(volatile unsigned long * )0x48000024)
12 #define BANKSIZE (*(volatile unsigned long * )0x48000028)
13 #define MRSRB6 (*(volatile unsigned long * )0x4800002c)
14 #define MRSRB7 (*(volatile unsigned long * )0x48000030)
15 
16 
17 void mem_set() 
18 {
19     BWSCON=    0x22011110;
20     BANKCON0=0x00000700;
21     BANKCON1=0x00000700;
22     BANKCON2=0x00000700;
23     BANKCON3=0x00000700;
24     BANKCON4=0x00000700;
25     BANKCON5=0x00000700;
26     BANKCON6=0x00018005;
27     BANKCON7=0x00018005;
28     REFRESH=0x008c07a3;
29     BANKSIZE=0x000000b1;
30     MRSRB6 =0x00000030;
31     MRSRB7=    0x00000030;
32 }
33 
34 
35 《二》。
36 void mem_set()   //与sdram设置有关的13个寄存器写入对应的值就ok
37 {
38     int i=0;
39     unsigned long *p=(unsigned long *)MEM_BASE;
40     unsigned long const mem_jcq[]={
41             0x22011110,
42             0x00000700,
43             0x00000700,
44             0x00000700,
45             0x00000700,
46             0x00000700,
47             0x00000700,
48             0x00018005,
49             0x00018005,
50             0x008c07a3,
51             0x000000b1,
52             0x00000030,
53             0x00000030,
54             };
55 
56     for(;i<13;i++)
57         p[i]=mem_jcq[i];
58 }
59 
60 《三》。
61 
62  #define       MEM_CTL_BASE               0x48000000
63 #define       MEM_CTL_END                0x48000034
64 unsigned long  const    mem_cfg_val[]={         // 声明数组存放内存控制器设置数据
65 
66            0x22000000,                //BWSCON
67            0x00000700,                //BANKCON0
68            0x00000700,                //BANKCON1
69            0x00000700,                //BANKCON2
70            0x00000700,                //BANKCON3 
71            0x00000700,                //BANKCON4
72            0x00000700,                //BANKCON5
73            0x00018005,                //BANKCON6
74            0x00018005,                //BANKCON7
75            0x008e07a3,                 //REFRESH(HCLK = 12MHz,该值为0x008e07a3                                                //HCLK = 100MHz 0x008e04f5)
76            0x000000b1,                //BANKSIZE
77            0x00000030,                //MRSRB6
78            0x00000030,                //MRSRB7
79 };

上面是三种写法,唯有第一种可行。why?

比较一,二,三以及查阅资料可知,其根本原因是位置无关码

注意,在复制代码到sdram之前,链接地址是0x30000000,也就是sdram的起始地址,此时若想正确执行,必须是使用跳转指令。

二和三中都是以数组的形式存储,自然不会是位置无关,因而行不通。

那么,怎么编写位置无关码呢?

先总结基本为两点

一。在汇编中,使用B/BL指令

二。在c中,避免使用static来限定范围;连续寄存器组尽量分别赋值。

附,另一个可行的办法:

 1 void memsetup(void)
 2 {
 3     volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
 4 
 5     /* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值
 6      * 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到
 7      * SDRAM之前就可以在steppingstone中运行
 8      */
 9     /* 存储控制器13个寄存器的值 */
10     p[0] = 0x22011110;     //BWSCON
11     p[1] = 0x00000700;     //BANKCON0
12     p[2] = 0x00000700;     //BANKCON1
13     p[3] = 0x00000700;     //BANKCON2
14     p[4] = 0x00000700;     //BANKCON3  
15     p[5] = 0x00000700;     //BANKCON4
16     p[6] = 0x00000700;     //BANKCON5
17     p[7] = 0x00018005;     //BANKCON6
18     p[8] = 0x00018005;     //BANKCON7
19     p[9]  = 0x008C07A3;   //REFRESH
20     p[10] = 0x000000B1;     //BANKSIZE
21     p[11] = 0x00000030;     //MRSRB6
22     p[12] = 0x00000030;     //MRSRB7
23 }
原文地址:https://www.cnblogs.com/hulig7/p/4083511.html