432 lines
12 KiB
C
432 lines
12 KiB
C
#include "SPI_Flash.h"
|
|
#include "SPI.h"
|
|
#include "BoardCfg.h"
|
|
|
|
unsigned char mSPIFlashBaudrate;
|
|
unsigned char mSPIFlashHighSpeedBaudrate;
|
|
unsigned char mFlashSectorBuffer[SPI_FLASH_SECTOR_SIZE];
|
|
unsigned int mSPIFlashOK;
|
|
|
|
int InitSPIFlash()
|
|
{
|
|
FLASH_SS_PIN = 1;
|
|
|
|
mSPIFlashBaudrate = SPICalculateBRG(PERIPHERAL_FREQ, 25000000);
|
|
// mSPIFlashHighSpeedBaudrate = SPICalculateBRG(PERIPHERAL_FREQ, 50000000);
|
|
mSPIFlashHighSpeedBaudrate = SPICalculateBRG(PERIPHERAL_FREQ, 35000000);
|
|
mSPIFlashOK = 0;
|
|
}
|
|
|
|
int SPIFlashCheckAndConfigure()
|
|
{
|
|
|
|
if(SPIFlashCheckChipID() == RET_OK)
|
|
{
|
|
SPIFlashWriteEnable();
|
|
|
|
FLASH_SS_PIN = 0;
|
|
SPITransaction(SPI_FLASH_WRITE_STATUS_REG,mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(0x00,mSPIFlashHighSpeedBaudrate); //Configure for write enable the whole memory
|
|
FLASH_SS_PIN = 1;
|
|
|
|
SPIFlashReadStatusReg(1);
|
|
|
|
mSPIFlashOK = 1;
|
|
printf("SPI Flash configured\n");
|
|
return RET_OK;
|
|
}
|
|
|
|
mSPIFlashOK = 0;
|
|
printf("ERROR: SPI Flash not detected\n");
|
|
return RET_ERROR;
|
|
|
|
}
|
|
|
|
int SPIFlashIsPresent()
|
|
{
|
|
return mSPIFlashOK;
|
|
}
|
|
|
|
int SPIFlashWriteEnable()
|
|
{
|
|
FLASH_SS_PIN = 0;
|
|
SPITransaction(SPI_FLASH_WRITE_ENABLE,mSPIFlashHighSpeedBaudrate);
|
|
FLASH_SS_PIN = 1;
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
|
|
|
|
unsigned char SPIFlashReadStatusReg(int print)
|
|
{
|
|
unsigned char result;
|
|
|
|
FLASH_SS_PIN = 0;
|
|
result = SPITransaction(SPI_FLASH_READ_STATUS_REG,mSPIFlashBaudrate);
|
|
result = SPITransaction(0x00,mSPIFlashBaudrate); //get data
|
|
FLASH_SS_PIN = 1;
|
|
|
|
if(print)
|
|
{
|
|
printf("Flash status register : 0x%x\n",result);
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
int SPIFlashCheckBusy()
|
|
{
|
|
unsigned char status = SPIFlashReadStatusReg(0);
|
|
if((status & SPI_FLASH_BUSY_MASK) != 0)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int SPIFlashCheckChipID()
|
|
{
|
|
unsigned char VendorID, ChipID;
|
|
|
|
FLASH_SS_PIN = 0;
|
|
SPITransaction(SPI_FLASH_READ_ID,mSPIFlashBaudrate);
|
|
SPITransaction(0x00,mSPIFlashBaudrate);
|
|
SPITransaction(0x00,mSPIFlashBaudrate);
|
|
SPITransaction(0x00,mSPIFlashBaudrate); //Vendor address
|
|
VendorID = SPITransaction(0x00,mSPIFlashBaudrate); //Vendor ID, should be 0xBF
|
|
ChipID = SPITransaction(0x00,mSPIFlashBaudrate); //Device ID, should be 0x41
|
|
FLASH_SS_PIN = 1;
|
|
|
|
if(VendorID != SPI_FLASH_VENDOR_ID || ChipID != SPI_FLASH_CHIP_ID)
|
|
{
|
|
printf("SPI Flash detection FAILED. Vendor: 0x%x, Chip ID: 0x%x\n",VendorID,ChipID);
|
|
return RET_ERROR;
|
|
}
|
|
printf("SPI Flash detected. Vendor: 0x%x, Chip ID: 0x%x\n",VendorID,ChipID);
|
|
return RET_OK;
|
|
|
|
}
|
|
|
|
|
|
int SPIFlashReadBuffer(unsigned char *Buf, int Size, int StartAddress)
|
|
{
|
|
if(StartAddress + Size - 1 > SPI_FLASH_MAX_ADDRESS)
|
|
{
|
|
return RET_ERROR;
|
|
}
|
|
|
|
FLASH_SS_PIN = 0;
|
|
SPITransaction(SPI_FLASH_HI_SPEED_READ,mSPIFlashBaudrate);
|
|
SPITransaction(((StartAddress & 0xFF0000) >> 16),mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(((StartAddress & 0x00FF00) >> 8),mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction((StartAddress & 0x0000FF),mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction((0x00),mSPIFlashHighSpeedBaudrate); //Chip requires a dummy read in high speed
|
|
|
|
int i;
|
|
for(i = 0; i < Size; i++)
|
|
{
|
|
unsigned char tmp;
|
|
tmp =SPITransaction(0xDE,mSPIFlashHighSpeedBaudrate);
|
|
*Buf++ = tmp;
|
|
// *Buf++ = SPITransaction(0xDE,mSPIFlashHighSpeedBaudrate);
|
|
}
|
|
|
|
FLASH_SS_PIN = 1;
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
int SPIFlashEraseSector(int SectorAddress)
|
|
{
|
|
if(SectorAddress % SPI_FLASH_SECTOR_SIZE != 0) //Sectors are aligned on 0x1000
|
|
{
|
|
return RET_ERROR;
|
|
}
|
|
|
|
SPIFlashWriteEnable();
|
|
|
|
FLASH_SS_PIN = 0;
|
|
SPITransaction(SPI_FLASH_4KB_SECOTR_ERASE,mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(((SectorAddress & 0xFF0000) >> 16),mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(((SectorAddress & 0x00FF00) >> 8),mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction((SectorAddress & 0x0000FF),mSPIFlashHighSpeedBaudrate);
|
|
FLASH_SS_PIN = 1;
|
|
|
|
SectorAddress++;
|
|
|
|
while( SPIFlashCheckBusy() == true);
|
|
//SPIFlashWriteEnable();
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
int SPIFlashErase64KSector(int SectorAddress, int Blocking)
|
|
{
|
|
if(SectorAddress % SPI_FLASH_64K_SECTOR_SIZE != 0) //Sectors are aligned on 0x1000
|
|
{
|
|
return RET_ERROR;
|
|
}
|
|
if((SectorAddress + SPI_FLASH_64K_SECTOR_SIZE - 1) > SPI_FLASH_MAX_ADDRESS)
|
|
{
|
|
return RET_ERROR;
|
|
}
|
|
|
|
SPIFlashWriteEnable();
|
|
|
|
FLASH_SS_PIN = 0;
|
|
SPITransaction(SPI_FLASH_64KB_BLOCK_ERASE,mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(((SectorAddress & 0xFF0000) >> 16),mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(((SectorAddress & 0x00FF00) >> 8),mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction((SectorAddress & 0x0000FF),mSPIFlashHighSpeedBaudrate);
|
|
FLASH_SS_PIN = 1;
|
|
|
|
if(Blocking != 0)
|
|
{
|
|
while( SPIFlashCheckBusy() == true);
|
|
// SPIFlashWriteEnable();
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
|
|
|
|
int SPIFlashWriteSectorWorkingBuffer(int SectorAddress, int Erase)
|
|
{
|
|
if(SectorAddress % SPI_FLASH_SECTOR_SIZE != 0) //Sectors are aligned on 0x1000
|
|
{
|
|
return RET_ERROR;
|
|
}
|
|
|
|
if(Erase == 1)
|
|
{
|
|
SPIFlashEraseSector(SectorAddress);
|
|
}
|
|
|
|
unsigned char *DataPtr = &mFlashSectorBuffer[0];
|
|
int j;
|
|
for(j = 0; j < SPI_FLASH_SECTOR_SIZE; j++)
|
|
{
|
|
unsigned char curbyte;
|
|
curbyte = *DataPtr;
|
|
SPIFlashWriteEnable();
|
|
|
|
|
|
|
|
char Add1, Add2, Add3;
|
|
Add1 = (unsigned char)((SectorAddress & 0xFF0000) >> 16);
|
|
Add2 = ((unsigned char)((SectorAddress & 0x00FF00) >> 8));
|
|
Add3 = ((unsigned char)(SectorAddress & 0x0000FF));
|
|
|
|
int t;
|
|
t = 0;
|
|
|
|
FLASH_SS_PIN = 0;
|
|
SPITransaction(SPI_FLASH_BYTE_PROGRAM,mSPIFlashHighSpeedBaudrate);
|
|
// SPITransaction((unsigned char)((SectorAddress & 0xFF0000) >> 16),mSPIFlashHighSpeedBaudrate);
|
|
// SPITransaction((unsigned char)((SectorAddress & 0x00FF00) >> 8),mSPIFlashHighSpeedBaudrate);
|
|
// SPITransaction((unsigned char)(SectorAddress & 0x0000FF),mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(Add1,mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(Add2,mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(Add3,mSPIFlashHighSpeedBaudrate);
|
|
|
|
SPITransaction(curbyte,mSPIFlashHighSpeedBaudrate);
|
|
// SPITransaction(*DataPtr,mSPIFlashHighSpeedBaudrate);
|
|
FLASH_SS_PIN = 1;
|
|
|
|
DataPtr++;
|
|
SectorAddress++;
|
|
|
|
while( SPIFlashCheckBusy() == true);
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
int SPIFlashWriteByte(unsigned int ByteAddress, char byte, int blocking)
|
|
{
|
|
if(ByteAddress > SPI_FLASH_MAX_ADDRESS)
|
|
{
|
|
return RET_ERROR;
|
|
}
|
|
|
|
SPIFlashWriteEnable();
|
|
|
|
FLASH_SS_PIN = 0;
|
|
SPITransaction(SPI_FLASH_BYTE_PROGRAM,mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(((ByteAddress & 0xFF0000) >> 16),mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(((ByteAddress & 0x00FF00) >> 8),mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction((ByteAddress & 0x0000FF),mSPIFlashHighSpeedBaudrate);
|
|
SPITransaction(byte,mSPIFlashHighSpeedBaudrate);
|
|
FLASH_SS_PIN = 1;
|
|
|
|
if(blocking)
|
|
{
|
|
while( SPIFlashCheckBusy() == true);
|
|
}
|
|
|
|
|
|
return RET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//int SPIFlashEraseSectorForWrite(unsigned char StartAddress, int Size)
|
|
//{
|
|
// //First, let's determine which sector to erase.
|
|
//
|
|
// int NbSectors = 1;
|
|
// int FirstSector = StartAddress / 0x1000;
|
|
// int LastSector = (StartAddress + Size) / 0x1000;
|
|
//
|
|
// if(LastSector > FirstSector)
|
|
// {
|
|
// NbSectors = LastSector - FirstSector;
|
|
// }
|
|
//
|
|
// int i;
|
|
// for(i = FirstSector; i < LastSector; i++ ) //Erase each sector one by one
|
|
// {
|
|
//
|
|
// }
|
|
//
|
|
//}
|
|
|
|
//int SPIFlashWriteBuffer(unsigned char *Buf, int Size, int StartAddress)
|
|
//{
|
|
// //First, we need to determine if the data overlaps or uses more than one sector
|
|
// //First, let's determine which sector to erase.
|
|
// int EndAddress = StartAddress + Size - 1;
|
|
// if(EndAddress > SPI_FLASH_MAX_ADDRESS)
|
|
// {
|
|
// return RET_ERROR;
|
|
// }
|
|
//
|
|
// int NbSectors = 1;
|
|
// int FirstSector = StartAddress / SPI_FLASH_SECTOR_SIZE;
|
|
// int LastSector = EndAddress / SPI_FLASH_SECTOR_SIZE;
|
|
//
|
|
// if(LastSector > FirstSector)
|
|
// {
|
|
// NbSectors = LastSector - FirstSector + 1;
|
|
// }
|
|
//
|
|
// int i;
|
|
// int FlashAddress = StartAddress;
|
|
// int CurSector = FirstSector;
|
|
// for(i = 0; i < NbSectors; i++ ) //Read, erase and write each sector one by one
|
|
// {
|
|
// //first we need to backup the data outside our buffer.
|
|
// //TODO: optimize
|
|
// int SectorStartAddress = CurSector++ * SPI_FLASH_SECTOR_SIZE;
|
|
// int SectorEndAddress = SectorStartAddress + SPI_FLASH_SECTOR_SIZE - 1;
|
|
// if(SectorEndAddress > EndAddress)
|
|
// {
|
|
// SectorEndAddress = EndAddress;
|
|
// }
|
|
//
|
|
// SPIFlashReadBuffer(mFlashSectorBuffer,SPI_FLASH_SECTOR_SIZE,SectorStartAddress); //Get local RAM buffer of the sector
|
|
//
|
|
// //Update the data to write.
|
|
// int RAMAddress = FlashAddress - SectorStartAddress;
|
|
// int RAMSectorSize = SectorEndAddress - FlashAddress + 1;
|
|
// FlashAddress += RAMSectorSize;
|
|
//
|
|
// unsigned char* RAMPtr = &mFlashSectorBuffer[RAMAddress];
|
|
// int j;
|
|
// for(j = 0; j < RAMSectorSize; j++)
|
|
// {
|
|
// *RAMPtr++ = *Buf++;
|
|
// }
|
|
//
|
|
// int SectorAddress = SectorStartAddress;
|
|
// RAMPtr = mFlashSectorBuffer;
|
|
//
|
|
// for(j = 0; j < SPI_FLASH_SECTOR_SIZE; j++)
|
|
// {
|
|
// SPIFlashWriteEnable();
|
|
//
|
|
// FLASH_SS_PIN = 0;
|
|
// SPITransaction(SPI_FLASH_BYTE_PROGRAM,mSPIFlashHighSpeedBaudrate);
|
|
// SPITransaction(((SectorAddress & 0xFF0000) >> 16),mSPIFlashBaudrate);
|
|
// SPITransaction(((SectorAddress & 0x00FF00) >> 8),mSPIFlashBaudrate);
|
|
// SPITransaction((SectorAddress & 0x0000FF),mSPIFlashBaudrate);
|
|
// SPITransaction(*RAMPtr++,mSPIFlashBaudrate);
|
|
// FLASH_SS_PIN = 1;
|
|
//
|
|
// SectorAddress++;
|
|
//
|
|
// while( SPIFlashCheckBusy() == true);
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
int SPIFlashWriteBuffer(unsigned char *Buf, int Size, int StartAddress)
|
|
{
|
|
int CurDataFlashAddress, DataFlashEndAddress;
|
|
char *DataBufPtr, *WorkPagePtr;
|
|
int WriteFinished;
|
|
|
|
|
|
//Init stuff
|
|
WriteFinished = 0;
|
|
DataFlashEndAddress = StartAddress + Size; //Start + size means the data at "DataFlashEndAddress" should not be written.
|
|
CurDataFlashAddress = StartAddress;
|
|
DataBufPtr = Buf;
|
|
|
|
if(DataFlashEndAddress > SPI_FLASH_MAX_ADDRESS)
|
|
{
|
|
return RET_ERROR;
|
|
}
|
|
|
|
while(WriteFinished == 0)
|
|
{
|
|
//Determine the current sector start address.
|
|
int SectorStartAddress;
|
|
SectorStartAddress = ((CurDataFlashAddress / SPI_FLASH_SECTOR_SIZE) * SPI_FLASH_SECTOR_SIZE); //Weird but it works
|
|
|
|
//Load the sector in RAM working buffer
|
|
if(SPIFlashReadBuffer(mFlashSectorBuffer,SPI_FLASH_SECTOR_SIZE,SectorStartAddress) != RET_OK)
|
|
{
|
|
return RET_ERROR;
|
|
}
|
|
|
|
//Set the working buffer pointer to the right value.
|
|
WorkPagePtr = &mFlashSectorBuffer[CurDataFlashAddress - SectorStartAddress];
|
|
|
|
//Modify the working buffer with data to write.
|
|
int SectorFinished = 0;
|
|
while(SectorFinished == 0)
|
|
{
|
|
*WorkPagePtr++ = *DataBufPtr++;
|
|
CurDataFlashAddress++;
|
|
|
|
//Are we at the end of the buffer to write?
|
|
if(CurDataFlashAddress == DataFlashEndAddress)
|
|
{
|
|
SectorFinished = 1;
|
|
WriteFinished = 1;
|
|
// SPIFlashEraseSector(SectorStartAddress);
|
|
SPIFlashWriteSectorWorkingBuffer(SectorStartAddress,1);
|
|
|
|
break;
|
|
}
|
|
else if(CurDataFlashAddress % SPI_FLASH_SECTOR_SIZE == 0) //Are we at the beginning of the next sector?
|
|
{
|
|
SectorFinished = 1;
|
|
// SPIFlashEraseSector(SectorStartAddress);
|
|
SPIFlashWriteSectorWorkingBuffer(SectorStartAddress,1);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
} |