【STM32】HAL库开发教程(九)—W25qxx使用

前言

不必害怕未知,无需恐惧犯错,做一个Creator!

本文主要介绍STM32_HAL库开发中W25qxx的配置使用

一、开发步骤

1.指令表配置

W25qxx的系列芯片的指令表大部分是互通,在参照芯片确定后,对指令进行宏指令配置。
定义包括:读指令,写指令,擦除指令

#define W25X_WriteEnable		0x06 
#define W25X_WriteDisable		0x04 
#define W25X_ReadStatusReg1		0x05 
#define W25X_ReadStatusReg2		0x35 
#define W25X_ReadStatusReg3		0x15 
#define W25X_WriteStatusReg1    0x01 
#define W25X_WriteStatusReg2    0x31 
#define W25X_WriteStatusReg3    0x11 
#define W25X_ReadData			0x03 
#define W25X_FastReadData		0x0B 
#define W25X_FastReadDual		0x3B 
#define W25X_PageProgram		0x02 
#define W25X_BlockErase			0xD8 
#define W25X_SectorErase		0x20 
#define W25X_ChipErase			0xC7 
#define W25X_PowerDown			0xB9 
#define W25X_ReleasePowerDown	0xAB 
#define W25X_DeviceID			0xAB 
#define W25X_ManufactDeviceID	0x90 
#define W25X_JedecDeviceID		0x9F 
#define W25X_Enable4ByteAddr    0xB7
#define W25X_Exit4ByteAddr      0xE9

2.各功能函数

/*************************************************************\
Function Name:W25Q64使能写
\*************************************************************/
void W25QXX_Write_Enable(void)   
{
	CS(0);
  SPI1_ReadWriteByte(W25X_WriteEnable);   //发送写使能  
  CS(1);	
} 

/*************************************************************\
Function Name:W25Q64禁止写
\*************************************************************/ 
void W25QXX_Write_Disable(void)   
{  
  CS(0);
  SPI1_ReadWriteByte(W25X_WriteDisable);  //发送写禁止指令    
  CS(1);	
}  		    

/*************************************************************\
Function Name:W25Q64读函数
Arguments:读取数据指针,读取首地址,读取长度(256字节)
\*************************************************************/ 
void W25QXX_Read(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)   
{ 
	uint16_t i; 
	
	CS(0);
    SPI1_ReadWriteByte(W25X_ReadData);      //发送读取命令  
    SPI1_ReadWriteByte((uint8_t)((ReadAddr) >> 16));   //发送24bit地址    
    SPI1_ReadWriteByte((uint8_t)((ReadAddr) >> 8));   
    SPI1_ReadWriteByte((uint8_t)ReadAddr);   
    for (i = 0; i < NumByteToRead; i++)
	{ 
		pBuffer[i] = SPI1_ReadWriteByte(0XFF);    //循环读数  
    }
	CS(1);		
}  

/*************************************************************\
Function Name:W25Q64写函数
Function Description:按页写入
Arguments:写入数据指针,读取首地址,读取长度(256字节)
\*************************************************************/ 
void W25QXX_Write_Page(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
	uint16_t i; 
	
    W25QXX_Write_Enable();                  //SET WEL 
    
	CS(0);
    SPI1_ReadWriteByte(W25X_PageProgram);   //发送写页命令   
    SPI1_ReadWriteByte((uint8_t)((WriteAddr) >> 16)); //发送24bit地址    
    SPI1_ReadWriteByte((uint8_t)((WriteAddr) >> 8));   
    SPI1_ReadWriteByte((uint8_t)WriteAddr);   
    for (i = 0; i < NumByteToWrite; i++)
	SPI1_ReadWriteByte(pBuffer[i]);//循环写数  
    CS(1);		
    
    W25QXX_Wait_Busy();					   //等待写入结束
} 

/*************************************************************\
Function Name:W25Q64扇区擦除
Function Description:擦除一个扇区
Arguments:扇区地址
\*************************************************************/ 
void W25QXX_Erase_Sector(uint32_t Dst_Addr)   
{  
  W25QXX_Write_Enable();                  //SET WEL 	 
  W25QXX_Wait_Busy(); 
    
  CS(0);
  SPI1_ReadWriteByte(W25X_SectorErase);   //发送扇区擦除指令 
  SPI1_ReadWriteByte((u8)((Dst_Addr) >> 16));  //发送24bit地址    
  SPI1_ReadWriteByte((u8)((Dst_Addr) >> 8));   
  SPI1_ReadWriteByte((u8)Dst_Addr);   
  CS(1);
  		
  W25QXX_Wait_Busy();   				    //等待擦除完成		
} 

/*************************************************************\
Function Name:W25Q64等待空闲
\*************************************************************/
void W25QXX_Wait_Busy(void)   
{   
	while ((W25QXX_ReadSR(1) & 0x01) == 0x01);   // 等待BUSY位清空
}

/*************************************************************\
Function Name:W25Q64读取状态函数
Function Description:读取W25QXX的状态寄存器,W25QXX一共有3个状态寄存器
Arguments:状态寄存器号码
Return Value:状态寄存器值
\*************************************************************/
uint8_t W25QXX_ReadSR(uint8_t regno)   
{  
	uint8_t byte = 0, command = 0;
	
    switch (regno)
    {
		case 1:
		command = W25X_ReadStatusReg1;    //读状态寄存器1指令
		break;
		case 2:
		command = W25X_ReadStatusReg2;    //读状态寄存器2指令
		break;
		case 3:
		command = W25X_ReadStatusReg3;    //读状态寄存器3指令
		break;
		default:
		command = W25X_ReadStatusReg1;    
		break;
    }    
	
	CS(0);
	SPI1_ReadWriteByte(command);            //发送读取状态寄存器命令    
	byte = SPI1_ReadWriteByte(0Xff);          //读取一个字节  
	CS(1);
		
	return byte;   
} 

/*************************************************************\
Function Name:W25Q64芯片擦除
Function Description:擦除整个芯片,时间在十多秒
\*************************************************************/ 
void W25QXX_Erase_Chip(void)   
{                                   
  W25QXX_Write_Enable();                  //SET WEL 
  W25QXX_Wait_Busy();  
	
  CS(0);                            //使能器件   
  SPI1_ReadWriteByte(W25X_ChipErase);        //发送片擦除命令  
  CS(1);   	
	
  W25QXX_Wait_Busy();   				   //等待芯片擦除结束
}

二、使用示例

1.W25qxx数据写入管理

//将Flash看做一个FIFO,读写指针进行控制,每次先从读写指针地址中读出相应值

void ReceiveInterMess(void)
{
	uint8_t  ucData;
	uint8_t  ucaInterBuf[256];
	uint8_t  usInterPos = 0;
	uint8_t  usRxLength = 0;
	
	if(InterFifo.RxLength > 0) //判断FIFO中是否有数据
	{
		HAL_Delay(1000);
		__HAL_UART_DISABLE_IT(&huart2, UART_IT_RXNE); //延迟1S确保接收完全
		usRxLength = InterFifo.RxLength;
		for ( ; usRxLength > 0; usRxLength--) //接收FIFO所以数据
		{		
			if (InterRxBufferRead(&ucData))
			{	
				ucaInterBuf[usInterPos++] = ucData;																		
			}				
		}
		InterRxBufferClear();
		__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);			
	}
		
	if (usInterPos > 0)
	{
		//读取读写指针地址
		W25QXX_Read(ucaWriteAddrValue, uiWriteSaveAddr, 3);
		uiUserWriteAddr = ucaWriteAddrValue[2] + (ucaWriteAddrValue[1] << 8) + (ucaWriteAddrValue[0] << 16);

		W25QXX_Read(ucaReadAddrValue, uiReadSaveAddr, 3);
		uiUserReadAddr = ucaReadAddrValue[2] + (ucaReadAddrValue[1] << 8) + (ucaReadAddrValue[0] << 16);
		
		//写入数据到Flash中
		W25QXX_Write_Page(&usInterPos, uiUserWriteAddr, 1);	
		W25QXX_Write_Page(ucaInterBuf, uiUserWriteAddr+W25X_INTER_PAGE_ADDR, usInterPos);
		
		W25QXX_Read(&ucDataCounter, uiDataCounterAddr, 1);
		
		//队列满了,全部擦除
		if ((uiUserWriteAddr + W25X_INTER_SECTOR_ADDR) % W25X_SECTOR_ADDR_MAX == uiUserReadAddr)
		{
			#if TEST_FALG
			printf("队列满,全部擦除\r\n");
			#endif
			
			W25QXX_ExceptionHandling();
			return ;			
		}
		
		//刷新写地址		
        uiUserWriteAddr = (uiUserWriteAddr + W25X_INTER_SECTOR_ADDR) % W25X_SECTOR_ADDR_MAX;
		ucaWriteAddrValue[0] = (uiUserWriteAddr >> 16);
		ucaWriteAddrValue[1] = (uiUserWriteAddr >> 8);
		ucaWriteAddrValue[2] = uiUserWriteAddr;
		W25QXX_Erase_Sector(uiWriteSaveAddr);
		W25QXX_Write_Page(ucaWriteAddrValue, uiWriteSaveAddr, 3);			

		ucDataCounter++;
        W25QXX_Erase_Sector(uiDataCounterAddr);
		W25QXX_Write_Page(&ucDataCounter, uiDataCounterAddr, 1);
		
		#if TEST_FALG
		printf("捕获一条数据:");
		for (int i = 0; i < usInterPos; i++)
		printf( " %02X", ucaInterBuf[i]);
		printf("\r\n待发数据条数:%d\r\n", ucDataCounter);
		printf("\r\nFlash读地址:%02X\r\n", uiUserReadAddr);	
		printf("Flash写地址:%02X\r\n", uiUserWriteAddr);
		#endif		
	}
	
	
}

总结

本项目中W25qxx的使用主要可以归纳为:
1.熟知使用W25qxx的哪些指令
2.编写读、写、擦除功能基本函数
3.根据需求对各数据以及变量对操作


提示:若有错误不足,欢迎批评指正。该系列文章仅供参考,欢迎互相学习交流。

感谢你的阅读,期待你的关注收藏点赞!

你可能感兴趣的:(stm32,flash,spi)