在MINI2440开发板上,NAND Flash型号K9F2G08,大小256MB。
1.首先是启动代码
- ################################
- #head.S
- #作为启动代码,负责初始化工作,并将nand 4k 之后的代码copy到内存,跳到内存执行程序
- ##############################################
- .text
- .global _start
- _start:
- @函数disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定义
- ldr sp, =4096 @调用C函数之前必须设置堆栈
- bl disable_watch_dog @关WATCH DOG
- bl memsetup @初始化SDRAM
- bl nand_init @初始化NAND Flash
- @将NAND Flash中地址4096开始的2048字节代码(main.c编译得到)复制到SDRAM中
- @nand_read_ll函数需要3个参数:
- ldr r0, =0x30000000 @1目标地址=0x30000000,这是SDRAM的起始地址
- mov r1, #4096 @2.源地址 = 4096,连接的时候,main.c中的代码都存在NAND Flash地址4096开始处
- mov r2, #2048 @3. 复制长度= 2048(bytes)
- bl nand_read @调用C函数nand_read
- ldr sp, =0x34000000 @跳到内存中,重新设置栈
- ldr lr, =halt_loop @设置返回地址
- ldr pc, =main @b指令和bl指令只能前后跳转32M的范围,所以这里使用向pc赋值的方法进行跳转
- halt_loop:
- b halt_loop
2.第二是init.c文件
- /* WATCH DOG register */
- #define WTCON (*(volatile unsigned long *)0x53000000)
- /* SDRAM regisers */
- #define MEM_CTL_BASE 0x48000000
-
- void disable_watch_dog();
- void memsetup();
- /*上电后,WATCH DOG默认是开着的,要把它关掉 */
- void disable_watch_dog()
- {
- WTCON = 0;
- }
- /* 设置控制SDRAM的13个寄存器 */
- void memsetup()
- {
- int i = 0;
- unsigned long *p = (unsigned long *)MEM_CTL_BASE;
- /* SDRAM 13个寄存器的值
- .long 0x22011110 @BWSCON
- .long 0x00000700 @BANK0
- .long 0x00000700 @BANK1
- .long 0x00000700 @BANK2
- .long 0x00000700 @BANK3
- .long 0x00000700 @BANK4
- .long 0x00000700 @BANK5
- .long 0x00018005 @BANK6
- .long 0x00018005 @BANK7
- .long 0x008c07a3 @REFRESH 刷新控制寄存器 在未使用PLL时,SDRAM是时钟频率等于晶振频率12Mhz
- @R_CNT=2^11+1-12(HCLK)*(64ms/8192)(刷新周期)=1955=0x07A3
- .long 0x000000b1 @BANKSIZE寄存器
- .long 0x00000030 @MRSRB6
- .long 0x00000030 @MRSRB7
- */
- unsigned long const mem_cfg_val[]={ 0x22011110, //BWSCON
- 0x00000700, //BANKCON0
- 0x00000700, //BANKCON1
- 0x00000700, //BANKCON2
- 0x00000700, //BANKCON3
- 0x00000700, //BANKCON4
- 0x00000700, //BANKCON5
- 0x00018005, //BANKCON6
- 0x00018005, //BANKCON7
- 0x008C07A3, //REFRESH
- 0x000000B1, //BANKSIZE
- 0x00000030, //MRSRB6
- 0x00000030, //MRSRB7
- };
- for(; i < 13; i++)
- p[i] = mem_cfg_val[i];
- }
3.最重要的nand.c
- #define LARGER_NAND_PAGE
- #define GPACON (*(volatile unsigned long *)0x56000000)
- #define GPBDAT (*(volatile unsigned long *)0x56000014)
- #define NAND_SECTOR_SIZE 512
- #define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
- #define NAND_SECTOR_SIZE_LP 2048
- #define NAND_BLOCK_MASK_LP (NAND_SECTOR_SIZE_LP - 1)
- #define GSTATUS1 (*(volatile unsigned int *)0x560000B0)
- #define BUSY (1<<2)
- static read_count = 0; //这个变量纯粹是用来测试用的,点亮led
- /* NAND FLASH (see S3C2440 manual chapter 6, www.100ask.net) */
- #define NFCONF (*(volatile unsigned int *)0x4e000000) //0x48000000
- #define NFCONT (*(volatile unsigned int *)0x4e000004) //0x48000004
- #define NFCMD (0x4e000008) //0x48000008
- #define NFADDR (0x4e00000C) //0x4800000C
- #define NFDATA (0x4e000010) //0x48000010
- #define NFMECCD0 (*(volatile unsigned int *)0x4e000014) //0x48000014
- #define NFMECCD1 (*(volatile unsigned int *)0x4e000018) //0x48000018
- #define NFSECCD (*(volatile unsigned int *)0x4e00001c) //0x4800001C
- #define NFSTAT (0x4e000020) //0x48000020
- #define NFESTAT0 (*(volatile unsigned int *)0x4e000024) //0x48000024
- #define NFESTAT1 (*(volatile unsigned int *)0x4e000028) //0x48000028
- #define NFMECC0 (*(volatile unsigned int *)0x4e00002c) //0x4800002C
- #define NFMECC1 (*(volatile unsigned int *)0x4e000030) //0x48000030
- #define NFSECC (*(volatile unsigned int *)0x4e000034) //0x48000034
- #define NFSBLK (*(volatile unsigned int *)0x4e000038) //0x48000038
- #define NFEBLK (*(volatile unsigned int *)0x4e00003c) //0x4800003C
- typedef struct {
- void (*nand_reset)(void);
- void (*wait_idle)(void);
- void (*nand_select_chip)(void);
- void (*nand_deselect_chip)(void);
- void (*write_cmd)(int cmd);
- void (*write_addr)(unsigned int addr);
- unsigned char (*read_data)(void);
- }nand_chip_ops;
- static nand_chip_ops nand_chip;
- /* 供外部调用的函数 */
- void nand_init(void);
- void nand_read(unsigned char *buf, unsigned long start_addr, int size);
- /* NAND Flash操作的总入口, 它们将调用S3C2410或S3C2440的相应函数 */
- 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);
- /* S3C2440的NAND Flash处理函数 */
- static void s3c2440_nand_reset(void);
- static void s3c2440_wait_idle(void);
- static void s3c2440_nand_select_chip(void);
- static void s3c2440_nand_deselect_chip(void);
- static void s3c2440_write_cmd(int cmd);
- static void s3c2440_write_addr(unsigned int addr);
- static unsigned char s3c2440_read_data(void);
- /* -------------------S3C2440的NAND Flash操作函数---------------------------- */
- /* 复位 */
- static void s3c2440_nand_reset(void)
- {
- s3c2440_nand_select_chip();
- s3c2440_write_cmd(0xff); // 复位命令
- s3c2440_wait_idle();
- s3c2440_nand_deselect_chip();
- }
- /* 发出片选信号 */
- static void s3c2440_nand_select_chip(void)
- {
- int i;
- NFCONT =NFCONT & (~(1<<1)); //NFCONT的1位清零,片选使能
- for(i=0; i<10; i++);
- }
- /*等待就绪*/
- static void s3c2440_wait_idle(void)
- {
- int i;
- //对寄存器的操作,最好用volatile声明一下。有时候不明显的错误就是因为这个造成的
- volatile unsigned char *p = (volatile unsigned char *)NFSTAT;
- //{while(!(rNFSTAT&(1<<2)));}
- while(!(*p & BUSY)) //NFSTAT的最低位为1,表明存储器就绪,为0表示忙
- for(i=0; i<10; i++);
- }
- /* 取消片选信号 */
- static void s3c2440_nand_deselect_chip(void)
- {
- NFCONT =NFCONT |(1<<1);
- }
- /* 发出命令 */
- static void s3c2440_write_cmd(int cmd)
- {
- volatile unsigned char *p = (volatile unsigned char *)NFCMD;
- *p = cmd; //强制类型转换,将int型数据转换为字符型数据,
- }
- /* 发出地址,在发地址时要弄清nandflash的页大小,手册上的写地址周期是按照4k/页的大小,这里板子上的nand页大小默认设置为2k */
- static void s3c2440_write_addr(unsigned int addr)
- {
- int i;
- volatile unsigned char *p = (volatile unsigned char *)NFADDR;
-
- //K9F2G08U0A芯片 的写地址过程分为5步,不同于1208的4步。
- *p = addr & 0xFF; //先发低八位,从0-7,
- for(i=0; i<10; i++); //延时
- *p = (addr >> 8) & 0xFF;//再发从8位开始的8.9,10,11,共4位,这样把列地址发完,共12位,可寻址2^12=4096bytes
- for(i=0; i<10; i++);
- *p = (addr >> 11) & 0xFF;
- for(i=0; i<10; i++);
- *p = (addr >> 19) & 0xFF;
- for(i=0; i<10; i++);
- *p = (addr >> 27) & 0xff;//最后发送页地址的高2位。
- for(i=0; i<10; i++);
- }
- /*2440读数据函数*/
- static unsigned char s3c2440_read_data(void)
- {
- /*这里读到的是个16位数据,unsigned char 是8位的,由于读写数据时数据寄存器的
- 配置是按照IO口8位的宽度读写的,参照芯片手册6-5页,只有一个IO周期,且只有7:0位有效
- 这里进行强制转换,只取最低8位*/
- unsigned char ch = *((volatile unsigned char *)NFDATA);
- /*
- if(read_count == 1)
- GPBDAT &= ~(1<<6);
- if(read_count ==2)
- GPBDAT &= ~(1<<7);
- */
- if(read_count == 2048)
- GPBDAT &= ~(1<<5); //read_data函数确实被调用了2048次。
- return ch;
- }
- /* ------------------------初始化NAND Flash------------------ */
- /* 在第一次使用NAND Flash前,复位一下NAND Flash */
- static void nand_reset(void)
- {
- nand_chip.nand_reset();
- }
- static void wait_idle(void)
- {
- nand_chip.wait_idle();
- }
- static void nand_select_chip(void)
- {
- int i;
- nand_chip.nand_select_chip();
- for(i=0; i<10; i++);
- }
- static void nand_deselect_chip(void)
- {
- nand_chip.nand_deselect_chip();
- }
- static void write_cmd(int cmd)
- {
- nand_chip.write_cmd(cmd);
- }
- static void write_addr(unsigned int addr)
- {
- nand_chip.write_addr(addr);
- }
- static unsigned char read_data(void)
- {
- return nand_chip.read_data();
- }
- void nand_init()
- {
- //#define TACLS 0
- #define TACLS 1 //这里改为1,默认值也是1,WE信号延迟CLE/ALE一个时钟周期
- #define TWRPH0 5
- #define TWRPH1 0
- GPACON = (GPACON &~(0x3f<<17)) | (0x3f<<17); //配置芯片引脚,为1用作NAND控制引脚
- nand_chip.nand_reset = s3c2440_nand_reset;
- nand_chip.wait_idle = s3c2440_wait_idle;
- nand_chip.nand_select_chip = s3c2440_nand_select_chip;
- nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;
- nand_chip.write_cmd = s3c2440_write_cmd;
- nand_chip.write_addr = s3c2440_write_addr;
- nand_chip.read_data = s3c2440_read_data;
- /* 设置时序 */
- NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); //0xe=1110,设置AdvFlash2k字节,
- /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
- NFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)\
- |(1<<4)|(1<<1)|(1<<0);
-
-
- /* 复位NAND Flash ,就是向nand_flash发送一个复位命令*/
- nand_reset();
-
- }
- /*
- //读函数,将nand_flash从4096地址处开始的数据拷贝到SDRAM起始地址,大小为1kb
- void nand_read(unsigned char *buf, unsigned long start_addr, int size)
- {
- int i, j;
-
- #ifdef LARGER_NAND_PAGE
- if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {
- return ; //地址或长度不对齐
- }
- #else
- if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
- return ; //地址或长度不对齐
- }
- #endif
-
- nand_select_chip();
- for(i=start_addr; i < (start_addr + size);) {
-
- write_cmd(0);
-
- //Write Address
- write_addr(i);
- //在程序开头定义了LARGER_NAND_PAGE,表明该nand_flash是大页
- //#ifdef LARGER_NAND_PAGE
- write_cmd(0x30);
- //#endif
- wait_idle();
- //GPBDAT &= ~(1<<7); //test
- #ifdef LARGER_NAND_PAGE
- for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {
- //#else
- //for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
- //#endif
- *buf = read_data(); //将读到的数据放到第一个参数buf指定的地址处,0x3000 0000
- buf++;
- //GPBDAT &= ~(1<<7);
- }
- //GPBDAT |= (1<<7);
- //GPBDAT &= ~(1<<5);
- }
- //GPBDAT = 0xffff;
- //GPBDAT = 0xfeff; //第八位清零,led4亮
- GPBDAT &= (~1<<8);
- //取消片选信号
- nand_deselect_chip();
- // GPBDAT |= (1<<5); //test
- return ;
- }
- */
- /*自己的nand_read函数,相比韦大侠的,移植性差一点*/
- void nand_read(unsigned char *buf, unsigned long start_addr, int len)
- {
- unsigned long i,j;
- unsigned char *des_addr=buf;
- nand_select_chip();
- *(unsigned char *)NFSTAT = (*(unsigned char *)NFSTAT) | (1<<2); //清除等待位
- for(i=start_addr;i<(start_addr+len);)
- { //发出页读命令
- write_cmd(0x00);
- write_addr(i);
- write_cmd(0x30);
- wait_idle();
- //GPBDAT &= ~(1<<8);
- for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++)
- {
- read_count++;
- *des_addr=read_data();
- des_addr++;
- //read_count++;
- }
- }
- if(read_count==2048)
- GPBDAT &=~(1<<6);
- nand_deselect_chip();
- //GPBDAT &= ~(1<<8);
- }
4.最后main.c
- #include "s3c24xx.h"
- int main(void)
- {
- unsigned long i=0;
- //GPBCON = (1<<(2*5)) | (1<<(2*6)) | (1<<(2*7)) | (1<<(2*8)) ;
- GPBDAT = 0xffffffff; //全部熄灭led
- while(1){
- for(i=1000000;i>0;i--); //delay
- GPBDAT = ~(GPBDAT &(0xf<<5)); //GPBDAT的5,6,7,8进行位翻转,其余位不变
- }
-
- return 0;
- }
阅读(474) | 评论(0) | 转发(0) |