/*******************************************************************************/
/* */
/* (C) Copyright 2008 - Analog Devices, Inc. All rights reserved. */
/* */
/* FILE: m25p16.c */
/* */
/* PURPOSE: Performs operations specific to the M25P16 flash device. */
/* */
/*******************************************************************************/
/* includes */
#ifdef __ADSPBF548__
#include <cdefBF548.h>
#elif __ADSPBF518__
#include <cdefBF518.h>
#elif __ADSPBF527__
#include <cdefBF527.h>
#endif
#include <ccblkfn.h>
#include <stdio.h>
#include <drivers\flash\util.h>
#include <drivers\flash\Errors.h>
#include <drivers\flash\m25p16.h>
#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
char SPI_Page_Buffer[SPI_PAGE_SIZE];
int SPI_Page_Index = 0;
char SPI_Status;
/* function prototypes */
static ERROR_CODE SetupForFlash();
static ERROR_CODE GetCodes();
static ERROR_CODE Wait_For_nStatus(void);
ERROR_CODE Wait_For_Status( char Statusbit );
static ERROR_CODE Wait_For_WEL(void);
char ReadStatusRegister(void);
void Wait_For_SPIF(void);
extern void SetupSPI( const int spi_setting );
extern void SPI_OFF(void);
void SendSingleCommand( const int iCommand );
unsigned long DataFlashAddress (unsigned long address);
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 PollToggleBit(void);
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);
ERROR_CODE m25p16_Open(void)
{
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++)
{
SetupSPI( (COMMON_SPI_SETTINGS|TIMOD01) );
/* send the bulk erase command to the flash */
WriteFlash( ulCurrentAddress , SPI_READ );
WriteFlash( ulCurrentAddress , (ulCurrentAddress ) >> 16);
WriteFlash( ulCurrentAddress , (ulCurrentAddress ) >> 8);
WriteFlash( ulCurrentAddress , ulCurrentAddress );
/* read the data now */
Result = ReadFlash( ulCurrentAddress, pusCurrentData );
SPI_OFF();
}
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 char *pusCurrentData = (unsigned char *)pusData;
unsigned long ulCurrentAddress = ulStartAddress;
for (i = 0; i < uiCount; i++, ulCurrentAddress++, pusCurrentData++)
{
/* first, a "Write Enable" command must be sent to the SPI */
SendSingleCommand(SPI_WREN);
/* second, the SPI Status Register will be tested whether the
Write Enable Bit has been set */
Result = Wait_For_WEL();
if( POLL_TIMEOUT == Result )
return Result;
else
{
SetupSPI( (COMMON_SPI_SETTINGS|TIMOD01) );
/* send the bulk erase command to the flash */
WriteFlash( ulCurrentAddress , SPI_PP );
WriteFlash( ulCurrentAddress , (ulCurrentAddress ) >> 16);
WriteFlash( ulCurrentAddress , (ulCurrentAddress ) >> 8);
WriteFlash( ulCurrentAddress , ulCurrentAddress );
/* program our actual value now */
Result = WriteFlash( ulCurrentAddress, *pusCurrentData );
SPI_OFF();
}
}
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);
}
//----- H e l p e r F u n c t i o n s ----//
//----------- 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