ADSP-21489的开发详解:SPIflash的硬件设计及程序烧写详解(含Flash驱动源码)_spi烧录原理图-程序员宅基地

技术标签: ADI DSP中文资料  ADI DSP资料下载  ADI DSP  ADI音频DSP开发  ADI DSP技术中心  音频DSP开发  

硬件准备

ADSP-21489EVB:ADI 21489处理器的开发板
AD-HP530ICE:ADI DSP专用仿真器
USBi:ADI SigmaDSP和SHARC DSP的图形化编程调试器

软件准备:

Visual DSP++
CCES
SigmaStudio

硬件链接示意图

在这里插入图片描述
SPIflash设计的硬件原理图

在这里插入图片描述

编程

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

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

在这里插入图片描述

烧写

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

在这里插入图片描述

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

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

在这里插入图片描述

  1. 找到“ADSP21489_SPIFlashDriver”文件。

在这里插入图片描述

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

在这里插入图片描述

  1. 烧写过程中的读条,请静心等待。(由于选择的是擦空整个 Flash,然后再写入,所以进度条有点慢,刚开始的时候不读条是在擦空,后面如果自己做板子,空白 Flash 进行烧写,则可以选不擦出直接烧,读条进度就很快了)

在这里插入图片描述

  1. 完成烧写。

在这里插入图片描述

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

在这里插入图片描述

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

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

驱动程序源码

/* includes /
#ifdef ADSP21469
#include <cdef21469.h>
#include <def21469.h>
#elif ADSP21479
#include <cdef21479.h>
#include <def21479.h>
#elif ADSP21489
#include <cdef21489.h>
#include <def21489.h>
#else
#error "
** The flash driver does not yet support this processor ***"
#endif
#include <stdio.h>
#include <drivers\flash\util.h>
#include <drivers\flash\Errors.h>
#include <drivers\flash\m25p16.h>

#include <sru.h>
#include <sysreg.h>

#define NRDY BIT_0
#define PAGE_LENGTH 64 //(in 32-bit words)
#define NUM_SECTORS 32 /* number of sectors in the flash device */

static char *pFlashDesc = “STMicro. M25P16”;
static char *pDeviceCompany = “STMicroelectronics”;

static int gNumSectors = NUM_SECTORS;

#undef TIMEOUT
#undef DELAY

/* flash commands */
#define SPI_WREN (0x06) //Set Write Enable Latch
#define SPI_WRDI (0x04) //Reset Write Enable Latch
#define SPI_RDID (0x9F) //Read Identification
#define SPI_RDSR (0x05) //Read Status Register
#define SPI_WRSR (0x01) //Write Status Register
#define SPI_READ (0x03) //Read data from memory
#define SPI_FAST_READ (0x0B) //Read data from memory
#define SPI_PP (0x02) //Program Data into memory
#define SPI_SE (0xD8) //Erase one sector in memory
#define SPI_BE (0xC7) //Erase all memory
#define WIP (0x1) //Check the write in progress bit of the SPI status register
#define WEL (0x2) //Check the write enable bit of the SPI status register

#define SPI_PAGE_SIZE (528)
#define SPI_SECTORS (512)
#define SPI_SECTOR_SIZE (4224)
#define SPI_SECTOR_DIFF (3968)
#define PAGE_BITS (10)
#define PAGE_SIZE_DIFF (496)

#define DELAY 300
#define TIMEOUT 35000*64

/* function prototypes */
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 ReadFlash(unsigned long ulOffset, unsigned short *pusValue );
static ERROR_CODE ResetFlash(unsigned long ulStartAddr);
static ERROR_CODE WriteFlash(unsigned long ulOffset, unsigned short usValue );
static unsigned long GetFlashStartAddress( unsigned long ulAddr);

static ERROR_CODE ReadStatusRegister(int *pStatus);
static ERROR_CODE Wait_For_SPIF(void);
static ERROR_CODE SendSingleCommand( const int nCommand );
static ERROR_CODE Wait_For_RDY( void );
static void Assert_SPI_CS(void);
static void Clear_SPI_CS(void);
static ERROR_CODE WriteByteToSPI(const int byByte, const int msb_lsb);
static ERROR_CODE ReadByteFromSPI(int *pbyByte, const int msb_lsb);

ERROR_CODE m25p16_Open(void)
{
/* setup baud rate */
*pSPIBAUD = BAUD_RATE_DIVISOR;

return (NO_ERR);

}

ERROR_CODE m25p16_Close(void)
{
return (NO_ERR);
}

ERROR_CODE m25p16_Read( unsigned short *pusData,
unsigned long ulStartAddress,
unsigned int uiCount )
{
ERROR_CODE Result = NO_ERR;
unsigned int i = 0;
unsigned short *pusCurrentData = pusData;
unsigned long ulCurrentAddress = ulStartAddress;

for (i = 0; i < uiCount; i++, ulCurrentAddress++, pusCurrentData++)
{
	Assert_SPI_CS();

	// 1 byte of command
	if( NO_ERR != WriteByteToSPI( SPI_READ, MSBF ) )
	{
		Clear_SPI_CS();
		return POLL_TIMEOUT;
	}

	// 1 byte of address
	if( NO_ERR != WriteByteToSPI( (ulCurrentAddress >> 16), MSBF ) )
	{
		Clear_SPI_CS();
		return POLL_TIMEOUT;
	}

	// 1 byte of address
	if( NO_ERR != WriteByteToSPI( (ulCurrentAddress >> 8), MSBF ) )
	{
		Clear_SPI_CS();
		return POLL_TIMEOUT;
	}

	// 1 byte of address
	if( NO_ERR != WriteByteToSPI( ulCurrentAddress, MSBF ) )
	{
		Clear_SPI_CS();
		return POLL_TIMEOUT;
	}

	// 1 byte of garbage data
	if( NO_ERR != ReadByteFromSPI( (int*)pusCurrentData, 0 ) )
	{
		Clear_SPI_CS();
		return POLL_TIMEOUT;
	}

	// 1 byte of GOOD data
	if( NO_ERR != ReadByteFromSPI( (int*)pusCurrentData, 0 ) )
	{
		Clear_SPI_CS();
		return POLL_TIMEOUT;
	}

	Clear_SPI_CS();
}

return(Result);

}

ERROR_CODE m25p16_Write( unsigned short *pusData,
unsigned long ulStartAddress,
unsigned int uiCount )
{
ERROR_CODE Result = NO_ERR;
unsigned int i = 0;
unsigned short *pusCurrentData = pusData;
unsigned long ulCurrentAddress = ulStartAddress;

for (i = 0; i < uiCount; i++, ulCurrentAddress++, pusCurrentData++)
{
	SendSingleCommand( SPI_WREN );	// write enable

	Assert_SPI_CS();

	// 1 byte of command
	if( NO_ERR != WriteByteToSPI( SPI_PP, MSBF ) )
	{
		Clear_SPI_CS();
		return POLL_TIMEOUT;
	}

	// 1 byte of address
	if( NO_ERR != WriteByteToSPI( (ulCurrentAddress >> 16), MSBF ) )
	{
		Clear_SPI_CS();
		return POLL_TIMEOUT;
	}

	// 1 byte of address
	if( NO_ERR != WriteByteToSPI( (ulCurrentAddress >> 8), MSBF ) )
	{
		Clear_SPI_CS();
		return POLL_TIMEOUT;
	}

	// 1 byte of address
	if( NO_ERR != WriteByteToSPI( ulCurrentAddress, MSBF ) )
	{
		Clear_SPI_CS();
		return POLL_TIMEOUT;
	}

	// 1 byte of data
	if( NO_ERR != WriteByteToSPI( *pusCurrentData, 0 ) )
	{
		Clear_SPI_CS();
		return POLL_TIMEOUT;
	}

	Clear_SPI_CS();

	// wait for the write to complete.
	if( NO_ERR != Wait_For_RDY() )
	{
		return POLL_TIMEOUT;
	}


	// send the write disable command
	return SendSingleCommand( SPI_WRDI );	// write disable
}

return(Result);

}

ERROR_CODE m25p16_Control( unsigned int uiCmd,
COMMAND_STRUCT *pCmdStruct)
{
ERROR_CODE ErrorCode = NO_ERR;

// switch on the command
switch ( uiCmd )
{
	// 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.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;

	// get the number of sectors
	case CNTRL_GETNUM_SECTORS:
		pCmdStruct->SGetNumSectors.pnNumSectors[0] = gNumSectors;
		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);

}

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

ERROR_CODE ErrorCode = NO_ERR;
int nStatus;

ErrorCode = ReadStatusRegister(&nStatus);

return ErrorCode;

}

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

int nTimeout = 1000;

if( NO_ERR != SendSingleCommand( SPI_WREN ) )	// write enable
{
	return POLL_TIMEOUT;
}

if( NO_ERR != SendSingleCommand( SPI_BE ) )	// erase command
{
	return POLL_TIMEOUT;
}

// The Wait_For_RDY() function will timeout after 1000 loops,
// however that is not long enough for an erase, so it's enclosed
// here to give it 1000 * 1000 loops, long enough for an erase  operation
while(nTimeout-- > 0 )
{
	if( NO_ERR == Wait_For_RDY() )
	{
		// send the write disable command
		return SendSingleCommand( SPI_WRDI );	// write disable
	}
}

return POLL_TIMEOUT;

}

//----------- 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)
int nTimeout = 1000;
int nSecAddr = 0;

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

SendSingleCommand( SPI_WREN );	// write enable

Assert_SPI_CS();

// 1 byte of data
if( NO_ERR != WriteByteToSPI( SPI_SE, MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of address
if( NO_ERR != WriteByteToSPI( (ulSectStart >> 16), MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of address
if( NO_ERR != WriteByteToSPI( (ulSectStart >> 8), MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of address
if( NO_ERR != WriteByteToSPI( ulSectStart, MSBF ) )
	{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

Clear_SPI_CS();

// The Wait_For_RDY() function will timeout after 1000 loops,
// however that is not long enough for an erase, so it's enclosed
// here to give it 1000 * 1000 loops, long enough for an erase  operation
while(nTimeout-- > 0 )
{
	if( NO_ERR == Wait_For_RDY() )
	{
		// send the write disable command
		return SendSingleCommand( SPI_WRDI );	// write disable
	}
}

return POLL_TIMEOUT;

}

//----------- 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)
{
int wWord = 0;

Assert_SPI_CS();

if( NO_ERR != WriteByteToSPI( SPI_RDID, MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// This is a dummy read which pulls in the
// SO data clocked in from the write.
if( NO_ERR != ReadByteFromSPI(&wWord, MSBF) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// this is the real data after the write
if( NO_ERR != ReadByteFromSPI(pnManCode, MSBF) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// This is a dummy read which pulls in the
// SO data clocked in from the write.
if( NO_ERR != ReadByteFromSPI(&wWord, MSBF) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// this is the real data after the write
if( NO_ERR != ReadByteFromSPI(pnDevCode, MSBF) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

Clear_SPI_CS();

return ResetFlash(ulAddr);

}

//----------- 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;
int i;
int error_code = 1;
unsigned long ulMask; //offset mask
unsigned long ulOffset; //offset
unsigned long ulStartOff;
unsigned long ulEndOff;

ulMask      	  = 0x7ffffff;
ulOffset		  = ulAddr & ulMask;

for(i = 0; i < gNumSectors; i++)
{
    GetSectorStartEnd(&ulStartOff, &ulEndOff, i);
	if ( (ulOffset >= ulStartOff)
		&& (ulOffset <= ulEndOff) )
	{
		error_code = 0;
		nSector = i;
		break;
	}
}

// if it is a valid sector, set it
if (error_code == 0)
	*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 )
{
unsigned long ulSectorSize = 0x10000;

if( ( nSector >= 0 ) && ( nSector < gNumSectors ) ) // 32 sectors
	{
		*ulStartOff = nSector * ulSectorSize;
		*ulEndOff = ( (*ulStartOff) + ulSectorSize - 1 );
	}
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

ulFlashStartAddr  =  0;

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( unsigned long ulAddr, unsigned short *pusValue )
{

Assert_SPI_CS();

// 1 byte of command
if( NO_ERR != WriteByteToSPI( SPI_READ, MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of address
if( NO_ERR != WriteByteToSPI( (ulAddr >> 16), MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of address
if( NO_ERR != WriteByteToSPI( (ulAddr >> 8), MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of address
if( NO_ERR != WriteByteToSPI( ulAddr, MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of garbage data
if( NO_ERR != ReadByteFromSPI( (int*)pusValue, 0 ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of GOOD data
if( NO_ERR != ReadByteFromSPI( (int*)pusValue, 0 ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

Clear_SPI_CS();

// 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( unsigned long ulAddr, unsigned short usValue )
{
SendSingleCommand( SPI_WREN ); // write enable

Assert_SPI_CS();

// 1 byte of command
if( NO_ERR != WriteByteToSPI( SPI_PP, MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of address
if( NO_ERR != WriteByteToSPI( (ulAddr >> 16), MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of address
if( NO_ERR != WriteByteToSPI( (ulAddr >> 8), MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of address
if( NO_ERR != WriteByteToSPI( ulAddr, MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// 1 byte of data
if( NO_ERR != WriteByteToSPI( usValue, 0 ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}


Clear_SPI_CS();

// wait for the write to complete.
if( NO_ERR != Wait_For_RDY() )
{
	return POLL_TIMEOUT;
}


// send the write disable command
return SendSingleCommand( SPI_WRDI );	// write disable

}

//----------- R e a d S t a t u s R e g i s t e r ( ) ----------//
//
// PURPOSE (2 Bytes)
// Returns the 8-bit value of the status register.
//
// OUTPUTS second read byte ,
// first read byte is garbage.
// Core sends the command
//
// RETURN VALUE
// Staus of the register

ERROR_CODE ReadStatusRegister(int *pStatus)
{
int wWord = 0;

// clear the RX buffer
*pSPICTL |= (RXFLSH);
asm("nop;");
asm("nop;");
asm("nop;");

Assert_SPI_CS();

if( NO_ERR != WriteByteToSPI( SPI_RDSR, MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// This is a dummy read which pulls in the
// SO data clocked in from the write.
if( NO_ERR != ReadByteFromSPI(pStatus, MSBF) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

// this is the real data after the write
if( NO_ERR != ReadByteFromSPI(pStatus, MSBF) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

Clear_SPI_CS();


return NO_ERR;

}

//
//
// ERROR_CODE WriteByteToSPI(const int byByte, const int msb_lsb)
//
// Writes one byte to the SPI port can write in either msb or lsb format
// waits for the spi to clear the SPIF bit meaning the data
// has been sent
//
//

ERROR_CODE WriteByteToSPI(const int byByte, const int msb_lsb)
{
int nTimeOut = 100000;
int n;

if( NO_ERR != Wait_For_SPIF() )
{
	return POLL_TIMEOUT;
}

while( (TXS & *pSPISTAT) )
{
	if( nTimeOut-- < 0 )
	{
		return POLL_TIMEOUT;
	}
}

*pSPICTL = (SPIEN|SPIMS|SENDZ|TIMOD1|WL8|msb_lsb);
asm("nop;");
asm("nop;");
asm("nop;");
*pTXSPI = byByte;

if( NO_ERR != Wait_For_SPIF() )
{
	return POLL_TIMEOUT;
}

return NO_ERR;

}

//
//
// ERROR_CODE ReadByteFromSPI(int *pbyByte, const int msb_lsb)
//
// Reads one byte from the spi port. This may or may not cause a sclk or send
// event. If there is something waiting in the spi RX buffer, this will not
// cause an sclk shift from the spi
//
//

ERROR_CODE ReadByteFromSPI(int *pbyByte, const int msb_lsb)
{
int nTimeOut = 1000;

if( NO_ERR != Wait_For_SPIF() )
{
	return POLL_TIMEOUT;
}


// don't read until there is something to read.
nTimeOut = 1000;
while( !(RXS & *pSPISTAT) )
{
	if( nTimeOut-- < 0 )
	{
		return POLL_TIMEOUT;
	}
}

*pSPICTL = (SPIEN|SPIMS|SENDZ|WL8|msb_lsb);
asm("nop;");
asm("nop;");
asm("nop;");
*pbyByte = *pRXSPI;

return NO_ERR;

}

//
//
// void Assert_SPI_CS(void)
//
// Asserts the CS on FLG4 setup by the SRU
//
//

void Assert_SPI_CS(void)
{
int n;

#if ( defined(ADSP21375) || defined(ADSP21369) || defined(ADSP21469) || defined (ADSP21479)|| defined (ADSP21489) )
//Then control the level of flag 4
sysreg_bit_clr( sysreg_FLAGS, FLG4 ); //logic low
#elif (ADSP21364) || (ADSP21262)
//Then control the level of flag 0
sysreg_bit_clr( sysreg_FLAGS, FLG0 ); //logic low
#endif

*pSPIBAUD = BAUD_RATE_DIVISOR;

}

//
//
// void Clear_SPI_CS(void)
//
// DE-Asserts the CS on FLG4 setup by the SRU
//
//

void Clear_SPI_CS(void)
{
int n;

#if ( defined(ADSP21375) || defined(ADSP21369) || defined(ADSP21469) || defined (ADSP21479) || defined (ADSP21489) )
//Then control the level of flag 4
sysreg_bit_set( sysreg_FLAGS, FLG4 ); //Logic high
#elif (ADSP21364) || (ADSP21262)
//Then control the level of flag 0
sysreg_bit_set( sysreg_FLAGS, FLG0 ); //Logic high
#endif
*pSPIBAUD = 0;

}

//----------- W a i t _ f o r _ S P I F ( ) ----------//
//
// PURPOSE (1 Byte)
// Polls the SPIF (SPI single word transfer complete) bit
// of SPISTAT until the transfer is complete.
//

ERROR_CODE Wait_For_SPIF(void)
{

int nTimeout = 10000;
// status updates can be delayed up to 10 cycles
// so wait at least 10 cycles before even
// checking them
int n;

// make sure nothing is waiting to be sent
while( !(SPIF & *pSPISTAT) )
{
	if( nTimeout-- < 0 )
	{
		return POLL_TIMEOUT;
	}
}

return NO_ERR;

}

ERROR_CODE SendSingleCommand( const int iCommand )
{

Assert_SPI_CS();

if( NO_ERR != WriteByteToSPI( iCommand, MSBF ) )
{
	Clear_SPI_CS();
	return POLL_TIMEOUT;
}

Clear_SPI_CS();

return NO_ERR;

}

//----------- W a i t _ f o r _ R D Y ( ) ----------//
//
// PURPOSE (1 Byte)
// Polls the RDY (Write In Progress) bit of the Flash’s status
// register until the Flash is finished with its access. Accesses
// that are affected by a latency are Page_Program, Sector_Erase,
// and Block_Erase.

ERROR_CODE Wait_For_RDY( void )
{
int nTimeout = 10000;
int n;
int iTest;

while(nTimeout-- > 0)
{
	ReadStatusRegister(&iTest);
	if( !(iTest & NRDY) )
	{
		return NO_ERR;
	}
};


// we can return
return POLL_TIMEOUT;

}

main.c

#ifdef ADSP21489
#include <cdef21489.h>
#include <def21489.h>
#elif ADSP21479
#include <cdef21479.h>
#include <def21479.h>
#endif

#include <stdlib.h> /* malloc */
#include <drivers\flash\util.h>
#include <drivers\flash\Errors.h>
#include <drivers\flash\m25p16.h>
#include <sru.h>
#include <sysreg.h>

#ifndef TRUE
#define TRUE (1)
#endif

#ifndef FALSE
#define FALSE (0)
#endif

#define FLASH_START_ADDR 0x000000
#define BUFFER_SIZE 0x400
//#define BAUD_RATE_DIVISOR 100

/* Flash Programmer commands */
typedef enum
{
FLASH_NO_COMMAND, // 0
FLASH_GET_CODES, // 1
FLASH_RESET, // 2
FLASH_WRITE, // 3
FLASH_FILL, // 4
FLASH_ERASE_ALL, // 5
FLASH_ERASE_SECT, // 6
FLASH_READ, // 7
FLASH_GET_SECTNUM, // 8
FLASH_GET_SECSTARTEND, // 9
}enProgCmds;

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

char *AFP_Title ; // EzKit info
char *AFP_Description; // Device Description
char *AFP_DeviceCompany; // Device Company
char *AFP_DrvVersion = “1.00.0”; // Driver Version
char *AFP_BuildDate = DATE; // Driver Build Date
enProgCmds AFP_Command = FLASH_NO_COMMAND; // command sent down from the GUI
int AFP_ManCode = -1; // manufacturer code
int AFP_DevCode = -1; // device code
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 = -1; // number of sectors in the flash device
int AFP_Sector = -1; // sector number
int AFP_Error = NO_ERR; // 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

#ifdef ADSP21489
static char *pEzKitTitle = “ADSP-21489 EZ-Board”;
#elif ADSP21479
static char *pEzKitTitle = “ADSP-21479 EZ-Board”;
#else
#error “Error: Unknown EZ-Board”
#endif

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

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

ERROR_CODE OpenFlashDevice(void);
ERROR_CODE GetNumSectors(void);
ERROR_CODE AllocateAFPBuffer(void);
ERROR_CODE GetSectorMap(SECTORLOCATION *pSectInfo);
ERROR_CODE GetFlashInfo(void);
ERROR_CODE ProcessCommand(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 );
ERROR_CODE SetupForFlash(void);
void FreeAFPBuffer(void);
void InitPLL_SDRAM(void);

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

int main(void)
{

SECTORLOCATION *pSectorInfo;
ERROR_CODE Result;							// result

/* open flash driver */
AFP_Error = m25p16_Open();

// 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 == NO_ERR )
{
	AFP_Error = GetFlashInfo();
}

// get the number of sectors for this device
if( AFP_Error == NO_ERR )
{
	AFP_Error = GetNumSectors();
}

if( AFP_Error == NO_ERR )
{
	// malloc enough space to hold our start and end offsets
	pSectorInfo = (SECTORLOCATION *)malloc(AFP_NumSectors * sizeof(SECTORLOCATION));
}

// allocate AFP_Buffer
if( AFP_Error == NO_ERR )
{
	AFP_Error = AllocateAFPBuffer();
}

// get sector map
if( AFP_Error == NO_ERR )
{
	AFP_Error = GetSectorMap(pSectorInfo);
}

// point AFP_SectorInfo to our sector info structure
if( AFP_Error == NO_ERR )
{
	AFP_SectorInfo = (int*)pSectorInfo;
}

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

if( pSectorInfo )
{
	free(pSectorInfo);
	pSectorInfo = NULL;
}

// Close the Device
AFP_Error = m25p16_Close();

if (AFP_Error != NO_ERR)
	return FALSE;

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 FLASH_ERASE_ALL:
		CmdStruct.SEraseAll.ulFlashStartAddr 	= FLASH_START_ADDR;	//FlashStartAddress
		ErrorCode = m25p16_Control( CNTRL_ERASE_ALL, &CmdStruct );
		break;

	// erase sector
	case FLASH_ERASE_SECT:
		CmdStruct.SEraseSect.nSectorNum  		= AFP_Sector;		// Sector Number to erase
		CmdStruct.SEraseSect.ulFlashStartAddr 	= FLASH_START_ADDR;	// FlashStartAddress
		ErrorCode = m25p16_Control( CNTRL_ERASE_SECT, &CmdStruct);
		break;

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

	// get manufacturer and device codes
	case FLASH_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 = m25p16_Control( CNTRL_GET_CODES, &CmdStruct);
		break;

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

	// get sector number start and end offset
	case FLASH_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 = m25p16_Control( CNTRL_GET_SECSTARTEND, &CmdStruct );
		break;

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

	// reset
	case FLASH_RESET:
		CmdStruct.SGetCodes.ulFlashStartAddr 	= FLASH_START_ADDR; //Flash start address
		ErrorCode = m25p16_Control( CNTRL_RESET, &CmdStruct);
		break;

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

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

// clear the command
AFP_Command = FLASH_NO_COMMAND;

return(ErrorCode);

}

//----------- 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()
{

#if ( defined(ADSP21375) || defined(ADSP21369) || defined(ADSP21469) || defined(ADSP21479) || defined(ADSP21489))
SRU(SPI_CLK_O,DPI_PB03_I);
SRU(HIGH,DPI_PBEN03_I);

// for the flag pins to act as chip select
SRU(FLAG4_O, DPI_PB05_I);
SRU(HIGH, DPI_PBEN05_I);


//First set flag 4 as an output
sysreg_bit_set( sysreg_FLAGS, FLG4O ); //asm("bit set flags FLG4O;");
sysreg_bit_set( sysreg_FLAGS, FLG4 ); //asm("bit set flags FLG4;"); //Logic high

#elif (ADSP21364) || (ADSP21262)

//First set flag 0 as an output
sysreg_bit_set( sysreg_FLAGS, FLG0O ); //asm("bit set flags FLG0O;");
sysreg_bit_set( sysreg_FLAGS, FLG0 ); //asm("bit set flags FLG0;"); //Logic high

#endif

*pSPIDMAC = 0;
*pSPIBAUD = 0;
*pSPIFLG = 0xF80;
*pSPICTL = 0x400;

return NO_ERR;

}

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

// the data type of the data being sent from the flash programmer GUI
// is in bytes but we store the data as integers to make data
// manipulation easier when actually programming the data.  This is why
// BUFFER_SIZE bytes are being allocated rather than BUFFER_SIZE * sizeof(int).
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 );

}

//----------- G e t N u m S e c t o r s ( ) ----------//
//
// PURPOSE
// Get the number of sectors for this device.
//
// RETURN VALUE
// ERROR_CODE - value if any error occurs
// NO_ERR - otherwise
//
// CHANGES
// 9-28-2005 Created

ERROR_CODE GetNumSectors(void)
{

ERROR_CODE ErrorCode = NO_ERR;			//return error code

GET_NUM_SECTORS_STRUCT	SGetNumSectors;	//structure for GetNumSectors
SGetNumSectors.pnNumSectors = &AFP_NumSectors;

ErrorCode = m25p16_Control( CNTRL_GETNUM_SECTORS, (COMMAND_STRUCT *)&SGetNumSectors  );

return(ErrorCode);

}

//----------- 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(SECTORLOCATION *pSectInfo)
{

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<AFP_NumSectors; i++)
{
	SSectStartEnd.nSectorNum = i;
	SSectStartEnd.pStartOffset = &pSectInfo[i].ulStartOff;
	SSectStartEnd.pEndOffset = &pSectInfo[i].ulEndOff;

	ErrorCode = m25p16_Control( CNTRL_GET_SECSTARTEND, (COMMAND_STRUCT *)&SSectStartEnd  );
}

return(ErrorCode);

}

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

ErrorCode = m25p16_Control( CNTRL_GET_CODES, &CmdStruct );

if(!ErrorCode)
{
	ErrorCode = m25p16_Control( 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

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 = m25p16_Control( CNTRL_GET_SECTNUM, &CmdStruct  );

		if( NO_ERR == ErrorCode )
		{
			// unlock the flash, do the write, and wait for completion
			ErrorCode = m25p16_Write( (unsigned short*)&pnData[0], ulStartAddr, 0x1 );
			ErrorCode = m25p16_Read( (unsigned short*)&nCompare, ulStartAddr, 0x1 );

		if( nCompare != ( pnData[0] & 0x0000FFFF ) )
			{
				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 = m25p16_Control( CNTRL_GET_SECTNUM, &CmdStruct  );

		if( NO_ERR == ErrorCode )
		{
			// unlock the flash, do the write, and wait for completion
			ErrorCode = m25p16_Write( (unsigned short*)&pnData[0], ulStartAddr, 0x1 );
		}
		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
COMMAND_STRUCT CmdStruct; //structure for GetSectStartEnd

ulAbsoluteAddr = FLASH_START_ADDR + ulStart;

// 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 = m25p16_Control( CNTRL_GET_SECTNUM, &CmdStruct );

		if( NO_ERR == ErrorCode )
	 	{
		// unlock the flash, do the write, increase shift, and wait for completion
		ErrorCode = m25p16_Write( (unsigned short*)&pnData[i], ulAbsoluteAddr, 0x1 );

		ErrorCode = m25p16_Read( (unsigned short*)&nCompare, ulAbsoluteAddr, 0x1 );

			if( ( nCompare ) != (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 = m25p16_Control( CNTRL_GET_SECTNUM, &CmdStruct );

		if( NO_ERR == ErrorCode )
		{
			// unlock the flash, do the write, increase shift, and wait for completion
			ErrorCode = m25p16_Write( (unsigned short*)&pnData[i], ulAbsoluteAddr, 0x1 );
		}
		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 =0xff;
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 = m25p16_Control( CNTRL_GET_SECTNUM, &CmdStruct );

	if( NO_ERR == ErrorCode )
	{
		ErrorCode = m25p16_Read( (unsigned short*)&pnData[i], ulAbsoluteAddr, 0x1 );
	}
	else
	{
		return ErrorCode;
	}
}

// return the appropriate error code
return ErrorCode;

}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ADI_OP/article/details/128189320

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签