📄 am29lv160d.c
字号:
/*******************************************************************************/
/* */
/* FILE: am29lv160d.c() */
/* */
/* PURPOSE: Performs operations specific to the am29lv160d flash device */
/* while adhering to the adi device drivers model. */
/* */
/*******************************************************************************/
//----- Includes -----//
#include "am29lv160d.h"
//---- Function Prototypes ----//
static ERROR_CODE GetSectorNumber( unsigned long ulAddr, int *pnSector );
static ERROR_CODE GetSectorStartEnd( unsigned long *ulStartOff, unsigned long *ulEndOff, int nSector );
static unsigned long GetFlashStartAddress( unsigned long ulAddr);
static void ReadFlash(unsigned long ulOffset, unsigned short *pusValue );
static void WriteFlash(unsigned long ulOffset, unsigned short usValue );
static void ResetFlash(unsigned long ulStartAddr);
void GetCodes(unsigned short *pnManCode, unsigned short *pnDevCode, unsigned long ulStartAddr);
static ERROR_CODE PollToggleBit(unsigned long ulOffset);
ERROR_CODE EraseBlock( int nBlock, unsigned long ulStartAddr );
ERROR_CODE EraseFlash(unsigned long ulStartAddr);
ERROR_CODE ProgramFlash( unsigned long ulAddr, unsigned short usValue );
//----------- Get Sector Number() ----------//
//
// PURPOSE
// Gets a sector number based on the offset.
//
// INPUTS
// unsigned long ulAddr - absolute address
// int *pnSector - pointer to sector number
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
static ERROR_CODE GetSectorNumber( unsigned long ulAddr, int *pnSector )
{
int nSector = 0;
unsigned long ulMask; //offset mask
unsigned long ulOffset; //offset
unsigned long ulBlkSize = 0x10000; // Block size 0
// get offset from absolute address
ulMask = 0x3fffff;
ulOffset = ulAddr & ulMask;
// sector numbers for the FLASH A boot sectors
if(0 < ulOffset < 0x004000)
{
nSector = 0;
}
else if(ulOffset < 0x006000)
{
nSector = 1;
}
else if(ulOffset < 0x008000)
{
nSector = 2;
}
else if(ulOffset < 0x010000)
{
nSector = 3;
}
else if( 0x010000 <= ulOffset < 0x1fffff)
{
nSector = (ulOffset - 0x010000)/ulBlkSize + 3;
}
else
{
// invalid sector
return INVALID_SECTOR;
}
// if it is a valid sector, set it
if ( (nSector >= 0) && (nSector < NUM_SECTORS) )
*pnSector = nSector;
// else it is an invalid sector
else
return INVALID_SECTOR;
// ok
return NO_ERR;
}
//----------- Get Sector Start End() ----------//
//
// PURPOSE
// Gets a sector start and end address based on the sector number.
//
// INPUTS
// unsigned long *ulStartOff - pointer to the start offset
// unsigned long *ulEndOff - pointer to the end offset
// int nSector - sector number
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
static ERROR_CODE GetSectorStartEnd( unsigned long *ulStartOff, unsigned long *ulEndOff, int nSector )
{
// The blocks in the flash memory are asymmetrically arranged
// Thus we use block sizes to determine the block addresses
unsigned long ulBlkSize = 0x10000; // Block size
// main block
if( nSector == 0 )
{
*ulStartOff = 0;
*ulEndOff = 0x003fff;
}
else if( nSector == 1 )
{
*ulStartOff = 0x004000;
*ulEndOff = 0x005fff;
}
else if( nSector == 2 )
{
*ulStartOff = 0x006000;
*ulEndOff = 0x007fff;
}
else if( nSector == 3 )
{
*ulStartOff = 0x008000;
*ulEndOff = 0x00ffff;
}
else if( (nSector >= 4) && (nSector < 35) )
{
*ulStartOff = 0x010000 + (nSector-4) * ulBlkSize;
*ulEndOff = ( (*ulStartOff) + ulBlkSize );
}
else
return INVALID_SECTOR;
*ulEndOff -= 1;
// ok
return NO_ERR;
}
//----------- Get Flash Start Address() ----------//
//
// PURPOSE
// Gets flash start address from an absolute address.
//
// INPUTS
// unsigned long ulAddr - absolute address
//
// RETURN VALUE
// unsigned long - Flash start address
static unsigned long GetFlashStartAddress( unsigned long ulAddr)
{
ERROR_CODE ErrorCode = NO_ERR; //tells us if there was an error erasing flash
unsigned long ulFlashStartAddr; //flash start address
unsigned long ulSectStartAddr; //sector start address
unsigned long ulSectEndAddr; //sector end address
unsigned long ulMask; //offset mask
// get flash start address from absolute address
GetSectorStartEnd( &ulSectStartAddr, &ulSectEndAddr, (NUM_SECTORS-1));
ulMask = ~(ulSectEndAddr);
ulFlashStartAddr = ulAddr & ulMask;
return(ulFlashStartAddr);
}
//----------- Read Flash() ----------//
//
// PURPOSE
// Reads a value from an address in flash.
//
// INPUTS
// unsigned long ulAddr - the address to read from
// int pnValue - pointer to store value read from flash
//
// RETURN VALUE
static void ReadFlash( unsigned long ulAddr, unsigned short *pusValue )
{
// set our flash address to where we want to read
unsigned short *pFlashAddr = (unsigned short *)(ulAddr);
// read the value
*pusValue = (unsigned short)*pFlashAddr;
}
//----------- Write Flash() ----------//
//
// PURPOSE
// Write a value to an address in flash.
//
// INPUTS
// unsigned long ulAddr - address to write to
// unsigned short nValue - value to write
//
// RETURN VALUE
static void WriteFlash( unsigned long ulAddr, unsigned short usValue )
{
// set the address
unsigned short *pFlashAddr = (unsigned short *)(ulAddr);
*pFlashAddr = usValue;
}
//----------- Reset Flash() ----------//
//
// PURPOSE
// Sends a "reset" command to the flash.
//
// INPUTS
// unsigned long ulStartAddr - flash start address
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
void ResetFlash(unsigned long ulAddr)
{
unsigned long ulFlashStartAddr; //flash start address
// get flash start address from absolute address
// The ulAddr should ideally be pointing to the flash start
// address. However we just verify it here again.
ulFlashStartAddr = GetFlashStartAddress(ulAddr);
// send the reset command to the flash
WriteFlash( ulFlashStartAddr + 0x0555, 0xf0 );
}
//----------- Get Codes() ----------//
//
// PURPOSE
// Sends an "auto select" command to the flash which will allow
// us to get the manufacturer and device codes.
//
// INPUTS
// int *pnManCode - pointer to manufacture code
// int *pnDevCode - pointer to device code
// unsigned long ulStartAddr - flash start address
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
void GetCodes(unsigned short *pnManCode, unsigned short *pnDevCode, unsigned long ulAddr)
{
unsigned long ulFlashStartAddr; //flash start address
// get flash start address from absolute address
// The ulAddr should ideally be pointing to the flash start
// address. However we just verify it here again.
ulFlashStartAddr = GetFlashStartAddress(ulAddr);
// send the auto select command to the flash
WriteFlash( ulFlashStartAddr + 0x0AAA, 0xaa );
WriteFlash( ulFlashStartAddr + 0x0555, 0x55 );
WriteFlash( ulFlashStartAddr + 0x0AAA, 0x90 );
// now we can read the codes
ReadFlash( ulFlashStartAddr + 0x0000, (unsigned short *)pnManCode );
*pnManCode &= 0xFFFF;
ReadFlash( ulFlashStartAddr + 0x0002, (unsigned short *)pnDevCode );
*pnDevCode &= 0xFFFF;
// we need to issue another command to get the part out
// of auto select mode so issue a reset which just puts
// the device back in read mode
ResetFlash(ulAddr);
}
//----------- Poll Toggle Bit() ----------//
//
// PURPOSE
// Polls the toggle bit in the flash to see when the operation
// is complete.
//
// INPUTS
// unsigned long ulAddr - address in flash
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
static ERROR_CODE PollToggleBit(unsigned long ulAddr)
{
ERROR_CODE ErrorCode = NO_ERR; // flag to indicate error
unsigned short usVal1;
unsigned short usVal2;
// read flash 1 time
ReadFlash( ulAddr, &usVal1 );
while( ErrorCode == NO_ERR )
{
// read the value 2 times
ReadFlash( ulAddr, &usVal1 );
ReadFlash( ulAddr, &usVal2 );
// XOR to see if any bits are different
usVal1 ^= usVal2;
// see if we are toggling
if( !(usVal1 & 0x40) )
break;
// check error bit
if( !(usVal2 & 0x20) )
continue;
else
{
// read the value 2 times
ReadFlash( ulAddr, &usVal1 );
ReadFlash( ulAddr, &usVal2 );
// XOR to see if any bits are different
usVal1 ^= usVal2;
// see if we are toggling
if( !(usVal1 & 0x40) )
break;
else
{
ErrorCode = POLL_TIMEOUT;
ResetFlash(ulAddr);
}
}
}
// now return
return ErrorCode;
}
//----------- Erase Block() ----------//
//
// PURPOSE
// Sends an "erase block" command to the flash.
//
// INPUTS
// int nBlock - block to erase
// unsigned long ulStartAddr - flash start address
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
ERROR_CODE EraseBlock( int nBlock, unsigned long ulAddr )
{
ERROR_CODE ErrorCode = NO_ERR; //tells us if there was an error erasing flash
unsigned long ulSectStart = 0x0; //stores the sector start offset
unsigned long ulSectEnd = 0x0; //stores the sector end offset(however we do not use it here)
unsigned long ulFlashStartAddr; //flash start address
// get flash start address from absolute address
// The ulAddr should ideally be pointing to the flash start
// address. However we just verify it here again.
ulFlashStartAddr = GetFlashStartAddress(ulAddr);
// Get the sector start offset
// we get the end offset too however we do not actually use it for Erase sector
GetSectorStartEnd( &ulSectStart, &ulSectEnd, nBlock );
// send the erase block command to the flash
WriteFlash( (ulFlashStartAddr + 0x0AAA), 0xaa );
WriteFlash( (ulFlashStartAddr + 0x0555), 0x55 );
WriteFlash( (ulFlashStartAddr + 0x0AAA), 0x80 );
WriteFlash( (ulFlashStartAddr + 0x0AAA), 0xaa );
WriteFlash( (ulFlashStartAddr + 0x0555), 0x55 );
// the last write has to be at an address in the block
WriteFlash( (ulFlashStartAddr + ulSectStart), 0x30 );
// poll until the command has completed
ErrorCode = PollToggleBit(ulFlashStartAddr + ulSectStart);
// block erase should be complete
return ErrorCode;
}
//----------- Erase Flash() ----------//
//
// PURPOSE
// Sends an "erase all" command to the flash.
//
// INPUTS
// unsigned long ulStartAddr - flash start address
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
ERROR_CODE EraseFlash(unsigned long ulAddr)
{
ERROR_CODE ErrorCode = NO_ERR; // tells us if there was an error erasing flash
unsigned long ulFlashStartAddr; // flash start address
// get flash start address from absolute address
// The ulAddr should ideally be pointing to the flash start
// address. However we just verify it here again.
ulFlashStartAddr = GetFlashStartAddress(ulAddr);
// erase contents of Flash
WriteFlash( ulFlashStartAddr + 0x0AAA, 0xaa );
WriteFlash( ulFlashStartAddr + 0x0555, 0x55 );
WriteFlash( ulFlashStartAddr + 0x0AAA, 0x80 );
WriteFlash( ulFlashStartAddr + 0x0AAA, 0xaa );
WriteFlash( ulFlashStartAddr + 0x0555, 0x55 );
WriteFlash( ulFlashStartAddr + 0x0AAA, 0x10 );
// poll until the command has completed
ErrorCode = PollToggleBit(ulFlashStartAddr + 0x0000);
// erase should be complete
return ErrorCode;
}
//----------- Program Flash() ----------//
//
// PURPOSE
// Sends an "program" command to the flash.
//
// INPUTS
// unsigned long ulAddr - address to write to
// unsigned short nValue - value to write
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
ERROR_CODE ProgramFlash( unsigned long ulAddr, unsigned short usValue )
{
ERROR_CODE ErrorCode = NO_ERR; // tells us if there was an error erasing flash
unsigned long ulFlashStartAddr; // flash start address
// get flash start address from absolute address
// The ulAddr should ideally be pointing to the flash start
// address. However we just verify it here again.
ulFlashStartAddr = GetFlashStartAddress(ulAddr);
// unlock flash
WriteFlash( ulFlashStartAddr + 0x0AAA, 0xaa );
WriteFlash( ulFlashStartAddr + 0x0555, 0x55 );
WriteFlash( ulFlashStartAddr + 0x0AAA, 0xa0 );
// program our actual value now
WriteFlash( ulFlashStartAddr + ulAddr, usValue );
// make sure the write was successful
ErrorCode = PollToggleBit(ulFlashStartAddr + 0x0000);
return(ErrorCode);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -