📄 drvserflash.c
字号:
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2006-2007 MStar Semiconductor, Inc.
// All rights reserved.
//
// Unless otherwise stipulated in writing, any and all information contained
// herein regardless in any format shall remain the sole proprietary of
// MStar Semiconductor Inc. and be kept in strict confidence
// (¨MStar Confidential Information〃) by the recipient.
// Any unauthorized act including without limitation unauthorized disclosure,
// copying, use, reproduction, sale, distribution, modification, disassembling,
// reverse engineering and compiling of the contents of MStar Confidential
// Information is unlawful and strictly prohibited. MStar hereby reserves the
// rights to any and all damages, losses, costs and expenses resulting therefrom.
//
///@file Drvflash.h
///@brief Driver interface for accessing the flash.
///
///@author MStarSemi Inc.
///
///- Providing Read/Write and Erase function for accessing the flash.
///- Support 2 types of flash: Serial flash and Parallel flash.
///- Selecting different flash type by flag, but the Driver interface for serial/parallel flash is the same.
///
///@image html flash.jpg
///
///@par Example
///@code
/// //Erase database in flash
/// //Input StartAddr:Database base address in flash
/// //Input databaseSize: database size
/// BOOL msAPI_EraseFlashDatabase(U32 StartAddr, U16 databaseSize)
/// {
/// // Erase flash from "Database Start Address" to "End address"
/// MDrv_Flash_Erase(StartAddr, StartAddr+databaseSize);
/// }
///@endcode
///
///@internal This file is for Serial flash ONLY
////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <intrins.h>
#include "hwreg.h"
#include "debug.h"
#include "datatype.h"
#include "sysinfo.h"
#include "mreg51.h"
#include "drvuart.h"
#include "drvserflash_db.h"
/******************************************************************************/
// Local functions
/******************************************************************************/
#define BUSY_BIT 7
#define USE_FAST_READ 0
#define SPI_INFO(x) // x
extern void MDrv_Timer_Delayms(U32 u32DelayTime) ;
//------------------------------------------------------------------------------
void SFSH_RIU_REG16(U8 AddrOffset, U16 Data)
{
XBYTE[ISP_BASE+AddrOffset] =LOWBYTE(Data);
XBYTE[ISP_BASE+AddrOffset+1]=HIGHBYTE(Data);
}
//------------------------------------------------------------------------------
U8 SFSH_RIU_Read8(U8 AddrOffset)
{
return( XBYTE[ISP_BASE+AddrOffset]);
}
#define RESET_SPI() (XBYTE[0x3C4D] = (XBYTE[0x3C4D] = (XBYTE[0x3C4D] | 0x01)) & ~0x01)
#define ENABLE_ISP() SFSH_RIU_REG16(REG_SFSH_ISP_PASSWORD, 0xAAAA)
#define DISABLE_ISP() do { SFSH_RIU_REG16(REG_SFSH_ISP_PASSWORD, 0x5555); RESET_SPI(); } while (0)
/*
#define ENABLE_ISP() SFSH_RIU_REG16(REG_SFSH_ISP_PASSWORD, 0xAAAA)
//#define DISABLE_ISP() SFSH_RIU_REG16(REG_SFSH_ISP_PASSWORD, 0x5555)
#define DISABLE_ISP() {\
SFSH_RIU_REG16(REG_SFSH_ISP_PASSWORD, 0x5555);\
XBYTE[0x3C4D] |= BIT0;\
XBYTE[0x3C4D] &= ~BIT0;\
}
*/
//------------------------------------------------------------------------------
#if 0
void SerialFlashDelayLoop( U8 DlyCnt )
{
U8 i;
// TODO: can this be loop delay? what happens if CPU freq changes
for ( i = 0; i <DlyCnt; i++ );
}
#endif
//------------------------------------------------------------------------------
// Wait for SPI Write Cmd Ready
// @return TRUE : succeed
// @return FALSE : fail before timeout
//------------------------------------------------------------------------------
BOOLEAN _MDrv_SerFlash_WaitWriteCmdRdy(void)
{
BOOLEAN bRet = FALSE;
//U8 DlyCnt0 = 0xff;
do
{
if ( (SFSH_RIU_Read8(REG_SFSH_SPI_WR_CMD_RDY) & 0x1) == 0x1 )
{
bRet = TRUE;
break;
}
//DlyCnt0--;
//SerialFlashDelayLoop(0xff);
} while ( 1 ); //DlyCnt0 > 0);
//if ( DlyCnt0 == 0 )
//{
// SPI_INFO(printf("_MDrv_SerFlash_WaitWriteCmdRdy time out\n"));
//}
return bRet;
}
//------------------------------------------------------------------------------
// Wait for SPI Write Data Ready
// @return TRUE : succeed
// @return FALSE : fail before timeout
//------------------------------------------------------------------------------
BOOLEAN _MDrv_SerFlash_WaitWriteDataRdy(void)
{
BOOLEAN bRet = FALSE;
//U8 DlyCnt0=0xff;
do
{
if ( (SFSH_RIU_Read8(REG_SFSH_SPI_WR_DATA_RDY) & 0x1) == 0x1 )
{
bRet = TRUE;
break;
}
//DlyCnt0--; SerialFlashDelayLoop(0xff);
} while ( 1 ); //DlyCnt0 > 0 );
if (bRet == FALSE)
{
SPI_INFO(printf("Wait for SPI Write Data Ready fails!\r\n"));
}
return bRet;
}
//------------------------------------------------------------------------------
// Wait for SPI Read Data Ready
// @return TRUE : succeed
// @return FALSE : fail before timeout
//------------------------------------------------------------------------------
BOOLEAN _MDrv_SerFlash_WaitReadDataRdy(void)
{
BOOLEAN bRet = FALSE;
//U8 DlyCnt0=0xff;
do
{
if ( (SFSH_RIU_Read8(REG_SFSH_SPI_RD_DATA_RDY) & 0x1) == 0x1 )
{
bRet = TRUE;
break;
}
//DlyCnt0--; SerialFlashDelayLoop(0x20);
} while ( 1 ); //( DlyCnt0 > 0 );
if (bRet == FALSE)
{
SPI_INFO(printf("Wait for SPI Read Data Ready fails!\r\n"));
}
return bRet;
}
//------------------------------------------------------------------------------
// Wait for Write/Erase to be done
// @return TRUE : succeed
// @return FALSE : fail before timeout
//------------------------------------------------------------------------------
BOOLEAN _MDrv_SerFlash_WaitWriteDone(void)
{
BOOLEAN bRet = FALSE;
if ( _MDrv_SerFlash_WaitWriteCmdRdy() == FALSE )
{
return FALSE;
}
do
{
SFSH_RIU_REG16(REG_SFSH_SPI_COMMAND, 0x8005); // RDSR
SFSH_RIU_REG16(REG_SFSH_SPI_RD_REQ ,0x01); // SPI read request
if ( _MDrv_SerFlash_WaitReadDataRdy() == FALSE )
{
//printf("start check..2.\r\n");
break;
}
if ( (SFSH_RIU_Read8(REG_SFSH_RDATA) & 0x1) == 0 ) //WIP =0 write done
{
bRet = TRUE;
break;
}
} while (1); // (MsOS_GetSystemTime()-u32Timer) < 100 ); //max (chip erase = 100ms, sector erase = 25ms, byte program = 20 us)
if (bRet == FALSE)
{
SPI_INFO(printf("Wait for Write to be done fails!\r\n"));
}
SFSH_RIU_REG16(REG_SFSH_SPI_CE_CLR, 1); //SPI CEB dis
return bRet;
}
//------------------------------------------------------------------------------
// Check for Write/Erase to be done
// @return TRUE : Done
// @return FALSE : Write In Progress
//------------------------------------------------------------------------------
BOOLEAN _MDrv_SerFlash_CheckWriteDone(void)
{
BOOLEAN bRet = FALSE;
if ( _MDrv_SerFlash_WaitWriteCmdRdy() == FALSE )
{
return FALSE;
}
SFSH_RIU_REG16(REG_SFSH_SPI_COMMAND, 0x8005); // RDSR
SFSH_RIU_REG16(REG_SFSH_SPI_RD_REQ ,0x01); // SPI read request
if ( _MDrv_SerFlash_WaitReadDataRdy() == FALSE )
{
//printf("start check..2.\r\n");
//break;
}
if ( (SFSH_RIU_Read8(REG_SFSH_RDATA) & 0x1) == 0 ) //WIP =0 write done
{
bRet = TRUE;
}
if (bRet == FALSE)
{
SPI_INFO(printf("Write In Progress!\r\n"));
}
SFSH_RIU_REG16(REG_SFSH_SPI_CE_CLR, 1); //SPI CEB dis
return bRet;
}
//------------------------------------------------------------------------------
/// Initialize Serial Flash
/// @return None
//------------------------------------------------------------------------------
void MDrv_SerFlash_Init(void)
{
// this could be changed depends on different flash type; should this depends on CPU freq?
// div 4 is safe even MCU runs up to 200Mhz
SFSH_RIU_REG16(REG_SFSH_SPI_CLK_DIV, 0x0004); // Div 4;
SFSH_RIU_REG16(REG_SFSH_DEV_SEL, BRAND_PMC); // PMC flash
SFSH_RIU_REG16(REG_SFSH_ENDIAN_SEL_SPI, 0); // Little-Endian
}
/******************************************************************************/
/// Write data to flash
/// @param -u32addr \b IN: Starting address in flash to write
/// @param -u32size \b IN: Total size to write
/// @param -pdat \b IN: Pointer to the data buffer which is going to be written to flash
/// @par Function Actions:
/******************************************************************************/
BOOLEAN MDrv_Flash_Write(U32 u32Addr, U32 u32Size, U8 *pu8Data)
{
BOOLEAN bRet = FALSE;
U32 u32I;
U32 u32Rem, u32WriteBytes;
#define SERFLASH_PAGE_SIZE 256
ENABLE_ISP();
u32Rem = u32Addr % SERFLASH_PAGE_SIZE;
if ( u32Rem )
{
u32WriteBytes = SERFLASH_PAGE_SIZE - u32Rem;
if ( u32Size < u32WriteBytes )
{
u32WriteBytes = u32Size;
}
if ( _MDrv_SerFlash_WaitWriteCmdRdy() == FALSE )
{
goto MDrv_SerFlash_Write_return;
}
//SFSH_RIU_REG16(REG_SFSH_SPI_COMMAND , 0x8006 ); //WREN
SFSH_RIU_REG16(REG_SFSH_SPI_COMMAND , 0x0006 ); //WREN
SFSH_RIU_REG16(REG_SFSH_ADDRESS21 , LOU16(u32Addr) );
SFSH_RIU_REG16(REG_SFSH_ADDRESS3 , HIU16(u32Addr) );
if ( _MDrv_SerFlash_WaitWriteCmdRdy() == FALSE )
{
goto MDrv_SerFlash_Write_return;
}
SFSH_RIU_REG16(REG_SFSH_SPI_COMMAND , 0x8002 ); //PAGE_PROG
for ( u32I = 0; u32I < u32WriteBytes; u32I++ )
{
SFSH_RIU_REG16(REG_SFSH_WDATA , ( 0x8000 | pu8Data[u32I] ) );
if ( _MDrv_SerFlash_WaitWriteDataRdy() == FALSE )
{
goto MDrv_SerFlash_Write_return;
}
}
SFSH_RIU_REG16(REG_SFSH_SPI_CE_CLR , 1 ); //SPI CEB dis
bRet = _MDrv_SerFlash_WaitWriteDone();
if ( bRet == TRUE )
{
u32Addr += u32WriteBytes;
pu8Data += u32WriteBytes;
u32Size -= u32WriteBytes;
}
else
{
goto MDrv_SerFlash_Write_return;
}
}
while ( u32Size )
{
if ( u32Size > SERFLASH_PAGE_SIZE )
{
u32WriteBytes = SERFLASH_PAGE_SIZE; //write EEPROM_WRITE_BYTES_MAX bytes one time
}
else
{
u32WriteBytes = u32Size;
}
if ( _MDrv_SerFlash_WaitWriteCmdRdy() == FALSE )
{
goto MDrv_SerFlash_Write_return;
}
SFSH_RIU_REG16(REG_SFSH_SPI_COMMAND , 0x8006 ); //WREN
SFSH_RIU_REG16(REG_SFSH_ADDRESS21, LOU16(u32Addr) ) ;
SFSH_RIU_REG16(REG_SFSH_ADDRESS3 , HIU16(u32Addr) );
if ( _MDrv_SerFlash_WaitWriteCmdRdy() == FALSE )
{
goto MDrv_SerFlash_Write_return;
}
SFSH_RIU_REG16(REG_SFSH_SPI_COMMAND , 0x8002 ); //PAGE_PROG
for ( u32I = 0; u32I < u32WriteBytes; u32I++ )
{
SFSH_RIU_REG16(REG_SFSH_WDATA , ( 0x8000 | pu8Data[u32I] ) );
if ( _MDrv_SerFlash_WaitWriteDataRdy() == FALSE )
{
goto MDrv_SerFlash_Write_return;
}
}
SFSH_RIU_REG16(REG_SFSH_SPI_CE_CLR , 1 ); //SPI CEB dis
bRet = _MDrv_SerFlash_WaitWriteDone();
if ( bRet == TRUE )
{
u32Addr += u32WriteBytes;
pu8Data += u32WriteBytes;
u32Size -= u32WriteBytes;
}
else
{
goto MDrv_SerFlash_Write_return;
}
}
MDrv_SerFlash_Write_return:
SFSH_RIU_REG16(REG_SFSH_SPI_CE_CLR , 1 ); //SPI CEB dis
DISABLE_ISP();
//MDrv_Timer_Delayms(5); // seven 20070808 for SPI
SPI_INFO(printf("MDrv_SerFlash_Write %x\n", bRet));
return bRet;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -