不必害怕未知,无需恐惧犯错,做一个Creator!
本文主要介绍STM32_HAL库开发中W25qxx的配置使用
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
/*************************************************************\
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(); //等待芯片擦除结束
}
//将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.根据需求对各数据以及变量对操作
提示:若有错误不足,欢迎批评指正。该系列文章仅供参考,欢迎互相学习交流。
感谢你的阅读,期待你的关注收藏点赞!