SPI nandflash 驅動程序

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<word_size;index++)
    {
        dat_temp  = *DataBuf;DataBuf+=1;
        buff[0] = ((uint32_t)dat_temp>>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<Length; i=i+1 )
          {
        SendByte( DataBuf[i] );
          }
    // Chip select go high to end a flash command
    CS_High();
    return Flash_Success;
}


/*
 * Function:       CMD_Program_Exec
 * Arguments:      address, 32 bit flash memory address
 * Description:    Enter block/page address,no data,execute
 * Return Message: Flash_Success,Flash_OperationTimeOut
 */
ReturnMsg CMD_PROGRAM_EXEC( uint32 address )//程序執行命令 ,讓寫入數據生效
{
    uint8_t status;
    // Chip select go low to start a flash command
    CS_Low();
    /* Send program execute command */
    SendByte( FLASH_CMD_PROGRAM_EXEC ); 
    /* Send flash address */
    SendRowAddr( 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_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
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章