用ADSP-21489开发板教你做音频开发,有手就行(十一)SPIflash的硬件设计及程序烧写详解(含Flash驱动源码)
此章将详细讲解如何使用 VDSP 软件来进行 SPIFLASH 编程,生成 boot 用的 LDR 文件。我们以按键控制 LED 灯的程序来做例程讲解。包含Flash驱动的源代码
作者的话
本文用到的硬件如下:
ADSP-21489EVB开发板产品链接:
https://item.taobao.com/item.htm?id=539694123232&spm=a1z10.5-c.w4002-5192690539.15.467c40d8gngZ5W
AD-HP530ICE仿真器产品链接:
https://item.taobao.com/item.htm?id=38007242820&spm=a1z10.5-c.w4002-5192690539.11.7fef4901MmOMav
软件准备:
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 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;
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)