这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【STM32F103ZET6】03:硬件SPI驱动W25Q128

共1条 1/1 1 跳转至

【STM32F103ZET6】03:硬件SPI驱动W25Q128

高工
2025-09-02 08:20:28     打赏

一:W25Q128芯片介绍:       W25Q128 是一款常见的串行 Flash 存储器芯片,由华邦(Winbond)公司生产。它的存储容量为 128Mbit(16MB),采用 SPI(串行外设接口)进行通信,常用于嵌入式系统中存储代码或数据

二:W25Q128操作注意事项:

W25Q128 的基本操作遵循 SPI 协议,一般流程是:片选拉低 → 发送命令字 → 发送地址(如需)→ 交换数据 → 片选拉高。

2.1:写使能(Write Enable, 06h):在执行任何编程或擦除操作前,必须先发送写使能指令。该指令会将状态寄存器中的写使能锁存(WEL)

2.2:页编程(Page Program, 02h):向指定地址写入数据。一次最多写入256字节(一页),且不能跨页写入。如果写入数据地址会跨页,超出页首地址部分会从当前页的开头覆写8。写入前必须确保目标区域已被擦除。

2.3:扇区擦除(Sector Erase, 20h):擦除指定4KB扇区。擦除操作会将所有位变为1。擦除前需写使能。

2.4:块擦除(Block Erase):提供32KB (52h) 和64KB (D8h) 块擦除选项。

2.5:芯片擦除(Chip Erase, C7h / 60h):擦除整个芯片。谨慎使用。

2.6:读数据(Read Data, 03h):从指定地址开始读取数据。读取操作没有页的限制8。

2.7:读状态寄存器(Read Status Register, 05h):主要用于检查 BUSY 位(S0)和 WEL 位(S1)。在编程、擦除或写状态寄存器期间,BUSY位会置1,此时芯片仅响应读状态寄存器和擦除暂停等少数指令。

读设备ID:如 Read JEDEC ID (9Fh) 可用于识别器件。

三:STM32cube MX软件配置如下所示:

03-1.png

这里需要配置一下 SPI的片选引脚,PB引脚,配置工作模式为开漏输出模式

  GPIO_InitStruct.Pin = SPI2_CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(SPI2_CS_GPIO_Port, &GPIO_InitStruct);

四:软件代码如下所示:

4.1 修改硬件底层驱动函数:

//SPI2 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
uint8_t SPI2_ReadWriteByte(uint8_t TxData)
{
    uint8_t Rxdata;
    HAL_SPI_TransmitReceive(&hspi2,&TxData,&Rxdata,1, HAL_MAX_DELAY);       
 	return Rxdata;          		    //返回收到的数据		
}

4.2 写入函数如下所示:

//写SPI FLASH  
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)						
//NumByteToWrite:要写入的字节数(最大65535)   
uint8_t W25QXX_BUFFER[4096];		 
void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
{ 
	uint32_t secpos;
	uint16_t secoff;
	uint16_t secremain;	   
 	uint16_t i;    
	uint8_t * 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;			//下一个扇区可以写完了
		}	 
	};	 
}

4.3 读取函数如下所示:

//读取SPI FLASH  
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   
{ 
 	  uint16_t i;   										    
	  FLASH_CS_LOW() ;                           //使能器件   
    SPI2_ReadWriteByte(W25X_ReadData);      //发送读取命令  
    if(W25QXX_TYPE==W25Q256)                //如果是W25Q256的话地址为4字节的,要发送最高8位
    {
       SPI2_ReadWriteByte((uint8_t)((ReadAddr)>>24));    
    }
    SPI2_ReadWriteByte((uint8_t)((ReadAddr)>>16));   //发送24bit地址    
    SPI2_ReadWriteByte((uint8_t)((ReadAddr)>>8));   
    SPI2_ReadWriteByte((uint8_t)ReadAddr);   
    for(i=0;i<NumByteToRead;i++)
	 { 
        pBuffer[i]=SPI2_ReadWriteByte(0XFF);    //循环读数  
    }
		FLASH_CS_HIGH();			    	      
}

4.4 测试代码如下所示:

uint8_t WriteBuffer[] ={"EEPW STM32F103 W25Q128 test !!"};
uint8_t ReadBuffer[256] ;

void Test_SPI_Funtion(void)
{

	W25QXX_Write(&WriteBuffer[0],0,sizeof(WriteBuffer));
  HAL_Delay(20);
  W25QXX_Read(&ReadBuffer[0],0,sizeof(WriteBuffer)) ;
  HAL_UART_Transmit(&huart1, &ReadBuffer[0], sizeof(WriteBuffer), 100); 
}

五:测试图片如下所示:

03-3.png

对于SPI调试的经验,大家可以参考下,我之前的帖子

【我踩过的那些坑】STM32的硬件通讯调试过程的“坑”-电子产品世界论坛

测试代码如下:

03_USB_SPI.zip




关键词: STM32F103ZET6     硬件SPI    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]