⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flash.cpp

📁 基于Nuleus操作系统和s3c4510的编写的EFC。已经包含了该EFC的设计说明。这是个实际产品的代码
💻 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 + -