前言 不必害怕未知,无需恐惧犯错,做一个Creator!
本文主要介绍STM32_HAL库开发中W25qxx的配置使用
一、开发步骤
1.指令表配置 W25qxx的系列芯片的指令表大部分是互通,在参照芯片确定后,对指令进行宏指令配置。
定义包括:读指令,写指令,擦除指令
#define W25X_WriteEnable0x06
#define W25X_WriteDisable0x04
#define W25X_ReadStatusReg10x05
#define W25X_ReadStatusReg20x35
#define W25X_ReadStatusReg30x15
#define W25X_WriteStatusReg10x01
#define W25X_WriteStatusReg20x31
#define W25X_WriteStatusReg30x11
#define W25X_ReadData0x03
#define W25X_FastReadData0x0B
#define W25X_FastReadDual0x3B
#define W25X_PageProgram0x02
#define W25X_BlockErase0xD8
#define W25X_SectorErase0x20
#define W25X_ChipErase0xC7
#define W25X_PowerDown0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID0x9F
#define W25X_Enable4ByteAddr0xB7
#define W25X_Exit4ByteAddr0xE9
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_tucData;
uint8_tucaInterBuf[256];
uint8_tusInterPos = 0;
uint8_tusRxLength = 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");
#endifW25QXX_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|【STM32】HAL库开发教程(九)—W25qxx使用】感谢你的阅读,期待你的关注收藏点赞!
推荐阅读
- STM32|W25QXX使用教程
- Winbond W25QXX SPI Flash使用笔记
- 笔记|STM32使用W25QXX flash闪存芯片基于串口自由写入或读取数据
- 单片机|点灯科技esp32函数库+Arduino环境配置+DHT11温湿度
- 智能车|电磁循迹智能车基于stm32cubeMX、HAL库—我的第一辆智能车
- PCB设计|PCB设计技巧百问:
- #|HAL库_源码阅读
- 嵌入式|六轴陀螺仪简介及在智能车中的应用
- LINUX|【正点原子Linux连载】第三十八章 根文件系统构建 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0