打印
[应用相关]

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

[复制链接]
2236|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
梅花香自123|  楼主 | 2021-9-28 22:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

本文主要介绍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


使用特权

评论回复
沙发
梅花香自123|  楼主 | 2021-9-28 22:28 | 只看该作者
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();                                      //等待芯片擦除结束
}

使用特权

评论回复
板凳
梅花香自123|  楼主 | 2021-9-28 22:29 | 只看该作者
二、使用示例
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               
        }
       
       
}

使用特权

评论回复
地板
梅花香自123|  楼主 | 2021-9-28 22:29 | 只看该作者
总结
本项目中W25qxx的使用主要可以归纳为:
1.熟知使用W25qxx的哪些指令
2.编写读、写、擦除功能基本函数
3.根据需求对各数据以及变量对操作

使用特权

评论回复
5
wakayi| | 2021-10-12 15:33 | 只看该作者
请问这个是什么系列的芯片啊

使用特权

评论回复
6
labasi| | 2021-10-12 15:34 | 只看该作者
这是一个存储芯片吗

使用特权

评论回复
7
paotangsan| | 2021-10-12 15:34 | 只看该作者
它本身有自己的寄存器?

使用特权

评论回复
8
renzheshengui| | 2021-10-12 15:36 | 只看该作者
好像是一个eeprom芯片

使用特权

评论回复
9
wakayi| | 2021-10-12 15:38 | 只看该作者
有没有时序要求呢

使用特权

评论回复
10
wowu| | 2021-10-12 16:26 | 只看该作者
这个芯片用的多吗

使用特权

评论回复
11
mickit| | 2021-10-18 19:59 | 只看该作者
采用SPI进行读写吧  

使用特权

评论回复
12
mikewalpole| | 2021-10-18 19:59 | 只看该作者
W25QXX_ReadID有数据吗  

使用特权

评论回复
13
robincotton| | 2021-10-18 20:00 | 只看该作者
使用HAL库的SPI外挂W25Q32

使用特权

评论回复
14
jackcat| | 2021-10-18 20:00 | 只看该作者
调用W25QXX_Write出现RAM不够怎么办?

使用特权

评论回复
15
hearstnorman323| | 2021-10-18 20:00 | 只看该作者
ST的HAL库例程吗   

使用特权

评论回复
16
tifmill| | 2021-10-18 20:00 | 只看该作者
不同型号的QSPI Flash会有一些参数和命令不同吧  

使用特权

评论回复
17
nomomy| | 2021-10-18 20:01 | 只看该作者
STM32 的 HAL 库好用吗  

使用特权

评论回复
18
abotomson| | 2021-10-18 20:01 | 只看该作者
STM32 用新版的HAL库好还是3.5的库好

使用特权

评论回复
19
ulystronglll| | 2021-10-18 20:01 | 只看该作者
stm32库函数算hal层吗

使用特权

评论回复
20
elsaflower| | 2021-10-18 20:01 | 只看该作者
stm32的hal库为什么编译变慢

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

92

主题

1059

帖子

0

粉丝