- #ifndef __TEST_H__
- #define __TEST_H__
- #include"def.h"
- #define MAX_NAND_BLOCK 2048 //一共2048块
- #define NAND_PAGE_SIZE 2048 //每块main区2k字节=2048
- typedef struct nand_id_info //芯片的ID信息
- {
- U8 IDm; //厂商ID
- U8 IDd; //设备ID
- U8 ID3rd;
- U8 ID4th;
- U8 ID5th;
- } nand_id_info;
- typedef struct bad_block_info //登记坏块
- {
- U8 area[MAX_NAND_BLOCK]; //0表示非坏块,1表示坏块
- U32 sum; //坏块的总数
- } bad_block_info;
- //NAND 操作指令
- #define NAND_CMD_READ_1st 0x00
- #define NAND_CMD_READ_2st 0x30
- #define NAND_CMD_RANDOM_WRITE 0x85 //随机写
- #define NAND_CMD_RANDOM_READ_1st 0x05
- #define NAND_CMD_RANDOM_READ_2st 0xe0
- #define NAND_CMD_READ_CB_1st 0x00 //将NAND里一块内容写进另一块
- #define NAND_CMD_READ_CB_2st 0x35
- #define NAND_CMD_READ_ID 0x90
- #define NAND_CMD_RES 0xff //复位命令
- #define NAND_CMD_WRITE_PAGE_1st 0x80
- #define NAND_CMD_WRITE_PAGE_2st 0x10
- #define NAND_CMD_BLOCK_ERASE_1st 0x60 //擦除命令
- #define NAND_CMD_BLOCK_ERASE_2st 0xd0
- #define NAND_CMD_READ_STATUS 0x70
- //NAND 中断向量
- #define INT_NFCON 24
- //NFCONF HCLK=100MHZ
- #define S3C2440_NFCONF_TACLS_init (1<<12)
- #define S3C2440_NFCONF_TWRPH0_init (4<<8)
- #define S3C2440_NFCONF_TWRPH1_init (0<<4)
- #define S3C2440_NFCONF_BusWidth_init (0)
- #define S3C2440_NFCONF_init() ( rNFCONF = S3C2440_NFCONF_TACLS_init | /
- S3C2440_NFCONF_TWRPH0_init | /
- S3C2440_NFCONF_TWRPH1_init | /
- S3C2440_NFCONF_BusWidth_init )
- //NFCONT
- #define S3C2440_NFCONT_LockTight_init (0<<13)
- #define S3C2440_NFCONT_SoftLock_init (0<<12)
- #define S3C2440_NFCONT_EnbIllegalAccINT_init (1<<10)
- #define S3C2440_NFCONT_EnbRnBINT_init (0<<9)
- #define S3C2440_NFCONT_RnB_TransMode_init (0<<8)
- #define S3C2440_NFCONT_SpareECCLock_init (1<<6)
- #define S3C2440_NFCONT_MainECCLock_init (1<<5)
- #define S3C2440_NFCONT_InitECC_init (1<<4)
- #define S3C2440_NFCONT_Reg_nCE_init (1<<1) //初始配置片选无效
- #define S3C2440_NFCONT_MODE_init (0)
- #define S3C2440_NFCONT_init() ( rNFCONT = S3C2440_NFCONT_LockTight_init | /
- S3C2440_NFCONT_SoftLock_init | /
- S3C2440_NFCONT_EnbIllegalAccINT_init | /
- S3C2440_NFCONT_EnbRnBINT_init | /
- S3C2440_NFCONT_RnB_TransMode_init | /
- S3C2440_NFCONT_SpareECCLock_init | /
- S3C2440_NFCONT_MainECCLock_init | /
- S3C2440_NFCONT_InitECC_init | /
- S3C2440_NFCONT_Reg_nCE_init | /
- S3C2440_NFCONT_MODE_init )
- //NFSTAT
- #define S3C2440_NFSTAT_init() ( rNFSTAT &= 0x3 )
- //NFESTAT0
- #define S3C2440_NFESTAT0_init() ( rNFESTAT0 = 0 )
- //NFESTAT1
- #define S3C2440_NFESTAT1_init() ( rNFESTAT1 = 0 )
- //
- #define select_nand() ( rNFCONT &= ~(1<<1) )
- #define dis_select_nand() ( rNFCONT |= 1<<1 )
- #define controller_enable() ( rNFCONT |= 1 )
- #define controller_disable() ( rNFCONT &= ~1 )
- //
- void nand_flash_init(void); //初始化
- void nand_read_id(void);
- extern int nand_block_erase(U32 num); //num要删除的块号
- extern int nand_page_write(U32 addr,U8 *buffer,U32 size); //addr要写的起始页地址,buffer要写的缓存,size要写的字节大小最大为4G
- extern int nand_page_read(U32 addr,U8 *buffer,U32 size); //addr开始页地址,从每页00地址开始读
- extern int nand_random_read(U32 paddr,U32 offset,U8 *data); //随机读数据 paddr页地址,offset页内偏移地址
- extern int nand_random_write(U32 paddr,U32 offset,U8 data); //随机写,paddr页地址,offset页内区最后一个地偏移地址
- extern void nand_test_bad_block(void); //测试坏块函数,并标记在nand_bbi变量里和spare里(如果非0xff则为坏块)
- #endif
- #include "2440addr.h"
- #include "test.h"
- #include"def.h"
- #define NAND_DEBUG 1 //打印一些串口调试信息
- #define USE_ECC 1 //使用ECC验证
- nand_id_info nand_id; //定义登记芯片ID的全局变量
- bad_block_info nand_bbi; //定义来登记坏的全局变量
- void init_nand_bbi(void) //初始化变量
- {
- U32 i;
- nand_bbi.sum=0;
- for (i=0;i
- nand_bbi.area[i]=0; //全部初始化为0
- }
- void nand_mask_bad_block(U32 n) //标志坏块,n是坏块的块号
- {
- #ifdef NAND_DEBUG
- Uart_Printf("NAND found and mask a bad block= %d .",n);
- #endif
- if (nand_bbi.area[n]!=1)
- {
- nand_bbi.area[n]=1;
- nand_bbi.sum++;
- nand_random_write(n*64,2048+64-1,0);//每块的第一个spare的最后一个字节,标志本块是否为坏块,非0xff为坏块
- }
- }
- int detect_nand_busy(void) //检测是否忙
- {
- U32 a;
- a=0;
- while(!(rNFSTAT&(1<<2)))
- {
- a++;
- if (a==5000000) //等待超时
- {
- Uart_Printf("/r/n Error: Detect Nand Busy time out!!! /r/n");
- rNFSTAT |= (1<<2); //清忙标志
- return -1; //错误返回-1
- }
- }
- rNFSTAT |= (1<<2); //清忙标志
- return 1;
- }
- void nand_reset(void) //NAND复位
- {
- rNFCMD = NAND_CMD_RES;
- detect_nand_busy(); //检测忙
- }
- void control_start(void) //芯片开启
- {
- select_nand();
- controller_enable();
- rNFSTAT |= (1<<2); //清忙标志
- nand_reset();
- }
- void control_end(void) //芯片关闭
- {
- dis_select_nand();
- controller_disable();
- }
- void ecc_main_init(void) //初始化ECC值
- {
- rNFCONT |= 1<<4; //initEcc
- }
- void ecc_main_start(void) //开锁main ECC
- {
- rNFCONT &= ~(1<<5); //unlock
- }
- void ecc_main_end(void) //锁定main ECC
- {
- rNFCONT |= 1<<5; //lock
- }
- void ecc_spare_start(void) //开锁spare ECC
- {
- rNFCONT &= ~(1<<6); //unlock
- }
- void ecc_spare_end(void) //锁定spare ECC
- {
- rNFCONT |= 1<<6; //lock
- }
- void __irq nandINT(void) //NAND中断函数
- {
- //此处写处理代码
- #ifdef NAND_DEBUG
- Uart_Printf("/r/n Nand Error... In interrupt now!!!");//只有错误才会进入中断
- #endif
- rSRCPND |= 0x1<
- rINTPND |= 0x1<
- }
- void nand_read_id(void)//读取芯片ID信息
- {
- control_start();//开控制
- rNFCMD = NAND_CMD_READ_ID;
- rNFADDR = 0;
- //读芯片ID
- nand_id.IDm=(U8)rNFDATA8;
- nand_id.IDd=(U8)rNFDATA8;
- nand_id.ID3rd=(U8)rNFDATA8;
- nand_id.ID4th=(U8)rNFDATA8;
- nand_id.ID5th=(U8)rNFDATA8;
- //打印ID信息
- #ifdef NAND_DEBUG
- Uart_Printf("/r/n Read NAND Flash ID:");
- Uart_Printf("/r/n NAND Mark code: 0x%x ",nand_id.IDm);
- Uart_Printf("/r/n NAND Device code: 0x%x ",nand_id.IDd);
- Uart_Printf("/r/n NAND 3rdID code: 0x%x ",nand_id.ID3rd);
- Uart_Printf("/r/n NAND 4thID code: 0x%x ",nand_id.ID4th);
- Uart_Printf("/r/n NAND 5thID code: 0x%x ",nand_id.ID5th);
- #endif
- control_end(); //关控制
- }
- //擦出时只要给定块所在页的地址,就能擦除整个块
- int nand_block_erase(U32 num) //num要删除的块号
- {
- num=num*64; //每块的第一页
- control_start(); //开控制
- nand_reset(); //复位
- rNFCMD = NAND_CMD_BLOCK_ERASE_1st;
- rNFADDR = num&0xff;
- rNFADDR = (num>>8)&0xff;
- rNFADDR = (num>>16)&0xff;
- rNFCMD = NAND_CMD_BLOCK_ERASE_2st;
- detect_nand_busy();
- rNFCMD =NAND_CMD_READ_STATUS; //读状态
- if(rNFDATA8 & 1) //最低位可以判断擦除和写是否成功
- {
- #ifdef NAND_DEBUG
- Uart_Printf("/r/n Error:nand erase error... block=0x%x",num/64);
- #endif
- control_end();//关控制
- nand_mask_bad_block(num/64);//登记为坏块
- return -1;//删除错误返回0
- }
- control_end();//关控制
- #ifdef NAND_DEBUG
- Uart_Printf("/r/n NAND block %d erase completed.",num/64);
- #endif
- return 1; //擦除成功
- }
- int nand_page_write(U32 addr,U8 *buffer,U32 size) //addr要写的起始页地址,buffer要写的缓存,size要写的字节大小最大为4G
- {
- U32 i,n,p,temp,ecc;
- U8 *bu;
- bu=buffer;
- temp=0;
- n=size/2048+(((size%2048)==0)?0:1); //计算出要写的页数,小于一页的部分当作一页
- for(i=0;i
- {
- control_start(); //开控制
- nand_reset(); //复位
- #ifdef USE_ECC
- ecc_main_init();
- ecc_main_start(); //可以产生main区ECC
- #endif
- rNFCMD = NAND_CMD_WRITE_PAGE_1st;
- rNFADDR = 0; //从每页的0地址开始
- rNFADDR = 0; //从每页的0地址开始
- rNFADDR = (addr)&0xff;
- rNFADDR = (addr>>8)&0xff;
- rNFADDR = (addr>>16)&0xff;
- for (p=0;p<2048;p++) //写入一页
- {
- temp=temp+1;
- if (temp>size)
- {
- rNFDATA8 = 0xff; //多余的填写0xff
- }
- else
- {
- rNFDATA8 = *(bu+p);
- }
- }
- //delay_lhg(100,100);//
- #ifdef USE_ECC
- ecc_main_end(); //锁定main区ecc
- ecc=rNFMECC0;
- ecc_spare_start(); //解锁spare区ECC
- //main ECC值写入备用区的头0~4个地址内
- rNFDATA8 = ecc&0xff;
- rNFDATA8 = (ecc>>8)&0xff;
- rNFDATA8 = (ecc>>16)&0xff;
- rNFDATA8 = (ecc>>24)&0xff;
- ecc_spare_end(); //锁定spare区ECC
- // delay_lhg(100,100);//
- ecc = rNFSECC; //spare ECC值写入备用区的5~6两个地址内
- rNFDATA8 = ecc&0xff;
- rNFDATA8 = (ecc>>8)&0xff;
- #endif
- bu=bu+2048; //页增量
- addr++;
- rNFCMD = NAND_CMD_WRITE_PAGE_2st;
- detect_nand_busy();//检测忙
- rNFCMD =NAND_CMD_READ_STATUS; //读状态
- if (rNFDATA8&1)
- {
- #ifdef NAND_DEBUG
- Uart_Printf("/r/n nand write page error: page addr=0x%d",addr-1); //写入失败,以后改进
- #endif
- control_end(); //关控制
- nand_mask_bad_block((addr-1)/64);//登记为坏块
- return -1; //写入错误返回-1
- }
- control_end(); //关控制
- }
- return 1; //成功返回1
- }
- int nand_page_read(U32 addr,U8 *buffer,U32 size) //addr开始页地址,从每页00地址开始读,size为需要读的字节数
- {
- U32 i,n,p,temp,ecc;
- U8 *bu,no;
- bu=buffer;
- temp=0;
- n=size/2048+(((size%2048)==0)?0:1); //计算出要读的页数,小于一页的部分当作一页
- for (i=0;i
- {
- control_start(); //开控制
- nand_reset(); //复位
- #ifdef USE_ECC
- rNFESTAT0 = 0; //复位错误标志位
- ecc_main_init();
- ecc_main_start(); //可以产生main区ECC
- #endif
- rNFCMD = NAND_CMD_READ_1st;
- rNFADDR = 0;
- rNFADDR = 0;
- rNFADDR = addr&0xff;
- rNFADDR = (addr>>8)&0xff;
- rNFADDR = (addr>>16)&0xff;
- rNFCMD = NAND_CMD_READ_2st;
- detect_nand_busy();
- for (p=0;p<2048;p++)
- {
- temp=temp+1;
- if (temp>size)
- {
- no=rNFDATA8; //多余的读出来扔掉
- }
- else
- {
- *(bu+p) = rNFDATA8;
- }
- }
- #ifdef USE_ECC
- rNFESTAT0=0;
- ecc_main_end(); //锁定main区ECC
- //delay_lhg(100,100);//
- ecc_spare_start(); //解锁spare区ecc
- ecc=rNFDATA8; //从flash读出main区ECC,四个字节
- no=rNFDATA8;
- ecc |= ((U32)no)<<8;
- no=rNFDATA8;
- ecc |= ((U32)no)<<16;
- no=rNFDATA8;
- ecc |= ((U32)no)<<24;
- rNFMECCD0 = ((ecc&0xff00)<<8)|(ecc&0xff); //硬件检验main ECC
- rNFMECCD1 = ((ecc&0xff000000)>>8)|((ecc&0xff0000)>>16);
- ecc_spare_end();//锁定spare区ecc
- // delay_lhg(100,100);//
- ecc=rNFDATA8;//从flash读出spare区ECC的值
- no=rNFDATA8;
- ecc |= ((U32)no)<<8;
- rNFSECCD = ((ecc&0xff00)<<8)|(ecc&0xff);//硬件检验spare ECC
- //delay_lhg(100,100);//延时一会
- ecc=rNFESTAT0&0xffffff; //ecc只是临时用一下错误状态,并非ecc内容
- if (ecc!=0)//有错误
- {
- //以后再优化
- #ifdef NAND_DEBUG
- Uart_Printf("/r/n Nand ecc check error... page addr=0x%x,NFESTAT0=0x%x ",addr,ecc);
- #endif
- nand_mask_bad_block((addr+i)/64);//登记为坏块
- return -1;
- }
- #endif
- bu=bu+2048;
- addr++;
- control_end();//关控制
- }
- return 1;
- }
- int nand_random_read(U32 paddr,U32 offset,U8 *data) //随机读数据 paddr页地址,offset页内偏移地址
- {
- control_start(); //开控制
- nand_reset(); //复位
- rNFCMD = NAND_CMD_READ_1st;
- rNFADDR = 0;
- rNFADDR = 0;
- rNFADDR = paddr&0xff;
- rNFADDR = (paddr>>8)&0xff;
- rNFADDR = (paddr>>16)&0xff;
- rNFCMD = NAND_CMD_READ_2st;
- detect_nand_busy();
- rNFCMD = NAND_CMD_RANDOM_READ_1st;
- rNFADDR = offset&0xff; //写入页内偏移地址
- rNFADDR = (offset>>8)&0xff;
- rNFCMD = NAND_CMD_RANDOM_READ_2st;
- *data = rNFDATA8;
- control_end();
- return 1;
- }
- int nand_random_write(U32 paddr,U32 offset,U8 data)//随机写,paddr页地址,offset页内偏移地址
- {
- control_start(); //开控制
- nand_reset(); //复位
- rNFCMD = NAND_CMD_WRITE_PAGE_1st;
- rNFADDR = 0;
- rNFADDR = 0;
- rNFADDR = paddr&0xff;
- rNFADDR = (paddr>>8)&0xff;
- rNFADDR = (paddr>>16)&0xff;
- rNFCMD = NAND_CMD_RANDOM_WRITE;
- rNFADDR = offset&0xff; //写入页内偏移地址
- rNFADDR = (offset>>8)&0xff;
- rNFDATA8 = data;
- rNFCMD = NAND_CMD_WRITE_PAGE_2st;
- detect_nand_busy(); //检测忙
- rNFCMD =NAND_CMD_READ_STATUS; //读状态
- if (rNFDATA8&1)
- {
- #ifdef NAND_DEBUG
- Uart_Printf("/r/n Error:nand random write error... paddr=0x%x,offset=0x%x ",paddr,offset);
- #endif
- return -1;//删除错误返回0
- }
- control_end();
- return 1;//成功返回1
- }
- void nand_test_bad_block(void) //测试坏块函数,并标记spare区最后一个地址,如果非0xff则为坏块
- {
- U8 dest[64*2048]; //一个块的main区容量
- U8 src [64*2048];
- U32 i,k;
- #ifdef NAND_DEBUG
- Uart_Printf("/r/n test and mask bad block is begain. /r/n");
- #endif
- //main区检测
- for (i=0;i<64*2048;i++)
- {
- dest[i]=0xff; //初始化缓冲区
- src [i]=0;
- }
- //删除所有块
- for (i=0;i
- {
- nand_block_erase(i);
- }
- for (i=0;i
- {
- nand_page_write(i*64,src,64*2048);
- nand_page_read(i*64,dest,64*2048);//使用了ecc校验读出来即可登记坏块信息
- }
- for (i=0;i<64*2048;i++)
- {
- dest[i]=0;//初始化缓冲区
- src [i]=0xff;
- }
- //删除所有块
- for (i=0;i
- {
- nand_block_erase(i);
- }
- for (i=0;i
- {
- nand_page_write(i*64,src,64*2048);
- nand_page_read(i*64,dest,64*2048);//使用了ecc校验读出来即可登记坏块信息
- }
- //
- //spare区检测
- for (i=0;i<64;i++)
- {
- dest[i]=0xff;//初始化缓冲区
- src [i]=0;
- }
- //删除所有块
- for (i=0;i
- {
- nand_block_erase(i);
- }
- for (i=0;i
- {
- if ( nand_bbi.area[i/64] ==1 ) //如果是坏块则跳过
- continue;
- for (k=0;k<64;k++)
- {
- nand_random_write(i,2048+k,src[k]);
- nand_random_read(i,2048+k,&dest[k]);
- if (dest[k]!=src[k])//不相等则登记为坏块
- {
- nand_mask_bad_block(i/64);
- break;
- }
- }
- }
- for (i=0;i<64;i++)
- {
- dest[i]=0x0;//初始化缓冲区
- src [i]=0xff;
- }
- //删除所有块
- for (i=0;i
- {
- nand_block_erase(i);
- }
- for (i=0;i
- {
- if ( nand_bbi.area[i/64] ==1 )//如果是坏块则跳过
- continue;
- for (k=0;k<64;k++)
- {
- nand_random_write(i,2048+k,src[k]);
- nand_random_read(i,2048+k,&dest[k]);
- if (dest[k]!=src[k])//不相等则登记为坏块
- {
- nand_mask_bad_block(i/64);
- break;
- }
- }
- }
- #ifdef NAND_DEBUG
- Uart_Printf("/r/n test and mask bad block is over. /r/n");
- #endif
- }
- void nand_flash_init(void)//初始化
- {
- #ifdef NAND_DEBUG
- Uart_Printf("/r/nNAND FLASH init");//
- #endif
- //中断入口地址
- pISR_NFCON = (U32)nandINT;
- //配置GPIO
- rGPGUP |= 0x7<<13; //GPG13~15关闭上位
- rGPGCON &= ~((U32)0x3f<<26);//GPG13~15为输入
- //初始化各寄存器
- S3C2440_NFCONF_init();
- S3C2440_NFCONT_init();
- S3C2440_NFSTAT_init();
- S3C2440_NFESTAT0_init();
- S3C2440_NFESTAT1_init();
- //关于中断
- rINTMSK &= ~(0x1<
- rINTMOD &= ~(0x1<
- rSRCPND |= 0x1<
- rINTPND |= 0x1<
- // init_nand_bbi();//初始化全局变量
- nand_read_id();//读ID
- // nand_test_bad_block();//测试并登记坏块
- }
上一篇:s3c2440串口调试函数
下一篇:s3c2440的触摸屏校正与测试
推荐阅读最新更新时间:2024-03-16 14:52