nand的裸板驱动---写的很规范(s3c2410)

本文深入剖析了NAND Flash驱动程序的设计与实现,通过具体的代码示例,详细介绍了NAND Flash的基本操作流程,包括初始化配置、读取ID、数据读写及错误校验等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

nandflash在嵌入式设备中广泛的应用,学些nandflash的重要性不言而喻,这里分析一段实例代码,不管是编码规范还是程序的结构都是很有价值的。下边是K9F1208U0M的实例代码。首先看nand.h文件: #ifndef __NAND_Flash__ #define __NAND_Flash__ extern void InitNandCfg(void); //初始化K9F1208UOM NAND flash 配置 extern unsigned int ReadChipId(void); //读取NAND Flash的ID号 extern unsigned short ReadStatus(void); //读取NAND Flash的状态 extern unsigned int EraseBlock(unsigned int addr); //NAND Flash块擦除 extern void ReadPage(unsigned int addr, unsigned char *buf); //K9F1208U0M nand flash 的页数据读 extern void WritePage(unsigned int addr, unsigned char *buf); //K9F1208U0M nand flash 的页数据写 extern void MarkBadBlk(unsigned int addr); //屏蔽 K9F1208U0M nand flash 的坏块 extern int CheckBadBlk(unsigned int addr); //检查 K9F1208U0M nand flash 的坏块 extern void InitNandFlash(void); //K9F1208U0M nand flash 的初始化 #endif 需要详细看的是nandflash.c文件: //==================================================== // 常量定义区 //==================================================== #define EnNandFlash() (rNFCONF |= 0x8000) //bit15=1 enable NAND flash controller #define DsNandFlash() (rNFCONF &= ~0x8000) //bit15=1 disable NAND flash controller #define InitEcc() (rNFCONF |= 0x1000) //bit12=1 initialize ECC #define NoEcc() (rNFCONF &= ~0x1000) //bit12=0 initialize ECC #define NFChipEn() (rNFCONF &= ~0x800) //bit11=0 NAND flash nFCE = L (active) #define NFChipDs() (rNFCONF |= 0x800) //bit11=1 NAND flash nFCE = H (inactive) #define WrNFCmd(cmd) (rNFCMD = (cmd)) //write commond to nand flash #define WrNFAddr(addr) (rNFADDR = (addr)) //write address to nand flash #define WrNFDat(dat) (rNFDATA = (dat)) //write data to nand flash #define RdNFDat() (rNFDATA) //read data from nand flash #define RdNFStat() (rNFSTAT) //read status from nand flash #define NFIsBusy() (!(rNFSTAT&1)) //whether nand flash is busy? #define NFIsReady() (rNFSTAT&1) //whether nand flash is ready? #define READCMD0 0 //Read0 model command == Page addr 0~127 #define READCMD1 1 //Read1 model command == Page addr 128~511 #define READCMD2 0x50 //Read2 model command == Page addr 512~527 #define ERASECMD0 0x60 //Block erase command 0 #define ERASECMD1 0xd0 //Block erase command 1 #define PROGCMD0 0x80 //page write command 0 #define PROGCMD1 0x10 //page write command 1 #define QUERYCMD 0x70 //query command #define RdIDCMD 0x90 //read id command //==================================================== // 函数定义区 //==================================================== #include "NAND_Flash.h" #include "2410addr.h" static unsigned short NandAddr; //等待NAND FLASH不忙 void wait_idle(void) { int i; while(!(rNFSTAT & 0x1)) for(i=0; i<10; i++); } /* 在第一次实用NAND Flash前,复位一下NAND Flash */ void reset_nand() { int i=0; rNFCONF &= ~0x800; for(; i<10; i++); rNFCMD = 0xff; //reset command wait_idle(); } //==================================================== // 语法格式: void InitNandCfg(void) // 功能描述: 初始化 K9F1208U0M nand flash 配置 // 入口参数: 无 // 出口参数: 无 //==================================================== void InitNandCfg(void) { //enable nand flash control, initilize ecc, chip disable, //基本所有的falsh都可以公用的。 rNFCONF = (1<<15)|(1<<12)|(1<<11)|(7<<8)|(7<<4)|(7); } //==================================================== // 语法格式: unsigned int ReadChipId(void) // 功能描述: 读Nand Flash的ID号 // 入口参数: 无 // 出口参数: Nand Flash ID //==================================================== unsigned int ReadChipId(void) { unsigned int id; NFChipEn(); WrNFCmd(RdIDCMD); WrNFAddr(0); wait_idle(); id = RdNFDat()<<8; id |= RdNFDat(); NFChipDs(); return id; } //==================================================== // 语法格式: unsigned short ReadStatus(void) // 功能描述: 读Nand Flash的状态 // 入口参数: 无 // 出口参数: Nand Flash 状态 //==================================================== unsigned short ReadStatus(void) { unsigned short stat; NFChipEn(); WrNFCmd(QUERYCMD); stat = RdNFDat(); NFChipDs(); return stat; } //==================================================== // 语法格式: unsigned int EraseBlock(unsigned int addr) // 功能描述: Nand Flash块擦除 // 入口参数: 块地址 // 出口参数: 擦除状态 0 为成功 非0 失败 //==================================================== unsigned int EraseBlock(unsigned int addr) { unsigned char stat; addr &= ~0x1f; NFChipEn(); //使能 WrNFCmd(ERASECMD0); WrNFAddr(addr);//擦除只针对块操作 WrNFAddr(addr>>8); if(NandAddr) //判断Flash的型号 WrNFAddr(addr>>16); WrNFCmd(ERASECMD1); //发送擦除命令 wait_idle(); //等待,直到操作完成为止。 NFChipDs(); //失能 return stat&1; } //==================================================== // 语法格式: void ReadPage(unsigned int addr, unsigned char *buf) // 功能描述: 读取页的内容 // 入口参数: 1,页地址 2,读出的页内数据 // 出口参数: 无 //==================================================== /**** K9F1208U0M nand flash 的页数据读 ****/ void ReadPage(unsigned int addr,unsigned char *buf)//addr = page address { unsigned short i; NFChipEn(); WrNFCmd(READCMD0); WrNFAddr(0); WrNFAddr(addr); WrNFAddr(addr>>8); if(NandAddr) WrNFAddr(addr>>16); InitEcc(); wait_idle(); for(i=0; i<512; i++) buf[i] = RdNFDat(); NFChipDs(); } //=================================================== // 语法格式:extern unsigned int WritePage(unsigned int addr, unsigned char *buf) // 功能描述: 写页数据 // 入口参数: 1,页地址 2,写页内数据 // 出口参数: 无 //==================================================== /**** K9F1208U0M nand flash 的页数据写 ****/ void WritePage(unsigned int addr, unsigned char *buf) { unsigned short i; unsigned char tmp[3]; NFChipEn(); WrNFCmd(PROGCMD0); WrNFAddr(0); //低八位为0 WrNFAddr(addr); //页地址 WrNFAddr(addr>>8); // if(NandAddr) WrNFAddr(addr>>16); InitEcc(); for(i=0; i<512; i++) WrNFDat(buf[i]); tmp[0] = rNFECC0;//产生的3位校验码 tmp[1] = rNFECC1; tmp[2] = rNFECC2; WrNFDat(tmp[0]);//将校验码重新写入页 WrNFDat(tmp[1]); WrNFDat(tmp[2]); WrNFCmd(PROGCMD1);//正式开始写数据 wait_idle(); NFChipDs(); } //==================================================== // 语法格式:extern void MarkBadBlk(unsigned int addr) // 功能描述: 屏蔽 K9F1208U0M nand flash 的坏块 // 入口参数: 块地址 // 出口参数: 无 //==================================================== void MarkBadBlk(unsigned int addr) { addr &= ~0x1f; NFChipEn(); WrNFCmd(READCMD2); //point to area c WrNFCmd(PROGCMD0); WrNFAddr(4); //mark offset 4,5,6,7 WrNFAddr(addr); WrNFAddr(addr>>8); if(NandAddr) WrNFAddr(addr>>16); WrNFDat(0); //mark with 0 WrNFDat(0); WrNFDat(0); //mark with 0 WrNFDat(0); WrNFCmd(PROGCMD1); wait_idle(); WrNFCmd(READCMD0); //point to area a NFChipDs(); } //==================================================== // 语法格式:int CheckBadBlk(unsigned int addr) // 功能描述: 检查 K9F1208U0M nand flash 的坏块 // 入口参数: 块地址 // 出口参数: 是否为坏块 0 坏块 1非坏块 //==================================================== int CheckBadBlk(unsigned int addr) { unsigned char dat; addr &= ~0x1f; NFChipEn(); WrNFCmd(READCMD2); //point to area c WrNFAddr(5); //mark offset 4,5,6,7 WrNFAddr(addr); WrNFAddr(addr>>8); if(NandAddr) WrNFAddr(addr>>16); wait_idle(); dat = RdNFDat(); WrNFCmd(READCMD0); //point to area a NFChipDs(); return (dat!=0xff); } //==================================================== // 语法格式:void InitNandFlash(void) // 功能描述: K9F1208U0M nand flash 的初始化 // 入口参数: 无 // 出口参数: 无 //==================================================== static int support=0; void InitNandFlash(void) { unsigned int i; InitNandCfg(); //初始化配置 reset_nand(); i = ReadChipId(); //读取NAND Flash的ID号 if((i==0x9873)||(i==0xec75)) NandAddr = 0; else if(i==0xec76) { support=1; //by chang NandAddr = 1; } else { return; } } 从上边的代码可以看出,尽管nandflash自身的操作时序非常的复杂,但在nandflash控制器的帮助下,nandflash的操作就变得非常的简单,这里只需要操作少量的寄存器就可以完成操作。首先分析代码,在驱动程序编程中,用的非常广泛的就是宏的定义, #define EnNandFlash() (rNFCONF |= 0x8000) //bit15=1 enable NAND flash controller #define DsNandFlash() (rNFCONF &= ~0x8000) //bit15=1 disable NAND flash controller 可以在上边看到,同样是一个操作,定义成宏之后,就可以很直观的通过宏名来识别具体要完成的操作,所以以后在写一些和硬件相关的操作与函数时,要多加使用宏定义。 通常norflash与nandflash的区别在网上是很容易查到的,这里不重复了,这里看一些 nandflash 的ecc校验,nandflash存在两种导致数据出错的问题就是反转与坏块,坏块需要标记出来,以后不能在存入数据,而数据的反转是一种正常的现象,通常需要检测多次如果成功就认为是反转,不用标记为坏块了,通常情况下,在写数据之前需要进行坏块检测,首先关于ecc,ecc的实现在ARM中是通过硬件来完成,操作的时候只需要把经过ECC校验的结构重新写入到nandflash的相应区域就可以了。 nandflash是串行的数据传输,而norflash是三总线结构的存储器件,所以nandflash是不能随即读写的,通常的nandflash占用的I/O口有限,数据需要通过多次发送才能完成,我们需要了解nandflash的组织模式,nandflash通过层层细化,划分为不同的小单元进行操作。在进行擦除操作时,是以block为单位进行操作的,而编程与读取操作是以page为单位进行操作的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值