赞
踩
作者的话
本文用到的硬件如下:
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 灯的程序来做例程讲解。
烧写
这个是 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;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。