硬件平台 :JZ2440
实现功能:初始化 Nand Flash 和 sdram,并将代码从 Nand Flash 拷贝到 sdram。
start.s --> 上电初始化 nand 与sdram
nand.c --> Nand Flash 初始化函数
sdram.c --> sdram 初始化函数
leds.c --> led 闪烁
start.s 源码:
.text .global _start _start: ldr sp,=4096 bl disable_watch_dog bl sdram_init bl nand_init ldr r0,=0x30000000 mov r1,#4096 mov r2,#2048 bl nand_read ldr sp,=0x34000000 ldr lr,=loop1 ldr pc,=0x30000000 loop1: b loop1
nand.c 源码:
#define BUSY 1 #define NAND_SECTOR_SIZE_LP 2048 #define NAND_BLOCK_MASK_LP (NAND_SECTOR_SIZE_LP - 1) typedef struct { int NFCONF; int NFCONT; int NFCMD; int NFADDR; int NFDATA; int NFMECCD0; int NFMECCD1; int NFSECCD; int NFSTAT; int NFESTAT0; int NFESTAT1; int NFMECC0; int NFMECC1; int NFSECC; int NFSBLK; int NFEBLK; } S3C2440_NAND; static S3C2440_NAND *s3c2440nand = (S3C2440_NAND *)0x4e000000; /* 供外部调用的函数 */ void nand_init(void); void nand_read(unsigned char *buf, unsigned long start_addr, int size); /* S3C2440的NAND Flash处理函数 */ static void nand_reset(void); static void wait_idle(void); static void nand_select_chip(void); static void nand_deselect_chip(void); static void write_cmd(int cmd); static void write_addr(unsigned int addr); static unsigned char read_data(void); /* 复位 */ static void nand_reset(void) { nand_select_chip(); write_cmd(0xff); // 复位命令 wait_idle(); nand_deselect_chip(); } /* 等待NAND Flash就绪 */ static void wait_idle(void) { int i; volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT; while(!(*p & BUSY)) for(i=0; i<10; i++); } /* 发出片选信号 */ static void nand_select_chip(void) { int i; s3c2440nand->NFCONT &= ~(1<<1); for(i=0; i<10; i++); } /* 取消片选信号 */ static void nand_deselect_chip(void) { s3c2440nand->NFCONT |= (1<<1); } /* 发出命令 */ static void write_cmd(int cmd) { volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD; *p = cmd; } /* 发出地址 */ static void write_addr(unsigned int addr) { int i; volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR; int col, page; col = addr & NAND_BLOCK_MASK_LP; page = addr / NAND_SECTOR_SIZE_LP; *p = col & 0xff; /* Column Address A0~A7 */ for(i=0; i<10; i++); *p = (col >> 8) & 0x0f; /* Column Address A8~A11 */ for(i=0; i<10; i++); *p = page & 0xff; /* Row Address A12~A19 */ for(i=0; i<10; i++); *p = (page >> 8) & 0xff; /* Row Address A20~A27 */ for(i=0; i<10; i++); *p = (page >> 16) & 0x03; /* Row Address A28~A29 */ for(i=0; i<10; i++); } /* 读取数据 */ static unsigned char read_data(void) { volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA; return *p; } /* 初始化NAND Flash */ void nand_init(void) { #define TACLS 0 #define TWRPH0 3 #define TWRPH1 0 /* 设置时序 */ s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */ s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0); /* 复位NAND Flash */ nand_reset(); } /* 读函数 */ void nand_read(unsigned char *buf, unsigned long start_addr, int size) { int i, j; if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) { return ; /* 地址或长度不对齐 */ } /* 选中芯片 */ nand_select_chip(); for(i=start_addr; i < (start_addr + size);) { /* 发出READ0命令 */ write_cmd(0); /* Write Address */ write_addr(i); write_cmd(0x30); wait_idle(); for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) //一页2k { *buf = read_data(); buf++; } } /* 取消片选信号 */ nand_deselect_chip(); return ; }
sdram.c 源码:
void disable_watch_dog(void) { (*(unsigned long *)0x53000000)=0; } void sdram_init(void) { unsigned long p[]={ 0x22011110, 0x00000700, 0x00000700, 0x00000700, 0x00000700, 0x00000700, 0x00000700, 0x00018005, 0x00018005, 0x008c07a3, 0x000000b1, 0x00000030, 0x00000030 }; unsigned long *sdram_base=(unsigned long *)0x48000000; int i=0; for(;i<13;i++) sdram_base[i]=p[i]; }
leds.c 源码:
#define GPFCON (*(volatile unsigned long *)0x56000050) #define GPFDAT (*(volatile unsigned long *)0x56000054) #define GPF4_out (1<<(4*2)) #define GPF5_out (1<<(5*2)) #define GPF6_out (1<<(6*2)) void wait(volatile unsigned long dly) { for(; dly > 0; dly--); } int main(void) { unsigned long i = 0; GPFCON = GPF4_out|GPF5_out|GPF6_out; // 将LED1-3对应的GPF4/5/6三个引脚设为输出 while(1){ wait(80000); GPFDAT = (~(i<<4)); // 根据i的值,点亮LED1-3 if(++i == 8) i = 0; } return 0; }
链接脚本 nand.lds:
SECTIONS { first 0x00000000 :{start.o sdram.o nand.o} seconed 0x30000000 :AT(4096) {leds.o} }
编译的Makefile:
objs:=start.o sdram.o nand.o leds.o nand.bin:$(objs) arm-linux-ld -Tnand.lds -o nand_elf $^ arm-linux-objcopy -O binary -S nand_elf $@ arm-linux-objdump -D -m arm nand_elf > nand.dis %.o:%.c arm-linux-gcc -o $@ -c $< %.o:%.S arm-linux-gcc -o $@ -c $< clean: rm *.o *.bin *.dis nand_elf