?? flash.cpp
字號:
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003, Ulink Telecom Equipment Co., Ltd. All rights reserved.
//
// File:
//
// Flash.cpp
//
// Abstract:
//
// implementation of the CFlash class.
//
// History:
//
// V1.0 2003-02-25 Alex Duan Original version.
// V1.1 2003-05-07 Alex Duan Addressing mode, boundary condition...
// V1.2 2003-06-03 Alex Duan Add Lookup function
// V1.3 2003-06-09 Alex Duan Add semaphore
//
///////////////////////////////////////////////////////////////////////////////
#include "Flash.h"
#include "APPCORE.H"
///////////////////////////////////////////////////////////////////////////////
// Construction/Destruction
CFlash::CFlash()
{
m_pSemaphore = GetApp()->FindSemaphore("FlashSemaphore");
if (m_pSemaphore == NULL)
{
m_pSemaphore = GetApp()->CreateSemaphore("FlashSemaphore");
}
ASSERT(m_pSemaphore);
}
CFlash::~CFlash()
{
}
///////////////////////////////////////////////////////////////////////////////
// Helper functions
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// nSector Zero-based index of the sector
// dwAddr Start address of the sector
// dwSize Size of the sector, in bytes
// Return value:
// Address of the next sector border upon.
// Remarks:
// Sets the parameters of the sector. Call this in the initialization.
DWORD CFlash::SetSector(UINT nSector, DWORD dwAddr, DWORD dwSize)
{
FLASH_SECTOR fsSector;
fsSector.dwAddr = dwAddr;
fsSector.dwSize = dwSize;
m_mapSectors.SetAt(nSector, fsSector);
return dwAddr + dwSize;
}
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// dwAddr Address of the data to be compared (must be even address)
// wData Value to be compared
// dwTimeout Time-out value
// Return value:
// TRUE if pass, else FALSE
// Remarks:
// Check the data in the flash
BOOL CFlash::CheckWord(DWORD dwAddr, WORD wData, DWORD dwTimeout) const
{
ASSERT((dwAddr & 0x01) == 0);
for (; dwTimeout != 0 && VPword(dwAddr) != wData; dwTimeout--);
return (VPword(dwAddr) == wData);
}
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// dwAddr Address of the data to be compared
// uData Value to be compared
// dwTimeout Time-out value
// Return value:
// TRUE if pass, else FALSE
// Remarks:
// Check the data in the flash
BOOL CFlash::CheckByte(DWORD dwAddr, BYTE uData, DWORD dwTimeout) const
{
for (; dwTimeout != 0 && VPbyte(dwAddr) != uData; dwTimeout--);
return (VPbyte(dwAddr) == uData);
}
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// dwAddr The address of the word in the flash (must be even address)
// wData The data to be written
// Return Value:
// TRUE if successful, otherwise FALSE
// Remarks:
// Write one word (16bits) data to the flash chip.
BOOL CFlash::WriteWord(DWORD dwAddr, WORD wData)
{
ASSERT((dwAddr & 0x01) == 0); // can only be even address.
ASSERT(m_dwBaseAddr <= dwAddr && dwAddr < m_dwBaseAddr + GetFlashSize());
VWORD* pwBaseAddr = (VWORD*)m_dwBaseAddr;
*(pwBaseAddr + 0x555) = 0xAA;
*(pwBaseAddr + 0x2AA) = 0x55;
*(pwBaseAddr + 0x555) = 0xA0;
VPword(dwAddr) = wData;
return CheckWord(dwAddr, wData);
}
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// dwAddr The address of the word in the flash
// uData The data to be written
// Return Value:
// TRUE if successful, otherwise FALSE
// Remarks:
// Write one byte (8bits) data to the flash chip.
BOOL CFlash::WriteByte(DWORD dwAddr, BYTE uData)
{
ASSERT(m_dwBaseAddr <= dwAddr && dwAddr < m_dwBaseAddr + GetFlashSize());
VWORD* pwBaseAddr = (VWORD*) m_dwBaseAddr;
*(pwBaseAddr + 0x555) = 0xAA;
*(pwBaseAddr + 0x2AA) = 0x55;
*(pwBaseAddr + 0x555) = 0xA0;
#ifdef __BIG_ENDIAN // (high byte ==> low address)
if (dwAddr & 0x01)
{// odd address
VPword(dwAddr - 1) = MAKEWORD(uData, VPbyte(dwAddr - 1));
}
else
{
VPword(dwAddr) = MAKEWORD(VPbyte(dwAddr + 1), uData);
}
#else // __LITTLE_ENDIAN (high byte ==> high address)
if (dwAddr & 0x01)
{// odd address
VPword(dwAddr - 1) = MAKEWORD(VPbyte(dwAddr - 1), uData);
}
else
{
VPword(dwAddr) = MAKEWORD(uData, VPbyte(dwAddr + 1));
}
#endif
return CheckByte(dwAddr, uData);
}
///////////////////////////////////////////////////////////////////////////////
// public functions
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// eFlashType Flash type (enum value)
// dwBaseAddr Base address of the flash ROM
// Remarks:
// Set the flash type.
void CFlash::SetType(EFlashType eFlashType, DWORD dwBaseAddr)
{
ASSERT((dwBaseAddr & 0x01) == 0); // must be even address
m_eFlashType = eFlashType;
m_dwBaseAddr = dwBaseAddr;
m_mapSectors.RemoveAll();
UINT i; // loop counter
switch (eFlashType)
{
case AM29LV160D:
// 35 sectors total.
dwBaseAddr = SetSector(0, dwBaseAddr, 0x4000); // 16Kbyte
dwBaseAddr = SetSector(1, dwBaseAddr, 0x2000); // 8Kbyte
dwBaseAddr = SetSector(2, dwBaseAddr, 0x2000); // 8Kbyte
dwBaseAddr = SetSector(3, dwBaseAddr, 0x8000); // 32Kbyte
for (i = 0; i < 31; i++)
{// thirty-one 64Kbyte sectors
dwBaseAddr = SetSector(i + 4, dwBaseAddr, 0x10000); // 64Kbyte
}
break;
default:
break;
}
}
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// nSector Zero-based index of the sector
// nRetryCount Count of retrying if failed.
// Return value:
// TRUE if erasing successful, otherwise FALSE
// Remarks:
// Erase the specified sector of the flash
BOOL CFlash::EraseSector(UINT nSector, UINT nRetryCount)
{
BOOL bRetVal = FALSE;
FLASH_SECTOR fsSector;
VERIFY(NU_Obtain_Semaphore(m_pSemaphore, NU_SUSPEND) == NU_SUCCESS);
if (m_mapSectors.Lookup(nSector, fsSector))
{
VWORD* pwBaseAddr = (VWORD*)m_dwBaseAddr;
do
{
*(pwBaseAddr + 0x555) = 0xAA;
*(pwBaseAddr + 0x2AA) = 0x55;
*(pwBaseAddr + 0x555) = 0x80;
*(pwBaseAddr + 0x555) = 0xAA;
*(pwBaseAddr + 0x2AA) = 0x55;
VPword(fsSector.dwAddr) = 0x30;
Sleep(1); // sleep to wait erasure & other task can run
// Check result of erasure
bRetVal = CheckWord(fsSector.dwAddr, 0xFFFF);
} while (!bRetVal && nRetryCount--);
// Reset command
VPword(m_dwBaseAddr) = 0xF0;
}
VERIFY(NU_Release_Semaphore(m_pSemaphore) == NU_SUCCESS);
return bRetVal;
}
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// lpBuf Pointer to the user-supplied buffer that is to receive the
// data read from the flash chip.
// dwSrcAddr Absolute physical address from which to read data
// nCount The number of bytes to be read from the flash chip.
// Remarks:
// Read data into a buffer from specified address of the flash chip. Use
// this instead of reading directly is thinking of the odd source address.
void CFlash::Read(void *lpBuf, DWORD dwSrcAddr, UINT nCount) const
{
if (nCount == 0)
return;
// obtain an instance of the specified semaphore.
VERIFY(NU_Obtain_Semaphore(m_pSemaphore, NU_SUSPEND) == NU_SUCCESS);
DWORD dwDesAddr = (DWORD)lpBuf; // des. address
if ((dwSrcAddr & 0x01) || (dwDesAddr & 0x01))
{// odd address --> slow read (read one byte every time)
while (nCount > 0)
{
VPbyte(dwDesAddr) = VPbyte(dwSrcAddr);
dwSrcAddr++;
dwDesAddr++;
nCount--;
}
}
else
{// even address --> faster read (can use memcpy instead here?)
while (nCount > 1)
{
VPword(dwDesAddr) = VPword(dwSrcAddr);
dwSrcAddr += 2;
dwDesAddr += 2;
nCount -=2;
}
if (nCount == 1)
{
VPbyte(dwDesAddr) = VPbyte(dwSrcAddr);
}
}
// release an instance of the specified semaphore.
VERIFY(NU_Release_Semaphore(m_pSemaphore) == NU_SUCCESS);
}
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// dwDesAddr Absolute physical destination address in the flash.
// lpBuf Pointer to the buffer that contains the data to be programed.
// nCount The number of bytes to be transferred from the buffer.
// Return value:
// TRUE if successful, else FALSE
// Remarks:
// Write data from a buffer to the flash.
BOOL CFlash::Write(DWORD dwDesAddr, const void* lpBuf, UINT nCount)
{
if (nCount == 0)
return TRUE;
BOOL bRetVal = TRUE; // result
DWORD dwSrcAddr = (DWORD)lpBuf; // source address
// obtain an instance of the specified semaphore
VERIFY(NU_Obtain_Semaphore(m_pSemaphore, NU_SUSPEND) == NU_SUCCESS);
if ((dwDesAddr & 0x01) || (dwSrcAddr & 0x01))
{// it is started from odd address, so write one byte every time. (slow)
while (nCount > 0 && bRetVal)
{
bRetVal = WriteByte(dwDesAddr, VPbyte(dwSrcAddr));
dwSrcAddr++;
dwDesAddr++;
nCount--;
}
}
else
{// it is started from even address, so write two bytes every timer. (faster)
while (nCount > 1 && bRetVal)
{
bRetVal = WriteWord(dwDesAddr, VPword(dwSrcAddr));
dwSrcAddr += 2;
dwDesAddr += 2;
nCount -= 2;
}
if (nCount == 1 && bRetVal)
{
bRetVal = WriteByte(dwDesAddr, VPbyte(dwSrcAddr));
}
}
VPword(m_dwBaseAddr) = 0xF0; // Reset command
// release an instance of the specified semaphore.
VERIFY(NU_Release_Semaphore(m_pSemaphore) == NU_SUCCESS);
return bRetVal;
}
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// nSector Zero-based index of the sector. [0-34]
// Return Value:
// TRUE if the specified sector exists and is blank, else FALSE
// Remarks:
// Check the sector if it is blank.
BOOL CFlash::IsBlankSector(UINT nSector) const
{
BOOL bRetVal = FALSE;
FLASH_SECTOR fsSector;
if (m_mapSectors.Lookup(nSector, fsSector))
{
bRetVal = TRUE;
for (DWORD i = 0; i < fsSector.dwSize; i += 2)
{
if ((WORD)VPword(fsSector.dwAddr + i) != 0xFFFF)
{
bRetVal = FALSE;
break;
}
}
}
return bRetVal;
}
// Gets the size of the flash chip, in bytes
DWORD CFlash::GetFlashSize() const
{
DWORD dwFlashSize = 0;
UINT nSector; // zero-based index of the sector
FLASH_SECTOR fsSector;
POSITION pos = m_mapSectors.GetStartPosition();
while (pos != NULL)
{
m_mapSectors.GetNextAssoc(pos, nSector, fsSector);
dwFlashSize += fsSector.dwSize;
}
return dwFlashSize;
}
///////////////////////////////////////////////////////////////////////////////
// Return Value:
// TRUE if the flash is busy, otherwise FALSE.
// Remarks:
// Is the flash busy?
BOOL CFlash::IsBusy() const
{
ASSERT(m_pSemaphore);
char szName[8]; // semaphore name
DWORD nCount, nTask;
OPTION oSuspend;
NU_TASK *pTask = NULL;
NU_Semaphore_Information(m_pSemaphore, szName, &nCount, &oSuspend, &nTask,
&pTask);
return (nCount == 0);
}
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// nSector Sector number
// Return Value:
// Base address of the sector if sector exists, otherwise -1.
// Remarks:
// Get the base address of the specified sector.
DWORD CFlash::GetSectorAddr(UINT nSector) const
{
FLASH_SECTOR fsSector;
if (m_mapSectors.Lookup(nSector, fsSector))
{
return fsSector.dwAddr;
}
else
{
return -1;
}
}
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// nSector Sector number
// Return Value:
// Size of the sector if sector exists, otherwise -1.
// Remarks:
// Get the size of the specified sector.
DWORD CFlash::GetSectorSize(UINT nSector) const
{
FLASH_SECTOR fsSector;
if (m_mapSectors.Lookup(nSector, fsSector))
{
return fsSector.dwSize;
}
else
{
return -1;
}
}
///////////////////////////////////////////////////////////////////////////////
// Parameters:
// nSector Sector number
// Return Value:
// Next address of this sector if this sector exists, otherwise -1.
// Remarks:
// Get the next address relative to this sector
DWORD CFlash::GetSectorNext(UINT nSector) const
{
FLASH_SECTOR fsSector;
if (m_mapSectors.Lookup(nSector, fsSector))
{
return fsSector.dwAddr + fsSector.dwSize;
}
else
{
return -1;
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -