一、前言
S3C2440選擇Nand啓動模式之後,會將Nand Flash的塊0前4KB的數據拷貝到片內的4KB SRAM中去,然後PC指針指到SRAM的0地址去順序向下取指令執行,但是4KB的代碼運行空間太小了,所以SRAM的這4KB空間只用來做啓動前的一些必要初始化,更大型的代碼需要從Nand Flash的其他塊中讀出來,然後寫入到外部的SDRAM中去,PC指針再從片內的SRAM跳到外部SDRAM中去運行程序。JZ2440開發板上的SDRAM是16Mx16bit的,有兩片,總共是64MB容量。
二、實驗目標
在SRAM中完成關閉看門狗、初始化SDRAM、將main.c代碼拷貝到SDRAM中;然後跳到SDRAM中去執行main函數的代碼使LED閃爍。
三、硬件連線
SDRAM有數據總線和地址總線,由於有兩片SDRAM,1片SDRAM位寬時16位的,兩片並行組合起來使用,相當於位寬有32位,所以數據總線第一片連LDATA0到15,第二片連LDATA16到31;地址總線需要錯開兩位連接,即LADDR0和LADDR1是用不上的,因爲兩片SDRAM組合之後尋址是4字節對齊的,所以最低兩位地址線沒有意義。
S3C2440有專門的存儲器控制器來操作SDRAM,和STM32單片機的FSMC模塊原理是類似的,就是劃分了許多段虛擬的內存空間,這些內存空間映射到要控制的存儲器內存,我們往這些虛擬的內存地址上面進行數據讀寫,S3C2440的存儲控制器自動完成對外部設備對應的讀寫操作。
S3C2440的存儲器控制器劃分爲8個Bank,每個Bank映射空間爲128MB,8個Bank都可以控制ROM和SRAM類型的存儲器,但是隻有Bank 6和7可以控制SDRAM。該實驗中用Bank 6完成對兩個SDRAM的控制。存儲控制器涉及到的寄存器如下:
四、程序設計
本實驗包含5個源文件,分別如下:
head.S:啓動文件,關閉看門狗,初始化SDRAM,拷貝SRAM中的main函數代碼到SDRAM中運行。
init.c:包含關閉看門狗,初始化SDRAM和SRAM拷貝數據到SDRAM的C函數代碼。
main.c:循環閃爍LED。
sdram.lds:鏈接腳本,劃分代碼在bin文件中的存放位置。
Makefile:編譯代碼。
各個文件內容具體如下:
head.S
@*************************************************************************
@ File:head.S
@ 功能:設置SDRAM,將程序複製到SDRAM,然後跳到SDRAM繼續執行
@*************************************************************************
.text
.global _start
_start:
ldr sp, =4096 @設置堆棧,因爲要調用C語言函數
bl disable_watch_dog @關WATCH DOG
bl memsetup @初始化SDRAM
bl copy_steppingstone_to_sdram @ 複製代碼到SDRAM中
ldr sp, =0x34000000 @設置棧
ldr lr, =halt_loop @設置返回地址
ldr pc, =main @b指令和bl指令只能前後跳轉32M的範圍,所以這裏使用向pc賦值的方法進行跳轉
halt_loop:
b halt_loop
init.c
/* WOTCH DOG register */
#define WTCON (*(volatile unsigned long *)0x53000000)
/* SDRAM regisers */
#define REG_BWSCON (*(volatile unsigned long *)0x48000000)
#define REG_BANKCON6 (*(volatile unsigned long *)0x4800001C)
#define REG_REFRESH (*(volatile unsigned long *)0x48000024)
#define REG_BANKSIZE (*(volatile unsigned long *)0x48000028)
#define REG_MRSRB6 (*(volatile unsigned long *)0x4800002C)
/* SDRAM Start Addr*/
#define SDRAM_START_ADDR 0x30000000
/* main function offset*/
#define MAIN_FUNC_OFFSET 2048
void disable_watch_dog();
void memsetup();
void copy_steppingstone_to_sdram();
/*上電後,WATCH DOG默認是開着的,要把它關掉 */
void disable_watch_dog()
{
WTCON = 0;
}
/* 設置控制SDRAM的寄存器 */
void memsetup()
{
REG_BWSCON = 0x22011110;
REG_BANKCON6 = 0x00018005;
REG_REFRESH = 0x008C07A3;
REG_BANKSIZE = 0x000000B1;
REG_MRSRB6 = 0x00000030;
}
void copy_steppingstone_to_sdram()
{
int i;
unsigned long *p = (unsigned long *)SDRAM_START_ADDR;
unsigned long *pSrc = (unsigned long *)MAIN_FUNC_OFFSET;
for(i = 0; i < (2048 / sizeof(unsigned long)); i++)
{
p[i] = pSrc[i];
}
}
main.c
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
void wait(volatile unsigned long dly)
{
for(; dly > 0; dly--);
}
int main(void)
{
GPFCON = 0x00001500; //將GPF4、GPF5、GPF6設置爲輸出模式
while(1)
{
GPFDAT = 0x00000000; //亮燈
wait(30000);
GPFDAT = 0x00000070; //滅燈
wait(30000);
}
return 0;
}
sdram.lds
SECTIONS {
firtst 0x00000000 : { head.o init.o}
second 0x30000000 : AT(2048) { main.o }
}
該鏈接腳本指定了將main.c編譯的指令代碼放到bin文件的2048地址處,main.c中的代碼鏈接地址是0x30000000,表示main.c中的代碼運行的時候應該是位於0x30000000地址處的,也就是SDRAM的起始地址。拷貝main函數是從SRAM的2048地址處拷貝2048個字節到SDRAM的開頭處。
Makefile
objs := head.o init.o main.o
sdram.bin : $(objs)
arm-linux-ld -Tsdram.lds -o sdram_elf $^
arm-linux-objcopy -O binary -S sdram_elf $@
arm-linux-objdump -D -m arm sdram_elf > sdram.dis
%.o:%.c
arm-linux-gcc -Wall -c -O2 -o $@ $<
%.o:%.S
arm-linux-gcc -Wall -c -O2 -o $@ $<
clean:
rm -f sdram.dis sdram.bin sdram_elf *.o
執行make後得到的反彙編文件sdram.dis如下:
sdram.dis
sdram_elf: file format elf32-littlearm
Disassembly of section firtst:
00000000 <_start>:
0: e3a0da01 mov sp, #4096 ; 0x1000
4: eb000007 bl 28 <disable_watch_dog>
8: eb00000a bl 38 <memsetup>
c: eb00001a bl 7c <copy_steppingstone_to_sdram>
10: e3a0d30d mov sp, #872415232 ; 0x34000000
14: e59fe004 ldr lr, [pc, #4] ; 20 <firtst+0x20>
18: e59ff004 ldr pc, [pc, #4] ; 24 <firtst+0x24>
0000001c <halt_loop>:
1c: eafffffe b 1c <halt_loop>
20: 0000001c andeq r0, r0, ip, lsl r0
24: 30000034 andcc r0, r0, r4, lsr r0
00000028 <disable_watch_dog>:
28: e3a02000 mov r2, #0 ; 0x0
2c: e3a03453 mov r3, #1392508928 ; 0x53000000
30: e5832000 str r2, [r3]
34: e1a0f00e mov pc, lr
00000038 <memsetup>:
38: e3a03422 mov r3, #570425344 ; 0x22000000
3c: e3a00723 mov r0, #9175040 ; 0x8c0000
40: e2833a11 add r3, r3, #69632 ; 0x11000
44: e3a02906 mov r2, #98304 ; 0x18000
48: e3a01312 mov r1, #1207959552 ; 0x48000000
4c: e2833e11 add r3, r3, #272 ; 0x110
50: e2822005 add r2, r2, #5 ; 0x5
54: e2800e7a add r0, r0, #1952 ; 0x7a0
58: e5813000 str r3, [r1]
5c: e2800003 add r0, r0, #3 ; 0x3
60: e3a030b1 mov r3, #177 ; 0xb1
64: e581201c str r2, [r1, #28]
68: e3a02030 mov r2, #48 ; 0x30
6c: e5810024 str r0, [r1, #36]
70: e5813028 str r3, [r1, #40]
74: e581202c str r2, [r1, #44]
78: e1a0f00e mov pc, lr
0000007c <copy_steppingstone_to_sdram>:
7c: e3a01f7f mov r1, #508 ; 0x1fc
80: e2811003 add r1, r1, #3 ; 0x3
84: e3a0c203 mov ip, #805306368 ; 0x30000000
88: e3a00b02 mov r0, #2048 ; 0x800
8c: e3a02000 mov r2, #0 ; 0x0
90: e7903102 ldr r3, [r0, r2, lsl #2]
94: e78c3102 str r3, [ip, r2, lsl #2]
98: e2822001 add r2, r2, #1 ; 0x1
9c: e1520001 cmp r2, r1
a0: 9afffffa bls 90 <copy_steppingstone_to_sdram+0x14>
a4: e1a0f00e mov pc, lr
a8: 43434700 cmpmi r3, #0 ; 0x0
ac: 4728203a undefined
b0: 2029554e eorcs r5, r9, lr, asr #10
b4: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1}
b8: 00000035 andeq r0, r0, r5, lsr r0
Disassembly of section second:
30000000 <wait>:
30000000: e24dd004 sub sp, sp, #4 ; 0x4
30000004: e58d0000 str r0, [sp]
30000008: e59d3000 ldr r3, [sp]
3000000c: e3530000 cmp r3, #0 ; 0x0
30000010: 0a000005 beq 3000002c <wait+0x2c>
30000014: e59d3000 ldr r3, [sp]
30000018: e2433001 sub r3, r3, #1 ; 0x1
3000001c: e58d3000 str r3, [sp]
30000020: e59d2000 ldr r2, [sp]
30000024: e3520000 cmp r2, #0 ; 0x0
30000028: 1afffff9 bne 30000014 <wait+0x14>
3000002c: e28dd004 add sp, sp, #4 ; 0x4
30000030: e1a0f00e mov pc, lr
30000034 <main>:
30000034: e3a02456 mov r2, #1442840576 ; 0x56000000
30000038: e3a03c15 mov r3, #5376 ; 0x1500
3000003c: e92d4070 stmdb sp!, {r4, r5, r6, lr}
30000040: e1a04002 mov r4, r2
30000044: e3a06000 mov r6, #0 ; 0x0
30000048: e3a05070 mov r5, #112 ; 0x70
3000004c: e5823050 str r3, [r2, #80]
30000050: e3a00c75 mov r0, #29952 ; 0x7500
30000054: e2800030 add r0, r0, #48 ; 0x30
30000058: e5846054 str r6, [r4, #84]
3000005c: ebffffe7 bl 30000000 <wait>
30000060: e3a00c75 mov r0, #29952 ; 0x7500
30000064: e2800030 add r0, r0, #48 ; 0x30
30000068: e5845054 str r5, [r4, #84]
3000006c: ebffffe3 bl 30000000 <wait>
30000070: eafffff6 b 30000050 <main+0x1c>
30000074: 43434700 cmpmi r3, #0 ; 0x0
30000078: 4728203a undefined
3000007c: 2029554e eorcs r5, r9, lr, asr #10
30000080: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1}
30000084: 00000035 andeq r0, r0, r5, lsr r0
從反彙編得到的sdram.dis文件中可以看出main函數的鏈接地址是0x30000034,位於SDRAM區域,wait函數鏈接地址是30000000也是位於SDRAM區域。在head.S的開頭一段彙編代碼可以得知,在一系列初始化之後,最終PC被放入了0x30000034這個值,也就是跳到了main函數的開始地址去執行main函數了。
18: e59ff004 ldr pc, [pc, #4] ; 24 <firtst+0x24>
0000001c <halt_loop>:
1c: eafffffe b 1c <halt_loop>
20: 0000001c andeq r0, r0, ip, lsl r0
24: 30000034 andcc r0, r0, r4, lsr r0
經過代碼燒錄到開發板之後,看到三個LED燈在閃爍,實驗成功!