精华内容
下载资源
问答
  • 【STM32】HAL库开发教程(九)—W25qxx使用
    2020-12-28 18:58:07

    前言

    不必害怕未知,无需恐惧犯错,做一个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.根据需求对各数据以及变量对操作


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

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

    更多相关内容
  • W25Qxx串口助手XXXXXX.zip

    2020-08-27 18:41:46
    使用stm32串口向W25Qxx内部写入文件、字库、图片等等 文档内部包含串口调试助手,通过W25Qxx串口调试助手可以指定写入内存地址。 支持硬件:STM32系列MCU 支持硬件:W25Q80、W25Q16、W25Q32、W25Q64、W25Q128、W25Q...
  • 使用stm32串口向W25Qxx内部写入文件、字库、图片等等 文档内部包含串口调试助手,通过W25Qxx串口调试助手可以指定写入内存地址。 支持硬件:STM32系列MCU 支持硬件:W25Q80、W25Q16、W25Q32、W25Q64、W25Q128、W25Q...
  • W25qxx(STM32 SPI HAL库).rar

    2020-06-20 19:07:55
    实现对W25Q64/128/512等芯片的驱动,接口标准,实现对存储芯片的调用及管理,擦除,读写等功能。
  • spiflash驱动w25qxx.zip

    2020-04-20 11:16:08
    本资源为w25qxx系列flash的spi驱动代码 包含spi.h和spi.c和w25qxx.h和w25qxx.c四个驱动文件和头文件
  • W25Qxx串口助手.zip

    2020-08-27 22:37:04
    使用stm32串口向W25Qxx内部写入文件、字库、图片等等 文档内部包含串口调试助手,通过W25Qxx串口调试助手可以指定写入内存地址。 支持硬件:STM32系列MCU 支持硬件:W25Q80、W25Q16、W25Q32、W25Q64、W25Q128、W25Q...
  • 通过stm32单片机的spi实现flash的读写
  • STM32 串口更新字库W25QXX,里面有收集到的多个版本例程
  • w25qxx-master.zip

    2020-10-09 21:52:00
    基于STM32硬件平台实现了使用SPI读写W25Qxx系列的功能。调用初始化 函数后,能够自行打印出ID, 芯片型号, 页大小, 页数, 扇区大小,扇区数, 块大小, 块数, 总容量等基本数据。
  • STM32 串口字库 下载W25QXX 含12点,16点,24点,32点字库文件,可分开下载到flash
  • W25Qxx.zip

    2020-08-14 21:26:35
    W25QXX系列flash芯片可移植程序,在stm32下简单配置即可使用,可参考博主发布的博文,按照教程,几分钟即可完成移植。
  • W25Qxx使用

    2022-03-04 11:23:02
    W25Qxx系列中的xx代表容量,单位为Mb。 W25Qxx系列的Flash内部是按照Page(页)、Sector(扇区)、Block(块)的结构来划分的。 每页(Page)为256个字节, 每个扇区(Sector)有16页(Page)也就是4KB, 每个块...

    W25Qxx系列中的xx代表容量,单位为Mb。
    W25Qxx系列的Flash内部是按照Page(页)、Sector(扇区)、Block(块)的结构来划分的。
    每页(Page)为256个字节,
    每个扇区(Sector)有16页(Page)也就是4KB,
    每个块(Block)有16个扇区(Sector)也就是64KB,
    W25Qxx最小擦除单位为一个扇区(Sector),也就是每次至少擦除4KB。
    最大写入单位是一页(Page),也就是一次最多写入256个字节。

    以W25q128为例。
    The W25Q128JW array is organized into 65,536 programmable pages of 256-bytes each. Up to 256 bytes can be programmed at a time. Pages can be erased in groups of 16 (4KB sector erase), groups of 128 (32KB block erase), groups of 256 (64KB block erase) or the entire chip (chip erase). The W 25Q128JW has 4,096 erasable sectors and 256 erasable blocks respectively. The small 4KB sectors allow for greater flexibility in applications that require data and parameter storage.
    W25Q128的容量为128Mb,也就是16MB。包含了有256个可擦除块,4096个可擦除扇区,32768个可编程页。一次最多可编程256字节。页面可以按16组(4KB扇区擦除)、128组(32KB块擦除)、256组(64KB块擦除)或整个芯片(芯片擦除)擦除。
    框图如下。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QTH3aObq-1646364154917)(attachment:e134daa52d97dc2f73d41db691436d4f)]

    在这里插入图片描述

    ID读取函数如下
    //读取芯片ID
    //返回值如下:
    //0XEF13,表示芯片型号为W25Q80
    //0XEF14,表示芯片型号为W25Q16
    //0XEF15,表示芯片型号为W25Q32
    //0XEF16,表示芯片型号为W25Q64
    //0XEF17,表示芯片型号为W25Q128
    //0XEF18,表示芯片型号为W25Q256
    uint8_t W25qxx_ReadID(void)
    {
    uint8_t Temp0 = 0,Temp1 = 0;
    W25qxx_cs(0);
    W25qxx_SPIReadWrite(W25X_ManufactDeviceID);//发送读取ID命令
    W25qxx_SPIReadWrite(0x00);
    W25qxx_SPIReadWrite(0x00);
    W25qxx_SPIReadWrite(0x00);
    Temp0=W25qxx_SPIReadWrite(W25QXX_DUMMY_BYTE);
    Temp1=W25qxx_SPIReadWrite(W25QXX_DUMMY_BYTE);
    W25qxx_cs(1);
    if(Temp0 == 0xef && Temp1>= 0x10 && Temp1<= 0x19)
    {
    return Temp1;
    }
    else
    return 0;
    }
    void W25qxx_EraseSector(uint32_t SectorAddr)
    {
    W25qxx_WaitForWriteEnd();
    SectorAddr = SectorAddr * W25X_SectorSize;
    W25qxx_WriteEnable();
    W25qxx_cs(0);
    if (w25qxx.ID >= W25Q256)
    {
    W25qxx_SPIReadWrite(0x21);
    W25qxx_SPIReadWrite((SectorAddr & 0xFF000000) >> 24);
    }
    else
    {
    W25qxx_SPIReadWrite(W25X_SectorErase);
    }
    W25qxx_SPIReadWrite((SectorAddr & 0xFF0000) >> 16);
    W25qxx_SPIReadWrite((SectorAddr & 0xFF00) >> 8);
    W25qxx_SPIReadWrite(SectorAddr & 0xFF);
    W25qxx_cs(1);
    W25qxx_WaitForWriteEnd();
    W25qxx_Delay(1);
    }
    //在指定地址开始读取指定长度的数据
    //pBuffer:数据存储区
    //ReadAddr:开始读取的地址(24bit)
    //NumByteToRead:要读取的字节数(最大65535)
    void W25qxx_ReadBytes(uint8_t *pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead)
    {
    W25qxx_cs(0)
    if (w25qxx.ID >= W25Q256)
    {
    W25qxx_SPIReadWrite(0x0C);
    W25qxx_SPIReadWrite((ReadAddr & 0xFF000000) >> 24);
    }
    else
    {
    W25qxx_SPIReadWrite(W25X_FastReadData);
    }
    W25qxx_SPIReadWrite((ReadAddr & 0xFF0000) >> 16);
    W25qxx_SPIReadWrite((ReadAddr & 0xFF00) >> 8);
    W25qxx_SPIReadWrite(ReadAddr & 0xFF);
    W25qxx_SPIReadWrite(0);
    for(uint32_t i=0;i<NumByteToRead;i++)
    {
    pBuffer[i]=W25qxx_SPIReadWrite(0XFF); //循环读数
    }
    W25qxx_cs(1);
    }
    //在指定地址开始写入不大于一页的数据,写入前确保扇区已经擦除
    //pBuffer: 要写入的数据
    //Page_Address: 要写入的页地址(第几页)
    //OffsetInByte: 在页内的偏移字节
    //NumByteToWrite_up_to_PageSize: 要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
    void W25qxx_WritePage(uint8_t *pBuffer, uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_PageSize)
    {
    if (((NumByteToWrite_up_to_PageSize + OffsetInByte) > W25X_PageSize) || (NumByteToWrite_up_to_PageSize == 0)) //判断要写入的数据是否合法
    NumByteToWrite_up_to_PageSize = W25X_PageSize - OffsetInByte;
    W25qxx_WaitForWriteEnd();
    W25qxx_WriteEnable();
    W25qxx_cs(0);
    Page_Address = (Page_Address * W25X_PageSize) + OffsetInByte;
    if (w25qxx.ID >= W25Q256)
    {
    W25qxx_SPIReadWrite(0x12);
    W25qxx_SPIReadWrite((Page_Address & 0xFF000000) >> 24);
    }
    else
    {
    W25qxx_SPIReadWrite(W25X_PageProgram);
    }
    W25qxx_SPIReadWrite((Page_Address & 0xFF0000) >> 16);
    W25qxx_SPIReadWrite((Page_Address & 0xFF00) >> 8);
    W25qxx_SPIReadWrite(Page_Address & 0xFF);
    W25qxx_SPIWrite(pBuffer, NumByteToWrite_up_to_PageSize);
    W25qxx_cs(1);
    W25qxx_WaitForWriteEnd();
    W25qxx_Delay(1);
    }

    展开全文
  • W25QXX使用教程

    千次阅读 2021-01-24 19:28:46
    W25QXX是华邦公司生产的一块FLASH储存芯片 那W25Q256为例:驱动方式:单路双路四路SPI、QSPI; 擦写周期:10W次 支持电压:2.7~3.6V 频率:单路最大104Mhz、双路208Mhz、四路416Mhz 容量:容量为32M字节; 它将32M的...

    W25QXX是华邦公司生产的一块FLASH储存芯片

    那W25Q256为例:驱动方式:单路双路四路SPI、QSPI;
    擦写周期:10W次
    支持电压:2.7~3.6V
    频率:单路最大104Mhz、双路208Mhz、四路416Mhz
    容量:容量为32M字节;
    它将32M的容量分为512个块(Block),那么每个块的容量就是64K字节;
    每个块又分为16个扇区(Sector),每个扇区4K个字节;
    在这里插入图片描述

    那我们需要给W25Q256开辟一个至少4K的缓存区,这样对SRAM要求较高,芯片必须有4K以上的SRAM才能很好的操作,因为它的写操作需要先计算出它的扇区,把这个扇区的内容全部读出来,存放到芯片的SRAM里面进行修改,然后在一次性吧内容写入芯片。

    引脚排列

    在这里插入图片描述

    引脚描述

    在这里插入图片描述

    硬件连接

    在这里插入图片描述
    操作指令:
    在这里插入图片描述
    w25qxx.h

    #ifndef __W25QXX_H
    #define __W25QXX_H
    #include "sys.h"
    							  
    // 	
    
    //W25X系列/Q系列芯片列表	   
    //W25Q80  ID  0XEF13
    //W25Q16  ID  0XEF14
    //W25Q32  ID  0XEF15
    //W25Q64  ID  0XEF16	
    //W25Q128 ID  0XEF17	
    //W25Q256 ID  0XEF18
    #define W25Q80 	0XEF13 	
    #define W25Q16 	0XEF14
    #define W25Q32 	0XEF15
    #define W25Q64 	0XEF16
    #define W25Q128	0XEF17
    #define W25Q256 0XEF18
    
    extern u16 W25QXX_TYPE;					//定义W25QXX芯片型号		   
    
    #define	W25QXX_CS 		PFout(6)  		//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
    
    void W25QXX_Init(void);
    u16  W25QXX_ReadID(void);  	    		//读取FLASH ID
    u8 W25QXX_ReadSR(u8 regno);             //读取状态寄存器 
    void W25QXX_4ByteAddr_Enable(void);     //使能4字节地址模式
    void W25QXX_Write_SR(u8 regno,u8 sr);   //写状态寄存器
    void W25QXX_Write_Enable(void);  		//写使能 
    void W25QXX_Write_Disable(void);		//写保护
    void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);
    void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);   //读取flash
    void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//写入flash
    void W25QXX_Erase_Chip(void);    	  	//整片擦除
    void W25QXX_Erase_Sector(u32 Dst_Addr);	//扇区擦除
    void W25QXX_Wait_Busy(void);           	//等待空闲
    void W25QXX_PowerDown(void);        	//进入掉电模式
    void W25QXX_WAKEUP(void);				//唤醒
    
    #endif
    
    

    w25qxx.c

    #include "w25qxx.h"
    #include "spi.h"
    #include "delay.h"
    #include "usart.h"
    #include "stm32f4xx_hal_gpio.h"
    							  
    // 	
    
    u16 W25QXX_TYPE=W25Q256;	//默认是W25Q256
    
    //4Kbytes为一个Sector
    //16个扇区为1个Block
    //W25Q256
    //容量为32M字节,共有512个Block,8192个Sector 
    													 
    //初始化SPI FLASH的IO口
    void W25QXX_Init(void)
    { 
        u8 temp;
        GPIO_InitTypeDef GPIO_Initure;
        
        __HAL_RCC_GPIOF_CLK_ENABLE();           //使能GPIOF时钟
        
        //PF6
        GPIO_Initure.Pin=GPIO_PIN_6;            //PF6
        GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
        GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
        GPIO_Initure.Speed=GPIO_SPEED_FAST;     //快速         
        HAL_GPIO_Init(GPIOF,&GPIO_Initure);     //初始化
        
    	W25QXX_CS=1;			                //SPI FLASH不选中
    	SPI5_Init();		   			        //初始化SPI
    	SPI5_SetSpeed(SPI_BAUDRATEPRESCALER_2); //设置为45M时钟,高速模式
    	W25QXX_TYPE=W25QXX_ReadID();	        //读取FLASH ID.
        if(W25QXX_TYPE==W25Q256)                //SPI FLASH为W25Q256
        {
            temp=W25QXX_ReadSR(3);              //读取状态寄存器3,判断地址模式
            if((temp&0X01)==0)			        //如果不是4字节地址模式,则进入4字节地址模式
    		{
    			W25QXX_CS=0; 			        //选中
    			SPI5_ReadWriteByte(W25X_Enable4ByteAddr);//发送进入4字节地址模式指令   
    			W25QXX_CS=1;       		        //取消片选   
    		}
        }
    }  
    
    //读取W25QXX的状态寄存器,W25QXX一共有3个状态寄存器
    //状态寄存器1:
    //BIT7  6   5   4   3   2   1   0
    //SPR   RV  TB BP2 BP1 BP0 WEL BUSY
    //SPR:默认0,状态寄存器保护位,配合WP使用
    //TB,BP2,BP1,BP0:FLASH区域写保护设置
    //WEL:写使能锁定
    //BUSY:忙标记位(1,忙;0,空闲)
    //默认:0x00
    //状态寄存器2:
    //BIT7  6   5   4   3   2   1   0
    //SUS   CMP LB3 LB2 LB1 (R) QE  SRP1
    //状态寄存器3:
    //BIT7      6    5    4   3   2   1   0
    //HOLD/RST  DRV1 DRV0 (R) (R) WPS ADP ADS
    //regno:状态寄存器号,范:1~3
    //返回值:状态寄存器值
    u8 W25QXX_ReadSR(u8 regno)   
    {  
    	u8 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;
        }    
    	W25QXX_CS=0;                            //使能器件   
    	SPI5_ReadWriteByte(command);            //发送读取状态寄存器命令    
    	byte=SPI5_ReadWriteByte(0Xff);          //读取一个字节  
    	W25QXX_CS=1;                            //取消片选     
    	return byte;   
    } 
    //写W25QXX状态寄存器
    void W25QXX_Write_SR(u8 regno,u8 sr)   
    {   
        u8 command=0;
        switch(regno)
        {
            case 1:
                command=W25X_WriteStatusReg1;    //写状态寄存器1指令
                break;
            case 2:
                command=W25X_WriteStatusReg2;    //写状态寄存器2指令
                break;
            case 3:
                command=W25X_WriteStatusReg3;    //写状态寄存器3指令
                break;
            default:
                command=W25X_WriteStatusReg1;    
                break;
        }   
    	W25QXX_CS=0;                            //使能器件   
    	SPI5_ReadWriteByte(command);            //发送写取状态寄存器命令    
    	SPI5_ReadWriteByte(sr);                 //写入一个字节  
    	W25QXX_CS=1;                            //取消片选     	      
    }   
    //W25QXX写使能	
    //将WEL置位   
    void W25QXX_Write_Enable(void)   
    {
    	W25QXX_CS=0;                            //使能器件   
        SPI5_ReadWriteByte(W25X_WriteEnable);   //发送写使能  
    	W25QXX_CS=1;                            //取消片选     	      
    } 
    //W25QXX写禁止	
    //将WEL清零  
    void W25QXX_Write_Disable(void)   
    {  
    	W25QXX_CS=0;                            //使能器件   
        SPI5_ReadWriteByte(W25X_WriteDisable);  //发送写禁止指令    
    	W25QXX_CS=1;                            //取消片选     	      
    } 
    
    //读取芯片ID
    //返回值如下:				   
    //0XEF13,表示芯片型号为W25Q80  
    //0XEF14,表示芯片型号为W25Q16    
    //0XEF15,表示芯片型号为W25Q32  
    //0XEF16,表示芯片型号为W25Q64 
    //0XEF17,表示芯片型号为W25Q128 	  
    //0XEF18,表示芯片型号为W25Q256
    u16 W25QXX_ReadID(void)
    {
    	u16 Temp = 0;	  
    	W25QXX_CS=0;				    
    	SPI5_ReadWriteByte(0x90);//发送读取ID命令	    
    	SPI5_ReadWriteByte(0x00); 	    
    	SPI5_ReadWriteByte(0x00); 	    
    	SPI5_ReadWriteByte(0x00); 	 			   
    	Temp|=SPI5_ReadWriteByte(0xFF)<<8;  
    	Temp|=SPI5_ReadWriteByte(0xFF);	 
    	W25QXX_CS=1;				    
    	return Temp;
    }   		    
    //读取SPI FLASH  
    //在指定地址开始读取指定长度的数据
    //pBuffer:数据存储区
    //ReadAddr:开始读取的地址(24bit)
    //NumByteToRead:要读取的字节数(最大65535)
    void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   
    { 
     	u16 i;   										    
    	W25QXX_CS=0;                            //使能器件   
        SPI5_ReadWriteByte(W25X_ReadData);      //发送读取命令  
        if(W25QXX_TYPE==W25Q256)                //如果是W25Q256的话地址为4字节的,要发送最高8位
        {
            SPI5_ReadWriteByte((u8)((ReadAddr)>>24));    
        }
        SPI5_ReadWriteByte((u8)((ReadAddr)>>16));   //发送24bit地址    
        SPI5_ReadWriteByte((u8)((ReadAddr)>>8));   
        SPI5_ReadWriteByte((u8)ReadAddr);   
        for(i=0;i<NumByteToRead;i++)
    	{ 
            pBuffer[i]=SPI5_ReadWriteByte(0XFF);    //循环读数  
        }
    	W25QXX_CS=1;  				    	      
    }  
    //SPI在一页(0~65535)内写入少于256个字节的数据
    //在指定地址开始写入最大256字节的数据
    //pBuffer:数据存储区
    //WriteAddr:开始写入的地址(24bit)
    //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!	 
    void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
    {
     	u16 i;  
        W25QXX_Write_Enable();                  //SET WEL 
    	W25QXX_CS=0;                            //使能器件   
        SPI5_ReadWriteByte(W25X_PageProgram);   //发送写页命令   
        if(W25QXX_TYPE==W25Q256)                //如果是W25Q256的话地址为4字节的,要发送最高8位
        {
            SPI5_ReadWriteByte((u8)((WriteAddr)>>24)); 
        }
        SPI5_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址    
        SPI5_ReadWriteByte((u8)((WriteAddr)>>8));   
        SPI5_ReadWriteByte((u8)WriteAddr);   
        for(i=0;i<NumByteToWrite;i++)SPI5_ReadWriteByte(pBuffer[i]);//循环写数  
    	W25QXX_CS=1;                            //取消片选 
    	W25QXX_Wait_Busy();					   //等待写入结束
    } 
    //无检验写SPI FLASH 
    //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
    //具有自动换页功能 
    //在指定地址开始写入指定长度的数据,但是要确保地址不越界!
    //pBuffer:数据存储区
    //WriteAddr:开始写入的地址(24bit)
    //NumByteToWrite:要写入的字节数(最大65535)
    //CHECK OK
    void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
    { 			 		 
    	u16 pageremain;	   
    	pageremain=256-WriteAddr%256; //单页剩余的字节数		 	    
    	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
    	while(1)
    	{	   
    		W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
    		if(NumByteToWrite==pageremain)break;//写入结束了
    	 	else //NumByteToWrite>pageremain
    		{
    			pBuffer+=pageremain;
    			WriteAddr+=pageremain;	
    
    			NumByteToWrite-=pageremain;			  //减去已经写入了的字节数
    			if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
    			else pageremain=NumByteToWrite; 	  //不够256个字节了
    		}
    	};	    
    } 
    //写SPI FLASH  
    //在指定地址开始写入指定长度的数据
    //该函数带擦除操作!
    //pBuffer:数据存储区
    //WriteAddr:开始写入的地址(24bit)						
    //NumByteToWrite:要写入的字节数(最大65535)   
    u8 W25QXX_BUFFER[4096];		 
    void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
    { 
    	u32 secpos;
    	u16 secoff;
    	u16 secremain;	   
     	u16 i;    
    	u8 * W25QXX_BUF;	  
       	W25QXX_BUF=W25QXX_BUFFER;	     
     	secpos=WriteAddr/4096;//扇区地址  
    	secoff=WriteAddr%4096;//在扇区内的偏移
    	secremain=4096-secoff;//扇区剩余空间大小   
     	//printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用
     	if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
    	while(1) 
    	{	
    		W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容
    		for(i=0;i<secremain;i++)//校验数据
    		{
    			if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除  	  
    		}
    		if(i<secremain)//需要擦除
    		{
    			W25QXX_Erase_Sector(secpos);//擦除这个扇区
    			for(i=0;i<secremain;i++)	   //复制
    			{
    				W25QXX_BUF[i+secoff]=pBuffer[i];	  
    			}
    			W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区  
    
    		}else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间. 				   
    		if(NumByteToWrite==secremain)break;//写入结束了
    		else//写入未结束
    		{
    			secpos++;//扇区地址增1
    			secoff=0;//偏移位置为0 	 
    
    		   	pBuffer+=secremain;  //指针偏移
    			WriteAddr+=secremain;//写地址偏移	   
    		   	NumByteToWrite-=secremain;				//字节数递减
    			if(NumByteToWrite>4096)secremain=4096;	//下一个扇区还是写不完
    			else secremain=NumByteToWrite;			//下一个扇区可以写完了
    		}	 
    	};	 
    }
    //擦除整个芯片		  
    //等待时间超长...
    void W25QXX_Erase_Chip(void)   
    {                                   
        W25QXX_Write_Enable();                  //SET WEL 
        W25QXX_Wait_Busy();   
      	W25QXX_CS=0;                            //使能器件   
        SPI5_ReadWriteByte(W25X_ChipErase);        //发送片擦除命令  
    	W25QXX_CS=1;                            //取消片选     	      
    	W25QXX_Wait_Busy();   				   //等待芯片擦除结束
    }   
    //擦除一个扇区
    //Dst_Addr:扇区地址 根据实际容量设置
    //擦除一个扇区的最少时间:150ms
    void W25QXX_Erase_Sector(u32 Dst_Addr)   
    {  
    	//监视falsh擦除情况,测试用   
     	//printf("fe:%x\r\n",Dst_Addr);	  
     	Dst_Addr*=4096;
        W25QXX_Write_Enable();                  //SET WEL 	 
        W25QXX_Wait_Busy();   
      	W25QXX_CS=0;                            //使能器件   
        SPI5_ReadWriteByte(W25X_SectorErase);   //发送扇区擦除指令 
        if(W25QXX_TYPE==W25Q256)                //如果是W25Q256的话地址为4字节的,要发送最高8位
        {
            SPI5_ReadWriteByte((u8)((Dst_Addr)>>24)); 
        }
        SPI5_ReadWriteByte((u8)((Dst_Addr)>>16));  //发送24bit地址    
        SPI5_ReadWriteByte((u8)((Dst_Addr)>>8));   
        SPI5_ReadWriteByte((u8)Dst_Addr);  
    	W25QXX_CS=1;                            //取消片选     	      
        W25QXX_Wait_Busy();   				    //等待擦除完成
    }  
    //等待空闲
    void W25QXX_Wait_Busy(void)   
    {   
    	while((W25QXX_ReadSR(1)&0x01)==0x01);   // 等待BUSY位清空
    }  
    //进入掉电模式
    void W25QXX_PowerDown(void)   
    { 
      	W25QXX_CS=0;                            //使能器件   
        SPI5_ReadWriteByte(W25X_PowerDown);     //发送掉电命令  
    	W25QXX_CS=1;                            //取消片选     	      
        delay_us(3);                            //等待TPD  
    }   
    //唤醒
    void W25QXX_WAKEUP(void)   
    {  
      	W25QXX_CS=0;                                //使能器件   
        SPI5_ReadWriteByte(W25X_ReleasePowerDown);  //  send W25X_PowerDown command 0xAB    
    	W25QXX_CS=1;                                //取消片选     	      
        delay_us(3);                                //等待TRES1
    }   
    
    

    W25QXX_Write函数思路

    1. 每个扇区(sector)是4K,也就是4096个地址

    2. 在写任何一个地址之前,如果该地址的值不是0xFF,必须先擦除对应的扇区(sector),然后再写。

    3. 最大支持写操作的单元是page(页)一个扇区4K字节

    4. 根据要写的起始地址,确定要写的起始区域的扇区(Sector)号以及在起始扇区(Sector)中的偏移量。

    5. 根据要写的起始地址和字节数,确定要写的数据是否跨扇区(Sector)。

    6. 确定好要操作的扇区(Sector)以及扇区(Sector)的地址范围。

    7. 对每个扇区(Sector),先遍历要写的地址区域保存的数据是不是0xff,如果都是,就不用擦除。如果有不是0xff的区域,先读出里面的数据,保存在缓存W25QXX_BUFFER,然后擦除里面的内容。然后把这个sector要操作的数据,写到缓存。最后一次性吧缓存W25QXX_BUFFER的数据写到这个对应的扇区(Sector)。

    main.c

    //要写入到W25Q256的字符串数组
    const u8 TEXT_Buffer[]={"Apollo STM32F4 SPI TEST"};
    #define SIZE sizeof(TEXT_Buffer)	 
    	
    int main(void)
    {     
    	u8 key;
    	u16 i=0;
    	u8 datatemp[SIZE];
    	u32 FLASH_SIZE;
    	Stm32_Clock_Init(360,25,2,8);//设置时钟,180Mhz
    	delay_init(180);			//初始化延时函数 
    	uart_init(90,115200);		//初始化串口波特率为115200
    	usmart_dev.init(90);		//初始化USMART
     	LED_Init();					//初始化与LED连接的硬件接口
    	SDRAM_Init();				//初始化SDRAM 
    	LCD_Init();					//初始化LCD	
    	KEY_Init(); 				//按键初始化 
    	W25QXX_Init();				//W25QXX初始化
      	POINT_COLOR=RED;
    	LCD_ShowString(30,50,200,16,16,"Apollo STM32F4/F7"); 
    	LCD_ShowString(30,70,200,16,16,"SPI TEST");	
    	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
    	LCD_ShowString(30,110,200,16,16,"2021/01/24");	 		
    	LCD_ShowString(30,130,200,16,16,"KEY1:Write  KEY0:Read");	//显示提示信息		
    	while(W25QXX_ReadID()!=W25Q256)								//检测不到W25Q256
    	{
    		LCD_ShowString(30,150,200,16,16,"W25Q256 Check Failed!");
    		delay_ms(500);
    		LCD_ShowString(30,150,200,16,16,"Please Check!        ");
    		delay_ms(500);
    		LED0=!LED0;		//DS0闪烁
    	}
    	LCD_ShowString(30,150,200,16,16,"W25Q256 Ready!"); 
    	FLASH_SIZE=32*1024*1024;	//FLASH 大小为32M字节
      	POINT_COLOR=BLUE;			//设置字体为蓝色	  
    	while(1)
    	{
    		key=KEY_Scan(0);
    		if(key==KEY1_PRES)//KEY1按下,写入W25Q256
    		{
    			LCD_Fill(0,170,239,319,WHITE);//清除半屏    
     			LCD_ShowString(30,170,200,16,16,"Start Write W25Q256....");
    			W25QXX_Write((u8*)TEXT_Buffer,FLASH_SIZE-100,SIZE);		//从倒数第100个地址处开始,写入SIZE长度的数据
    			LCD_ShowString(30,170,200,16,16,"W25Q256 Write Finished!");	//提示传送完成
    		}
    		if(key==KEY0_PRES)//KEY0按下,读取字符串并显示
    		{
     			LCD_ShowString(30,170,200,16,16,"Start Read W25Q256.... ");
    			W25QXX_Read(datatemp,FLASH_SIZE-100,SIZE);					//从倒数第100个地址处开始,读出SIZE个字节
    			LCD_ShowString(30,170,200,16,16,"The Data Readed Is:   ");	//提示传送完成
    			LCD_ShowString(30,190,200,16,16,datatemp);					//显示读到的字符串
    		} 
    		i++;
    		delay_ms(10);
    		if(i==20)
    		{
    			LED0=!LED0;//提示系统正在运行	
    			i=0;
    		}		   
    	}	  
    }
    
    
    展开全文
  • w25qxx.zip

    2020-08-13 16:16:59
    W25Qxx驱动,在w25qxxConf.h中配置spi端口后看直接使用,记得main中初始化,详情可查看我的博客
  • 基于原子哥STM32H743-W25Q256例程修改的,STM32H750-W25Q40CL片外运行程序XIP
  • W25QXX_Template.zip

    2020-03-14 17:52:38
    适用于F767 核心板 QSPI W25QXX的烧写算法。根据所使用的W25QXX实际容量修改FlashDevice里的参数即可,编译后,把STM32F767_W25QXX.ELM拷贝到keil安装目录\ARM\Flash里。
  • W25Q系列芯片驱动,分离接口,需要自行实现SPI底层读写接口
  • W25QXX系列W25Q128 SPI_Flash存储模块驱动C源码: //初始化SPI FLASH void W25QXX_Init(void) { RCC->APB2ENR|=1; //PORTB时钟使能 GPIOB->CRH&=0XFFF0FFFF; GPIOB->CRH|=0X00030000; //PB12推挽输出 ...
  • W25Qxx - NOR Flash Libary for STM32 HALL
  • W25QXX驱动

    2020-08-17 11:09:31
    w25qxx多少多少M,指的是bit,需要除以8才是byte,由于容量小,可擦除一次要4k,不灵活,所以不再使用,此处记录使用过程及驱动 SPI设置 我比较喜欢支持多高就开多高,天下武功唯快不破,模式0,18M,Cube配置如下...

    下载

    设置的0积分,如果被系统修改可联系我发你

    csdn:https://download.csdn.net/download/shaynerain/12710107

    简介

    w25qxx多少多少M,指的是bit,需要除以8才是byte,由于容量小,可擦除一次要4k,不灵活,所以不再使用,此处记录使用过程及驱动

    SPI设置

    我比较喜欢支持多高就开多高,天下武功唯快不破,模式0,18M,Cube配置如下

    移植修改

    一共三个文件

    w25qxx.c:主要程序,读写擦,初始化

    w25qxx.h:头文件定义,数据类型定义

    w25qxxConf.h:配置文件,主要做修改,使用端口的片选引脚,如果SPI速度比较快建议CS引脚速度也提高,详细如下

    #define _W25QXX_SPI                   hspi2
    #define _W25QXX_CS_GPIO               GPIOB
    #define _W25QXX_CS_PIN                GPIO_PIN_4
    #define _W25QXX_USE_FREERTOS          0
    #define _W25QXX_DEBUG                 0

     

    展开全文
  • 1.使用时钟源为8Mhz有源晶振(根据自己实际情况修改主频和OCTOSPI时钟频率) 2.例子芯片为STM32H7B0VBT6,w25q128 3.内容亲测有效
  • W25QXX系列驱动,支持W25Q80,W25Q32,W25Q128,W25Q256,W25Q64,W25Q16,详细中文注释
  • W25QXX FLASH介绍

    千次阅读 2022-03-06 18:24:13
    W25QXX FLASH介绍 目录 W25QXX FLASH介绍 前言 1 W25QXX简介 2 硬件参数 3 寄存器介绍 4 编程相关 结束语 前言 FLASH在嵌入式开发是很常用的一种芯片。它是存储芯片的一种,通过特定的程序可以修改里面的数据。FLASH...
  • STM32H7驱动W25QXX

    2020-12-26 22:17:55
    首先读取W25Q64的ID,然后在程序中一直循环-(写数据,写完数据后用uart进行DMA传输给电脑,然后清楚数据) 工程建立 1.打开cubeMX,新建工程,选择芯片: 2.配置时钟源为外部时钟源 3.激活uart 4.配置uart的...
  • W25Qxx nor flash驱动学习

    2019-10-24 23:17:45
    如下所示是原子哥提供的w25qxx的驱动,作为学习参考非常实用,驱动比较通用,注释清晰,方便移植: #include "w25qxx.h" #include "spi.h" #include "delay.h" #include "usart.h" #include "stm32f4xx_hal_gpio.h...
  • 在使用52832的时候,有时候需要存储大量的数据,就需要外置存储芯片,这里我使用的存储是W25Qxx系列,并实现低功耗。 为了方便实现低功耗和代码移植的方便,这里我是用的是模拟SPI驱动W25Qxx.废话少说,上代码: ...
  • #ifndef W25QXX_CFG_H_ #define W25QXX_CFG_H_ ////////////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus extern "C" { #endif //////////////////////////...
  • 咚咚咚————【封装驱动】W25QXX全系列驱动程序,分享交流自己编写的程序。 /******************************************** 主控芯片:STM32 Controller 模块型号:W25QXX全系列芯片 通讯方式:SPI串口通信 作者...
  • 为什么要写以下内容是因为在板子上w25Q128是一个用户SPI接口的芯片: 粘贴出来下面将要出现的一些宏定义 这些数据在数据手册都可以查到 #define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,083
精华内容 433
关键字:

w25qxx

友情链接: 9.rar