nand.c
上传用户:kylngs
上传日期:2022-05-06
资源大小:5k
文件大小:16k
- /*
- Nand Flash基本底层驱动函数,完成基本的读、写和擦除功能,没有加入ECC校验和写后校验功能。
- 外部调用的函数有:
- 写一页:
- int WriteOnePage(unsigned long Address, unsigned int Length, unsigned char *buffer);
- 读一页:
- int ReadOnePage(unsigned long Address, unsigned int Length, unsigned char *buffer);
- 多页连续读:
- int NandMTDRead(unsigned long Address,unsigned char *buffer,unsigned int Length,unsigned int modes);
- 多页连续写:
- int NandMTDWrite(unsigned long Address,unsigned char *buffer,unsigned int Length,unsigned int modes);
- 擦除函数:
- int NandMTDErase(unsigned int BlockNo,unsigned int BlocksToErase);
- GPIO初始化:
- void BusyGPIOInit(void);
-
- CPU为150MHz频率下,使用1ms定时中断测试读写速度:
- 1.调用1000次ReadOnePage 用时1419ms
- 2.调用1000次WriteOnePage 用时1576ms
- 3.调用NandMTDErase擦除100块 用时126ms
- 注:如果在ReadOnePage和WriteOnePage中分别加入DEBUG_PRINT(宏定义为NoDEBUG_PRINT,即空函数)时,用时大幅度增加,分别为6973和6730
- 孟军 2008-5-26 16:36
- */
- #include "nand.h"
- #include "mcf523x_gpio.h"
- #include "m523xevb.h"
- /***********************************************************/
- /**********************调试用的宏定义***********************/
- //读扩展区
- #define EXTRA 4
- /*错误值
- *仅在纯C下测试用 VxWorks系统中注释掉
- */
- #define flTimeOut 0
- #define flOK 1
- #define flWriteFault 2
- #define flReadFault 4
- #define flEarseFault 3
- #define flBadParameter 5
- #define ERROR 0
- #define NO_ERROR 1
- /**********************调试用的宏定义***********************/
- /***********************************************************/
- /* Flash IDs
- */
- #define K9F4G08U0A_FLASH 0xECDC
- /* Flash 命令集*/
- #define PAGE_PROGRAM_START 0x80
- #define PAGE_PROGRAM_END 0x10
- #define READ_START 0x00
- #define READ_END 0x30
- #define READ_FOR_COPY_BACK_START 0x00
- #define READ_FOR_COPY_BACK_END 0x35
- #define COPY_BACK_PROGRAM_START 0x85
- #define COPY_BACK_PROGRAM_END 0x10
- #define CACHE_PROGRAM_START 0x80
- #define CACHE_PROGRAM_END 0x15
- #define RANDOM_DATA_INPUT 0x85
- #define RANDOM_DATA_OUTPUT_START 0x05
- #define RANDOM_DATA_OUTPUT_END 0xe0
- #define RESET_FLASH 0xff
- #define BLOCK_ERASE_START 0x60
- #define BLOCK_ERASE_END 0xd0
- #define READ_STATUS 0x70
- #define READ_ID 0x90
- /*子函数声明*/
- int WaitForReady(void);
- int ReadStatusForError(void);
- int AddressInput_3Cycle(unsigned int PageNo );
- int AddressInput_5Cycle(unsigned long Address );
- void NoDEBUG_PRINT(const char *fmt, ...);
- /*----------------------------------------------------------------------
- * ReadOnePage
- *功能:读函数
- *参数:Address 读取数据的起始地址(flash芯片),Length 长度(字节),buffer 写入数据的起始地址(SDRAM地址)
- *没有ECC校验
- *返回FLStatus flTimeOut flOK
- *20070202
- ----------------------------------------------------------------------*/
- int ReadOnePage(unsigned long Address, unsigned int Length, unsigned char *buffer)
- {
- unsigned int iLength;
- //DEBUG_PRINT("ReadOnePage: block = %d page = %d Address = 0x%x, Length = %dn", (Address>>(BLOCK_SIZE_BITS+1)),((Address&BLOCK_MASK)>>(PAGE_SIZE_BITS+1)),Address, Length);
-
- FLASH_COMMAND=READ_START;/*读命令开始*/
- AddressInput_5Cycle(Address);/*发送地址*/
- FLASH_COMMAND=READ_END;/*读命令结束*/
- /*等待芯片就绪*/
- if( WaitForReady() != flOK )
- {
- return flTimeOut;
- }
- /*读数据*/
- for(iLength=0; iLength<Length; iLength++)
- {
- *buffer = FLASH_DATA;
- //DEBUG_PRINT("ReadOnePage: %d data = %d ASCII = %c Address = 0x%x n", iLength+1,*buffer,*buffer,Address+iLength);
- buffer++;
- }
- return flOK;/*读成功*/
- }
- /*----------------------------------------------------------------------
- * WriteOnePage
- *功能:写函数
- *参数:Address 写入数据的起始地址(flash芯片),Length 长度(字节),buffer 读出数据的起始地址(SDRAM地址)
- *返回:FLStatus - flTimeOut flWriteFault flOK
- *20070202
- ----------------------------------------------------------------------*/
- int WriteOnePage(unsigned long Address, unsigned int Length, unsigned char *buffer)
- {
- unsigned int iLength;
-
- //DEBUG_PRINT("WriteOnePage: block = %d page = %d Address = 0x%x, Length = %dn",(Address>>(BLOCK_SIZE_BITS+1)),((Address&BLOCK_MASK)>>(PAGE_SIZE_BITS+1)),Address, Length);
-
- FLASH_COMMAND=PAGE_PROGRAM_START;/*写命令开始*/
- AddressInput_5Cycle(Address);/*写地址*/
- /*写数据*/
- for(iLength=0; iLength<Length; iLength++)
- {
- FLASH_DATA=*buffer;
- //DEBUG_PRINT("WriteOnePage: %d data = %d ASCII = %c Address= 0x%x n",iLength+1,*buffer,*buffer,Address+iLength);
- buffer++;
- }
- FLASH_COMMAND=PAGE_PROGRAM_END;/*写命令结束*/
-
- /*等待芯片就绪*/
- if( WaitForReady() != flOK )
- {
- return flTimeOut;
- }
- /*检查写操作是否成功
- */
- if(ReadStatusForError()==ERROR)
- {
- return flWriteFault;/*写错误*/
- }
- return flOK;/*写成功*/
- }
- /*----------------------------------------------------------------------
- * AddressInput_5Cycle
- *功能:将地址分5个周期输入到flash中
- *参数:地址 Address
- *时序参考k9f4g08的芯片资料
- *20070130
- ----------------------------------------------------------------------*/
- int AddressInput_5Cycle(unsigned long Address )
- {
- unsigned long AddressNow;
- DATA_ADDRESS=(unsigned char)Address;/*1st cycle A0-A7*/
- AddressNow = Address >> 8;
- DATA_ADDRESS=(unsigned char)(AddressNow&0x0f);/*2nd cycle A8-A11*/
- AddressNow = AddressNow >> 4;
- DATA_ADDRESS=(unsigned char)AddressNow;/*3rd cycle A12-A19*/
- AddressNow = AddressNow >> 8;
- DATA_ADDRESS=(unsigned char)AddressNow;/*4th cycle A20-A27*/
- AddressNow = AddressNow >> 8;
- DATA_ADDRESS=(unsigned char)(AddressNow&0x03);/*5th cycle A28-A29*/
- }
- /*----------------------------------------------------------------------
- * AddressInput_3Cycle
- *功能:将18位页号分3个周期输入到flash中
- *参数:PageNo 页号
- *时序参考k9f4g08的芯片资料。
- *20070130
- ----------------------------------------------------------------------*/
- int AddressInput_3Cycle(unsigned int PageNo )
- {
- DATA_ADDRESS=(unsigned char)PageNo; /*1st cycle A12-A19*/
- DATA_ADDRESS=(unsigned char)(PageNo>>8); /*2nd cycle A20-A27*/
- DATA_ADDRESS=(unsigned char)((PageNo>>16)&0x03);/*3rd cycle A28-A29*/
- }
- /*----------------------------------------------------------------------
- * ReadStatusForError
- *功能:读状态寄存器.
- *返回:TRUE-Error FAULT-NoError.
- *20070202
- ----------------------------------------------------------------------*/
- int ReadStatusForError(void)
- {
- unsigned char chipStatus;/*芯片状态*/
- FLASH_COMMAND = READ_STATUS;/*读芯片状态命令*/
- chipStatus=FLASH_DATA;/*读取状态*/
-
- if( chipStatus&1 )/*I/O0不等于0 Error*/
- {
- return ERROR;/*Error*/
- }
- return NO_ERROR;/*NoError*/
- }
- /*----------------------------------------------------------------------
- * WaitForReady
- *功能:等待芯片就绪.
- *参数:无
- *返回:flOK flTimeOut
- *20080519
- ----------------------------------------------------------------------*/
- int WaitForReady(void)
- {
- unsigned long i=0;
- for(i=0;i<0xff;i++)
- {
- if(BUSY_IO == 1)
- {
- return flOK;
- }
- }
- return flTimeOut;
- }
- /*----------------------------------------------------------------------
- * NandMTDRead
- *功能:从flash中读取数据。该程序将作为MTD读函数。
- *参数:Address-读地址 buffer-写数据指针 Length-长度(字节)
- modes-EXTRA:读扩展区;其他:读数据区
- *返回:成功返回flOK 失败返回flReadFault
- *20070315
- ----------------------------------------------------------------------*/
- int NandMTDRead( unsigned long Address, unsigned char *buffer, unsigned int Length, unsigned int modes)
- {
- unsigned char *temp;
- unsigned char AddressAvailableFlag;/*地址有效标志*/
- unsigned int LeftToRead;/*一个页面中偏移地址之后的空间大小,能表示现在读的位置*/
- unsigned int ReadStatus;/*读状态*/
- unsigned int PageSize;
-
- /*根据modes参数 设定所读区域大小 是读数据区 还是空闲区 并判断地址是否有效*/
- if(modes&EXTRA)/*空闲区 页地址大于等于PAGE_SIZE且小于PAGE_SIZE+SPARE_SIZE有效*/
- {
- PageSize = SPARE_SIZE;
- if( ( ( (unsigned short)Address & PAGE_MASK ) >= PAGE_SIZE)
- && ( ( (unsigned short)Address & PAGE_MASK ) < PAGE_SIZE+SPARE_SIZE)
- && ( Address+Length <= MAX_ADDRESS ) )
- {
- AddressAvailableFlag = 1;/*地址有效*/
- }
- else
- {
- AddressAvailableFlag = 0;/*地址无效*/
- }
- }
- else/*modes!=EXTRA 数据区 页地址大于等于0且小于PAGE_SIZE有效*/
- {
- PageSize = PAGE_SIZE;
- if( ( ( (unsigned short)Address & PAGE_MASK ) >= 0)
- && ( ( (unsigned short)Address & PAGE_MASK ) < PAGE_SIZE)
- && ( Address+Length <= (MAX_ADDRESS-SPARE_SIZE) ) )
- {
- AddressAvailableFlag = 1;/*地址有效*/
- }
- else
- {
- AddressAvailableFlag = 0;/*地址无效*/
- }
- }
-
- /*越界错误*/
- if(!AddressAvailableFlag) /* 越界 */
- {
- ERROR_PRINT("NandMTDRead:OutOfBoundary Address = 0x%x, Length = %dn",Address, Length);
- return flBadParameter;
- }
-
- /*计算一个页面中偏移地址之后的空间大小*/
- LeftToRead = PageSize - ( (unsigned short)Address & (PageSize - 1) );
- /*将buffer指针赋给temp*/
- temp = buffer;
- DEBUG_PRINT("NandMTDRead: Address = 0x%x, Length = %dn", Address, Length);
- for ( ; Length > 0 ; )
- {
- if( Length < LeftToRead ) /* 如果要读的长度小于一个页面中偏移地址之后的空间大小 */
- {
- LeftToRead = Length; /* 那要读的就是该长度*/
- }
- /* 如果要读的长度大于一个页面的大小,就先读一个页面 *//* turn off EDC on partial block read*/
- ReadStatus=ReadOnePage(Address,LeftToRead,temp);
- if(ReadStatus!=flOK)/*如果读取错误,返回flReadFault*/
- {
- ERROR_PRINT("NandMTDRead:ReadErrorn");
- return flReadFault;
- }
- Length = Length - LeftToRead;/*更新长度*/
- if(Length>0)
- {
- if(PageSize==PAGE_SIZE)/*如果是读数据区*/
- {
- Address = (Address&CHIP_MASK)+(PAGE_SIZE*2);/*页地址加1,地址变为下一页的数据区*/
- }
- else if( PageSize==SPARE_SIZE)/*如果是读空闲区*/
- {
- Address = (Address&CHIP_MASK)+(PAGE_SIZE*3);/*地址变为下一页的空闲区*/
- }
- temp = temp + LeftToRead;/*移动指针*/
- LeftToRead = PageSize;/*新的一页 更新LeftToRead*/
- }
- }
- return flOK;
- }
- /*----------------------------------------------------------------------
- * NandMTDWrite
- *功能:对flash写入数据。该程序将作为MTD写函数。
- *参数:Address-写地址 buffer-读数据指针 Length-长度(字节)
- modes-EXTRA:写扩展区;其他:写数据区
- *返回:成功返回flOK 失败返回flWriteFault
- *20070315
- ----------------------------------------------------------------------*/
- int NandMTDWrite( unsigned long Address,unsigned char *buffer,unsigned int Length, unsigned int modes)
- {
- unsigned char *temp;
- unsigned char AddressAvailableFlag;/*地址有效标志*/
- unsigned int LeftToWrite;/*一个页面中偏移地址之后的空间大小,能表示现在写的位置*/
- unsigned int WriteStatus;/*写状态*/
- unsigned int PageSize = PAGE_SIZE;
- /*根据modes参数 设定所读区域大小 是读数据区 还是空闲区 并判断地址是否有效*/
- if(modes&EXTRA)/*空闲区 页地址大于等于PAGE_SIZE且小于PAGE_SIZE+SPARE_SIZE有效*/
- {
- PageSize = SPARE_SIZE;
- if( ( ( (unsigned short)Address & PAGE_MASK ) >= PAGE_SIZE)
- && ( ( (unsigned short)Address & PAGE_MASK ) < PAGE_SIZE+SPARE_SIZE)
- && ( Address+Length <= MAX_ADDRESS ) )
- {
- AddressAvailableFlag = 1;/*地址有效*/
- }
- else
- {
- AddressAvailableFlag = 0;/*地址无效*/
- }
- }
- else/*modes!=EXTRA 数据区 页地址大于等于0且小于PAGE_SIZE有效*/
- {
- PageSize = PAGE_SIZE;
- if( ( ( (unsigned short)Address & PAGE_MASK ) >= 0)
- && ( ( (unsigned short)Address & PAGE_MASK ) < PAGE_SIZE)
- && ( Address+Length <= (MAX_ADDRESS-SPARE_SIZE) ) )
- {
- AddressAvailableFlag = 1;/*地址有效*/
- }
- else
- {
- AddressAvailableFlag = 0;/*地址无效*/
- }
- }
-
- /*越界错误*/
- if(!AddressAvailableFlag) /* 越界 */
- {
- ERROR_PRINT("NandMTDWrite:OutOfBoundary Address = 0x%x, Length = %dn",Address, Length);
- return flBadParameter;
- }
-
- /*是否开启写后校验*/
- #undef VERIFY_AFTER_WRITE
-
- #ifdef VERIFY_AFTER_WRITE
- unsigned long saveAddress = Address;
- unsigned char flReadback[BLOCKS_PER_CHIP * PAGE_SIZE / sizeof(unsigned short)];
- #endif/*是否开启写后校验*/
- /*计算一个页面中偏移地址之后的空间大小*/
- LeftToWrite = PageSize - ( (unsigned short)Address & (PageSize - 1) );
- /*将buffer指针赋给temp*/
- temp = buffer;
-
- DEBUG_PRINT("NandMTDWrite: Address = 0x%x, Length = %dn", Address, Length);
-
- for( ; Length > 0 ; )
- {
- if( Length < LeftToWrite ) /* 如果要写的长度小于一个页面中偏移地址之后的空间大小 */
- {
- LeftToWrite = Length; /* 那要写的就是该长度*/
- }
- /* 如果要读的长度大于一个页面的大小,就先读一个页面 *//* turn off EDC on partial block write*/
- WriteStatus = WriteOnePage(Address,LeftToWrite,temp);
- if(WriteStatus != flOK)/*如果写错误,返回flWriteFault*/
- {
- ERROR_PRINT("NandMTDWrite:WriteErrorn");
- return flWriteFault;
- }
-
- /*写后校验*/
- #ifdef VERIFY_AFTER_WRITE
- WriteStatus = ReadOnePage (Address,flReadback,LeftToWrite));
- if( (WriteStatus != flOK) || ( tffscmp(temp, flReadback, LeftToWrite ) != 0) )/*校验数据*/
- {
- ERROR_PRINT("NandMTDWrite:VerifyErrorn");
- return flWriteFault;
- }
- #endif/*VERIFY_AFTER_WRITE*/
- /*写后校验*/
- Length = Length - LeftToWrite;/*更新长度*/
- if(Length > 0)
- {
- if(PageSize==PAGE_SIZE)/*如果是写数据区*/
- {
- Address = (Address&CHIP_MASK)+(PAGE_SIZE*2);/*页地址加1,地址变为下一页的数据区*/
- }
- else if( PageSize==SPARE_SIZE)/*如果是写空闲区*/
- {
- Address = (Address&CHIP_MASK)+(PAGE_SIZE*3);/*地址变为下一页的空闲区*/
- }
- temp = temp + LeftToWrite;/*移动指针*/
- LeftToWrite = PageSize;/*新的一页 更新LeftToWrite*/
- }
- }
- return flOK ;
- }
- /*----------------------------------------------------------------------
- * NandMTDErase
- *功能:对flash进行擦除操作。该程序将作为MTD擦除函数。
- *参数:vol-设备指针 BlockNo-块号 BlocksToErase—需要擦除的块的总数
- *返回:成功返回flOK 失败返回其他
- *20070202
- ----------------------------------------------------------------------*/
- int NandMTDErase(unsigned int BlockNo,unsigned int BlocksToErase)
- {
- unsigned int iBlock;
- unsigned int PageNo;
- if( BlockNo + BlocksToErase > BLOCKS_PER_CHIP ) /* 越界 */
- {
- ERROR_PRINT("NandMTDErase:OutOfBoundary BlockNo = %d BlocksToErase = %dn",BlockNo, BlocksToErase);
- return flBadParameter;
- }
-
- DEBUG_PRINT("firstBlock = %d, numOfBlock = %dn", BlockNo, BlocksToErase);
- for ( iBlock=0; iBlock < BlocksToErase; iBlock++, BlockNo++ )
- {
- PageNo = BlockNo*PAGES_PER_BLOCK;/*计算页号*/
- FLASH_COMMAND=BLOCK_ERASE_START;/*输入擦除命令*/
- AddressInput_3Cycle(PageNo);/*将擦除地址输入*/
- FLASH_COMMAND=BLOCK_ERASE_END;/*执行擦除*/
- /*等待芯片就绪*/
- if( WaitForReady() != flOK )
- {
- ERROR_PRINT("NandMTDErase: TimeOutn");
- return flTimeOut;
- }
- /*检查写操作是否成功*/
- if(ReadStatusForError()==ERROR)
- {
- ERROR_PRINT("NandMTDErase:EraseErrorn");
- return flEarseFault;
- }
- DEBUG_PRINT("ERASE: BlockNo = %d Erased!n", BlockNo);
- }
- return flOK;
- }
- /*----------------------------------------------------------------------
- * NoDEBUG_PRINT
- *功能:不需要打印信息时将printf指向这个空函数
- *参数:空
- *返回:无
- *20070305
- ----------------------------------------------------------------------*/
- void NoDEBUG_PRINT( const char *fmt, ... )
- {}
- /*----------------------------------------------------------------------
- * BusyGPIOInit
- *功能:初始化busy管脚所连接的GPIO
- *参数:空
- *返回:无
- *20080519
- ----------------------------------------------------------------------*/
- void BusyGPIOInit(void)
- {
- MCF_GPIO_PAR_ETPU = MCF_GPIO_PAR_ETPU & 0xfe;//LTPUODIS为GPIO功能
- MCF_GPIO_PDDR_ETPU = MCF_GPIO_PDDR_ETPU & 0xfe;//LTPUODIS为GPIO输入
- }
- /*----------------------------------------------------------------------
- * NandFlashCSConfig
- *功能:配置片选,建议将函数内容复制到hwinit.c的mcf523x_cs_init()函数中
- *参数:空
- *返回:无
- *20080519
- ----------------------------------------------------------------------*/
- void NandFlashCSConfig(void)
- {
- MCF_CS_CSAR1 = MCF_CS_CSAR_BA(0x30000000);
- MCF_CS_CSCR1 = (0
- | MCF_CS_CSCR_IWS(6)
- | MCF_CS_CSCR_AA
- | MCF_CS_CSCR_PS_8);
- MCF_CS_CSMR1 = MCF_CS_CSMR_BAM_1M | MCF_CS_CSMR_V;
- }