nandflash有并行的,有串行方式的,8脚的SPI nandflash是众多工程师的首选,不占地方容量又大,这里奉上我总结的SPI nandflash驱动程序,不包含坏块管理机制:
H源文件:
#include "stdint.h"
#define MX35LF2G14AC 1
/*** MX35 series command hex code definition ***/
//ID comands
#define FLASH_CMD_RDID 0x9F //RDID (Read Identification)
#define FLASH_CMD_GET_FEATURE 0x0F //Get features
#define FLASH_CMD_SET_FEATURE 0x1F //Set features
#define FLASH_CMD_READ 0x13 //Array Read
#define FLASH_CMD_READ_CACHE 0x03 //Read From Cache
#define FLASH_CMD_READ_CACHE2 0x3B //Read From Cache*2
#define FLASH_CMD_READ_CACHE4 0x6B //Read From Cache*4
#define FLASH_CMD_READ_CACHE_SEQUENTIAL 0x31 //Read From Cache Sequential
#define FLASH_CMD_READ_CACHE_END 0x3F //Read From Cache End
#define FLASH_CMD_WREN 0x06 //Write Enable
#define FLASH_CMD_WRDI 0x04 //Write Disable
#define FLASH_CMD_PP_LOAD 0x02 //Page Program Load
#define FLASH_CMD_PP_RAND_LOAD 0x84 //Page Program Random Input
#define FLASH_CMD_4PP_LOAD 0x32 //Quad IO Page Program Load
#define FLASH_CMD_4PP_RAND_LOAD 0x34 //Quad IO Page Program Random Input
#define FLASH_CMD_PROGRAM_EXEC 0x10 //Program Execute
#define FLASH_CMD_BE 0xD8 //BLock Erase
#define BYTE_MASK 0xFF
// system flags
#define PASS 0
#define F_FAIL 1
#define F_BUSY 0
#define READY 1
#define PROTECTED 0
#define UNPROTECTED 1
#define TIMEOUT 0
#define TIMENOTOUT 1
// Flash control register mask define
// status register
// status register [7:0]
#define SR0_OIP 0x01
#define SR1_WEL 0x02
#define SR2_EraseF_FAIL 0x04
#define SR2_ProgramF_FAIL 0x08
#ifdef MX35LF2G14AC
#define FlashID 0xB248 //0xc220
#define FlashSize 0x10000000 // 256 MiB
#endif
#define nd_page_wordsize (512)//2048+64 = 2112byte/4 = 528word
#define nd_page_bytesize (2048)// = 2112byte
// 1块数据大小
#define nd_block_wordsize (32768)//((2048)*64) = 131,072byte /4 = 32768word
#define nd_block_bytesize (131072)
uint32_t Get_nfaddr(uint32_t block);
#define GET_FLASH_ADDR Get_nfaddr
struct nandflash_addrst
{
uint32_t Col_addr :12;// bit11:bit0 => 数据地址(Col列地址)
uint32_t Page_addr :6;// bit17:bit12=> 页地址信息(最大63)
uint32_t Block_addr :11;// bit31:bit18=> 块地址信息(bit28:bit18=>11bit有效)
uint32_t Rsvd_addr :3; //保留
};
typedef union AddrMore_st
{
uint32_t all;
struct nandflash_addrst bit;
} addr_more_t;
/* Return Message */
typedef enum{
Flash_Success,
Flash_F_BUSY,
Flash_OperationTimeOut,
Flash_ProgramF_FAILed,
Flash_EraseF_FAILed,
Flash_ReadIDF_FAILed,
Flash_CmdInvalid,
Flash_DataInvalid,
Flash_AddrInvalid,
Flash_QuadNotEnable
}ReturnMsg;
// Flash status structure define
struct sFlashStatus{
/* Mode Register:
* Bit Description
* -------------------------
* 7 RYBY enable
* 6 Reserved
* 5 Reserved
* 4 Reserved
* 3 Reserved
* 2 Reserved
* 1 Parallel mode enable
* 0 QPI mode enable
*/
uint8_t ModeReg;
int ArrangeOpt;
};
C源文件:
#include "MX35_CMD.h"
//底层驱动接口
void CS_Low()
{
hdl_cs(0);
}
void CS_High()
{
hdl_cs(1);
}
uint8_t SendByte( uint8_t byte_value)
{
return hdl_Spi_Sendbyte(byte_value)&0xff;
}
/*
* Function: Reset_OP
* Arguments: None
* Return Value: Flash_Success
* Description: The reset command FFh resets the read/program/erase operation
*/
ReturnMsg CMD_RESET_OP( void )
{
CS_Low();
/* Send reset command */
SendByte( 0xFF );
CS_High();
/* Wait page program finish :等待页面程序完成*/
if(READY!=WaitFlashReady()) return Flash_F_BUSY;
else return Flash_Success;
}
/*
* Function: WaitFlashReady
* Arguments: None
* Description: If flash is ready return READY.
* If flash is time-out return TIMEOUT.
* Return Message: READY, TIMEOUT
*/
int WaitFlashReady( void ) //等待完成 1ms 超时时间
{
uint16_t last_time_tack=0;
uint16_t tick_ret=0;
uint16_t cur_time_tack =0;
last_time_tack = mde_stc_GetTick();//获取时间点
while(1)
{
if( CheckStatus( SR0_OIP ) == READY ) return READY;
cur_time_tack = mde_stc_GetTick();//获取时间点
tick_ret=cur_time_tack >= last_time_tack ? (cur_time_tack - last_time_tack)\
: (Sysms_time_MAX + cur_time_tack - last_time_tack);
if(tick_ret>3)return TIMEOUT;
}
}
/*
* Function: CheckStatus
* Arguments: CheckFlag -> the status bit to check
* Return Value: READY, F_BUSY
* Description: Check status register bit 7 ~ bit 0
*/
int CheckStatus( uint8_t CheckFlag )
{
uint8_t status;
CMD_GET_FEATURE( 0xc0, &status );
if( (status & CheckFlag) == CheckFlag )
return F_BUSY;
else
return READY;
}
/*
* Function: Get_Feature
* Arguments: addr, Set Feature Address
* StatusReg, 8 bit buffer to store Feature register value
* Description: Check Features Settings.
* Return Message: Flash_Success
*/
ReturnMsg CMD_GET_FEATURE( uint8_t addr, uint8_t *StatusReg )
{
// Chip select go low to start a flash command
CS_Low();
// Send command
SendByte( FLASH_CMD_GET_FEATURE );
//Send one byte Address
SendByte( addr );
//Get Features
*StatusReg = SendByte( 0 );
// Chip select go high to end a flash command
CS_High();
return Flash_Success;
}
/*
* Function: Set_Feature
* Arguments: addr, Set Feature Address
* value, 8 bit Feature register value to updata
* Description: Write Features Settings.
* Return Message: Flash_Success
*/
ReturnMsg CMD_SET_FEATURE( uint8_t addr, uint8_t value )
{
// Chip select go low to start a flash command
CS_Low();
// Send command
SendByte( FLASH_CMD_SET_FEATURE );
//Send one byte Address
SendByte( addr );
//Set Features
SendByte( value );
// Chip select go high to end a flash command
CS_High();
return Flash_Success;
}
/*
* Function: SendColAddr
* Arguments: Address, 16 bit col address
* wrap, wrap address bits define the four wrap length
* io_mode, I/O mode to transfer address
* Return Value: None.
* Description: Send col address
*/
void SendColAddr( uint16_t Address, uint8_t wrap ) //发送 flash 列地址信息
{
// Col_A11:A0: 页data寄存器地址
uint16_t ColAddr = Address & 0xFFFF;//12bit
ColAddr>>=8;
wrap<<=4;
/* Send 16 bit address data */
SendByte( (ColAddr & BYTE_MASK)|wrap);
SendByte( (Address & BYTE_MASK) );
}
/*
* Function: SendRowAddr
* Arguments: Address, 32 bit Row address
* io_mode, I/O mode to transfer address
* Return Value: None.
* Description: Send Row address
*/
void SendRowAddr( uint32_t Address ) //发送行地址 flash
{
/* Send 24 bit address data */
// Row_A15:A6 : 块地址
// Row_A5:A0 : 页地址
uint32_t temp = Address>>16;
SendByte(temp & BYTE_MASK);
temp = Address>>8;
SendByte(temp & BYTE_MASK);
SendByte(Address & BYTE_MASK);
}
/*
* Function: CMD_WREN
* Arguments: None
* Description: The WREN instruction is for setting rite Enable Latch
* (WEL) bit.
* Return Message: Flash_Success
*/
ReturnMsg CMD_WREN( void ) //flash 擦写使能打开
{
// Chip select go low to start a flash command
CS_Low();
// Write Enable command = 0x06, Setting Write Enable Latch Bit
SendByte( FLASH_CMD_WREN );
// Chip select go high to end a flash command
CS_High();
return Flash_Success;
}
/*
* Function: CMD_WRDI
* Arguments: None
* Description: The WRDI instruction is to reset
* Write Enable Latch (WEL) bit.
* Return Message: Flash_Success
*/
ReturnMsg CMD_WRDI( void )
{
// Chip select go low to start a flash command
CS_Low();
// Write Disable command = 0x04, resets Write Enable Latch Bit
SendByte( FLASH_CMD_WRDI );
CS_High();
return Flash_Success;
}
/*
* Function: CMD_RDID
* Arguments: Identification, 16 bit buffer to store id
* Description: The RDID instruction is to read the manufacturer ID
* of 1-byte and followed by Device ID of 1-byte.
* Return Message: Flash_F_BUSY,Flash_Success
*/
ReturnMsg CMD_RDID( uint16_t *Identification ) //获取芯片ID信息
{
uint16_t temp;
uint8_t gDataBuffer[2];
/* Check flash is F_BUSY or not */
if( CheckStatus( SR0_OIP ) != READY ) return Flash_F_BUSY;
// Chip select go low to start a flash command
CS_Low();
// Send command
SendByte( FLASH_CMD_RDID);
SendByte( 0); //哑数据
// Get manufacturer identification, device identification
gDataBuffer[0] = SendByte( 0 );
gDataBuffer[1] = SendByte( 0 );
// Chip select go high to end a command
CS_High();
// Store identification
temp = gDataBuffer[0];
temp<<=8;
*Identification = temp| gDataBuffer[1];
return Flash_Success;
}
/*
* Read Command
*/
/*
* Function: CMD_READ
* Arguments: flash_address, 32 bit flash memory address
* Description: The READ instruction is for reading data from array to cache.
* Return Message: Flash_AddrInvalid, Flash_F_BUSY, Flash_Success,Flash_OperationTimeOut
*/
ReturnMsg CMD_READ( uint32_t flash_address )
{
// Check flash address
if( flash_address> FlashSize ) return Flash_AddrInvalid;
/* Check flash is F_BUSY or not */
if( CheckStatus( SR0_OIP ) != READY ) return Flash_F_BUSY;
// Chip select go low to start a flash command
CS_Low();
// Write READ command and address
SendByte( FLASH_CMD_READ );//13H
SendRowAddr( flash_address>>12 );
// Chip select go high to end a flash command
CS_High();
/* Wait data transfer from array to cache finish */
if( WaitFlashReady() == READY )
{
return Flash_Success;
}
else
{
return Flash_OperationTimeOut;
}
}
/*
* Random Data Read Command
*/
/*
* Function: CMD_READCache
* Arguments: col_address, 16 bit flash memory address
* DataBuf, Data buffer address to store returned data
* byte_length, length of returned data in byte unit
* addr_flag, define wrap bit and Plane select bit (only for 2Gb and 4Gb)
* Description: The READCache instruction is for reading data out from cache on SO.
* Return Message: Flash_Success
*/
uint16_t CMD_READ_CACHE32bit( uint16_t col_address, uint8_t addr_flag, uint32_t * DataBuf, uint16_t word_size)
{
uint32 index;
uint32_t dat_temp =0;
uint8_t buff[4];
// Chip select go low to start a flash command
CS_Low();
// Write READ Cache command and address
SendByte( FLASH_CMD_READ_CACHE );
SendByte( 0);
SendColAddr( col_address, addr_flag );
// Set a loop to read data into buffer
if(word_size>nd_page_wordsize)word_size =nd_page_wordsize;
for( index=0; index < word_size; index++ )
{
// Read data one byte at a time
buff[0] = SendByte( 0 );
buff[1] = SendByte( 0 );
buff[2] = SendByte( 0 );
buff[3] = SendByte( 0 );
dat_temp = (uint32_t)buff[0]<<24;
dat_temp |= (uint32_t)buff[1]<<16;
dat_temp |= (uint32_t)buff[2]<<8;
dat_temp |= (uint32_t)buff[3];
*DataBuf = dat_temp;
DataBuf+=1;//2;
}
// Chip select go high to end a flash command
CS_High();
return word_size;
}
uint16_t CMD_READ_CACHE8bit( uint16_t col_address, uint8_t addr_flag, uint8_t * DataBuf, uint16_t byte_size )
{
uint16_t index;
// Chip select go low to start a flash command
CS_Low();
// Write READ Cache command and address
SendByte( FLASH_CMD_READ_CACHE );
SendByte( 0);
SendColAddr( col_address, addr_flag );
if(byte_size>nd_page_bytesize)byte_size =nd_page_bytesize;
// Set a loop to read data into buffer
for( index=0; index < byte_size; index++ )
{
// Read data one byte at a time
DataBuf[index] = SendByte( 0 );
}
// Chip select go high to end a flash command
CS_High();
return byte_size;
}
/*
* Page Read Cache Sequential Command
*/
/*
* Function: CMD_READ_CACHE_SEQUENTIAL
* Arguments: None.
* Description: The READCacheSequential instruction is for throughput enhancement
* by using the internal cache buffer.
* Return Message: Flash_F_BUSY, Flash_Success,Flash_OperationTimeOut
*/
ReturnMsg CMD_READ_CACHE_SEQUENTIAL( void )
{
// Chip select go low to start a flash command
CS_Low();
// Write READ Cache Sequential command
SendByte( FLASH_CMD_READ_CACHE_SEQUENTIAL );
// Chip select go high to end a flash command
CS_High();
/* Wait data transfer from array to cache finish */
if( WaitFlashReady() == READY )
{
return Flash_Success;
}
else
{
return Flash_OperationTimeOut;
}
}
/*
* Page Read Cache End Command
*/
/*
* Function: CMD_READ_CACHE_END
* Arguments: None.
* Description: The READCacheEnd instruction is for ending reading
* data from cache buffer.
* Return Message: Flash_F_BUSY, Flash_Success,Flash_OperationTimeOut
*/
ReturnMsg CMD_READ_CACHE_END( void )
{
// Chip select go low to start a flash command
CS_Low();
// Write READ Cache End command
SendByte( FLASH_CMD_READ_CACHE_END );
// Chip select go high to end a flash command
CS_High();
/* Wait data transfer from array to cache finish */
if( WaitFlashReady() == READY )
{
return Flash_Success;
}
else
{
return Flash_OperationTimeOut;
}
}
/*
* Program load Command
*/
/*
* Function: CMD_Program_Load
* Arguments: col_address, 16 bit col address
* DataBuf, buffer of source data to program
* byte_length, byte length of data to programm
* addr_flag, define Plane select bit (only for 2Gb and 4Gb)
* Description: load program data with cache reset first
* Return Message: Flash_F_BUSY, Flash_Success,
*/
uint16_t CMD_PP_LOAD32bit( uint16_t col_address,uint8_t addr_flag, uint32_t *DataBuf, uint16_t word_size ) //32bit页编程模式
{
uint32_t dat_temp =0;
uint8_t buff[4];
uint32_t index =0;
/* Check flash is F_BUSY or not */
if( CheckStatus( SR0_OIP ) != READY ) return Flash_F_BUSY;
//send write enable command
CMD_WREN();//flash 擦写使能打开
// Chip select go low to start a flash command
CS_Low();
/* Send program load command */
SendByte( FLASH_CMD_PP_LOAD );
/* Send flash address */
SendColAddr( col_address, addr_flag ); //发送 列地址
/* Send data to program */
if(word_size>nd_page_wordsize)word_size=nd_page_wordsize;
for(index=0;index>24)&0xff;
buff[1] = ((uint32_t)dat_temp>>16)&0xff;
buff[2] = ((uint32_t)dat_temp>>8)&0xff;
buff[3] = dat_temp&0xff;
hdl_Spi_SendNbyte(buff,4);
}
// Chip select go high to end a flash command
CS_High();
return word_size;
}
uint16_t CMD_PP_LOAD8bit( uint16_t col_address,uint8_t addr_flag, uint8_t *DataBuf, uint16_t byte_size ) //8bit 页编程模式
{
/* Check flash is F_BUSY or not */
if( CheckStatus( SR0_OIP ) != READY ) return Flash_F_BUSY;
//send write enable command
CMD_WREN();
// Chip select go low to start a flash command
CS_Low();
/* Send program load command */
SendByte( FLASH_CMD_PP_LOAD );
/* Send flash address */
SendColAddr( col_address, addr_flag );
/* Send data to program */
if(byte_size>nd_page_bytesize)byte_size=nd_page_bytesize;
hdl_Spi_SendNbyte(DataBuf,byte_size);
// Chip select go high to end a flash command
CS_High();
return byte_size;
}
/*
* Program load Random Data Command
*/
/*
* Function: CMD_Program_Load_RandData
* Arguments: col_address, 16 bit col address
* DataBuf, buffer of source data to program
* byte_length, byte length of data to programm
* addr_flag, define Plane select bit (only for 2Gb and 4Gb)
* Description: load program data without cache reset
* Return Message: Flash_Success
*/
ReturnMsg CMD_PP_RAND_LOAD( uint16_t col_address, uint8_t *DataBuf, uint32 Length, uint8_t addr_flag )
{
uint32 i;
// Chip select go low to start a flash command
CS_Low();
/* Send program load command */
SendByte( FLASH_CMD_PP_RAND_LOAD );
/* Send flash address */
SendColAddr( col_address, addr_flag );
/* Send data to program */
for( i=0; i>12 );//发送行地址
// Chip select go high to end a flash command
CS_High();
/* Wait page program finish */
if( WaitFlashReady() == READY )//等待完成 1ms 超时时间
{
/* Check program result */
CMD_GET_FEATURE( 0xc0, &status );
if( (status & SR2_ProgramF_FAIL ) == SR2_ProgramF_FAIL )
return Flash_ProgramF_FAILed;
else
return Flash_Success;
}
else
{
return Flash_OperationTimeOut;
}
}
/*
* Function: CMD_BE
* Arguments: flash_address, 32 bit flash memory address
* Description: The BE instruction is for erasing the data
* Return Message: Flash_AddrInvalid, Flash_F_BUSY, Flash_Success,
* Flash_OperationTimeOut
*/
ReturnMsg CMD_BE( uint32 flash_address ) //擦除flash
{
uint8_t status;
// Check flash address
if( flash_address > FlashSize ) return Flash_AddrInvalid;
/* Check flash is F_BUSY or not */
if( CheckStatus( SR0_OIP ) != READY ) return Flash_F_BUSY;
// Setting Write Enable Latch bit
CMD_WREN();
// Chip select go low to start a flash command
CS_Low();
//Write Block Erase command
SendByte( FLASH_CMD_BE );
SendRowAddr( flash_address>>12); //发送块地址信息
// Chip select go high to end a flash command
CS_High();
/* Wait page program finish
if( WaitFlashReady() == READY ) //等待完成 1ms超时时间
{
/* Check program result */
CMD_GET_FEATURE( 0xc0, &status );
if( (status & SR2_EraseF_FAIL ) == SR2_EraseF_FAIL )
return Flash_EraseF_FAILed;
else
return Flash_Success;
}
else
{
return Flash_OperationTimeOut;
}
}
uint32_t Get_nfaddr(uint32_t block){ return((uint32_t )block<<18);}
addr_more_t nand_flash_addr_convt(uint32_t addr) //物理地址转换
{
addr_more_t tempaddr;
addr_more_t flash_addr;
tempaddr.all = addr;
flash_addr.all =0;
flash_addr.bit.Block_addr = tempaddr.bit.Block_addr;
uint32_t temp = (2*tempaddr.bit.Page_addr);
flash_addr.all+=(temp<<12);
while(1)
{
if(tempaddr.bit.Col_addr>=nd_page_bytesize) //1 page
{
flash_addr.all+=0x1000;
tempaddr.bit.Col_addr-=nd_page_bytesize;
}
else
{
break;
}
}
flash_addr.bit.Col_addr = tempaddr.bit.Col_addr;
return flash_addr;
}
uint32_t flash_Cache_read_32bit(uint32_t addr,uint32_t *memory_addr,uint32_t word_len)
{
addr_more_t flash_addr;
ReturnMsg rets;
uint16_t err=0;
uint16_t size =0;
uint32_t len=0;
flash_addr = nand_flash_addr_convt(addr);
len =word_len;
while(len)
{
rets = CMD_RESET_OP();//rst nand flash sram
if(Flash_Success!=rets){ dbg_printf("CMD_RESET_OP err,%d\r\n",rets);return 0;}
rets = CMD_READ( flash_addr.all );
if(Flash_Success!=rets) dbg_printf("CMD_READ err,%d\r\n",rets);
if(len>nd_page_wordsize){size =nd_page_wordsize; len-=nd_page_wordsize;}
else {size = len;len=0;}
err = CMD_READ_CACHE32bit( flash_addr.all&0xffff,0, memory_addr, size);
if(err!=size){dbg_printf("read len err ,is %ld \r\n",err);return 0;}
memory_addr+=size;//*2;
flash_addr.all+=0x1000;
}
return word_len;
}
// return 0: fail ,1:ok
int nflash_Verify_data32bit(uint32_t addr ,uint32_t *cmp ,uint32_t word_len)
{
addr_more_t flash_addr;
ReturnMsg rets;
uint16_t size =0;
uint32_t len=0;
uint32 index;
uint32_t dat_temp =0;
uint8_t buff[4];
flash_addr = nand_flash_addr_convt(addr);
len =word_len;
while(len)
{
rets = CMD_RESET_OP();//rst nand flash sram
if(Flash_Success!=rets){ dbg_printf("CMD_RESET_OP err,%d\r\n",rets);return 0;}
rets = CMD_READ( flash_addr.all );
if(Flash_Success!=rets) dbg_printf("CMD_READ err,%d\r\n",rets);
if(len>nd_page_wordsize){size =nd_page_wordsize; len-=nd_page_wordsize;}
else {size = len;len=0;}
{//read
// Chip select go low to start a flash command
CS_Low();
// Write READ Cache command and address
SendByte( FLASH_CMD_READ_CACHE );
SendByte( 0);
SendColAddr( flash_addr.all&0xffff, 0 );
// Set a loop to read data into buffer
if(size>nd_page_wordsize)size =nd_page_wordsize;
for( index=0; index < size; index++ )
{
// Read data one byte at a time
buff[0] = SendByte( 0 );
buff[1] = SendByte( 0 );
buff[2] = SendByte( 0 );
buff[3] = SendByte( 0 );
dat_temp = (uint32_t)buff[0]<<24;
dat_temp |= (uint32_t)buff[1]<<16;
dat_temp |= (uint32_t)buff[2]<<8;
dat_temp |= (uint32_t)buff[3];
if(dat_temp!=cmp[0])
{
// Chip select go high to end a flash command
CS_High();
dbg_printf("src=%lx \r\n",cmp[0]);
dbg_printf("flash=%lx\r\n",dat_temp);
dbg_printf("write data fail,addr=%lx\r\n",flash_addr.all);
return 0;
}
cmp++;
}
// Chip select go high to end a flash command
CS_High();
}
flash_addr.all+=0x1000; //下一页
}
return 1;
}
//32 bit readwrite
uint32_t flash_progarm_write_32bit(uint32_t block,uint32_t *memory_addr,uint32_t word_len )
{
//1 block = (2K + 128 bytes) x 64 pages = 139,264 byte
ReturnMsg rets;
uint16_t err =0;
uint8_t st_reg1 = 0;
addr_more_t flash_addr;
uint32_t len;
uint32_t *mem_dat;
uint32_t size =0;
//step 1
rets = CMD_RESET_OP();
if(Flash_Success!=rets){ dbg_printf("CMD_RESET_OP err,%d\r\n",rets);return 0;}
/* Clear the block protection bit:*/
rets =CMD_GET_FEATURE( 0xa0, &st_reg1 );
if (st_reg1 & 0x38)
{
rets =CMD_SET_FEATURE( 0xa0, (st_reg1&0x87) );
if(Flash_Success!=rets){ dbg_printf("CMD_SET_FEATURE err,%d\r\n",rets);return 0;}
}
//step 2
flash_addr.all =0;
flash_addr.bit.Block_addr = block;
rets =CMD_BE( flash_addr.all );
if(Flash_Success!=rets) {dbg_printf("CMD_BE err,%d\r\n",rets);return 0;}
//step 3
len = (word_len>nd_block_wordsize)?nd_block_wordsize:word_len;
mem_dat = memory_addr;
while(len) //写入64个页面
{
/* Program data to flash memory */
if(len>nd_page_wordsize) {size = nd_page_wordsize;len-=nd_page_wordsize;} //确定1page 写入长度
else { size = len;len=0;}
// dbg_printf("mem : %lx \r\n",mem_dat[0]);//ok
err = CMD_PP_LOAD32bit( flash_addr.all&0xffff,0, mem_dat, size); // flash 页编程 ,一次最大写入 2176 byte
if(err!=size){dbg_printf("load pp err ,err:%ld\r\n",err);return 0;}
mem_dat+=nd_page_wordsize;//*2;
rets = CMD_PROGRAM_EXEC( flash_addr.all ); //等待写入数据生效
if(Flash_Success!=rets) dbg_printf("CMD_PROGRAM_EXEC err,%d\r\n",rets);
flash_addr.bit.Page_addr++;//页地址递增
}
CMD_WRDI(); //关闭擦写使能
// Verify data ...
len = (word_len>nd_block_wordsize)?nd_block_wordsize:word_len;
flash_addr.all =0;
flash_addr.bit.Block_addr = block; //初始化块 地址
err = nflash_Verify_data32bit(flash_addr.all,memory_addr,len);
if(err<1) return 0;
else return len;//ok
}
// 随机读取flash
uint32_t flash_Cache_read_8bit(uint32_t addr,uint8_t *memory_addr,uint32_t byte_len)
{
addr_more_t flash_addr;
ReturnMsg rets;
uint16_t err=0;
uint16_t size =0;
uint32_t len=0;
flash_addr = nand_flash_addr_convt(addr);
len =byte_len;
while(len)
{
rets = CMD_RESET_OP();//rst nand flash sram
if(Flash_Success!=rets){ dbg_printf("CMD_RESET_OP err,%d\r\n",rets);return 0;}
rets = CMD_READ( flash_addr.all );
if(Flash_Success!=rets) dbg_printf("CMD_READ err,%d\r\n",rets);
if(len>nd_page_bytesize){size =nd_page_bytesize; len-=nd_page_bytesize;}
else {size = len;len=0;}
err = CMD_READ_CACHE8bit( flash_addr.all&0xffff,0, memory_addr, size);
if(err!=size){dbg_printf("read len err ,is %ld \r\n",err);return 0;}
memory_addr+=size;
flash_addr.all+=0x1000; //下一页
}
return byte_len;
}
// return 0: fail ,1:ok
int nflash_Verify_data8bit(uint32_t addr ,uint8_t *cmp ,uint32_t byte_len)
{
addr_more_t flash_addr;
ReturnMsg rets;
uint16_t size =0;
uint32_t len=0;
uint32 index;
uint8_t dat_temp =0;
uint8_t buff8;
flash_addr = nand_flash_addr_convt(addr);
len =byte_len;
while(len)
{
rets = CMD_RESET_OP();//rst nand flash sram
if(Flash_Success!=rets){ dbg_printf("CMD_RESET_OP err,%d\r\n",rets);return 0;}
rets = CMD_READ( flash_addr.all );
if(Flash_Success!=rets) dbg_printf("CMD_READ err,%d\r\n",rets);
if(len>nd_page_bytesize){size =nd_page_bytesize; len-=nd_page_bytesize;}
else {size = len;len=0;}
{//read
// Chip select go low to start a flash command
CS_Low();
// Write READ Cache command and address
SendByte( FLASH_CMD_READ_CACHE );
SendByte( 0);
SendColAddr( flash_addr.all&0xffff, 0 );
// Set a loop to read data into buffer
if(size>nd_page_bytesize)size =nd_page_bytesize;
for( index=0; index < size; index++ )
{
// Read data one byte at a time
buff8 = SendByte( 0 )&0xff;
dat_temp = cmp[0]&0xff;cmp++;
if(dat_temp!=buff8)
{
// Chip select go high to end a flash command
CS_High();
dbg_printf("src=%lx \r\n",cmp[0]);
dbg_printf("flash=%lx\r\n",buff8);
dbg_printf("write data fail,addr=%lx\r\n",flash_addr.all);
return 0;
}
}
// Chip select go high to end a flash command
CS_High();
}
flash_addr.all+=0x1000; //下一页
}
return 1;
}
//8 bit readwrite
// 块编程 ,擦除地址按块擦除
uint32_t flash_progarm_write_8bit(uint32_t block,uint8_t *memory_addr,uint32_t byte_len )
{
//1 block = (2K + 128 bytes) x 64 pages = 139,264 byte
ReturnMsg rets;
uint8_t * pta =memory_addr;
uint16_t err =0;
uint8_t st_reg1 = 0;
addr_more_t flash_addr;
uint32_t len;
uint32_t size =0;
//step 1
/* Clear the block protection bit:清除块保护位*/
rets =CMD_GET_FEATURE( 0xa0, &st_reg1 );
if (st_reg1 & 0x38)
{
rets =CMD_SET_FEATURE( 0xa0, (st_reg1&0x87) );
if(Flash_Success!=rets){ dbg_printf("CMD_SET_FEATURE err,%d\r\n",rets);return 0;}
}
//step 2
flash_addr.all =0;
flash_addr.bit.Block_addr = block;//擦除这个块
rets =CMD_BE( flash_addr.all );
if(Flash_Success!=rets) {dbg_printf("CMD_BE err,%d\r\n",rets);return 0;}
//step 3
len = (byte_len>nd_block_bytesize)?nd_block_bytesize:byte_len;
pta = memory_addr;
while(len) //写入64个页面
{
/* Program data to flash memory */
if(len>nd_page_bytesize) {size = nd_page_bytesize;len-=nd_page_bytesize;} //确定1page 写入长度
else { size = len;len=0;}
err = CMD_PP_LOAD8bit( flash_addr.all,0, pta, size); // flash 页编程 ,一次最大写入 2176 byte
if(err!=size){dbg_printf("load pp err ,err:%ld\r\n",err);return 0;}
pta+=size;
rets = CMD_PROGRAM_EXEC( flash_addr.all ); //等待写入数据生效
if(Flash_Success!=rets) dbg_printf("CMD_PROGRAM_EXEC err,%d\r\n",rets);
flash_addr.bit.Page_addr++;//页地址递增
}
CMD_WRDI(); //关闭擦写使能
// Verify data ...
len = (byte_len>nd_block_bytesize)?nd_block_bytesize:byte_len;
flash_addr.all =0;
flash_addr.bit.Block_addr = block; //初始化块 地址
err = nflash_Verify_data8bit(flash_addr.all,memory_addr,len);
if(err<1) return 0;
else return len;//ok
}