用CFlashAmd对些DBAU1200开发板的BOOT FLASH
//========================================================================
//TITLE:
// DBAU1200开发板的BOOT FLASH读写
//AUTHOR:
// norains
//DATE:
// Saturday 31-May-2008
//Environment:
// VS2005 + DBAU1200 BOARD + MIPSII SDK
//========================================================================
WinCE的一个好处就是,能够在应用程序中访问物理内存。也正是在这个基础之上,才使我们在应用程序中能够更新boot flash。
为了使用上方便,已经将flash的读写操作封装为Class,在此先看代码:
//////////////////////////////////////////////////////////////////////
// Flash.h
//
//////////////////////////////////////////////////////////////////////
namespace Flash
{
//Flash information
struct FlashInfo
{
int Bank;
int Width;
unsigned long Size; //The size of the flash
unsigned long SectorSize; //The sector size, in bytes.
unsigned long BootSectorCount;
unsigned long BootSectorSize;
unsigned long WriteBufferSize;
};
//The information of the specified flash
const FlashInfo FLASH_INFO_AM29LV256M = {2,16,0x04000000,0x10000,0,0,(16 * (16 / 8))};
};
//////////////////////////////////////////////////////////////////////
// FlashAmd.h: interface for the CFlashAmd class.
//
//Version:
// 1.1.0
//
//Date:
// 2008.05.29
//
//Description:
//
//
//////////////////////////////////////////////////////////////////////
#pragma once
#include "Flash.h"
class CFlashAmd
{
public:
//Interface
//-------------------------------------------------------------------------------------------------------
//Description:
// Erase the flash
//
//Parameters:
// ulAddressOffset : [in] The offset address to erase
// ulSize : [in] The number of byte
// bCompletion : If true, the function would return after finish erasing,or it would return immediately.
//
//-------------------------------------------------------------------------------------------------------
virtual bool EraseFlash(unsigned long ulAddressOffset,unsigned long ulSize,bool bCompletion );
//-------------------------------------------------------------------------------------------------------
//Description:
// Lock the flash
//
//Parameters:
// ulAddressOffset : [in] The offset address to lock
// ulSize : [in] The number of byte to lock
//-------------------------------------------------------------------------------------------------------
virtual void LockFlash(unsigned long ulAddressOffset,unsigned long ulSize);
//-------------------------------------------------------------------------------------------------------
//Description:
// Unlock the flash
//
//Parameters:
// ulAddressOffset : [in] The offset address to unlock
// ulSize : [in] The number of byte to unlock
//-------------------------------------------------------------------------------------------------------
virtual void UnlockFlash(unsigned long ulAddressOffset,unsigned long ulSize);
//-------------------------------------------------------------------------------------------------------
//Description:
// Read the flash
//
//Parameters:
// ulAddressOffset : [in] The offset address to read
// pDataStore : [out] The buffer for storing the data.
// ulSize : [in] The size of the buffer
//-------------------------------------------------------------------------------------------------------
virtual bool ReadFlash(unsigned long ulAddressOffset,void *pDataStore,unsigned long ulSize);
//-------------------------------------------------------------------------------------------------------
//Description:
// Wait for finishing erasing
//
//Parameters:
// ulAddressOffset : [in] The offset address to wait
//-------------------------------------------------------------------------------------------------------
virtual bool WaitForEraseComplete(unsigned long ulAddressOffset);
//-------------------------------------------------------------------------------------------------------
//Description:
// Write the data to the flash
//
//Parameters:
// ulAddressOffset : [in] The offset address to write.
// pDataWrite : [in] The data buffer to write
// ulSize : [in] The source buffer length in bytes,must be multiple of 4
// bErase : [in] If true, it would erase the block before writing.
//-------------------------------------------------------------------------------------------------------
virtual bool WriteFlash(unsigned long ulAddressOffset,const void * pDataWrite,unsigned long ulSize,bool bErase);
//-------------------------------------------------------------------------------------------------------
//Description:
// Set the flash base address
//
//Parameters:
// dwAddress : [in] The base address to set
//-------------------------------------------------------------------------------------------------------
bool SetFlashAddressBase(unsigned long ulAddress);
//-------------------------------------------------------------------------------------------------------
//Description:
// Set the flash base address
//-------------------------------------------------------------------------------------------------------
unsigned long GetFlashAddressBase(void);
//-------------------------------------------------------------------------------------------------------
//Description:
// Set the flash information
//-------------------------------------------------------------------------------------------------------
bool SetFlashInfo(const Flash::FlashInfo & flashInfo);
//-------------------------------------------------------------------------------------------------------
//Description:
// Get the flash information
//-------------------------------------------------------------------------------------------------------
const Flash::FlashInfo& GetFlashInfo();
public:
CFlashAmd(void);
~CFlashAmd(void);
private:
//-------------------------------------------------------------------------------------------------------
//Description:
// Return the base address of a FLASH bank
//
//Parameters:
// iBank : [in] Bank number (zero based)
//
//Return Values:
// Base address of the FLASH bank
//
//-------------------------------------------------------------------------------------------------------
unsigned long GetBankBaseAddress(int iBank);
//-------------------------------------------------------------------------------------------------------
//Description:
// Returns the index of the FLASH bank containing the specified address
//
//Parameters:
// ulAddr : [in] FLASH Address
//
//Return Values:
// Index of the FLASH bank containing Address
//
//-------------------------------------------------------------------------------------------------------
int GetBankIndex(unsigned long ulAddr);
//-------------------------------------------------------------------------------------------------------
//Description:
// IssueFlashCommand RESET/UNLOCK/ERASE/.....
//
//Parameters:
// ulCommand : [in] command id
// ulParam1, ulParam2 : [in] Command Dependent:
// CMDRESET: ulParam1 - FLASH Bank
// ulParam2 - Ignore
// CMDUNLOCK: ulParam1 - FLASH Bank
// ulParam2 - Ignore
// CMDERASESET: ulParam1 - FLASH Bank
// ulParam2 - Ignore
// CMDERASESECTOR: ulParam1 - FLASH Bank
// ulParam2 - Sector
// CMDPROGRAM: ulParam1 - FLASH Bank
// ulParam2 - Ignore
// CMDWRITEBUFFER: ulParam1 - Program Location
// ulParam2 - Word Count - 1. Present twice in 32bit word
// CMDCOMMITBUFFER: ulParam1 - Program Location
// ulParam2 - Ignore
//
//Return Values:
// NONE
//
//-------------------------------------------------------------------------------------------------------
void IssueFlashCommand(unsigned long ulCommand, unsigned long ulParam1, unsigned long ulParam2);
//-------------------------------------------------------------------------------------------------------
//Description:
// Get the address of the specified sector
//
//Parameters:
// iBank : [in] Bank number (zero based)
// ulSector : [in] Sector number
//
//Return Values:
// Address of the sector
//
//-------------------------------------------------------------------------------------------------------
unsigned long GetSectorAddress(int iBank, unsigned long ulSector);
//-------------------------------------------------------------------------------------------------------
//Description:
// Return the size of sector, uses GetFlashInfo().Width to handle the case of two 16bit FLASH parts in parallel to form up a 32bit word.
//
//Parameters:
// ulSector - Sector number
//
//Return Values:
// Size in bytes of the sector including both parts
//
//-------------------------------------------------------------------------------------------------------
unsigned long GetSectorSize(unsigned long ulSector);
//-------------------------------------------------------------------------------------------------------
//Description:
// Returns the index of the FLASH bank and sector containing the specified address
//
//Parameters:
// ulAddress : [in] FLASH Address
// iBank : [out] The variable to receive the Bank containing Address
// ulSector : [out] The variable to receive the Sector containing Address
//
//Return Values:
// NONE
//
//-------------------------------------------------------------------------------------------------------
void GetBankAndSectorIndex(unsigned long ulAddress, int & iBank, unsigned long & ulSector);
//-------------------------------------------------------------------------------------------------------
//Description:
// Erases the specified sector and waits until sector is completely erased.
// Typical sector erase time varies from 0.7 seconds to 15 seconds.. See data sheet
//
//Parameters:
// BYTE bSector. Sector number to be erased .. 0 denotes SA0 and 70 denotes SA70
//
//Return Values:
// True to indicate that sector has been successfully erased and flash is ready for other operation
//
//-------------------------------------------------------------------------------------------------------
bool EraseSectorWithCompletion(int iBank, unsigned long ulSector, bool bCompletion);
//-------------------------------------------------------------------------------------------------------
//Description:
// Erases the specified sector
//
//Parameters:
// iBank : [in] Bank being worked on
// ulSector : [in] Sector number to be erased
//
//Return Values:
// True to indicate that erase command has been successfully erased
//
//-------------------------------------------------------------------------------------------------------
bool EraseSector(int iBank, unsigned long ulSector);
//-------------------------------------------------------------------------------------------------------
//Description:
// Get the status of operations(write/erase) on the flash
//
//Parameters:
// ulAddress : [in] Address of the flash to check status
//
//Return Values:
// STATUSREADY flash has completed an operation and is ready for new operation0
// STATUSERASESUSPEND .. flash erase has been suspended
// STATUSTIMEOUT Time out
// STATUSBUSY Busy
// STATUSERROR Error
//
//-------------------------------------------------------------------------------------------------------
unsigned long GetFlashStatus(unsigned long ulAddress);
//-------------------------------------------------------------------------------------------------------
//Description:
// Program an entire write buffers worth of data
//
//Parameters:
//
//
//Return Values:
//
//
//-------------------------------------------------------------------------------------------------------
bool WriteFlashBuffer(unsigned long ulAddress,const void * pSrcData, unsigned long ulByteCount);
//-------------------------------------------------------------------------------------------------------
//Description:
// Write the data to the flash address base on the flash width.
//-------------------------------------------------------------------------------------------------------
bool WriteFlash(unsigned long ulAddr, unsigned long ulValue);
//-------------------------------------------------------------------------------------------------------
//Description:
// Read the flash data from the address base on the flash width.
//-------------------------------------------------------------------------------------------------------
unsigned long ReadFlash(unsigned long ulAddr);
//-------------------------------------------------------------------------------------------------------
//Description:
// Write the flash which the width is 32bit
//-------------------------------------------------------------------------------------------------------
bool WriteFlash32(unsigned long ulAddr, unsigned long ulValue);
//-------------------------------------------------------------------------------------------------------
//Description:
// Read the flash which the width is 32bit
//-------------------------------------------------------------------------------------------------------
unsigned long ReadFlash32(unsigned long ulAddr);
//-------------------------------------------------------------------------------------------------------
//Description:
// Write the flash which the width is 16bit
//-------------------------------------------------------------------------------------------------------
bool WriteFlash16(unsigned long ulAddr, unsigned long ulValue);
//-------------------------------------------------------------------------------------------------------
//Description:
// Read the flash which the width is 16bit
//-------------------------------------------------------------------------------------------------------
unsigned short ReadFlash16(unsigned long ulAddr);
private:
unsigned long m_ulAddressBase;
Flash::FlashInfo m_FlashInfo;
};
//////////////////////////////////////////////////////////////////////
// FlashAmd.cpp
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "FlashAmd.h"
//------------------------------------------------------------------------------------------------------
//Macro define
// AMD Specifics
#define LATCH_OFFSET1 (0x555 * (GetFlashInfo().Width / 8))
#define LATCH_OFFSET2 (0x2AA * (GetFlashInfo().Width / 8))
#define LATCH_UNLOCKBYPASS (0xBA * (GetFlashInfo().Width / 8))
#define AMD_UNLOCK1 0x00AA00AA
#define AMD_UNLOCK2 0x00550055
#define AMD_AUTOSELECT32 0x00900090
#define AMD_RESET32 0x00F000F0
#define AMD_ERASESET 0x00800080
#define AMD_ERASESECTOR 0x00300030
#define AMD_SUSPENDERASE 0x00B000B0
#define AMD_RESUMEERASE 0x00300030
#define AMD_PROGRAM 0x00A000A0
#define AMD_PROGRAMBUFFER 0x00250025
#define AMD_UNLOCKBYPASS 0x00200020
#define AMD_UNLOCKBYPASSPROGRAM 0x00A000A0
#define AMD_UNLOCKBYPASSRESET1 0x00900090
#define AMD_UNLOCKBYPASSRESET2 0x00000000
#define AMD_CHIPERASE 0x00100010
#define AMD_COMMITBUFFER 0x00290029
// defines for GetFlashStatus() function
#define STATUS_READY 0x00000000
#define STATUS_ERASESUSPEND 0x00040004 // DQ2
#define STATUS_TIMEOUTVALUE 0x00200020 // DQ5
#define STATUS_TOGGLEVALUE 0x00400040 // DQ6 - toggle bit one
//Flash status
enum FlashStatus
{
STATUSREADY = 100,
STATUSERASESUSPEND = 101,
STATUSTIMEOUT = 102,
STATUSBUSY = 103,
STATUSERROR = 104
};
// Flash Commands
enum FlashCommand
{
CMDRESET = 0x1000,
CMDUNLOCK = 0x1001,
CMDAUTOSELECT = 0x1002,
CMDERASESET = 0x1003,
CMDERASESECTOR = 0x1004,
CMDSUSPENDERASE = 0x1005,
CMDRESUMEERASE = 0x1006,
CMDPROGRAM = 0x1007,
CMDUNLOCKBYPASSSET = 0x1008,
CMDUNLOCKBYPASSRESET = 0x1009,
CMDCHIPERASE = 0x1010,
CMDREADIDCODES = 0x1011,
CMDCLEARSTATUS = 0x1012,
CMDREADSTATUS = 0x1013,
CMDWRITEWORD = 0x1014,
CMDWRITEBUFFER = 0x1015,
CMDCOMMITBUFFER = 0x1016
};
//------------------------------------------------------------------------------------------------------
CFlashAmd::CFlashAmd(void):
m_ulAddressBase(0)
{
}
CFlashAmd::~CFlashAmd(void)
{
}
bool CFlashAmd::EraseFlash(unsigned long ulAddressOffset,unsigned long ulSize,bool bCompletion )
{
unsigned long ulBeginAddr = GetFlashAddressBase() + ulAddressOffset;
if(ulBeginAddr + ulSize - 1 > GetFlashAddressBase() + GetFlashInfo().Size)
{
return false;
}
unsigned long ulEndAddr = ulBeginAddr + ulSize - 1;
unsigned long ulCurAddr = ulBeginAddr;
//
// erase the sectors in this range
//
for (int i = 0; i < GetFlashInfo().Bank; i ++)
{
IssueFlashCommand(CMDRESET, i, 0);
}
int iBank = 0;
unsigned long ulSector = 0;
do{
GetBankAndSectorIndex(ulCurAddr, iBank, ulSector);
EraseSectorWithCompletion(iBank, ulSector, bCompletion);
ulCurAddr += GetSectorSize(ulSector);
}
while (ulCurAddr < ulEndAddr);
// Verify Erase
for (unsigned i = 0;i < ulSize; i += 4)
{
unsigned long ulTemp = ReadFlash32(ulBeginAddr + i);
if (0xFFFFFFFF != ulTemp)
{
return false;
}
}
return true;
}
void CFlashAmd::LockFlash(unsigned long ulAddressOffset,unsigned long ulSize)
{
return ;
}
void CFlashAmd::UnlockFlash(unsigned long ulAddressOffset,unsigned long ulSize)
{
return ;
}
bool CFlashAmd::ReadFlash(unsigned long ulAddressOffset,void *pDataStore,unsigned long ulSize)
{
unsigned long ulAddrRead = ulAddressOffset + GetFlashAddressBase();;
int iBank = GetBankIndex(ulAddrRead);
IssueFlashCommand(CMDRESET, iBank, 0);
while (ulSize --)
{
(reinterpret_cast<unsigned char *> (pDataStore))[ulSize] = *(reinterpret_cast<unsigned char *>(ulAddrRead + ulSize));
}
return true;
}
bool CFlashAmd::WaitForEraseComplete(unsigned long ulAddressOffset)
{
unsigned long ulAddr = GetFlashAddressBase() + ulAddressOffset;
return (GetFlashStatus(ulAddr) != 0 );
}
bool CFlashAmd::WriteFlash(unsigned long ulAddressOffset,const void * pDataWrite,unsigned long ulSize,bool bErase)
{
unsigned long ulAddr = ulAddressOffset + GetFlashAddressBase();
bool bResult = true;
// Check parameters...
if (ulAddressOffset + ulSize - 1 > GetFlashInfo().Size)
{
return false;
}
// Round up to whole word
if (ulSize & 0x3)
{
ulSize += ulSize % 4;
}
int iBank = GetBankIndex(ulAddr);
IssueFlashCommand(CMDRESET, iBank, 0);
// Firstly check that is is erased
if (!bErase)
{
for (unsigned long i = 0; i < ulSize; i ++)
{
if (0xff != *(reinterpret_cast<unsigned char *>(ulAddr + i)))
{
bResult = FALSE;
goto EXIT;
}
}
}
if (bErase)
{
// Erase the area before write
EraseFlash(ulAddressOffset,ulSize,true);
}
// Get to next buffer boundary
const unsigned long * pulData = reinterpret_cast<const unsigned long *>(pDataWrite);
while (ulSize && (ulAddr & (GetFlashInfo().WriteBufferSize - 1)) && bResult)
{
bResult = WriteFlash32(ulAddr, *pulData);
ulSize -= 4;
ulAddr += 4;
pulData ++;
}
IssueFlashCommand(CMDRESET, iBank, 0);
// Round Size up to multiple of 4 bytes
ulSize = (ulSize+3) & ~0x3;
while (ulSize && bResult)
{
unsigned long ulCopySize;
// GetFlashInfo().WriteBufferSize specifies the number of bytes of write buffer
ulCopySize = min(ulSize, GetFlashInfo().WriteBufferSize);
bResult = WriteFlashBuffer(ulAddr, pulData, ulCopySize);
//Sleep(5);//norains.Maybe don't finish writing.
ulSize -= ulCopySize;
ulAddr += ulCopySize;
pulData = &pulData[ulCopySize / 4];
}
EXIT:
return bResult;
}
unsigned long CFlashAmd::GetBankBaseAddress(int iBank)
{
return GetFlashAddressBase() + ( ( GetFlashInfo().Size / GetFlashInfo().Bank) * iBank);
}
int CFlashAmd::GetBankIndex(unsigned long ulAddr)
{
int iBank;
for(iBank = GetFlashInfo().Bank - 1; iBank >= 0; iBank--)
{
if(ulAddr >= GetBankBaseAddress(iBank))
{
break;
}
}
return iBank;
}
void CFlashAmd::IssueFlashCommand(unsigned long ulCommand, unsigned long ulParam1, unsigned long ulParam2)
{
unsigned long ulAddr; // will hold address of the flash
switch (ulCommand)
{
case CMDRESET:
ulAddr = GetBankBaseAddress(ulParam1);
WriteFlash(ulAddr, AMD_RESET32); // Set the Device to Read Mode
break;
case CMDUNLOCK:
ulAddr = GetBankBaseAddress(ulParam1);
WriteFlash(ulAddr + LATCH_OFFSET1, AMD_UNLOCK1);
WriteFlash(ulAddr + LATCH_OFFSET2, AMD_UNLOCK2);
break;
case CMDERASESET:
ulAddr = GetBankBaseAddress(ulParam1);
WriteFlash(ulAddr + LATCH_OFFSET1, AMD_ERASESET);
break;
case CMDERASESECTOR:
ulAddr = GetSectorAddress(ulParam1,ulParam2);
WriteFlash(ulAddr, AMD_ERASESECTOR); // issue erase sector command
break;
case CMDPROGRAM:
ulAddr = GetBankBaseAddress(ulParam1);
WriteFlash(ulAddr + LATCH_OFFSET1, AMD_PROGRAM);
break;
case CMDWRITEBUFFER:
WriteFlash(ulParam1, AMD_PROGRAMBUFFER);
WriteFlash(ulParam1, ulParam2); // word count - 1
break;
case CMDCOMMITBUFFER:
WriteFlash(ulParam1, AMD_COMMITBUFFER);
break;
default:
break;
}
}
unsigned long CFlashAmd::GetSectorAddress(int iBank, unsigned long ulSector)
{
unsigned long ulSectorAddr;
ulSectorAddr = GetBankBaseAddress(iBank);
for (unsigned long i=0; i < ulSector; i ++)
{
ulSectorAddr += GetSectorSize(ulSector);
}
return ulSectorAddr;
}
unsigned long CFlashAmd::GetSectorSize(unsigned long ulSector)
{
unsigned long ulSectorSize;
if (ulSector < GetFlashInfo().BootSectorCount)
{
ulSectorSize = GetFlashInfo().BootSectorSize;
}
else
{
ulSectorSize = GetFlashInfo().SectorSize;
}
return ulSectorSize * (GetFlashInfo().Width / 16);
}
void CFlashAmd::GetBankAndSectorIndex(unsigned long ulAddress, int & iBank, unsigned long & ulSector)
{
//Reset
iBank = 0;
ulSector = 0;
// Find the Bank number first
for (iBank = GetFlashInfo().Bank - 1; iBank >= 0; iBank --)
{
if (ulAddress >= GetBankBaseAddress(iBank))
{
break;
}
}
// Now work out the sector number
while (ulAddress >= GetSectorAddress(iBank,ulSector))
{
ulSector ++;
}
ulSector --;
}
bool CFlashAmd::EraseSectorWithCompletion(int iBank, unsigned long ulSector, bool bCompletion)
{
unsigned long ulAddr = GetSectorAddress(iBank, ulSector);
EraseSector(iBank, ulSector);
unsigned long ulStatus;
if (bCompletion)
{
// wait until flash state machine is ready for other operation
ulStatus = GetFlashStatus(ulAddr);
}
else
{
ulStatus = STATUSREADY;
}
return (ulStatus == STATUSREADY);
}
bool CFlashAmd::EraseSector(int iBank, unsigned long ulSector)
{
IssueFlashCommand(CMDUNLOCK, iBank, 0); // issue unlock command // no data to write
IssueFlashCommand(CMDERASESET, iBank, 0); // // erase setup command
IssueFlashCommand(CMDUNLOCK, iBank, 0);
IssueFlashCommand(CMDERASESECTOR, iBank, ulSector); // issue erase sector command
return true;
}
unsigned long CFlashAmd::GetFlashStatus(unsigned long ulAddress)
{
unsigned long ulStatus;
int iBank = GetBankIndex(ulAddress);
// Two consecutive reads to check if bits are toggling
unsigned long ulOldRead = ReadFlash(ulAddress);
unsigned long ulNewRead = ReadFlash(ulAddress);
//The timeout value
unsigned long ulStatusTimeoutValue = STATUS_TIMEOUTVALUE;
if(GetFlashInfo().Width == 16)
{
ulStatusTimeoutValue &= 0xFFFF;
}
do {
// XOR to see if bits toggled
ulStatus = ulOldRead ^ ulNewRead;
if (0 == (ulStatus & STATUS_TOGGLEVALUE))
{
ulStatus = STATUSREADY;
break;
}
if ((ulNewRead & ulStatusTimeoutValue) == ulStatusTimeoutValue)
{
ulNewRead = ReadFlash(ulAddress);
ulOldRead = ReadFlash(ulAddress);
ulStatus = ulOldRead ^ ulNewRead;
if (0 == (ulStatus & STATUS_TOGGLEVALUE))
{
ulStatus = STATUSREADY;
break;
}
ulStatus = STATUSTIMEOUT;
IssueFlashCommand(CMDRESET,iBank,0);
break;
}
ulOldRead = ulNewRead;
ulNewRead = ReadFlash(ulAddress);
} while(true);
return ulStatus;
}
bool CFlashAmd::WriteFlashBuffer(unsigned long ulAddress,const void * pSrcData, unsigned long ulByteCount)
{
if ((ulByteCount & 3) || (0 == ulByteCount))
{
//Flash Write buffer requires a whole multiple of words
return false;
}
//
// issue Program Command
// The Write buffer is GetFlashInfo().width entries deep
// With 2 chips it is 32 bits wide
unsigned long ulSize = (ulByteCount / (GetFlashInfo().Width / 8));
int iBank = GetBankIndex(ulAddress);
IssueFlashCommand(CMDUNLOCK, iBank, 0);
IssueFlashCommand(CMDWRITEBUFFER, ulAddress, ulSize - 1 |((ulSize - 1) << 16));
while (ulSize--)
{
if(GetFlashInfo().Width == 16)
{
WriteFlash(ulAddress, *(reinterpret_cast<const unsigned short *>(pSrcData)));
}
else if(GetFlashInfo().Width == 32)
{
WriteFlash(ulAddress, *(reinterpret_cast<const unsigned long *>(pSrcData)));
}
ulAddress = ulAddress + (GetFlashInfo().Width / 8);
if(GetFlashInfo().Width == 16)
{
pSrcData = reinterpret_cast<const void *>(reinterpret_cast<const unsigned short *>(pSrcData) + 1);
}
else if(GetFlashInfo().Width == 32)
{
pSrcData = reinterpret_cast<const void *>(reinterpret_cast<const unsigned long *>(pSrcData) + 1 );
}
}
ulAddress = ulAddress - (GetFlashInfo().Width / 8);
IssueFlashCommand(CMDCOMMITBUFFER, ulAddress, 0);
// wait until flash is ready to accept new command
unsigned long ulStatus = GetFlashStatus(ulAddress);
return (ulStatus != STATUSTIMEOUT);
}
bool CFlashAmd::SetFlashAddressBase(unsigned long ulAddress)
{
m_ulAddressBase = ulAddress;
return true;
}
unsigned long CFlashAmd::GetFlashAddressBase(void)
{
return m_ulAddressBase;
}
bool CFlashAmd::SetFlashInfo(const Flash::FlashInfo & flashInfo)
{
m_FlashInfo = flashInfo;
return true;
}
const Flash::FlashInfo & CFlashAmd::GetFlashInfo(void)
{
return m_FlashInfo;
}
bool CFlashAmd::WriteFlash32(unsigned long ulAddr, unsigned long ulValue)
{
*(volatile unsigned long * const)(ulAddr) = (ulValue);
__asm("sync");
return (*(volatile unsigned long * const)(ulAddr) == (ulValue));
}
unsigned long CFlashAmd::ReadFlash32(unsigned long ulAddr)
{
return *(volatile unsigned long * const)(ulAddr);
}
bool CFlashAmd::WriteFlash16(unsigned long ulAddr, unsigned long ulValue)
{
*(volatile unsigned short * const)(ulAddr) = static_cast<unsigned short>( (ulValue) & 0xFFFF);
__asm("sync");
return (*(volatile unsigned short * const)(ulAddr) == static_cast<unsigned short>( (ulValue) & 0xFFFF));
}
unsigned short CFlashAmd::ReadFlash16(unsigned long ulAddr)
{
return *(volatile unsigned short * const)(ulAddr);
}
bool CFlashAmd::WriteFlash(unsigned long ulAddr, unsigned long ulValue)
{
switch(m_FlashInfo.Width)
{
case 16:
WriteFlash16(ulAddr,ulValue);
break;
case 32:
WriteFlash32(ulAddr,ulValue);
break;
default:
return false;
}
return true;
}
unsigned long CFlashAmd::ReadFlash(unsigned long ulAddr)
{
switch(m_FlashInfo.Width)
{
case 16:
return ReadFlash16(ulAddr);
break;
case 32:
return ReadFlash32(ulAddr); ;
default:
return 0;
}
}
CFlashAmd主要限制于DBAU1200的开发板,并且该板子上的FLASH型号为AM29LV256M。
如果条件具备,那么让我们看看如何烧写flash吧。
CFlashAmd flashAmd;
//设置flash型号
flashAmd.SetFlashInfo(Flash::FLASH_INFO_AM29LV256M);
//设置flash的起始地址。在开发板中,FLASH的起始地址为0xBC000000。
flashAmd.SetFlashAddressBase(0xBC000000);
...
//烧写FLASH。在这里注意的是,地址为偏移地址。该偏移地址是相对于之前通过SetFlashAddressBase所设置的地址。
flashAmd.WriteFlash(dwOffsetAddr,&vtStore[0],vtStore.size(),true);
//TITLE:
// DBAU1200开发板的BOOT FLASH读写
//AUTHOR:
// norains
//DATE:
// Saturday 31-May-2008
//Environment:
// VS2005 + DBAU1200 BOARD + MIPSII SDK
//========================================================================
WinCE的一个好处就是,能够在应用程序中访问物理内存。也正是在这个基础之上,才使我们在应用程序中能够更新boot flash。
为了使用上方便,已经将flash的读写操作封装为Class,在此先看代码:
//////////////////////////////////////////////////////////////////////
// Flash.h
//
//////////////////////////////////////////////////////////////////////
namespace Flash
{
//Flash information
struct FlashInfo
{
int Bank;
int Width;
unsigned long Size; //The size of the flash
unsigned long SectorSize; //The sector size, in bytes.
unsigned long BootSectorCount;
unsigned long BootSectorSize;
unsigned long WriteBufferSize;
};
//The information of the specified flash
const FlashInfo FLASH_INFO_AM29LV256M = {2,16,0x04000000,0x10000,0,0,(16 * (16 / 8))};
};
//////////////////////////////////////////////////////////////////////
// FlashAmd.h: interface for the CFlashAmd class.
//
//Version:
// 1.1.0
//
//Date:
// 2008.05.29
//
//Description:
//
//
//////////////////////////////////////////////////////////////////////
#pragma once
#include "Flash.h"
class CFlashAmd
{
public:
//Interface
//-------------------------------------------------------------------------------------------------------
//Description:
// Erase the flash
//
//Parameters:
// ulAddressOffset : [in] The offset address to erase
// ulSize : [in] The number of byte
// bCompletion : If true, the function would return after finish erasing,or it would return immediately.
//
//-------------------------------------------------------------------------------------------------------
virtual bool EraseFlash(unsigned long ulAddressOffset,unsigned long ulSize,bool bCompletion );
//-------------------------------------------------------------------------------------------------------
//Description:
// Lock the flash
//
//Parameters:
// ulAddressOffset : [in] The offset address to lock
// ulSize : [in] The number of byte to lock
//-------------------------------------------------------------------------------------------------------
virtual void LockFlash(unsigned long ulAddressOffset,unsigned long ulSize);
//-------------------------------------------------------------------------------------------------------
//Description:
// Unlock the flash
//
//Parameters:
// ulAddressOffset : [in] The offset address to unlock
// ulSize : [in] The number of byte to unlock
//-------------------------------------------------------------------------------------------------------
virtual void UnlockFlash(unsigned long ulAddressOffset,unsigned long ulSize);
//-------------------------------------------------------------------------------------------------------
//Description:
// Read the flash
//
//Parameters:
// ulAddressOffset : [in] The offset address to read
// pDataStore : [out] The buffer for storing the data.
// ulSize : [in] The size of the buffer
//-------------------------------------------------------------------------------------------------------
virtual bool ReadFlash(unsigned long ulAddressOffset,void *pDataStore,unsigned long ulSize);
//-------------------------------------------------------------------------------------------------------
//Description:
// Wait for finishing erasing
//
//Parameters:
// ulAddressOffset : [in] The offset address to wait
//-------------------------------------------------------------------------------------------------------
virtual bool WaitForEraseComplete(unsigned long ulAddressOffset);
//-------------------------------------------------------------------------------------------------------
//Description:
// Write the data to the flash
//
//Parameters:
// ulAddressOffset : [in] The offset address to write.
// pDataWrite : [in] The data buffer to write
// ulSize : [in] The source buffer length in bytes,must be multiple of 4
// bErase : [in] If true, it would erase the block before writing.
//-------------------------------------------------------------------------------------------------------
virtual bool WriteFlash(unsigned long ulAddressOffset,const void * pDataWrite,unsigned long ulSize,bool bErase);
//-------------------------------------------------------------------------------------------------------
//Description:
// Set the flash base address
//
//Parameters:
// dwAddress : [in] The base address to set
//-------------------------------------------------------------------------------------------------------
bool SetFlashAddressBase(unsigned long ulAddress);
//-------------------------------------------------------------------------------------------------------
//Description:
// Set the flash base address
//-------------------------------------------------------------------------------------------------------
unsigned long GetFlashAddressBase(void);
//-------------------------------------------------------------------------------------------------------
//Description:
// Set the flash information
//-------------------------------------------------------------------------------------------------------
bool SetFlashInfo(const Flash::FlashInfo & flashInfo);
//-------------------------------------------------------------------------------------------------------
//Description:
// Get the flash information
//-------------------------------------------------------------------------------------------------------
const Flash::FlashInfo& GetFlashInfo();
public:
CFlashAmd(void);
~CFlashAmd(void);
private:
//-------------------------------------------------------------------------------------------------------
//Description:
// Return the base address of a FLASH bank
//
//Parameters:
// iBank : [in] Bank number (zero based)
//
//Return Values:
// Base address of the FLASH bank
//
//-------------------------------------------------------------------------------------------------------
unsigned long GetBankBaseAddress(int iBank);
//-------------------------------------------------------------------------------------------------------
//Description:
// Returns the index of the FLASH bank containing the specified address
//
//Parameters:
// ulAddr : [in] FLASH Address
//
//Return Values:
// Index of the FLASH bank containing Address
//
//-------------------------------------------------------------------------------------------------------
int GetBankIndex(unsigned long ulAddr);
//-------------------------------------------------------------------------------------------------------
//Description:
// IssueFlashCommand RESET/UNLOCK/ERASE/.....
//
//Parameters:
// ulCommand : [in] command id
// ulParam1, ulParam2 : [in] Command Dependent:
// CMDRESET: ulParam1 - FLASH Bank
// ulParam2 - Ignore
// CMDUNLOCK: ulParam1 - FLASH Bank
// ulParam2 - Ignore
// CMDERASESET: ulParam1 - FLASH Bank
// ulParam2 - Ignore
// CMDERASESECTOR: ulParam1 - FLASH Bank
// ulParam2 - Sector
// CMDPROGRAM: ulParam1 - FLASH Bank
// ulParam2 - Ignore
// CMDWRITEBUFFER: ulParam1 - Program Location
// ulParam2 - Word Count - 1. Present twice in 32bit word
// CMDCOMMITBUFFER: ulParam1 - Program Location
// ulParam2 - Ignore
//
//Return Values:
// NONE
//
//-------------------------------------------------------------------------------------------------------
void IssueFlashCommand(unsigned long ulCommand, unsigned long ulParam1, unsigned long ulParam2);
//-------------------------------------------------------------------------------------------------------
//Description:
// Get the address of the specified sector
//
//Parameters:
// iBank : [in] Bank number (zero based)
// ulSector : [in] Sector number
//
//Return Values:
// Address of the sector
//
//-------------------------------------------------------------------------------------------------------
unsigned long GetSectorAddress(int iBank, unsigned long ulSector);
//-------------------------------------------------------------------------------------------------------
//Description:
// Return the size of sector, uses GetFlashInfo().Width to handle the case of two 16bit FLASH parts in parallel to form up a 32bit word.
//
//Parameters:
// ulSector - Sector number
//
//Return Values:
// Size in bytes of the sector including both parts
//
//-------------------------------------------------------------------------------------------------------
unsigned long GetSectorSize(unsigned long ulSector);
//-------------------------------------------------------------------------------------------------------
//Description:
// Returns the index of the FLASH bank and sector containing the specified address
//
//Parameters:
// ulAddress : [in] FLASH Address
// iBank : [out] The variable to receive the Bank containing Address
// ulSector : [out] The variable to receive the Sector containing Address
//
//Return Values:
// NONE
//
//-------------------------------------------------------------------------------------------------------
void GetBankAndSectorIndex(unsigned long ulAddress, int & iBank, unsigned long & ulSector);
//-------------------------------------------------------------------------------------------------------
//Description:
// Erases the specified sector and waits until sector is completely erased.
// Typical sector erase time varies from 0.7 seconds to 15 seconds.. See data sheet
//
//Parameters:
// BYTE bSector. Sector number to be erased .. 0 denotes SA0 and 70 denotes SA70
//
//Return Values:
// True to indicate that sector has been successfully erased and flash is ready for other operation
//
//-------------------------------------------------------------------------------------------------------
bool EraseSectorWithCompletion(int iBank, unsigned long ulSector, bool bCompletion);
//-------------------------------------------------------------------------------------------------------
//Description:
// Erases the specified sector
//
//Parameters:
// iBank : [in] Bank being worked on
// ulSector : [in] Sector number to be erased
//
//Return Values:
// True to indicate that erase command has been successfully erased
//
//-------------------------------------------------------------------------------------------------------
bool EraseSector(int iBank, unsigned long ulSector);
//-------------------------------------------------------------------------------------------------------
//Description:
// Get the status of operations(write/erase) on the flash
//
//Parameters:
// ulAddress : [in] Address of the flash to check status
//
//Return Values:
// STATUSREADY flash has completed an operation and is ready for new operation0
// STATUSERASESUSPEND .. flash erase has been suspended
// STATUSTIMEOUT Time out
// STATUSBUSY Busy
// STATUSERROR Error
//
//-------------------------------------------------------------------------------------------------------
unsigned long GetFlashStatus(unsigned long ulAddress);
//-------------------------------------------------------------------------------------------------------
//Description:
// Program an entire write buffers worth of data
//
//Parameters:
//
//
//Return Values:
//
//
//-------------------------------------------------------------------------------------------------------
bool WriteFlashBuffer(unsigned long ulAddress,const void * pSrcData, unsigned long ulByteCount);
//-------------------------------------------------------------------------------------------------------
//Description:
// Write the data to the flash address base on the flash width.
//-------------------------------------------------------------------------------------------------------
bool WriteFlash(unsigned long ulAddr, unsigned long ulValue);
//-------------------------------------------------------------------------------------------------------
//Description:
// Read the flash data from the address base on the flash width.
//-------------------------------------------------------------------------------------------------------
unsigned long ReadFlash(unsigned long ulAddr);
//-------------------------------------------------------------------------------------------------------
//Description:
// Write the flash which the width is 32bit
//-------------------------------------------------------------------------------------------------------
bool WriteFlash32(unsigned long ulAddr, unsigned long ulValue);
//-------------------------------------------------------------------------------------------------------
//Description:
// Read the flash which the width is 32bit
//-------------------------------------------------------------------------------------------------------
unsigned long ReadFlash32(unsigned long ulAddr);
//-------------------------------------------------------------------------------------------------------
//Description:
// Write the flash which the width is 16bit
//-------------------------------------------------------------------------------------------------------
bool WriteFlash16(unsigned long ulAddr, unsigned long ulValue);
//-------------------------------------------------------------------------------------------------------
//Description:
// Read the flash which the width is 16bit
//-------------------------------------------------------------------------------------------------------
unsigned short ReadFlash16(unsigned long ulAddr);
private:
unsigned long m_ulAddressBase;
Flash::FlashInfo m_FlashInfo;
};
//////////////////////////////////////////////////////////////////////
// FlashAmd.cpp
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "FlashAmd.h"
//------------------------------------------------------------------------------------------------------
//Macro define
// AMD Specifics
#define LATCH_OFFSET1 (0x555 * (GetFlashInfo().Width / 8))
#define LATCH_OFFSET2 (0x2AA * (GetFlashInfo().Width / 8))
#define LATCH_UNLOCKBYPASS (0xBA * (GetFlashInfo().Width / 8))
#define AMD_UNLOCK1 0x00AA00AA
#define AMD_UNLOCK2 0x00550055
#define AMD_AUTOSELECT32 0x00900090
#define AMD_RESET32 0x00F000F0
#define AMD_ERASESET 0x00800080
#define AMD_ERASESECTOR 0x00300030
#define AMD_SUSPENDERASE 0x00B000B0
#define AMD_RESUMEERASE 0x00300030
#define AMD_PROGRAM 0x00A000A0
#define AMD_PROGRAMBUFFER 0x00250025
#define AMD_UNLOCKBYPASS 0x00200020
#define AMD_UNLOCKBYPASSPROGRAM 0x00A000A0
#define AMD_UNLOCKBYPASSRESET1 0x00900090
#define AMD_UNLOCKBYPASSRESET2 0x00000000
#define AMD_CHIPERASE 0x00100010
#define AMD_COMMITBUFFER 0x00290029
// defines for GetFlashStatus() function
#define STATUS_READY 0x00000000
#define STATUS_ERASESUSPEND 0x00040004 // DQ2
#define STATUS_TIMEOUTVALUE 0x00200020 // DQ5
#define STATUS_TOGGLEVALUE 0x00400040 // DQ6 - toggle bit one
//Flash status
enum FlashStatus
{
STATUSREADY = 100,
STATUSERASESUSPEND = 101,
STATUSTIMEOUT = 102,
STATUSBUSY = 103,
STATUSERROR = 104
};
// Flash Commands
enum FlashCommand
{
CMDRESET = 0x1000,
CMDUNLOCK = 0x1001,
CMDAUTOSELECT = 0x1002,
CMDERASESET = 0x1003,
CMDERASESECTOR = 0x1004,
CMDSUSPENDERASE = 0x1005,
CMDRESUMEERASE = 0x1006,
CMDPROGRAM = 0x1007,
CMDUNLOCKBYPASSSET = 0x1008,
CMDUNLOCKBYPASSRESET = 0x1009,
CMDCHIPERASE = 0x1010,
CMDREADIDCODES = 0x1011,
CMDCLEARSTATUS = 0x1012,
CMDREADSTATUS = 0x1013,
CMDWRITEWORD = 0x1014,
CMDWRITEBUFFER = 0x1015,
CMDCOMMITBUFFER = 0x1016
};
//------------------------------------------------------------------------------------------------------
CFlashAmd::CFlashAmd(void):
m_ulAddressBase(0)
{
}
CFlashAmd::~CFlashAmd(void)
{
}
bool CFlashAmd::EraseFlash(unsigned long ulAddressOffset,unsigned long ulSize,bool bCompletion )
{
unsigned long ulBeginAddr = GetFlashAddressBase() + ulAddressOffset;
if(ulBeginAddr + ulSize - 1 > GetFlashAddressBase() + GetFlashInfo().Size)
{
return false;
}
unsigned long ulEndAddr = ulBeginAddr + ulSize - 1;
unsigned long ulCurAddr = ulBeginAddr;
//
// erase the sectors in this range
//
for (int i = 0; i < GetFlashInfo().Bank; i ++)
{
IssueFlashCommand(CMDRESET, i, 0);
}
int iBank = 0;
unsigned long ulSector = 0;
do{
GetBankAndSectorIndex(ulCurAddr, iBank, ulSector);
EraseSectorWithCompletion(iBank, ulSector, bCompletion);
ulCurAddr += GetSectorSize(ulSector);
}
while (ulCurAddr < ulEndAddr);
// Verify Erase
for (unsigned i = 0;i < ulSize; i += 4)
{
unsigned long ulTemp = ReadFlash32(ulBeginAddr + i);
if (0xFFFFFFFF != ulTemp)
{
return false;
}
}
return true;
}
void CFlashAmd::LockFlash(unsigned long ulAddressOffset,unsigned long ulSize)
{
return ;
}
void CFlashAmd::UnlockFlash(unsigned long ulAddressOffset,unsigned long ulSize)
{
return ;
}
bool CFlashAmd::ReadFlash(unsigned long ulAddressOffset,void *pDataStore,unsigned long ulSize)
{
unsigned long ulAddrRead = ulAddressOffset + GetFlashAddressBase();;
int iBank = GetBankIndex(ulAddrRead);
IssueFlashCommand(CMDRESET, iBank, 0);
while (ulSize --)
{
(reinterpret_cast<unsigned char *> (pDataStore))[ulSize] = *(reinterpret_cast<unsigned char *>(ulAddrRead + ulSize));
}
return true;
}
bool CFlashAmd::WaitForEraseComplete(unsigned long ulAddressOffset)
{
unsigned long ulAddr = GetFlashAddressBase() + ulAddressOffset;
return (GetFlashStatus(ulAddr) != 0 );
}
bool CFlashAmd::WriteFlash(unsigned long ulAddressOffset,const void * pDataWrite,unsigned long ulSize,bool bErase)
{
unsigned long ulAddr = ulAddressOffset + GetFlashAddressBase();
bool bResult = true;
// Check parameters...
if (ulAddressOffset + ulSize - 1 > GetFlashInfo().Size)
{
return false;
}
// Round up to whole word
if (ulSize & 0x3)
{
ulSize += ulSize % 4;
}
int iBank = GetBankIndex(ulAddr);
IssueFlashCommand(CMDRESET, iBank, 0);
// Firstly check that is is erased
if (!bErase)
{
for (unsigned long i = 0; i < ulSize; i ++)
{
if (0xff != *(reinterpret_cast<unsigned char *>(ulAddr + i)))
{
bResult = FALSE;
goto EXIT;
}
}
}
if (bErase)
{
// Erase the area before write
EraseFlash(ulAddressOffset,ulSize,true);
}
// Get to next buffer boundary
const unsigned long * pulData = reinterpret_cast<const unsigned long *>(pDataWrite);
while (ulSize && (ulAddr & (GetFlashInfo().WriteBufferSize - 1)) && bResult)
{
bResult = WriteFlash32(ulAddr, *pulData);
ulSize -= 4;
ulAddr += 4;
pulData ++;
}
IssueFlashCommand(CMDRESET, iBank, 0);
// Round Size up to multiple of 4 bytes
ulSize = (ulSize+3) & ~0x3;
while (ulSize && bResult)
{
unsigned long ulCopySize;
// GetFlashInfo().WriteBufferSize specifies the number of bytes of write buffer
ulCopySize = min(ulSize, GetFlashInfo().WriteBufferSize);
bResult = WriteFlashBuffer(ulAddr, pulData, ulCopySize);
//Sleep(5);//norains.Maybe don't finish writing.
ulSize -= ulCopySize;
ulAddr += ulCopySize;
pulData = &pulData[ulCopySize / 4];
}
EXIT:
return bResult;
}
unsigned long CFlashAmd::GetBankBaseAddress(int iBank)
{
return GetFlashAddressBase() + ( ( GetFlashInfo().Size / GetFlashInfo().Bank) * iBank);
}
int CFlashAmd::GetBankIndex(unsigned long ulAddr)
{
int iBank;
for(iBank = GetFlashInfo().Bank - 1; iBank >= 0; iBank--)
{
if(ulAddr >= GetBankBaseAddress(iBank))
{
break;
}
}
return iBank;
}
void CFlashAmd::IssueFlashCommand(unsigned long ulCommand, unsigned long ulParam1, unsigned long ulParam2)
{
unsigned long ulAddr; // will hold address of the flash
switch (ulCommand)
{
case CMDRESET:
ulAddr = GetBankBaseAddress(ulParam1);
WriteFlash(ulAddr, AMD_RESET32); // Set the Device to Read Mode
break;
case CMDUNLOCK:
ulAddr = GetBankBaseAddress(ulParam1);
WriteFlash(ulAddr + LATCH_OFFSET1, AMD_UNLOCK1);
WriteFlash(ulAddr + LATCH_OFFSET2, AMD_UNLOCK2);
break;
case CMDERASESET:
ulAddr = GetBankBaseAddress(ulParam1);
WriteFlash(ulAddr + LATCH_OFFSET1, AMD_ERASESET);
break;
case CMDERASESECTOR:
ulAddr = GetSectorAddress(ulParam1,ulParam2);
WriteFlash(ulAddr, AMD_ERASESECTOR); // issue erase sector command
break;
case CMDPROGRAM:
ulAddr = GetBankBaseAddress(ulParam1);
WriteFlash(ulAddr + LATCH_OFFSET1, AMD_PROGRAM);
break;
case CMDWRITEBUFFER:
WriteFlash(ulParam1, AMD_PROGRAMBUFFER);
WriteFlash(ulParam1, ulParam2); // word count - 1
break;
case CMDCOMMITBUFFER:
WriteFlash(ulParam1, AMD_COMMITBUFFER);
break;
default:
break;
}
}
unsigned long CFlashAmd::GetSectorAddress(int iBank, unsigned long ulSector)
{
unsigned long ulSectorAddr;
ulSectorAddr = GetBankBaseAddress(iBank);
for (unsigned long i=0; i < ulSector; i ++)
{
ulSectorAddr += GetSectorSize(ulSector);
}
return ulSectorAddr;
}
unsigned long CFlashAmd::GetSectorSize(unsigned long ulSector)
{
unsigned long ulSectorSize;
if (ulSector < GetFlashInfo().BootSectorCount)
{
ulSectorSize = GetFlashInfo().BootSectorSize;
}
else
{
ulSectorSize = GetFlashInfo().SectorSize;
}
return ulSectorSize * (GetFlashInfo().Width / 16);
}
void CFlashAmd::GetBankAndSectorIndex(unsigned long ulAddress, int & iBank, unsigned long & ulSector)
{
//Reset
iBank = 0;
ulSector = 0;
// Find the Bank number first
for (iBank = GetFlashInfo().Bank - 1; iBank >= 0; iBank --)
{
if (ulAddress >= GetBankBaseAddress(iBank))
{
break;
}
}
// Now work out the sector number
while (ulAddress >= GetSectorAddress(iBank,ulSector))
{
ulSector ++;
}
ulSector --;
}
bool CFlashAmd::EraseSectorWithCompletion(int iBank, unsigned long ulSector, bool bCompletion)
{
unsigned long ulAddr = GetSectorAddress(iBank, ulSector);
EraseSector(iBank, ulSector);
unsigned long ulStatus;
if (bCompletion)
{
// wait until flash state machine is ready for other operation
ulStatus = GetFlashStatus(ulAddr);
}
else
{
ulStatus = STATUSREADY;
}
return (ulStatus == STATUSREADY);
}
bool CFlashAmd::EraseSector(int iBank, unsigned long ulSector)
{
IssueFlashCommand(CMDUNLOCK, iBank, 0); // issue unlock command // no data to write
IssueFlashCommand(CMDERASESET, iBank, 0); // // erase setup command
IssueFlashCommand(CMDUNLOCK, iBank, 0);
IssueFlashCommand(CMDERASESECTOR, iBank, ulSector); // issue erase sector command
return true;
}
unsigned long CFlashAmd::GetFlashStatus(unsigned long ulAddress)
{
unsigned long ulStatus;
int iBank = GetBankIndex(ulAddress);
// Two consecutive reads to check if bits are toggling
unsigned long ulOldRead = ReadFlash(ulAddress);
unsigned long ulNewRead = ReadFlash(ulAddress);
//The timeout value
unsigned long ulStatusTimeoutValue = STATUS_TIMEOUTVALUE;
if(GetFlashInfo().Width == 16)
{
ulStatusTimeoutValue &= 0xFFFF;
}
do {
// XOR to see if bits toggled
ulStatus = ulOldRead ^ ulNewRead;
if (0 == (ulStatus & STATUS_TOGGLEVALUE))
{
ulStatus = STATUSREADY;
break;
}
if ((ulNewRead & ulStatusTimeoutValue) == ulStatusTimeoutValue)
{
ulNewRead = ReadFlash(ulAddress);
ulOldRead = ReadFlash(ulAddress);
ulStatus = ulOldRead ^ ulNewRead;
if (0 == (ulStatus & STATUS_TOGGLEVALUE))
{
ulStatus = STATUSREADY;
break;
}
ulStatus = STATUSTIMEOUT;
IssueFlashCommand(CMDRESET,iBank,0);
break;
}
ulOldRead = ulNewRead;
ulNewRead = ReadFlash(ulAddress);
} while(true);
return ulStatus;
}
bool CFlashAmd::WriteFlashBuffer(unsigned long ulAddress,const void * pSrcData, unsigned long ulByteCount)
{
if ((ulByteCount & 3) || (0 == ulByteCount))
{
//Flash Write buffer requires a whole multiple of words
return false;
}
//
// issue Program Command
// The Write buffer is GetFlashInfo().width entries deep
// With 2 chips it is 32 bits wide
unsigned long ulSize = (ulByteCount / (GetFlashInfo().Width / 8));
int iBank = GetBankIndex(ulAddress);
IssueFlashCommand(CMDUNLOCK, iBank, 0);
IssueFlashCommand(CMDWRITEBUFFER, ulAddress, ulSize - 1 |((ulSize - 1) << 16));
while (ulSize--)
{
if(GetFlashInfo().Width == 16)
{
WriteFlash(ulAddress, *(reinterpret_cast<const unsigned short *>(pSrcData)));
}
else if(GetFlashInfo().Width == 32)
{
WriteFlash(ulAddress, *(reinterpret_cast<const unsigned long *>(pSrcData)));
}
ulAddress = ulAddress + (GetFlashInfo().Width / 8);
if(GetFlashInfo().Width == 16)
{
pSrcData = reinterpret_cast<const void *>(reinterpret_cast<const unsigned short *>(pSrcData) + 1);
}
else if(GetFlashInfo().Width == 32)
{
pSrcData = reinterpret_cast<const void *>(reinterpret_cast<const unsigned long *>(pSrcData) + 1 );
}
}
ulAddress = ulAddress - (GetFlashInfo().Width / 8);
IssueFlashCommand(CMDCOMMITBUFFER, ulAddress, 0);
// wait until flash is ready to accept new command
unsigned long ulStatus = GetFlashStatus(ulAddress);
return (ulStatus != STATUSTIMEOUT);
}
bool CFlashAmd::SetFlashAddressBase(unsigned long ulAddress)
{
m_ulAddressBase = ulAddress;
return true;
}
unsigned long CFlashAmd::GetFlashAddressBase(void)
{
return m_ulAddressBase;
}
bool CFlashAmd::SetFlashInfo(const Flash::FlashInfo & flashInfo)
{
m_FlashInfo = flashInfo;
return true;
}
const Flash::FlashInfo & CFlashAmd::GetFlashInfo(void)
{
return m_FlashInfo;
}
bool CFlashAmd::WriteFlash32(unsigned long ulAddr, unsigned long ulValue)
{
*(volatile unsigned long * const)(ulAddr) = (ulValue);
__asm("sync");
return (*(volatile unsigned long * const)(ulAddr) == (ulValue));
}
unsigned long CFlashAmd::ReadFlash32(unsigned long ulAddr)
{
return *(volatile unsigned long * const)(ulAddr);
}
bool CFlashAmd::WriteFlash16(unsigned long ulAddr, unsigned long ulValue)
{
*(volatile unsigned short * const)(ulAddr) = static_cast<unsigned short>( (ulValue) & 0xFFFF);
__asm("sync");
return (*(volatile unsigned short * const)(ulAddr) == static_cast<unsigned short>( (ulValue) & 0xFFFF));
}
unsigned short CFlashAmd::ReadFlash16(unsigned long ulAddr)
{
return *(volatile unsigned short * const)(ulAddr);
}
bool CFlashAmd::WriteFlash(unsigned long ulAddr, unsigned long ulValue)
{
switch(m_FlashInfo.Width)
{
case 16:
WriteFlash16(ulAddr,ulValue);
break;
case 32:
WriteFlash32(ulAddr,ulValue);
break;
default:
return false;
}
return true;
}
unsigned long CFlashAmd::ReadFlash(unsigned long ulAddr)
{
switch(m_FlashInfo.Width)
{
case 16:
return ReadFlash16(ulAddr);
break;
case 32:
return ReadFlash32(ulAddr); ;
default:
return 0;
}
}
CFlashAmd主要限制于DBAU1200的开发板,并且该板子上的FLASH型号为AM29LV256M。
如果条件具备,那么让我们看看如何烧写flash吧。
CFlashAmd flashAmd;
//设置flash型号
flashAmd.SetFlashInfo(Flash::FLASH_INFO_AM29LV256M);
//设置flash的起始地址。在开发板中,FLASH的起始地址为0xBC000000。
flashAmd.SetFlashAddressBase(0xBC000000);
...
//烧写FLASH。在这里注意的是,地址为偏移地址。该偏移地址是相对于之前通过SetFlashAddressBase所设置的地址。
flashAmd.WriteFlash(dwOffsetAddr,&vtStore[0],vtStore.size(),true);