【JZ2440筆記】裸機實驗使用SDRAM

 

一、前言

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燈在閃爍,實驗成功!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章