因公司需求,需要开发一个裸驱读写Qspi falsh的驱动。
首先需要了解两个方面的知识,一是spi驱动,二是flash读写指令。spi的驱动在sdk中有集成,在此不再赘述。
下面首先查看数据手册中的读取器件型号指令,确保spi驱动没有问题。spi读0x9F寄存器,读出正确的flashID证明spi驱动没有问题。
接下来,进行flash的读写操作。
首先查看手册,查找到读写指令(页编程指令)分别为:
Read Flash
根据读指令,查看读指令的时序,根据时序编写读代码段。
read flash 代码:
/**************
** IN u8 FlashSlave :spi select chips for more than one flash
** IN u32 ReadAddr :read flash start addderess
** IN u32 len :read flash data length
** OUT char *ReadBuff :read flash data
*************/
int readQspiFlash( u8 FlashSlave, u32 ReadAddr,char *ReadBuff,u32 len)
{
int Status = XSpi_SetSlaveSelect(&Spi, FlashSlave);
if(Status != 0)
{
return -1;
}
WriteBuffer[BYTE1] = 0x03;
WriteBuffer[BYTE2] = (u8) (ReadAddr >> 16);
WriteBuffer[BYTE3] = (u8) (ReadAddr >> 8);
WriteBuffer[BYTE4] = (u8) ReadAddr ;
Status = XSpi_Transfer( &Spi, WriteBuffer, (u8*)(det), len+4);
if(Status != 0)
{
return -1;
}
Status = SpiFlashWaitForFlashReady();
if(Status != 0)
{
return -1;
}
return 0;
}
Write Flash
根据写指令,查看写指令时序,写flash(即页编程:大概就是支持一页一页(256byte)的写入),写入之前需要注意的是先使能写,然后对写入区域进行擦除。
earse 代码:需要注意起始地址为flash的每64K块的起始地址
/**************
** IN eraseAddr : erase start address
*************/
int eraseQspiFlash64KSector( u32 eraseAddr)
{
int Status = XSpi_SetSlaveSelect(&Spi, 1);
if(Status != 0) {
return -1;
}
Status = SpiFlashWriteEnable(&Spi);
if(Status != 0) {
return -1;
}
Status = SpiFlashWaitForFlashReady();
if(Status != 0) {
return -1;
}
WriteBuffer[BYTE1] = 0x02;
WriteBuffer[BYTE2] = (u8) (addr >> 16);
WriteBuffer[BYTE3] = (u8) (addr >> 8);
WriteBuffer[BYTE4] = (u8) addr;
Status = XSpi_Transfer( &Spi, WriteBuffer, NULL, 4);
if(Status != 0)
{
return -1;
}
return 0
}
write 代码:
/**************
** IN u32 WriteAddr :write flash start addderess
** IN u32 len :read flash data length
** IN char *writeBuff:read flash data
*************/
int writeOneFlashPage(char *writeBuff, u32 WriteAddr, u32 len)
{
u32 Index;
int Status = SpiFlashWriteEnable(&Spi);
if(Status != FMSH_SUCCESS)
{
return -1;
}
Status = SpiFlashWaitForFlashReady();
if(Status != FMSH_SUCCESS)
{
return -1;
}
WriteBuffer[BYTE1] = XISF_CMD_PAGEPROG_WRITE;
WriteBuffer[BYTE2] = (u8) (WriteAddr >> 16);
WriteBuffer[BYTE3] = (u8) (WriteAddr >> 8);
WriteBuffer[BYTE4] = (u8) WriteAddr;
for(u32 Index = 4; Index < len; Index++)
{
WriteBuffer[Index] = writeBuff[Index-4];
}
Status = XSpi_Transfer(&Spi, WriteBuffer, NULL, (len + 4));
if(Status != FMSH_SUCCESS)
{
return -1;
}
Status = SpiFlashWaitForFlashReady();
if(Status != FMSH_SUCCESS)
{
return -1;
}
return FMSH_SUCCESS;
}
对一段地址连续读写
/**************
** IN u32 WriteAddr :write flash start addderess
** IN u32 len :read flash data length
** IN char *pBuffer :read flash data
*************/
#define DATA64K 65536
u8 W25QXX_BUFFER[DATA64K];
void spiWriteBuff(char* pBuffer,u32 WriteAddr,u16 len)
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
u8 * W25QXX_BUF;
W25QXX_BUF=W25QXX_BUFFER;
secpos=WriteAddr/DATA64K;
secoff=WriteAddr%DATA64K;
secremain=DATA64K-secoff;
if(len<=secremain)
{
secremain=len;
}
while(1)
{
qspiFlashReadBuff(secpos*DATA64K,1,W25QXX_BUF,DATA64K);
for(i=0;i<secremain;i++)
{
if(W25QXX_BUF[secoff+i]!=0XFF)
{
break;
}
}
if(i<secremain)
{
eraseQspiFlash64KSector(secpos);
for(i=0;i<secremain;i++)
{
W25QXX_BUF[i+secoff]=pBuffer[i];
}
writeNocheck(W25QXX_BUF,secpos*DATA64K,DATA64K);
}
else
{
writeNocheck(pBuffer,WriteAddr,secremain);
}
if(len==secremain)
{
break;
}
else
{
secpos++;
secoff=0;
pBuffer+=secremain;
WriteAddr+=secremain;
len-=secremain;
if(len>DATA64K)secremain=DATA64K;
else secremain=len;
}
}
}