Zynq-Linux移植学习3-Qspi flash读写操作:裸驱flash区域连续读写

因公司需求,需要开发一个裸驱读写Qspi falsh的驱动。

首先需要了解两个方面的知识,一是spi驱动,二是flash读写指令。spi的驱动在sdk中有集成,在此不再赘述。

下面首先查看数据手册中的读取器件型号指令,确保spi驱动没有问题。spi读0x9F寄存器,读出正确的flashID证明spi驱动没有问题。

Zynq-Linux移植学习3-Qspi flash读写操作:裸驱flash区域连续读写

接下来,进行flash的读写操作。

首先查看手册,查找到读写指令(页编程指令)分别为:

Zynq-Linux移植学习3-Qspi flash读写操作:裸驱flash区域连续读写

Read Flash

 根据读指令,查看读指令的时序,根据时序编写读代码段。

Zynq-Linux移植学习3-Qspi flash读写操作:裸驱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)的写入),写入之前需要注意的是先使能写,然后对写入区域进行擦除。

Zynq-Linux移植学习3-Qspi flash读写操作:裸驱flash区域连续读写

Zynq-Linux移植学习3-Qspi flash读写操作:裸驱flash区域连续读写

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;
}

对一段地址连续读写

Zynq-Linux移植学习3-Qspi flash读写操作:裸驱flash区域连续读写

 

/**************
** 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;		
		}	 
	}	 
}

 

 

上一篇:[操作系统原理][实验3]


下一篇:列表中使用bootstrap-switch开关