s3c2440 linux编写裸机程序,NAND FLASH - S3C2440裸机实验_Linux编程_Linux公社-Linux系统门户网站...

#include "def.h"

#include "2440addr.h"

#include "mynand.h"

//define command

#define CMD_READ1 0x00   //页读命令1

#define CMD_READ2 0x30   //页读命令2

#define CMD_READID 0x90   //读取ID

#define CMD_RESET 0xff    //复位

#define CMD_WRITE1 0x80   //页写命令1

#define CMD_WRITE2 0x10   //页写命令2

#define CMD_ERASE1 0x60   //块擦除命令1

#define CMD_ERASE2 0xd0   //块擦除命令2

#define CMD_STATUS 0x70   //读取状态命令

#define CMD_RANDOMREAD1 0X05  //随机读取命令1

#define CMD_RANDOMREAD2 0xe0   //随机读取命令2

#define CMD_RANDOMWRITE  0x85   //随机写命令

#define NF_CE_L()    {rNFCONT &=~(1<<1);}   //使能片选

#define NF_CE_H()     {rNFCONT |=(1<<1);}   //关闭片选

#define NF_MECC_UnLock()    {rNFCONT&=~(1<<5);}   //解锁main去ECC

#define NF_MECC_Lock()      {rNFCONT|=(1<<5);}    //锁定main去ECC

#define NF_SECC_UnLock()   {rNFCONT &= ~(1<<6); }   //解锁spare区ECC

#define NF_SECC_Lock()     {rNFCONT |= (1<<6); }    //锁定spare区ECC

#define NF_RSTECC()        {rNFCONT |= (1<<4); }        //复位ECC

#define NF_WAITRB()  {while(!(rNFSTAT &(1<<0))) ;}   //等待nand flash 空闲

#define NF_CLEAR_RB()           {rNFSTAT |= (1<<2); }   //清除RnB信号

#define NF_DETECT_RB()      {while(!(rNFSTAT&(1<<2)));}

#define NF_RDDATA8()        ((*(volatile unsigned char*)0x4E000010) )

#define NF_CMD(cmd)   {rNFCMD = (cmd);}  //命令

#define NF_ADDR( addr)  {rNFADDR = (addr);}  //地址

#define NF_RDDATA()     (rNFDATA)    //读取32位数据

//#define NF_RDDATA8()     (rNFDATA)    //读取8位数据

#define NF_WRDATA(data)  { rNFDATA = (data);}  //写32位数据

#define NF_WRDATA8(data)  { rNFDATA8 = (data);}  //写8位数据

#define TACLS  1

#define TWRPH0 2

#define TWRPH1 0

externvoidDelay(inttime);

voidnand_init(void)

{

rGPACON = rGPACON & (~(0x3f<<17)) |(0x3f<<17) ;

rNFCONF = (TACLS<<12) |(TWRPH0<<8) |(TWRPH1<<4) |(0<<0) ;

//非锁定,屏蔽nandflash中断,初始化ECC及锁定main区和spare区ECC,使能nandflash片选及控制器

rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);

}

//复位nand

voidnand_reset()

{

inti;

NF_CE_L();//cs

NF_CLEAR_RB();//清除RnB信号

for(i=0;i<10;i++)  ;

NF_CMD(CMD_RESET);//写入复位命令

NF_DETECT_RB();//等待RnB信号变高,即不忙

NF_CE_H();//关闭nandflash片选

}

//读取nand的id号,首先需要写入读ID命令,然后再写入0x00地址,就可以读取到一共五个周期的芯片ID,第一个周期为厂商ID,第二个周期为设备ID,

//第三个周期至第五个周期包括了一些具体的该芯片信息

U8 read_id(void)

{

inti;

U8 first, second, third, forth, fifth;//分别读取1---5个周期的数据

NF_CE_L();//cs

//NF_CLEAR_RB();                      //清除RnB信号

// for(i=0;i<10;i++)  ;

NF_CMD(CMD_READID);//读ID命令

NF_ADDR(0x0);//写0x00地址

first = NF_RDDATA8()  ;//厂商ID:    0Xec

second = NF_RDDATA8()  ;//设备ID,一般从这个参数可以判断出nand的一些参数

third = NF_RDDATA8()  ;//0x00

forth = NF_RDDATA8()  ;//0x95

fifth = NF_RDDATA8()  ;// 0x40

NF_CE_H();//关闭nandflash片选

returnsecond;

}

//带硬件ECC校验的读,page_numer为页号,每页2K

U8 nand_readpage_ecc(U32 page_number, U8 *buffer)

{

inti;

U32 mainecc0, spareecc;//用于存放ecc的临时值

NF_RSTECC();//复位ECC

NF_MECC_UnLock()//解锁主区ECC

NF_CE_L();//cs

NF_CLEAR_RB();//清除RnB信号

NF_CMD(CMD_READ1);//页读命令周期1

//写入地址,首先写入列地址(也即相对每一个页开始的地址),再写入行地址(也即页号)

NF_ADDR(0x00);//列地址A0~A7,这里直接从每页的开始读可以使用下面被注释的4行代码优化

NF_ADDR(0x00);//列地址A8~A11

// page = page_number/4;

// data_addr = 512 *(page_number%4);

// NF_ADDR(data_addr&0xff);

// NF_ADDR((data_addr>>8)&0xff);

NF_ADDR((page_number) & 0xff);//行地址A12~A19

NF_ADDR((page_number >> 8) & 0xff);//行地址A20~A27

NF_CMD(CMD_READ2);//页读命令周期2

NF_DETECT_RB();//等待RnB信号变高,即不忙

for(i=0;i<2048;i++)

buffer[i] = NF_RDDATA8() ;

NF_MECC_Lock();//锁定main区ECC值

NF_SECC_UnLock();//解锁spare区ECC

mainecc0=NF_RDDATA();//读spare区的前4个地址内容,即第2048~2051地址,这4个字节为main区的ECC

//把读取到的main区的ECC校验码放入NFMECCD0/1的相应位置内

rNFMECCD0=((mainecc0&0xff00)<<8)|(mainecc0&0xff);

rNFMECCD1=((mainecc0&0xff000000)>>8)|((mainecc0&0xff0000)>>16);

NF_SECC_Lock();//锁定spare区的ECC值

spareecc=NF_RDDATA();//继续读spare区的4个地址内容,即第2052~2055地址,其中前2个字节为spare区的ECC值

//把读取到的spare区的ECC校验码放入NFSECCD的相应位置内

rNFSECCD=((spareecc&0xff00)<<8)|(spareecc&0xff);

NF_CE_H();//关闭nandflash片选

//判断所读取到的数据是否正确

if((rNFESTAT0&0xf) == 0x0)

return0x66;//正确

else

return0x44;

}

U8 nand_writepage_ecc(U32 page_number, U8 *buffer)

{

inti,stat;

U32 mecc0, secc;//用于存放ecc的临时值

charECCBuf[10];

i = nand_is_badblock(page_number>>6) ;

if( i ==0x33)

return0x42 ;//坏块

NF_RSTECC();//复位ECC

NF_MECC_UnLock()//解锁主区ECC

NF_CE_L();//cs

NF_CLEAR_RB();//清除RnB信号

NF_CMD(CMD_WRITE1);//页读命令周期1

//写入地址,首先写入列地址(也即相对每一个页开始的地址),再写入行地址(也即页号)

NF_ADDR(0x00);//列地址A0~A7,这里直接从每页的开始读可以使用下面被注释的4行代码优化

NF_ADDR(0x00);//列地址A8~A11

// page = page_number/4;

// data_addr = 512 *(page_number%4);

// NF_ADDR(data_addr&0xff);

// NF_ADDR((data_addr>>8)&0xff);

NF_ADDR((page_number) & 0xff);//行地址A12~A19

NF_ADDR((page_number >> 8) & 0xff);//行地址A20~A27

for(i=0;i<2048;i++)

NF_WRDATA8(buffer[i]);

NF_MECC_Lock();//锁定main区ECC值

mecc0=rNFMECC0;//读取main区的ECC校验码

//把ECC校验码由字型转换为字节型,并保存到全局变量数组ECCBuf中

ECCBuf[0]=(U8)(mecc0&0xff);

ECCBuf[1]=(U8)((mecc0>>8) & 0xff);

ECCBuf[2]=(U8)((mecc0>>16) & 0xff);

ECCBuf[3]=(U8)((mecc0>>24) & 0xff);

NF_SECC_UnLock();//解锁spare区ECC

for(i=0;i<4;i++)

{

NF_WRDATA8(ECCBuf[i]);

}

NF_SECC_Lock();//锁定spare区的ECC值

secc=rNFSECC;//读取spare区的ECC校验码

//把ECC校验码保存到全局变量数组ECCBuf中

ECCBuf[4]=(U8)(secc&0xff);

ECCBuf[5]=(U8)((secc>>8) & 0xff);

//把spare区的ECC值继续写入到spare区的第2052~2053地址内

for(i=4;i<6;i++)

{

NF_WRDATA8(ECCBuf[i]);

}

NF_CMD(CMD_WRITE2);//页读命令周期2

Delay(100);

NF_CMD(CMD_STATUS);//读状态命令

//判断状态值的第6位是否为1,即是否在忙,该语句的作用与NF_DETECT_RB();相同

do{

stat = NF_RDDATA8();

}while(!(stat&0x40));

NF_CE_H();//关闭nandflash片选

//判断所读取到的数据是否正确

if(stat & 0x1)

{

i = rNF_MarkBadBlock(page_number>>6);//标注该页所在的块为坏块

if(i == 0x21)

return0x43  ;//标注坏块失败

else

return0x44;//写操作失败

}

else

return0x66;

}

U8 nand_random_readpage(U32 page_number, U32 add)

{

NF_CE_L();//cs

NF_CLEAR_RB();//清除RnB信号

NF_CMD(CMD_READ1);//页读命令周期1

//写入地址,首先写入列地址(也即相对每一个页开始的地址),再写入行地址(也即页号)

NF_ADDR(0x00);//列地址A0~A7,这里直接从每页的开始读可以使用下面被注释的4行代码优化

NF_ADDR(0x00);//列地址A8~A11

// page = page_number/4;

// data_addr = 512 *(page_number%4);

// NF_ADDR(data_addr&0xff);

// NF_ADDR((data_addr>>8)&0xff);

NF_ADDR((page_number) & 0xff);//行地址A12~A19

NF_ADDR((page_number >> 8) & 0xff);//行地址A20~A27

NF_CMD(CMD_READ2);//页读命令周期2

NF_DETECT_RB();//等待RnB信号变高,即不忙

NF_CMD(CMD_RANDOMREAD1);//随意读命令周期1

//页内地址

NF_ADDR((char)(add&0xff));//列地址A0~A7

NF_ADDR((char)((add>>8)&0x0f));//列地址A8~A11

NF_CMD(CMD_RANDOMREAD2);//随意读命令周期2

returnNF_RDDATA8();//读取数据

}

U8 nand_random_writepage(U32 page_number, U32 add, U8 data)

{

U8 stat;

NF_CE_L();//cs

NF_CLEAR_RB();//清除RnB信号

NF_CMD(CMD_WRITE1);//页读命令周期1

//写入地址,首先写入列地址(也即相对每一个页开始的地址),再写入行地址(也即页号)

NF_ADDR(0x00);//列地址A0~A7,这里直接从每页的开始读可以使用下面被注释的4行代码优化

NF_ADDR(0x00);//列地址A8~A11

// page = page_number/4;

// data_addr = 512 *(page_number%4);

// NF_ADDR(data_addr&0xff);

// NF_ADDR((data_addr>>8)&0xff);

NF_ADDR((page_number) & 0xff);//行地址A12~A19

NF_ADDR((page_number >> 8) & 0xff);//行地址A20~A27

NF_CMD(CMD_RANDOMWRITE);//页读命令周期2

//页内地址

NF_ADDR((char)(add&0xff));//列地址A0~A7

NF_ADDR((char)((add>>8)&0x0f));//列地址A8~A11

NF_WRDATA8(data);//写入数据

NF_CMD(CMD_WRITE2);//页写命令周期2

//判断状态值的第6位是否为1,即是否在忙,该语句的作用与NF_DETECT_RB();相同

do{

stat = NF_RDDATA8();

}while(!(stat&0x40));

NF_CE_H();//关闭nandflash片选

//判断所读取到的数据是否正确

if(stat & 0x1)

return0x44;

else

return0x66;

}

U8  nand_is_badblock(U32 block)

{

returnnand_random_readpage(block*64, 2054);

}

U8 rNF_MarkBadBlock(U32 block)

{

U8 result;

result = nand_random_writepage(block*64, 2054, 0x33);

if(result == 0x44)

return0x21;//写坏块标注失败

else

return0x60 ;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值