ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)

编者的话

Flash 编程与烧写,原本应该是开发的最后一步,当所有程序都做好了,在线编译运行正常,才会通过 Flash 编程,生成二进制的可执行文件 LDR,再通过 JTAG 仿真器将 LDR 文件烧写到 Flash 中,上电 BOOT 实现脱机运行的功能。

我们为何把这个章节安排在第二个阶段,是因为 21489 的第二种编程方式,首选就需要烧写程序,所以在这个文档里,先把烧写程序的方法给用户做详细的阐述,也好顺利的进入第三个阶段。

ADI 的 DSP,通过 Flash 编程生成的二进制可执行文件尾椎为 LDR,但实际上他的数据格式仍然是通过用户自己选择,而组合成的 BIN,HEX 等常规数据。所以大家不要被 LDR 这个名字所疑惑,仅仅只是 ADI 取的名字罢了。打个比方就是,ADI 拿一个叫做 LDR 的瓶子来装BOOT 数据,而这些数据归根到底,依然是我们在其他嵌入式处理器开发中所熟知的 BIN,HEX 等等,ADI 也无法别出心裁的整出一个独特的数据格式来。

21489 的这块板上,我们做了 NORFLASH 和 SPIFLASH 两种,下面也会对每一种 Flash 做详细的注解,如何来生成这两种 flash 可用的 LDR 文件,又如何来通过 AD-HP530ICE 仿真器去烧写相应的 LDR 文件到 FLASH 中,实现脱机。

Flash 编程和烧写前所需要做的准备工作

硬件准备

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第1张图片
仿真器:AD-HP530ICE
开发板:ADSP-21489EVB

硬件设计原理图

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第2张图片

软件准备

Visual DSP++5.1.2

硬件链接

仿真器和开发板通过 JTAG 连接,开发板上电,仿真器上电。

软件链接

新建 21489 的 session,具体可参见前面文章中的详细说明,此处不再讲解。

NORFLASH 编程

此章将详细讲解如何使用 VDSP 软件来进行 NORFLASH 编程,生成 boot 用的 LDR 文件。我们以按键控制 LED 灯的程序来做例程讲解。

  1. 把工程拖到 VDSP 软件中来。

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第3张图片

  1. 在工程名上按鼠标右键,选择“Project Options…”

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第4张图片

  1. 根据芯片的实际版本,为工程选择一个芯片版本,将“Type”选为“Loader File”。我们现在用的 21489 都是 0.2 版,所以就选择 0.2。

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第5张图片

  1. 按下图为生成的 LDR 文件选择格式,设置完成后点“确定”按钮,完成 LDR 文件的配置。ADSP21489_prom.dxe 文件位于 FlashDriver 文件夹里的 NORFLASH 文件夹下。

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第6张图片

NORFLASH 生成 LDR,所以在 Boot Type 里选择 Parallel port;Format 我选择的是 Binary,一直用这个,没啥因为所以;Width 选择 8-bit,因为 Flash 就是 8bit 的。

Kernel file 这个就很关键了,必须要需要添加这个 kernel,这个 kernel 是 ADI 公司提供的,我只是把它单独拧出来放到我的 Flash Driver 文件夹里,方便调用。

  1. 选择“ ReBuild all“按钮全编译工程。

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第7张图片

  1. 编译完成后,会看到生成文件提示。该文件默认生成地址为当前工程的 Debug 文件夹下。

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第8张图片

烧写

  1. 选择 Tools 里的 Flash Programmer。特别注意,一定要链接好 session,才有此选项!

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第9张图片

  1. 为 NorFlash 加载一个“.dxe”格式的驱动文件,这个文件在 “Flash Driver”文件夹下。

这个是 Flash 的烧写驱动,每一个型号的 Flash 都需要专门对应自己的驱动,ADI 提供了一个驱动源码,如果用户的 Flash 型号与原厂提供的这个不符,则需要对驱动进行修改。我们开发板使用的就是ADI原厂的这个Flash型号,所以就可以直接用这个Driver,不用做任何修改。在这里 OP 也建议大家都用原厂提供的这个型号,否则自己改 Flash烧写驱动,还是一件挺麻烦的事情。

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第10张图片

  1. 找到“ ADSP21489_FlashDriver.dxe”文件。

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第11张图片

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第12张图片

  1. 按下图选择选项,然后点“ Data”后面的按钮,找到 ADSP21489_PBLED 工程下 Debug 文件夹下刚才生成的“ ADSP21489_PBLED.ldr”文件。

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第13张图片

  1. 烧写过程中的读条,请静心等待。

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第14张图片

  1. 完成烧写。

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第15张图片

  1. 断开链接,完整 Flash 编程和烧写得工作。

ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)_第16张图片

  1. 将 BOOT 开关 SW2 和 SW3 分别拨到 OFF 和 ON,设置成 NORFLASH 启动

  2. 拔掉电源插头,重新上电,并打开电源开关,按下按键,相应的 LED 灯亮,验证完成。

驱动程序的源代码

main.c

#include
#include
#include // malloc includes
#include “s29al016.h” // flash-S29AL016D includes
#include “Services_Sharc.h” // system services buffers
#include “util.h” // library struct includes
#include “Errors.h” // error type includes

#define FLASH_START_ADDR 0x4000000
static char *pEzKitTitle = “ADSP-21489-CORE_FlashDriver”;

#define BUFFER_SIZE 0x400

//Flash Programmer commands
typedef enum
{
NO_COMMAND, // 0
GET_CODES, // 1
RESET, // 2
WRITE, // 3
FILL, // 4
ERASE_ALL, // 5
ERASE_SECT, // 6
READ, // 7
GET_SECTNUM, // 8
GET_SECSTARTEND,// 9
}enProgCmds;

//----- g l o b a l s -----//

char *AFP_Title ;
char *AFP_Description; // Device Description: AMD S29AL016D
char *AFP_DeviceCompany; // Device Company
char *AFP_DrvVersion = “1.01.0”; // Driver Version
char *AFP_BuildDate = DATE; // Driver Build Date
enProgCmds AFP_Command = NO_COMMAND; // command sent down from the GUI
int AFP_ManCode = -1;
int AFP_DevCode = -1;
unsigned long AFP_Offset = 0x0; // offset into flash
int *AFP_Buffer; // buffer used to read and write flash
long AFP_Size = BUFFER_SIZE; // buffer size
long AFP_Count = -1; // count of locations to be read or written
long AFP_Stride = -1; // stride used when reading or writing
int AFP_NumSectors = NUM_SECTORS; // number of sectors in the flash device
int AFP_Sector = -1; // sector number
int AFP_Error = 0; // contains last error encountered
bool AFP_Verify = FALSE; // verify writes or not
unsigned long AFP_StartOff = 0x0; // sector start offset
unsigned long AFP_EndOff = 0x0; // sector end offset
int AFP_FlashWidth = 0x8; // width of the flash device
int *AFP_SectorInfo;

bool bExit = FALSE; //exit flag

//----- c o n s t a n t d e f i n i t i o n s -----//

// structure for flash sector information

typedef struct _SECTORLOCATION
{
unsigned long ulStartOff;
unsigned long ulEndOff;
}SECTORLOCATION;

SECTORLOCATION SectorInfo[NUM_SECTORS];

//----- f u n c t i o n p r o t o t y p e s -----//

ERROR_CODE AllocateAFPBuffer(void);
ERROR_CODE GetSectorMap(void);
ERROR_CODE GetFlashInfo(void);
ERROR_CODE ProcessCommand(void);
ERROR_CODE SetupForFlash(void);
ERROR_CODE FillData( unsigned long ulStart, long lCount, long lStride, int *pnData );
ERROR_CODE ReadData( unsigned long ulStart, long lCount, long lStride, int *pnData );
ERROR_CODE WriteData( unsigned long ulStart, long lCount, long lStride, int *pnData );
void FreeAFPBuffer(void);

//------------- m a i n ( ) ----------------//

int main(void)
{
// open the device
AFP_Error = ADIS29AL016DEntryPoint.adi_pdd_Open( NULL, // DevMgr handle
0, // pdd entry point
NULL, // device instance
NULL, // client handle callback identifier
ADI_DEV_DIRECTION_BIDIRECTIONAL,// data direction for this device
NULL, // DevMgr handle for this device
NULL, // handle to DmaMgr for this device
NULL, // handle to deferred callback service
NULL ); // client’s callback function

// allocate AFP_Buffer
if (( AFP_Error = AllocateAFPBuffer()) != NO_ERR)
	return FALSE;

// get sector map
if (( AFP_Error = GetSectorMap())!= NO_ERR)
	return FALSE;

	// setup the device so the DSP can access it
if (SetupForFlash() != NO_ERR)
	return FALSE;

// get flash manufacturer & device codes, title & desc
if (( AFP_Error = GetFlashInfo()) != NO_ERR)
	return FALSE;

// command processing loop
while ( !bExit )
{
	// the plug-in will set a breakpoint at "AFP_BreakReady" so it knows
	// when we are ready for a new command because the DSP will halt
	//
	// the jump is used so that the label will be part of the debug
	// information in the driver image otherwise it may be left out
	// since the label is not referenced anywhere
	asm("AFP_BreakReady:");
   		asm("nop;");
		if ( FALSE )
			asm("jump AFP_BreakReady;");

	// Make a call to the ProcessCommand
	   AFP_Error = ProcessCommand();
}

// Clear the AFP_Buffer
FreeAFPBuffer();

// Close the Device
AFP_Error = ADIS29AL016DEntryPoint.adi_pdd_Close(NULL);

return TRUE;

}

//----------- P r o c e s s C o m m a n d ( ) ----------//
//
// PURPOSE
// Process each command sent by the GUI based on the value in
// the AFP_Command.
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs during Opcode scan
// NO_ERR - otherwise
//
// CHANGES
// 9-28-2005 Created

ERROR_CODE ProcessCommand()
{

ERROR_CODE ErrorCode = 	NO_ERR; 		//return error code

COMMAND_STRUCT CmdStruct;

// switch on the command and fill command structure.
switch ( AFP_Command )
{

	// erase all
	case ERASE_ALL:
		CmdStruct.SEraseAll.ulFlashStartAddr 	= FLASH_START_ADDR;	//FlashStartAddress
		ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_ERASE_ALL, &CmdStruct );
		break;

	// erase sector
	case ERASE_SECT:
		CmdStruct.SEraseSect.nSectorNum  		= AFP_Sector;		// Sector Number to erase
		CmdStruct.SEraseSect.ulFlashStartAddr 	= FLASH_START_ADDR;	// FlashStartAddress
		ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_ERASE_SECT, &CmdStruct);
		break;

	// fill
	case FILL:
		ErrorCode = FillData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer );
		break;

	// get manufacturer and device codes
	case GET_CODES:
		CmdStruct.SGetCodes.pManCode 			= (unsigned long *)&AFP_ManCode;	// Manufacturer Code
		CmdStruct.SGetCodes.pDevCode 			= (unsigned long *)&AFP_DevCode;	// Device Code
		CmdStruct.SGetCodes.ulFlashStartAddr 	= FLASH_START_ADDR;
		ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_GET_CODES, &CmdStruct);
		break;

	// get sector number based on address
	case GET_SECTNUM:
		CmdStruct.SGetSectNum.ulOffset 			= AFP_Offset;	// offset from the base address
		CmdStruct.SGetSectNum.pSectorNum 		= (unsigned long *)&AFP_Sector;	//Sector Number
		ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_GET_SECTNUM, &CmdStruct);
		break;

	// get sector number start and end offset
	case GET_SECSTARTEND:
		CmdStruct.SSectStartEnd.nSectorNum 		= AFP_Sector;	// Sector Number
		CmdStruct.SSectStartEnd.pStartOffset 	= &AFP_StartOff;// sector start address
		CmdStruct.SSectStartEnd.pEndOffset	 	= &AFP_EndOff;	// sector end address
		ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_GET_SECSTARTEND, &CmdStruct );
		break;

	// read
	case READ:
		ErrorCode = ReadData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer );
		break;

	// reset
	case RESET:
		CmdStruct.SReset.ulFlashStartAddr 	= FLASH_START_ADDR; //Flash start address
		ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_RESET, &CmdStruct);
		break;

	// write
	case WRITE:
		ErrorCode = WriteData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer );
		break;

	// no command or unknown command do nothing
	case NO_COMMAND:
	default:
		// set our error
		ErrorCode = UNKNOWN_COMMAND;
		break;
}

// clear the command
AFP_Command = NO_COMMAND;

return(ErrorCode);

}

//----------- A l l o c a t e A F P B u f f e r ( ) ----------//
//
// PURPOSE
// Allocate memory for the AFP_Buffer
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
//
// CHANGES
// 9-28-2005 Created

ERROR_CODE AllocateAFPBuffer()
{

ERROR_CODE ErrorCode = NO_ERR;	//return error code

// by making AFP_Buffer as big as possible the plug-in can send and
// receive more data at a time making the data transfer quicker
//
// by allocating it on the heap the compiler does not create an
// initialized array therefore making the driver image smaller
// and faster to load
//
// The linker description file (LDF) could be modified so that
// the heap is larger, therefore allowing the BUFFER_SIZE to increase.
AFP_Buffer = (int *)malloc(BUFFER_SIZE);

// AFP_Buffer will be NULL if we could not allocate storage for the
// buffer
if ( AFP_Buffer == NULL )
{
	// tell GUI that our buffer was not initialized
	ErrorCode = BUFFER_IS_NULL;
}

return(ErrorCode);

}

//----------- F r e e A F P B u f f e r ( ) ----------//
//
// PURPOSE
// Free the AFP_Buffer
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
//
// CHANGES
// 9-28-2005 Created

void FreeAFPBuffer()
{
// free the buffer if we were able to allocate one
if ( AFP_Buffer )
free( AFP_Buffer );

}

//----------- S e t u p F o r F l a s h ( ) ----------//
//
// PURPOSE
// Perform necessary setup for the processor to talk to the
// flash such as external memory interface registers, etc.
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs during Opcode scan
// NO_ERR - otherwise

ERROR_CODE SetupForFlash()
{

// setup EPCTL to use bank 2 (MS1) core accesses.
*pEPCTL = (((*pEPCTL) & (~B1SD)) | EPBRCORE);


//*pPMCTL = (PLLM16 | INDIV | DIVEN | SDCKR3); 
*pPMCTL = (PLLM16|PLLD4|DIVEN);
// setup for max waitstates
// NOTE:  The PKDIS bit is set which makes a 1 to 1 mapping, each 8 bit byte
///       maps to an address.
*pAMICTL1 = ( PKDIS | WS31 | HC1 | HC2 | RHC1 | RHC2 | IC7 | AMIEN | AMIFLSH);

return NO_ERR;

}

//----------- G e t S e c t o r M a p ( ) ----------//
//
// PURPOSE
// Get the start and end offset for each sector in the flash.
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
//
// CHANGES
// 9-28-2005 Created

ERROR_CODE GetSectorMap()
{

ERROR_CODE ErrorCode = NO_ERR;			//return error code
GET_SECTSTARTEND_STRUCT	SSectStartEnd;	//structure for GetSectStartEnd
int i;									//index

//initiate sector information structures
for( i=0;i

}

//----------- G e t F l a s h I n f o ( ) ----------//
//
// PURPOSE
// Get the manufacturer code and device code
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
//
// CHANGES
// 9-28-2005 Created

ERROR_CODE GetFlashInfo()
{

ERROR_CODE ErrorCode = NO_ERR;		//return error code
static GET_CODES_STRUCT  SGetCodes;	//structure for GetCodes
COMMAND_STRUCT CmdStruct;

//setup code so that flash programmer can just read memory instead of call GetCodes().
CmdStruct.SGetCodes.pManCode = (unsigned long *)&AFP_ManCode;
CmdStruct.SGetCodes.pDevCode = (unsigned long *)&AFP_DevCode;
CmdStruct.SGetCodes.ulFlashStartAddr = FLASH_START_ADDR;

AFP_Error = ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_GET_CODES, &CmdStruct );


AFP_Error = ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_GET_DESC, &CmdStruct );
AFP_Title = pEzKitTitle;
AFP_Description = CmdStruct.SGetDesc.pDesc;
AFP_DeviceCompany = CmdStruct.SGetDesc.pFlashCompany;

return(ErrorCode);

}

//----------- F i l l D a t a ( ) ----------//
//
// PURPOSE
// Fill flash device with a value.
//
// INPUTS
// unsigned long ulStart - address in flash to start the writes at
// long lCount - number of elements to write, in this case bytes
// long lStride - number of locations to skip between writes
// int *pnData - pointer to data buffer
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs during fill
// NO_ERR - otherwise
//
// CHANGES
// 9-28-2005 Created

ERROR_CODE FillData( unsigned long ulStart, long lCount, long lStride, int *pnData )
{
long i = 0; // loop counter
ERROR_CODE ErrorCode = NO_ERR; // tells whether we had an error while filling
bool bVerifyError = FALSE; // lets us know if there was a verify error
unsigned long ulStartAddr; // current address to fill
unsigned long ulSector = 0; // sector number to verify address
int nCompare = 0; // value that we use to verify flash

ADI_DEV_1D_BUFFER		WriteBuff;	// buffer pointer
ADI_DEV_1D_BUFFER		ReadBuff;	// buffer pointer

ulStartAddr = FLASH_START_ADDR + ulStart;
COMMAND_STRUCT	CmdStruct;	//structure for GetSectStartEnd

// verify writes if the user wants to
if( AFP_Verify == TRUE )
{
	// fill the value
	for (i = 0; ( ( i < lCount ) && ( ErrorCode == NO_ERR ) ); i++, ulStartAddr += ( lStride ) )
	{

		// check to see that the address is within a valid sector
		CmdStruct.SGetSectNum.ulOffset = ulStartAddr;
		CmdStruct.SGetSectNum.pSectorNum = &ulSector;
		ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_GET_SECTNUM, &CmdStruct  );

		if( NO_ERR == ErrorCode )
		{
			// unlock the flash, do the write, and wait for completion
			WriteBuff.Data 				= (void *)&pnData[0];
			WriteBuff.pAdditionalInfo 	= (void *)&ulStartAddr;
			ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Write(NULL, ADI_DEV_1D, (ADI_DEV_BUFFER *)&WriteBuff);

			ReadBuff.Data 				= (void *)&nCompare;
			ReadBuff.pAdditionalInfo 	= (void *)&ulStartAddr ;
			ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Read(NULL, ADI_DEV_1D, (ADI_DEV_BUFFER *)&ReadBuff);

			//if( nCompare != ( pnData[0] & 0x0000FFFF ) )
			if( ( nCompare & 0xFF ) != (pnData[0] & 0xFF) )
			{
				bVerifyError = TRUE;
				break;
			}
		}
		else
		{
			return ErrorCode;
		}

	}

	// return appropriate error code if there was a verification error
	if( bVerifyError == TRUE )
		return VERIFY_WRITE;
}
// user did not want to verify writes
else
{
	// fill the value
	for (i = 0; ( ( i < lCount ) && ( ErrorCode == NO_ERR ) ); i++, ulStartAddr += ( lStride ))
	{

		// check to see that the address is within a valid sector
		CmdStruct.SGetSectNum.ulOffset = ulStartAddr;
		CmdStruct.SGetSectNum.pSectorNum = &ulSector;
		ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_GET_SECTNUM, &CmdStruct  );

		if( NO_ERR == ErrorCode )
		{
			// unlock the flash, do the write, and wait for completion
			WriteBuff.Data 				= (void *)&pnData[0];
			WriteBuff.pAdditionalInfo 	= (void *)&ulStartAddr;
			ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Write(NULL, ADI_DEV_1D, (ADI_DEV_BUFFER *)&WriteBuff);
		}
		else
		{
			return ErrorCode;
		}
	}
}

// return the appropriate error code
return ErrorCode;

}

//----------- W r i t e D a t a ( ) ----------//
//
// PURPOSE
// Write a buffer to flash device.
//
// INPUTS
// unsigned long ulStart - address in flash to start the writes at
// long lCount - number of elements to write, in this case bytes
// long lStride - number of locations to skip between writes
// int *pnData - pointer to data buffer
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs during writing
// NO_ERR - otherwise
//
// CHANGES
// 9-28-2005 Created

ERROR_CODE WriteData( unsigned long ulStart, long lCount, long lStride, int *pnData )
{
long i = 0; // loop counter
ERROR_CODE ErrorCode = NO_ERR; // tells whether there was an error trying to write
int nCompare = 0; // value that we use to verify flash
bool bVerifyError = FALSE; // lets us know if there was a verify error
unsigned long ulAbsoluteAddr; // current address to write
unsigned long ulSector = 0; // sector number to verify address

ADI_DEV_1D_BUFFER		WriteBuff;	// buffer pointer
ADI_DEV_1D_BUFFER		ReadBuff;	// buffer pointer

ulAbsoluteAddr = FLASH_START_ADDR + ulStart;

COMMAND_STRUCT	CmdStruct;	//structure for GetSectStartEnd

// if the user wants to verify then do it
if( AFP_Verify == TRUE )
{
	// write the buffer up to BUFFER_SIZE items
	for (i = 0; ( i < lCount ) && ( ErrorCode == NO_ERR ); i++, ulAbsoluteAddr += lStride)
	{

		// check to see that the address is within a valid sector
		CmdStruct.SGetSectNum.ulOffset = ulAbsoluteAddr;
		CmdStruct.SGetSectNum.pSectorNum = &ulSector;
		ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_GET_SECTNUM, &CmdStruct  );

		if( NO_ERR == ErrorCode )
		{
			// unlock the flash, do the write, increase shift, and wait for completion
			WriteBuff.Data 				= (void *)&pnData[i];
			WriteBuff.pAdditionalInfo 	= (void *)&ulAbsoluteAddr ;
			ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Write(NULL, ADI_DEV_1D, (ADI_DEV_BUFFER *)&WriteBuff);

			ReadBuff.Data 				= (void *)&nCompare;
			ReadBuff.pAdditionalInfo 	= (void *)&ulAbsoluteAddr ;
			ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Read(NULL, ADI_DEV_1D, (ADI_DEV_BUFFER *)&ReadBuff);

			if( ( nCompare & 0xFF ) != (pnData[i] & 0xFF) )
			{
				bVerifyError = TRUE;
				break;
			}
		}
		else
		{
			return ErrorCode;
		}
	}

	// return appropriate error code if there was a verification error
	if( bVerifyError == TRUE )
		return VERIFY_WRITE;
}
// the user does not want to verify
else
{
	// write the buffer up to BUFFER_SIZE items
	for (i = 0; ( i < lCount ) && ( ErrorCode == NO_ERR ); i++, ulAbsoluteAddr += lStride)
	{

		// check to see that the address is within a valid sector
		CmdStruct.SGetSectNum.ulOffset = ulAbsoluteAddr;
		CmdStruct.SGetSectNum.pSectorNum = &ulSector;
		ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_GET_SECTNUM, &CmdStruct  );

		if( NO_ERR == ErrorCode )
		{
			// unlock the flash, do the write, increase shift, and wait for completion
			WriteBuff.Data 				= (void *)&pnData[i] ;
			WriteBuff.pAdditionalInfo 	= (void *)&ulAbsoluteAddr ;
			ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Write(NULL, ADI_DEV_1D, (ADI_DEV_BUFFER *)&WriteBuff);
		}
		else
		{
			return ErrorCode;
		}
	}
}

// return the appropriate error code
return ErrorCode;

}

//----------- R e a d D a t a ( ) ----------//
//
// PURPOSE
// Read a buffer from flash device.
//
// INPUTS
// unsigned long ulStart - address in flash to start the reads at
// long lCount - number of elements to read, in this case bytes
// long lStride - number of locations to skip between reads
// int *pnData - pointer to data buffer to fill
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs during reading
// NO_ERR - otherwise
//
// CHANGES
// 9-28-2005 Created

ERROR_CODE ReadData( unsigned long ulStart, long lCount, long lStride, int *pnData )
{

long i = 0;						// loop counter
ERROR_CODE ErrorCode = NO_ERR;	// tells whether there was an error trying to read
unsigned long ulAbsoluteAddr;   // current address to read
unsigned long ulSector = 0;		// sector number to verify address
unsigned long ulMask =0xffff;

ADI_DEV_1D_BUFFER		ReadBuff;	// buffer pointer

COMMAND_STRUCT	CmdStruct;	//structure for GetSectStartEnd

ulAbsoluteAddr = FLASH_START_ADDR + ulStart;

// read the buffer up to BUFFER_SIZE items
for (i = 0; (i < lCount) && (i < BUFFER_SIZE); i++, ulAbsoluteAddr += lStride)
{
	// check to see that the address is within a valid sector
	CmdStruct.SGetSectNum.ulOffset = ulAbsoluteAddr;
	CmdStruct.SGetSectNum.pSectorNum = &ulSector;
	ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Control(NULL, CNTRL_GET_SECTNUM, &CmdStruct  );

	if( NO_ERR == ErrorCode )
	{
		ReadBuff.Data 				= (void *)&pnData[i];
		ReadBuff.pAdditionalInfo 	= (void *)&ulAbsoluteAddr ;
		ErrorCode = (ERROR_CODE) ADIS29AL016DEntryPoint.adi_pdd_Read(NULL, ADI_DEV_1D, (ADI_DEV_BUFFER *)&ReadBuff);
	}
	else
	{
		return ErrorCode;
	}
}

// return the appropriate error code
return ErrorCode;

}

flash.c

//----- I n c l u d e s -----//
#include
#include
#include “s29al016.h”
#include “util.h”
#include “Errors.h”

//---- c o n s t a n t d e f i n i t i o n s -----//

static char *pFlashDesc = “S29AL016D70”;
static char *pDeviceCompany = “SPANSION”;

//---- F u n c t i o n P r o t o t y p e s ----//
// (for Helper Functions) //

static ERROR_CODE EraseFlash(unsigned long ulStartAddr);
static ERROR_CODE EraseBlock( int nBlock, unsigned long ulStartAddr );
static ERROR_CODE GetCodes(int *pnManCode, int *pnDevCode, unsigned long ulStartAddr);
static ERROR_CODE GetSectorNumber( unsigned long ulAddr, int *pnSector );
static ERROR_CODE GetSectorStartEnd( unsigned long *ulStartOff, unsigned long *ulEndOff, int nSector );
static ERROR_CODE PollToggleBit( const unsigned long ulOffset, const unsigned short usValue );
static ERROR_CODE ReadFlash(const unsigned long ulOffset, unsigned short *pusValue );
static ERROR_CODE ResetFlash(unsigned long ulStartAddr);
static ERROR_CODE WriteFlash(const unsigned long ulOffset, const unsigned short usValue );
static unsigned long GetFlashStartAddress( unsigned long ulAddr);

// Open a device
static u32 adi_pdd_Open(
ADI_DEV_MANAGER_HANDLE ManagerHandle, // device manager handle
u32 DeviceNumber, // device number
ADI_DEV_DEVICE_HANDLE DeviceHandle, // device handle
ADI_DEV_PDD_HANDLE *pPDDHandle, // pointer to PDD handle location
ADI_DEV_DIRECTION Direction, // data direction
void *pEnterCriticalArg, // enter critical region parameter
ADI_DMA_MANAGER_HANDLE DMAHandle, // handle to the DMA manager
ADI_DCB_HANDLE DCBHandle, // callback handle
ADI_DCB_CALLBACK_FN DMCallback // device manager callback function
);

// Close a device
static u32 adi_pdd_Close(
ADI_DEV_PDD_HANDLE PDDHandle
);

// Read from a device
static u32 adi_pdd_Read( ADI_DEV_PDD_HANDLE PDDHandle,
ADI_DEV_BUFFER_TYPE BufferType,
ADI_DEV_BUFFER *pBuffer);

// Write to a device
static u32 adi_pdd_Write( ADI_DEV_PDD_HANDLE PDDHandle,
ADI_DEV_BUFFER_TYPE BufferType,
ADI_DEV_BUFFER *pBuffer);

// Control the device
static u32 adi_pdd_Control( ADI_DEV_PDD_HANDLE PDDHandle,
u32 Command,
void *pArg);

ADI_DEV_PDD_ENTRY_POINT ADIS29AL016DEntryPoint =
{
adi_pdd_Open,
adi_pdd_Close,
adi_pdd_Read,
adi_pdd_Write,
adi_pdd_Control
};

// ---- P h y s i c a l D e v i c e D r i v e A P I f u n c t i o n s ----//

//----------- a d i _ p d d _ C l o s e ( ) ----------//
//
// PURPOSE
// This function opens the S29AL016D flash device for use.
//
// INPUTS
// ManagerHandle - device manager handle
// DeviceNumber - device number
// DeviceHandle - device handle
// PDDHandle - This is the handle used to identify the device
// Direction - data direction
// *pEnterCriticalArg - enter critical region parameter
// DMAHandle - handle to the DMA manager
// DCBHandle - callback handle
// DMCallback - device manager callback function
//
// RETURN VALUE
// Result

u32 adi_pdd_Open( // Open a device
ADI_DEV_MANAGER_HANDLE ManagerHandle, // device manager handle
u32 DeviceNumber, // device number
ADI_DEV_DEVICE_HANDLE DeviceHandle, // device handle
ADI_DEV_PDD_HANDLE *pPDDHandle, // pointer to PDD handle location
ADI_DEV_DIRECTION Direction, // data direction
void *pEnterCriticalArg, // enter critical region parameter
ADI_DMA_MANAGER_HANDLE DMAHandle, // handle to the DMA manager
ADI_DCB_HANDLE DCBHandle, // callback handle
ADI_DCB_CALLBACK_FN DMCallback ) // device manager callback function
{

// check for errors if required

#ifdef ADI_S29AL016D_ERROR_CHECKING_ENABLED
if (DeviceNumber > 0) // check the device number
return (ADI_DEV_RESULT_BAD_DEVICE_NUMBER);
if (Direction != ADI_DEV_DIRECTION_BIDIRECTIONAL) // check the direction
return (ADI_DEV_RESULT_DIRECTION_NOT_SUPPORTED);
#endif

return (NO_ERR);

}

//----------- a d i _ p d d _ C l o s e ( ) ----------//
//
// PURPOSE
// This function closes the S29AL016D flash device.
//
// INPUTS
// PDDHandle - This is the handle used to identify the device
//
// RETURN VALUE
// Result

u32 adi_pdd_Close(ADI_DEV_PDD_HANDLE PDDHandle) // PDD handle
{
return (NO_ERR);
}

//----------- a d i _ p d d _ R e a d ( ) ----------//
//
// PURPOSE
// Provides buffers to the S29AL016D flash device for reception
// of inbound data.
//
// INPUTS
// PDDHandle - This is the handle used to identify the device
// BufferType - This argument identifies the type of buffer: one-
// dimentional, two-dimensional or circular
// *pBuffer - The is the address of the buffer or first buffer in
// a chain of buffers
//
// RETURN VALUE
// Result

u32 adi_pdd_Read( ADI_DEV_PDD_HANDLE PDDHandle,
ADI_DEV_BUFFER_TYPE BufferType,
ADI_DEV_BUFFER *pBuffer)
{

ADI_DEV_1D_BUFFER *pBuff1D;
unsigned short    *pusValue;
unsigned long	  *pulAbsoluteAddr;
u32		Result;

// cast our buffer to a 1D buffer
pBuff1D = (ADI_DEV_1D_BUFFER*)pBuffer;

// cast our data buffer
pusValue = (unsigned short *)pBuff1D->Data;

// cast our offset
pulAbsoluteAddr = (unsigned long *)pBuff1D->pAdditionalInfo;

Result = ReadFlash( *pulAbsoluteAddr, pusValue );

return(Result);

}

//----------- a d i _ p d d _ W r i t e ( ) ----------//
//
// PURPOSE
// Provides buffers to the S29AL016D flash device for transmission
// of outbound data.
//
// INPUTS
// PDDHandle - This is the handle used to identify the device
// BufferType - This argument identifies the type of buffer: one-
// dimentional, two-dimensional or circular
// *pBuffer - The is the address of the buffer or first buffer in
// a chain of buffers
//
// RETURN VALUE
// Result

u32 adi_pdd_Write( ADI_DEV_PDD_HANDLE PDDHandle,
ADI_DEV_BUFFER_TYPE BufferType,
ADI_DEV_BUFFER *pBuffer)
{
ADI_DEV_1D_BUFFER *pBuff1D; // buffer pointer
short *psValue; // stores the value to be written to flash
unsigned long *pulAbsoluteAddr; // the absolute address to write
unsigned long ulFlashStartAddr; // flash start address
u32 Result; // error code returned

// cast our buffer to a 1D buffer
pBuff1D = (ADI_DEV_1D_BUFFER*)pBuffer;

// cast our data buffer
psValue = (short *)pBuff1D->Data;

// cast our offset
pulAbsoluteAddr = (unsigned long *)pBuff1D->pAdditionalInfo;

// get flash start address from absolute address
ulFlashStartAddr = *pulAbsoluteAddr;
ulFlashStartAddr &= 0xFFFF0000;

WriteFlash( ulFlashStartAddr, 0x00 );
WriteFlash( ulFlashStartAddr+0xaaa, 0xaa );
WriteFlash( ulFlashStartAddr+0x555, 0x55 );
WriteFlash( ulFlashStartAddr+0xaaa, 0xa0 );

// program our actual value now
Result = WriteFlash( *pulAbsoluteAddr, *psValue);

// make sure the write was successful
Result = PollToggleBit(*pulAbsoluteAddr, *psValue & 0xff);

return(Result);

}

//----------- a d i _ p d d _ C o n t r o l ( ) ----------//
//
// PURPOSE
// This function sets or detects a configuration parameter
// for the S29AL016D flash device.
//
// INPUTS
// PDDHandle - This is the handle used to identify the device
// Command - This is the command identifier
// *pArg - The is the address of command-specific parameter
//
// RETURN VALUE
// Result

u32 adi_pdd_Control( ADI_DEV_PDD_HANDLE PDDHandle,
u32 Command,
void *pArg)
{

ERROR_CODE ErrorCode = NO_ERR;

COMMAND_STRUCT *pCmdStruct = (COMMAND_STRUCT *)pArg;

// switch on the command
switch ( Command )
{
	// erase all
	case CNTRL_ERASE_ALL:
		ErrorCode = EraseFlash(pCmdStruct->SEraseAll.ulFlashStartAddr);
		break;

	// erase sector
	case CNTRL_ERASE_SECT:
		ErrorCode = EraseBlock( pCmdStruct->SEraseSect.nSectorNum, pCmdStruct->SEraseSect.ulFlashStartAddr );
		break;

	// get manufacturer and device codes
	case CNTRL_GET_CODES:
		ErrorCode = GetCodes((int *)pCmdStruct->SGetCodes.pManCode, (int *)pCmdStruct->SGetCodes.pDevCode, (unsigned long)pCmdStruct->SGetCodes.ulFlashStartAddr);
		break;

	case CNTRL_GET_DESC:
		//Filling the contents with data
		//pCmdStruct->SGetDesc.pTitle = pEzKitTitle;
		pCmdStruct->SGetDesc.pDesc  = pFlashDesc;
		pCmdStruct->SGetDesc.pFlashCompany  = pDeviceCompany;
		break;

	// get sector number based on address
	case CNTRL_GET_SECTNUM:
		ErrorCode = GetSectorNumber( pCmdStruct->SGetSectNum.ulOffset, (int *)pCmdStruct->SGetSectNum.pSectorNum );
		break;

	// get sector number start and end offset
	case CNTRL_GET_SECSTARTEND:
		ErrorCode = GetSectorStartEnd( pCmdStruct->SSectStartEnd.pStartOffset, pCmdStruct->SSectStartEnd.pEndOffset, pCmdStruct->SSectStartEnd.nSectorNum );
		break;

	// reset
	case CNTRL_RESET:
		ErrorCode = ResetFlash(pCmdStruct->SReset.ulFlashStartAddr);
		break;

	// no command or unknown command do nothing
	default:
		// set our error
		ErrorCode = UNKNOWN_COMMAND;
		break;
}

// return
return(ErrorCode);

}

//----- H e l p e r F u n c t i o n s ----//

//----------- R e s e t F l a s h ( ) ----------//
//
// 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

ERROR_CODE 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
// return to standard operation mode

WriteFlash( ulFlashStartAddr + 0xaaa , 0xF0 );

// WriteFlash( ulFlashStartAddr + 0x555 , 0xF0 );

// reset should be complete
return NO_ERR;

}

//----------- E r a s e F l a s h ( ) ----------//
//
// 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 in Main Flash Array

WriteFlash( ulFlashStartAddr + 0xaaa, 0xaa );
WriteFlash( ulFlashStartAddr + 0x555, 0x55 );
WriteFlash( ulFlashStartAddr + 0xaaa, 0x80 );
WriteFlash( ulFlashStartAddr + 0xaaa, 0xaa );
WriteFlash( ulFlashStartAddr + 0x555, 0x55 );
WriteFlash( ulFlashStartAddr + 0xaaa, 0x10 );
	
	// poll until the command has completed
ErrorCode = PollToggleBit(ulFlashStartAddr, 0xFF);

// erase should be complete
return ErrorCode;

}

//----------- E r a s e B l o c k ( ) ----------//
//
// 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 + ulSectStart+ 0xaaa), 0xaa );
WriteFlash( (ulFlashStartAddr + ulSectStart+ 0x555), 0x55 );
WriteFlash( (ulFlashStartAddr + ulSectStart+ 0xaaa), 0x80 );
WriteFlash( (ulFlashStartAddr + ulSectStart+ 0xaaa), 0xaa );
WriteFlash( (ulFlashStartAddr + ulSectStart+ 0x555), 0x55 );
WriteFlash( (ulFlashStartAddr + ulSectStart), 0x30 );

// poll until the command has completed
ErrorCode = PollToggleBit(ulFlashStartAddr + ulSectStart, 0xFF);

// block erase should be complete
return ErrorCode;

}

//----------- P o l l T o g g l e B i t ( ) ----------//
//
// 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

ERROR_CODE PollToggleBit( const unsigned long ulOffset, const unsigned short usValue )
{
bool bError = TRUE; // flag to indicate error
bool bPass = FALSE; // flag indicating passing
int nTimeOut = 0x1FFFFF; // timeout after a while
ERROR_CODE ErrorCode = NO_ERR; // flag to indicate error
unsigned short nReadVal = 0;

while( bError && !bPass )
{
	// read the data
	ReadFlash( ulOffset, &nReadVal );

	// see if the data read == data written
	if( (nReadVal & 0xFF) != usValue )
	{
		// check DQ5 bit for error
		if( (nReadVal & 0x20) == 0x20 )
			bError = FALSE;
	}
	else
		bPass = TRUE;
}

// if we didn't pass yet then make sure DQ7 was
// not changing simultaneously with DQ5
if( !bPass )
{
	ReadFlash( ulOffset, &nReadVal );

	// see if the data read == data written
	if( (nReadVal & 0xFF) == usValue )
		bPass = TRUE;
}

if( !bPass )
	ErrorCode = POLL_TIMEOUT;

// we can return
return ErrorCode;

}

//----------- G e t C o d e s ( ) ----------//
//
// 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

ERROR_CODE GetCodes(int *pnManCode, int *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
// return to standard operation mode

WriteFlash( ulFlashStartAddr + 0xaaa, 0xAA );
WriteFlash( ulFlashStartAddr + 0x555, 0x55 );
WriteFlash( ulFlashStartAddr + 0xaaa, 0x90 );

// read the manufacturer code
ReadFlash( ulFlashStartAddr , (unsigned short *)pnManCode );
*pnManCode &= 0x00FF;

ReadFlash( ulFlashStartAddr + 0x02, (unsigned short *)pnDevCode );
*pnDevCode &= 0x00FF;

// 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);

// ok
return NO_ERR;

}

//----------- G e t S e c t o r N u m b e r ( ) ----------//
//
// 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

ERROR_CODE GetSectorNumber( unsigned long ulAddr, int *pnSector )
{
int nSector = 0;

// get offset from absolute address
unsigned long ulMask  = 0x3fffff;		 //offset mask
unsigned long ulOffset= ulAddr & ulMask; //offset

// determine the sector
nSector = ulOffset & 0xffff0000;
nSector = ulOffset >> 16;
nSector = nSector & 0x000f;

// 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;

}

//----------- G e t S e c t o r S t a r t E n d ( ) ----------//
//
// 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

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 0

// block is in main flash
if( ( nSector < NUM_SECTORS ))
{
	*ulStartOff =(nSector * ulBlkSize );
	*ulEndOff = ( (*ulStartOff) + ulBlkSize ) - 1;
}
// no such sector
else
  	return INVALID_SECTOR;

// ok
return NO_ERR;

}

//----------- G e t F l a s h S t a r t A d d r e s s ( ) ----------//
//
// PURPOSE
// Gets flash start address from an absolute address.
//
// INPUTS
// unsigned long ulAddr - absolute address
//
// RETURN VALUE
// unsigned long - Flash start address

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);

}

//----------- R e a d F l a s h ( ) ----------//
//
// 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
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise

ERROR_CODE ReadFlash( const unsigned long ulAddr, unsigned short *pusValue )
{
// set our flash address to where we want to read
volatile unsigned short *pFlashAddr = (volatile unsigned short *)(ulAddr);

// read the value
*pusValue = (unsigned short)*pFlashAddr;

// ok
return NO_ERR;

}

//----------- W r i t e F l a s h ( ) ----------//
//
// 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
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise

ERROR_CODE WriteFlash( const unsigned long ulAddr, const unsigned short usValue )
{

// set the address
volatile unsigned short *pFlashAddr = (volatile unsigned short *)(ulAddr);

*pFlashAddr = usValue;

// ok
return NO_ERR;

}

你可能感兴趣的:(ADI,DSP资料下载,ADI,DSP技术中心,音频DSP开发,ADI,DSP,ADI,DSP中文资料,ADI音频DSP开发)