ADSP-21489的开发详解:SPIflash的硬件设计及程序烧写详解(含Flash驱动源码)
硬件准备
ADSP-21489EVB:ADI 21489处理器的开发板
AD-HP530ICE:ADI DSP专用仿真器
USBi:ADI SigmaDSP和SHARC DSP的图形化编程调试器
软件准备:
Visual DSP++
CCES
SigmaStudio
硬件链接示意图
SPIflash设计的硬件原理图
编程
此章将详细讲解如何使用 VDSP 软件来进行 SPIFLASH 编程,生成 boot 用的 LDR 文件。我们以按键控制 LED 灯的程序来做例程讲解。
- 把工程拖到 VDSP 软件中来。
- 在工程名上按鼠标右键,选择“Project Options…”
- 根据芯片的实际版本,为工程选择一个芯片版本,将“Type”选为“Loader File”。我们现在用的 21489 都是 0.2 版,所以就选择 0.2。
- 按下图为生成的 LDR 文件选择格式,设置完成后点“确定”按钮,完成 LDR 文件的配置。489_spi 文件位于 FlashDriver 文件夹里的 SPIFLASH 文件夹下。
- 选择“ ReBuild all“按钮全编译工程。
- 编译完成后,会看到生成文件提示。该文件默认生成地址为当前工程的 Debug 文件夹下。
烧写
- 选择 Tools 里的 Flash Programmer。特别注意,一定要链接好 session,才有此选项!
- 为 SPIFLASH 加载一个“.dxe”格式的驱动文件,这个文件在 “Flash Driver”文件夹下。
这个是 Flash 的烧写驱动,每一个型号的 Flash 都需要专门对应自己的驱动,ADI 提供了一个驱动源码,如果用户的 Flash 型号与原厂提供的这个不符,则需要对驱动进行修改。我们开发板使用的就是ADI原厂的这个Flash型号,所以就可以直接用这个Driver,不用做任何修改。在这里 OP 也建议大家都用原厂提供的这个型号,否则自己改 Flash烧写驱动,还是一件挺麻烦的事情。
- 找到“ADSP21489_SPIFlashDriver”文件。
- 按下图选择选项,然后点“ Data”后面的按钮,找到 ADSP21489_PBLED 工程下 Debug 文件夹下刚才生成的“ ADSP21489_PBLED.ldr”文件。
- 烧写过程中的读条,请静心等待。(由于选择的是擦空整个 Flash,然后再写入,所以进度条有点慢,刚开始的时候不读条是在擦空,后面如果自己做板子,空白 Flash 进行烧写,则可以选不擦出直接烧,读条进度就很快了)
- 完成烧写。
- 断开链接,完整 Flash 编程和烧写得工作。
将 BOOT 开关 SW2 和 SW3 分别拨到 ON 和 OFF,设置成 SPIFLASH 启动
拔掉电源插头,重新上电,并打开电源开关,按下按键,相应的 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 commandif( NO_ERR != WriteByteToSPI( SPI_READ, MSBF ) ){Clear_SPI_CS();return POLL_TIMEOUT;}// 1 byte of addressif( NO_ERR != WriteByteToSPI( (ulCurrentAddress >> 16), MSBF ) ){Clear_SPI_CS();return POLL_TIMEOUT;}// 1 byte of addressif( NO_ERR != WriteByteToSPI( (ulCurrentAddress >> 8), MSBF ) ){Clear_SPI_CS();return POLL_TIMEOUT;}// 1 byte of addressif( NO_ERR != WriteByteToSPI( ulCurrentAddress, MSBF ) ){Clear_SPI_CS();return POLL_TIMEOUT;}// 1 byte of garbage dataif( NO_ERR != ReadByteFromSPI( (int*)pusCurrentData, 0 ) ){Clear_SPI_CS();return POLL_TIMEOUT;}// 1 byte of GOOD dataif( 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 enableAssert_SPI_CS();// 1 byte of commandif( NO_ERR != WriteByteToSPI( SPI_PP, MSBF ) ){Clear_SPI_CS();return POLL_TIMEOUT;}// 1 byte of addressif( NO_ERR != WriteByteToSPI( (ulCurrentAddress >> 16), MSBF ) ){Clear_SPI_CS();return POLL_TIMEOUT;}// 1 byte of addressif( NO_ERR != WriteByteToSPI( (ulCurrentAddress >> 8), MSBF ) ){Clear_SPI_CS();return POLL_TIMEOUT;}// 1 byte of addressif( NO_ERR != WriteByteToSPI( ulCurrentAddress, MSBF ) ){Clear_SPI_CS();return POLL_TIMEOUT;}// 1 byte of dataif( 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 commandreturn 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 allcase CNTRL_ERASE_ALL:ErrorCode = EraseFlash(pCmdStruct->SEraseAll.ulFlashStartAddr);break;// erase sectorcase CNTRL_ERASE_SECT:ErrorCode = EraseBlock( pCmdStruct->SEraseSect.nSectorNum, pCmdStruct->SEraseSect.ulFlashStartAddr );break;// get manufacturer and device codescase 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 datapCmdStruct->SGetDesc.pDesc = pFlashDesc;pCmdStruct->SGetDesc.pFlashCompany = pDeviceCompany;break;// get sector number based on addresscase CNTRL_GET_SECTNUM:ErrorCode = GetSectorNumber( pCmdStruct->SGetSectNum.ulOffset, (int *)pCmdStruct->SGetSectNum.pSectorNum );break;// get sector number start and end offsetcase CNTRL_GET_SECSTARTEND:ErrorCode = GetSectorStartEnd( pCmdStruct->SSectStartEnd.pStartOffset, pCmdStruct->SSectStartEnd.pEndOffset, pCmdStruct->SSectStartEnd.nSectorNum );break;// get the number of sectorscase CNTRL_GETNUM_SECTORS:pCmdStruct->SGetNumSectors.pnNumSectors[0] = gNumSectors;break;// resetcase CNTRL_RESET:ErrorCode = ResetFlash(pCmdStruct->SReset.ulFlashStartAddr);break;// no command or unknown command do nothingdefault:// set our errorErrorCode = 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 commandreturn 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 enableAssert_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 commandreturn 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
elsereturn 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 );}
elsereturn 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 addressulFlashStartAddr = 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 offsetspSectorInfo = (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 anywhereasm("AFP_BreakReady:");asm("nop;");if ( FALSE )asm("jump AFP_BreakReady;");// Make a call to the ProcessCommandAFP_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 allcase FLASH_ERASE_ALL:CmdStruct.SEraseAll.ulFlashStartAddr = FLASH_START_ADDR; //FlashStartAddressErrorCode = m25p16_Control( CNTRL_ERASE_ALL, &CmdStruct );break;// erase sectorcase FLASH_ERASE_SECT:CmdStruct.SEraseSect.nSectorNum = AFP_Sector; // Sector Number to eraseCmdStruct.SEraseSect.ulFlashStartAddr = FLASH_START_ADDR; // FlashStartAddressErrorCode = m25p16_Control( CNTRL_ERASE_SECT, &CmdStruct);break;// fillcase FLASH_FILL:ErrorCode = FillData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer );break;// get manufacturer and device codescase FLASH_GET_CODES:CmdStruct.SGetCodes.pManCode = (unsigned long *)&AFP_ManCode; // Manufacturer CodeCmdStruct.SGetCodes.pDevCode = (unsigned long *)&AFP_DevCode; // Device CodeCmdStruct.SGetCodes.ulFlashStartAddr = FLASH_START_ADDR;ErrorCode = m25p16_Control( CNTRL_GET_CODES, &CmdStruct);break;// get sector number based on addresscase FLASH_GET_SECTNUM:CmdStruct.SGetSectNum.ulOffset = AFP_Offset; // offset from the base addressCmdStruct.SGetSectNum.pSectorNum = (unsigned long *)&AFP_Sector; //Sector NumberErrorCode = m25p16_Control( CNTRL_GET_SECTNUM, &CmdStruct);break;// get sector number start and end offsetcase FLASH_GET_SECSTARTEND:CmdStruct.SSectStartEnd.nSectorNum = AFP_Sector; // Sector NumberCmdStruct.SSectStartEnd.pStartOffset = &AFP_StartOff;// sector start addressCmdStruct.SSectStartEnd.pEndOffset = &AFP_EndOff; // sector end addressErrorCode = m25p16_Control( CNTRL_GET_SECSTARTEND, &CmdStruct );break;// readcase FLASH_READ:ErrorCode = ReadData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer );break;// resetcase FLASH_RESET:CmdStruct.SGetCodes.ulFlashStartAddr = FLASH_START_ADDR; //Flash start addressErrorCode = m25p16_Control( CNTRL_RESET, &CmdStruct);break;// writecase FLASH_WRITE:ErrorCode = WriteData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer );break;// no command or unknown command do nothingcase FLASH_NO_COMMAND:default:// set our errorErrorCode = 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 initializedErrorCode = 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 codeGET_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 valuefor (i = 0; ( ( i < lCount ) && ( ErrorCode == NO_ERR ) ); i++, ulStartAddr += ( lStride ) ){// check to see that the address is within a valid sectorCmdStruct.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 completionErrorCode = 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 errorif( bVerifyError == TRUE )return VERIFY_WRITE;
}
// user did not want to verify writes
else
{// fill the valuefor (i = 0; ( ( i < lCount ) && ( ErrorCode == NO_ERR ) ); i++, ulStartAddr += ( lStride )){// check to see that the address is within a valid sectorCmdStruct.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 completionErrorCode = 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 itemsfor (i = 0; ( i < lCount ) && ( ErrorCode == NO_ERR ); i++, ulAbsoluteAddr += lStride){// check to see that the address is within a valid sectorCmdStruct.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 completionErrorCode = 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 errorif( bVerifyError == TRUE )return VERIFY_WRITE;
}
// the user does not want to verify
else
{// write the buffer up to BUFFER_SIZE itemsfor (i = 0; ( i < lCount ) && ( ErrorCode == NO_ERR ); i++, ulAbsoluteAddr += lStride){// check to see that the address is within a valid sectorCmdStruct.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 completionErrorCode = 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 GetSectStartEndulAbsoluteAddr = 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 sectorCmdStruct.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;
}
ADSP-21489的开发详解:SPIflash的硬件设计及程序烧写详解(含Flash驱动源码)相关推荐
- ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)
编者的话 Flash 编程与烧写,原本应该是开发的最后一步,当所有程序都做好了,在线编译运行正常,才会通过 Flash 编程,生成二进制的可执行文件 LDR,再通过 JTAG 仿真器将 LDR 文件烧 ...
- 详解5种红黑树的场景,从Linux内核谈到Nginx源码,听完醍醐灌顶丨Linux服务器开发丨Linux后端开发
5种红黑树的场景,从Linux内核谈到Nginx源码,听完醍醐灌顶 1. 进程调度CFS的红黑树场景 2. 虚拟内存管理的红黑树场景 3. 共享内存slab的红黑树场景 视频讲解如下,点击观看: [干 ...
- 音频接口设计详解!智能硬件设计,I2S、PDM、TDM选什么接口?
音频接口设计详解!智能硬件设计,I2S.PDM.TDM选什么接口? 在智能硬件和物联网产品设计中,经常遇到声音的传输.本文主要讲一下最常用的音频接口,以及使用场景. 主要分类:模拟.数字(I2S.PC ...
- Davinci DM6446开发攻略——LINUX GPIO驱动源码移植
一. DM6446 GPIO的介绍 说到LINUX 驱动移植,没有移植过的朋友,或刚刚进入LINUX领域的朋友,最好去看看<LINUX 设备驱动程序>第三版,有个理 ...
- NET开发邮件发送功能的全面教程(含邮件组件源码)(
天,给大家分享的是如何在.NET平台中开发"邮件发送"功能.在网上搜的到的各种资料一般都介绍的比较简单,那今天我想比较细的整理介绍下. AD:2013云计算架构师峰会精彩课程曝光 ...
- .NET开发邮件发送功能的全面教程(含邮件组件源码)
今天,给大家分享的是如何在.NET平台中开发"邮件发送"功能.在网上搜的到的各种资料一般都介绍的比较简单,那今天我想比较细的整理介绍下: 1) 邮件基础理论知识 2 ...
- [转].NET开发邮件发送功能的全面教程(含邮件组件源码)
转载自http://www.cnblogs.com/heyuquan/p/net-batch-mail-send-async.html 今天,给大家分享的是如何在.NET平台中开发"邮件发送 ...
- 【微信小程序控制硬件16 】 安信可 ESP32-S 开发板实现移植腾讯物联开发平台蓝牙 llsync 协议,实现一键蓝牙快速配网+远程控制。(附带源码)
文章目录 一.前言 二.源码目录说明 三.编译指导 四.常见问题 五.开源微信物联网控制一览表 另外,不要把我的博客作为学习标准,我的只是笔记,难有疏忽之处,如果有,请指出来,也欢迎留言哈! 微信物联 ...
- 【嵌入式开发】LED 驱动 ( LED发光二极管原理 | 底板原理图分析 | 核心板原理图分析 | GPIO | 裸板程序烧写流程 )
文章目录 开发板 的 LED 灯 作用 : 嵌入式软件的开发初期, 如 开发 BootLoader 代码 或者 Kernel 内核代码 过程中, 有效的调试方法有限, 此时通常使用 开发板上的 LED ...
最新文章
- HTML5 文件域+FileReader 读取文件并上传到服务器(三)
- Nginx安装及运行服务
- 移动端页面自适应解决方案—rem布局
- 【转载】天际网-Viadeo集团宣布收购移动商务社交应用“在这儿”
- 用CRF做命名实体识别——NER系列(三)
- 简而言之,JUnit:单元测试断言
- 3d000: no database selected_No.[C9]020
- 【Linux】第一章 整合 JDK 和 MariaDB(附 Linux 基本命令)
- 关于Spring.net+NHibernate的事务控制
- 旋风解析磁力php,2018年免费引擎和正版旋风四核引擎棋力测试分析
- linux查看cpu核数命令,Linux系統下如何查看CPU型號、核心數量、頻率和溫度?
- 一、目标检测入门VOC2012
- 红米1s 一键root测试
- java经典算法(八)---zws
- Android字符小写转大写,大写转小写
- 【Java系列】:异常-Exception
- 怎么查看无线路由器连接的设备连接服务器,路由器怎么看几个人连接
- 分时线的9代表什么_一位深藏不露的股神告诉你:为什么要打板?
- 手机桌面上的计算机为什么不能删除,为什么我的电脑无法删除C盘上的文件当删除 – 手机爱问...
- Windows系统共享文件夹或打印机等设备的dos脚本自动化