技术标签: 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 灯的程序来做例程讲解。
烧写
这个是 Flash 的烧写驱动,每一个型号的 Flash 都需要专门对应自己的驱动,ADI 提供了一个驱动源码,如果用户的 Flash 型号与原厂提供的这个不符,则需要对驱动进行修改。我们开发板使用的就是ADI原厂的这个Flash型号,所以就可以直接用这个Driver,不用做任何修改。在这里 OP 也建议大家都用原厂提供的这个型号,否则自己改 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 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;
}
文章浏览阅读1.3w次。转载自 http://www.miui.com/thread-2003672-1-1.html 当手机在刷错包或者误修改删除系统文件后会出现无法开机或者是移动定制(联通合约机)版想刷标准版,这时就会用到线刷,首先就是安装线刷驱动。 在XP和win7上线刷是比较方便的,用那个驱动自动安装版,直接就可以安装好,完成线刷。不过现在也有好多机友换成了win8/8.1系统,再使用这个_mt65驱动
文章浏览阅读1k次。SonarQube是一个代码质量管理平台,可以扫描监测代码并给出质量评价及修改建议,通过插件机制支持25+中开发语言,可以很容易与gradle\maven\jenkins等工具进行集成,是非常流行的代码质量管控平台。通CheckStyle、findbugs等工具定位不同,SonarQube定位于平台,有完善的管理机制及强大的管理页面,并通过插件支持checkstyle及findbugs等既有的流..._sonar的客户端区别
文章浏览阅读3.4k次,点赞2次,收藏27次。神经图灵机是LSTM、GRU的改进版本,本质上依然包含一个外部记忆结构、可对记忆进行读写操作,主要针对读写操作进行了改进,或者说提出了一种新的读写操作思路。神经图灵机之所以叫这个名字是因为它通过深度学习模型模拟了图灵机,但是我觉得如果先去介绍图灵机的概念,就会搞得很混乱,所以这里主要从神经图灵机改进了LSTM的哪些方面入手进行讲解,同时,由于模型的结构比较复杂,为了让思路更清晰,这次也会分开几..._神经图灵机方法改进
文章浏览阅读2.8k次。一、模型迭代方法机器学习模型在实际应用的场景,通常要根据新增的数据下进行模型的迭代,常见的模型迭代方法有以下几种:1、全量数据重新训练一个模型,直接合并历史训练数据与新增的数据,模型直接离线学习全量数据,学习得到一个全新的模型。优缺点:这也是实际最为常见的模型迭代方式,通常模型效果也是最好的,但这样模型迭代比较耗时,资源耗费比较多,实时性较差,特别是在大数据场景更为困难;2、模型融合的方法,将旧模..._模型迭代
文章浏览阅读2.3k次。1、前言上传图片一般采用异步上传的方式,但是异步上传带来不好的地方,就如果图片有改变或者删除,图片服务器端就会造成浪费。所以有时候就会和参数同步提交。笔者喜欢base64图片一起上传,但是图片过多时就会出现数据丢失等异常。因为tomcat的post请求默认是2M的长度限制。2、解决办法有两种:① 修改tomcat的servel.xml的配置文件,设置 maxPostSize=..._base64可以装换zip吗
文章浏览阅读1k次,点赞17次,收藏22次。Opencv自然场景文本识别系统(源码&教程)_opencv自然场景实时识别文字
文章浏览阅读1.3k次。拷贝虚拟机文件时间比较长,因为虚拟机 flat 文件很大,所以要等。脚本完成后,以复制虚拟机文件夹。将以下脚本内容写入文件。_exsi6.7快速克隆centos
文章浏览阅读2k次。本文主要实现基于二度好友的推荐。数学公式参考于:http://blog.csdn.net/qq_14950717/article/details/52197565测试数据为自己随手画的关系图把图片整理成文本信息如下:a b c d e f yb c a f gc a b dd c a e h q re f h d af e a b gg h f bh e g i di j m n ..._本关任务:使用 spark core 知识完成 " 好友推荐 " 的程序。
文章浏览阅读367次。南京大学高级程序设计期末复习总结,c++面向对象编程_南京大学高级程序设计
文章浏览阅读3.1k次,点赞2次,收藏12次。实现朴素贝叶斯分类器,并且根据李航《统计机器学习》第四章提供的数据训练与测试,结果与书中一致分别实现了朴素贝叶斯以及带有laplace平滑的朴素贝叶斯%书中例题实现朴素贝叶斯%特征1的取值集合A1=[1;2;3];%特征2的取值集合A2=[4;5;6];%S M LAValues={A1;A2};%Y的取值集合YValue=[-1;1];%数据集和T=[ 1,4,-1;..._朴素贝叶斯 matlab训练和测试输出
文章浏览阅读1.6k次。Markdown 文本换行_markdowntext 换行
文章浏览阅读6.7w次,点赞2次,收藏37次。win10 2016长期服务版激活错误解决方法:打开“注册表编辑器”;(Windows + R然后输入Regedit)修改SkipRearm的值为1:(在HKEY_LOCAL_MACHINE–》SOFTWARE–》Microsoft–》Windows NT–》CurrentVersion–》SoftwareProtectionPlatform里面,将SkipRearm的值修改为1)重..._错误: 0xc0000022 在运行 microsoft windows 非核心版本的计算机上,运行“slui.ex