[应用相关] HAL库开发教程(九)—W25qxx使用

[复制链接]
 楼主| 梅花香自123 发表于 2021-9-28 22:04 | 显示全部楼层 |阅读模式

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

一、开发步骤1.指令表配置

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

  1. #define W25X_WriteEnable                0x06
  2. #define W25X_WriteDisable                0x04
  3. #define W25X_ReadStatusReg1                0x05
  4. #define W25X_ReadStatusReg2                0x35
  5. #define W25X_ReadStatusReg3                0x15
  6. #define W25X_WriteStatusReg1    0x01
  7. #define W25X_WriteStatusReg2    0x31
  8. #define W25X_WriteStatusReg3    0x11
  9. #define W25X_ReadData                        0x03
  10. #define W25X_FastReadData                0x0B
  11. #define W25X_FastReadDual                0x3B
  12. #define W25X_PageProgram                0x02
  13. #define W25X_BlockErase                        0xD8
  14. #define W25X_SectorErase                0x20
  15. #define W25X_ChipErase                        0xC7
  16. #define W25X_PowerDown                        0xB9
  17. #define W25X_ReleasePowerDown        0xAB
  18. #define W25X_DeviceID                        0xAB
  19. #define W25X_ManufactDeviceID        0x90
  20. #define W25X_JedecDeviceID                0x9F
  21. #define W25X_Enable4ByteAddr    0xB7
  22. #define W25X_Exit4ByteAddr      0xE9


 楼主| 梅花香自123 发表于 2021-9-28 22:28 | 显示全部楼层
2.各功能函数
  1. /*************************************************************\
  2. Function Name:W25Q64使能写
  3. \*************************************************************/
  4. void W25QXX_Write_Enable(void)   
  5. {
  6.         CS(0);
  7.   SPI1_ReadWriteByte(W25X_WriteEnable);   //发送写使能  
  8.   CS(1);       
  9. }

  10. /*************************************************************\
  11. Function Name:W25Q64禁止写
  12. \*************************************************************/
  13. void W25QXX_Write_Disable(void)   
  14. {  
  15.   CS(0);
  16.   SPI1_ReadWriteByte(W25X_WriteDisable);  //发送写禁止指令   
  17.   CS(1);       
  18. }                      

  19. /*************************************************************\
  20. Function Name:W25Q64读函数
  21. Arguments:读取数据指针,读取首地址,读取长度(256字节)
  22. \*************************************************************/
  23. void W25QXX_Read(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)   
  24. {
  25.         uint16_t i;
  26.        
  27.         CS(0);
  28.     SPI1_ReadWriteByte(W25X_ReadData);      //发送读取命令  
  29.     SPI1_ReadWriteByte((uint8_t)((ReadAddr) >> 16));   //发送24bit地址   
  30.     SPI1_ReadWriteByte((uint8_t)((ReadAddr) >> 8));   
  31.     SPI1_ReadWriteByte((uint8_t)ReadAddr);   
  32.     for (i = 0; i < NumByteToRead; i++)
  33.         {
  34.                 pBuffer[i] = SPI1_ReadWriteByte(0XFF);    //循环读数  
  35.     }
  36.         CS(1);               
  37. }  

  38. /*************************************************************\
  39. Function Name:W25Q64写函数
  40. Function Description:按页写入
  41. Arguments:写入数据指针,读取首地址,读取长度(256字节)
  42. \*************************************************************/
  43. void W25QXX_Write_Page(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
  44. {
  45.         uint16_t i;
  46.        
  47.     W25QXX_Write_Enable();                  //SET WEL
  48.    
  49.         CS(0);
  50.     SPI1_ReadWriteByte(W25X_PageProgram);   //发送写页命令   
  51.     SPI1_ReadWriteByte((uint8_t)((WriteAddr) >> 16)); //发送24bit地址   
  52.     SPI1_ReadWriteByte((uint8_t)((WriteAddr) >> 8));   
  53.     SPI1_ReadWriteByte((uint8_t)WriteAddr);   
  54.     for (i = 0; i < NumByteToWrite; i++)
  55.         SPI1_ReadWriteByte(pBuffer[i]);//循环写数  
  56.     CS(1);               
  57.    
  58.     W25QXX_Wait_Busy();                                           //等待写入结束
  59. }

  60. /*************************************************************\
  61. Function Name:W25Q64扇区擦除
  62. Function Description:擦除一个扇区
  63. Arguments:扇区地址
  64. \*************************************************************/
  65. void W25QXX_Erase_Sector(uint32_t Dst_Addr)   
  66. {  
  67.   W25QXX_Write_Enable();                  //SET WEL          
  68.   W25QXX_Wait_Busy();
  69.    
  70.   CS(0);
  71.   SPI1_ReadWriteByte(W25X_SectorErase);   //发送扇区擦除指令
  72.   SPI1_ReadWriteByte((u8)((Dst_Addr) >> 16));  //发送24bit地址   
  73.   SPI1_ReadWriteByte((u8)((Dst_Addr) >> 8));   
  74.   SPI1_ReadWriteByte((u8)Dst_Addr);   
  75.   CS(1);
  76.                  
  77.   W25QXX_Wait_Busy();                                       //等待擦除完成               
  78. }

  79. /*************************************************************\
  80. Function Name:W25Q64等待空闲
  81. \*************************************************************/
  82. void W25QXX_Wait_Busy(void)   
  83. {   
  84.         while ((W25QXX_ReadSR(1) & 0x01) == 0x01);   // 等待BUSY位清空
  85. }

  86. /*************************************************************\
  87. Function Name:W25Q64读取状态函数
  88. Function Description:读取W25QXX的状态寄存器,W25QXX一共有3个状态寄存器
  89. Arguments:状态寄存器号码
  90. Return Value:状态寄存器值
  91. \*************************************************************/
  92. uint8_t W25QXX_ReadSR(uint8_t regno)   
  93. {  
  94.         uint8_t byte = 0, command = 0;
  95.        
  96.     switch (regno)
  97.     {
  98.                 case 1:
  99.                 command = W25X_ReadStatusReg1;    //读状态寄存器1指令
  100.                 break;
  101.                 case 2:
  102.                 command = W25X_ReadStatusReg2;    //读状态寄存器2指令
  103.                 break;
  104.                 case 3:
  105.                 command = W25X_ReadStatusReg3;    //读状态寄存器3指令
  106.                 break;
  107.                 default:
  108.                 command = W25X_ReadStatusReg1;   
  109.                 break;
  110.     }   
  111.        
  112.         CS(0);
  113.         SPI1_ReadWriteByte(command);            //发送读取状态寄存器命令   
  114.         byte = SPI1_ReadWriteByte(0Xff);          //读取一个字节  
  115.         CS(1);
  116.                
  117.         return byte;   
  118. }

  119. /*************************************************************\
  120. Function Name:W25Q64芯片擦除
  121. Function Description:擦除整个芯片,时间在十多秒
  122. \*************************************************************/
  123. void W25QXX_Erase_Chip(void)   
  124. {                                   
  125.   W25QXX_Write_Enable();                  //SET WEL
  126.   W25QXX_Wait_Busy();  
  127.        
  128.   CS(0);                            //使能器件   
  129.   SPI1_ReadWriteByte(W25X_ChipErase);        //发送片擦除命令  
  130.   CS(1);          
  131.        
  132.   W25QXX_Wait_Busy();                                      //等待芯片擦除结束
  133. }
 楼主| 梅花香自123 发表于 2021-9-28 22:29 | 显示全部楼层
二、使用示例
1.W25qxx数据写入管理
  1. //将Flash看做一个FIFO,读写指针进行控制,每次先从读写指针地址中读出相应值

  2. void ReceiveInterMess(void)
  3. {
  4.         uint8_t  ucData;
  5.         uint8_t  ucaInterBuf[256];
  6.         uint8_t  usInterPos = 0;
  7.         uint8_t  usRxLength = 0;
  8.        
  9.         if(InterFifo.RxLength > 0) //判断FIFO中是否有数据
  10.         {
  11.                 HAL_Delay(1000);
  12.                 __HAL_UART_DISABLE_IT(&huart2, UART_IT_RXNE); //延迟1S确保接收完全
  13.                 usRxLength = InterFifo.RxLength;
  14.                 for ( ; usRxLength > 0; usRxLength--) //接收FIFO所以数据
  15.                 {               
  16.                         if (InterRxBufferRead(&ucData))
  17.                         {       
  18.                                 ucaInterBuf[usInterPos++] = ucData;                                                                                                                                               
  19.                         }                               
  20.                 }
  21.                 InterRxBufferClear();
  22.                 __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);                       
  23.         }
  24.                
  25.         if (usInterPos > 0)
  26.         {
  27.                 //读取读写指针地址
  28.                 W25QXX_Read(ucaWriteAddrValue, uiWriteSaveAddr, 3);
  29.                 uiUserWriteAddr = ucaWriteAddrValue[2] + (ucaWriteAddrValue[1] << 8) + (ucaWriteAddrValue[0] << 16);

  30.                 W25QXX_Read(ucaReadAddrValue, uiReadSaveAddr, 3);
  31.                 uiUserReadAddr = ucaReadAddrValue[2] + (ucaReadAddrValue[1] << 8) + (ucaReadAddrValue[0] << 16);
  32.                
  33.                 //写入数据到Flash中
  34.                 W25QXX_Write_Page(&usInterPos, uiUserWriteAddr, 1);       
  35.                 W25QXX_Write_Page(ucaInterBuf, uiUserWriteAddr+W25X_INTER_PAGE_ADDR, usInterPos);
  36.                
  37.                 W25QXX_Read(&ucDataCounter, uiDataCounterAddr, 1);
  38.                
  39.                 //队列满了,全部擦除
  40.                 if ((uiUserWriteAddr + W25X_INTER_SECTOR_ADDR) % W25X_SECTOR_ADDR_MAX == uiUserReadAddr)
  41.                 {
  42.                         #if TEST_FALG
  43.                         printf("队列满,全部擦除\r\n");
  44.                         #endif
  45.                        
  46.                         W25QXX_ExceptionHandling();
  47.                         return ;                       
  48.                 }
  49.                
  50.                 //刷新写地址               
  51.         uiUserWriteAddr = (uiUserWriteAddr + W25X_INTER_SECTOR_ADDR) % W25X_SECTOR_ADDR_MAX;
  52.                 ucaWriteAddrValue[0] = (uiUserWriteAddr >> 16);
  53.                 ucaWriteAddrValue[1] = (uiUserWriteAddr >> 8);
  54.                 ucaWriteAddrValue[2] = uiUserWriteAddr;
  55.                 W25QXX_Erase_Sector(uiWriteSaveAddr);
  56.                 W25QXX_Write_Page(ucaWriteAddrValue, uiWriteSaveAddr, 3);                       

  57.                 ucDataCounter++;
  58.         W25QXX_Erase_Sector(uiDataCounterAddr);
  59.                 W25QXX_Write_Page(&ucDataCounter, uiDataCounterAddr, 1);
  60.                
  61.                 #if TEST_FALG
  62.                 printf("捕获一条数据:");
  63.                 for (int i = 0; i < usInterPos; i++)
  64.                 printf( " %02X", ucaInterBuf[i]);
  65.                 printf("\r\n待发数据条数:%d\r\n", ucDataCounter);
  66.                 printf("\r\nFlash读地址:%02X\r\n", uiUserReadAddr);       
  67.                 printf("Flash写地址:%02X\r\n", uiUserWriteAddr);
  68.                 #endif               
  69.         }
  70.        
  71.        
  72. }
 楼主| 梅花香自123 发表于 2021-9-28 22:29 | 显示全部楼层
总结
本项目中W25qxx的使用主要可以归纳为:
1.熟知使用W25qxx的哪些指令
2.编写读、写、擦除功能基本函数
3.根据需求对各数据以及变量对操作
wakayi 发表于 2021-10-12 15:33 | 显示全部楼层
请问这个是什么系列的芯片啊
labasi 发表于 2021-10-12 15:34 | 显示全部楼层
这是一个存储芯片吗
paotangsan 发表于 2021-10-12 15:34 | 显示全部楼层
它本身有自己的寄存器?
renzheshengui 发表于 2021-10-12 15:36 | 显示全部楼层
好像是一个eeprom芯片
wakayi 发表于 2021-10-12 15:38 | 显示全部楼层
有没有时序要求呢
wowu 发表于 2021-10-12 16:26 | 显示全部楼层
这个芯片用的多吗
mickit 发表于 2021-10-18 19:59 | 显示全部楼层
采用SPI进行读写吧  
mikewalpole 发表于 2021-10-18 19:59 | 显示全部楼层
W25QXX_ReadID有数据吗  
robincotton 发表于 2021-10-18 20:00 | 显示全部楼层
使用HAL库的SPI外挂W25Q32
jackcat 发表于 2021-10-18 20:00 | 显示全部楼层
调用W25QXX_Write出现RAM不够怎么办?
hearstnorman323 发表于 2021-10-18 20:00 | 显示全部楼层
ST的HAL库例程吗   
tifmill 发表于 2021-10-18 20:00 | 显示全部楼层
不同型号的QSPI Flash会有一些参数和命令不同吧  
nomomy 发表于 2021-10-18 20:01 | 显示全部楼层
STM32 的 HAL 库好用吗  
abotomson 发表于 2021-10-18 20:01 | 显示全部楼层
STM32 用新版的HAL库好还是3.5的库好
ulystronglll 发表于 2021-10-18 20:01 | 显示全部楼层
stm32库函数算hal层吗
elsaflower 发表于 2021-10-18 20:01 | 显示全部楼层
stm32的hal库为什么编译变慢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

101

主题

1215

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部