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"
#define W25Q80 0XEF13
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q128 0XEF17
#define W25Q256 0XEF18
extern u16 W25QXX_TYPE;
#define W25QXX_CS PFout(6)
#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);
u8 W25QXX_ReadSR(u8 regno);
void W25QXX_4ByteAddr_Enable(void);
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);
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);
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;
void W25QXX_Init(void)
{
u8 temp;
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOF_CLK_ENABLE();
GPIO_Initure.Pin=GPIO_PIN_6;
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;
SPI5_Init();
SPI5_SetSpeed(SPI_BAUDRATEPRESCALER_2);
W25QXX_TYPE=W25QXX_ReadID();
if(W25QXX_TYPE==W25Q256)
{
temp=W25QXX_ReadSR(3);
if((temp&0X01)==0)
{
W25QXX_CS=0;
SPI5_ReadWriteByte(W25X_Enable4ByteAddr);
W25QXX_CS=1;
}
}
}
u8 W25QXX_ReadSR(u8 regno)
{
u8 byte=0,command=0;
switch(regno)
{
case 1:
command=W25X_ReadStatusReg1;
break;
case 2:
command=W25X_ReadStatusReg2;
break;
case 3:
command=W25X_ReadStatusReg3;
break;
default:
command=W25X_ReadStatusReg1;
break;
}
W25QXX_CS=0;
SPI5_ReadWriteByte(command);
byte=SPI5_ReadWriteByte(0Xff);
W25QXX_CS=1;
return byte;
}
void W25QXX_Write_SR(u8 regno,u8 sr)
{
u8 command=0;
switch(regno)
{
case 1:
command=W25X_WriteStatusReg1;
break;
case 2:
command=W25X_WriteStatusReg2;
break;
case 3:
command=W25X_WriteStatusReg3;
break;
default:
command=W25X_WriteStatusReg1;
break;
}
W25QXX_CS=0;
SPI5_ReadWriteByte(command);
SPI5_ReadWriteByte(sr);
W25QXX_CS=1;
}
void W25QXX_Write_Enable(void)
{
W25QXX_CS=0;
SPI5_ReadWriteByte(W25X_WriteEnable);
W25QXX_CS=1;
}
void W25QXX_Write_Disable(void)
{
W25QXX_CS=0;
SPI5_ReadWriteByte(W25X_WriteDisable);
W25QXX_CS=1;
}
u16 W25QXX_ReadID(void)
{
u16 Temp = 0;
W25QXX_CS=0;
SPI5_ReadWriteByte(0x90);
SPI5_ReadWriteByte(0x00);
SPI5_ReadWriteByte(0x00);
SPI5_ReadWriteByte(0x00);
Temp|=SPI5_ReadWriteByte(0xFF)<<8;
Temp|=SPI5_ReadWriteByte(0xFF);
W25QXX_CS=1;
return Temp;
}
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{
u16 i;
W25QXX_CS=0;
SPI5_ReadWriteByte(W25X_ReadData);
if(W25QXX_TYPE==W25Q256)
{
SPI5_ReadWriteByte((u8)((ReadAddr)>>24));
}
SPI5_ReadWriteByte((u8)((ReadAddr)>>16));
SPI5_ReadWriteByte((u8)((ReadAddr)>>8));
SPI5_ReadWriteByte((u8)ReadAddr);
for(i=0;i<NumByteToRead;i++)
{
pBuffer[i]=SPI5_ReadWriteByte(0XFF);
}
W25QXX_CS=1;
}
void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 i;
W25QXX_Write_Enable();
W25QXX_CS=0;
SPI5_ReadWriteByte(W25X_PageProgram);
if(W25QXX_TYPE==W25Q256)
{
SPI5_ReadWriteByte((u8)((WriteAddr)>>24));
}
SPI5_ReadWriteByte((u8)((WriteAddr)>>16));
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();
}
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 pageremain;
pageremain=256-WriteAddr%256;
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;
while(1)
{
W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
if(NumByteToWrite==pageremain)break;
else
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain;
if(NumByteToWrite>256)pageremain=256;
else pageremain=NumByteToWrite;
}
};
}
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;
if(NumByteToWrite<=secremain)secremain=NumByteToWrite;
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++;
secoff=0;
pBuffer+=secremain;
WriteAddr+=secremain;
NumByteToWrite-=secremain;
if(NumByteToWrite>4096)secremain=4096;
else secremain=NumByteToWrite;
}
};
}
void W25QXX_Erase_Chip(void)
{
W25QXX_Write_Enable();
W25QXX_Wait_Busy();
W25QXX_CS=0;
SPI5_ReadWriteByte(W25X_ChipErase);
W25QXX_CS=1;
W25QXX_Wait_Busy();
}
void W25QXX_Erase_Sector(u32 Dst_Addr)
{
Dst_Addr*=4096;
W25QXX_Write_Enable();
W25QXX_Wait_Busy();
W25QXX_CS=0;
SPI5_ReadWriteByte(W25X_SectorErase);
if(W25QXX_TYPE==W25Q256)
{
SPI5_ReadWriteByte((u8)((Dst_Addr)>>24));
}
SPI5_ReadWriteByte((u8)((Dst_Addr)>>16));
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);
}
void W25QXX_PowerDown(void)
{
W25QXX_CS=0;
SPI5_ReadWriteByte(W25X_PowerDown);
W25QXX_CS=1;
delay_us(3);
}
void W25QXX_WAKEUP(void)
{
W25QXX_CS=0;
SPI5_ReadWriteByte(W25X_ReleasePowerDown);
W25QXX_CS=1;
delay_us(3);
}
W25QXX_Write函数思路
-
每个扇区(sector)是4K,也就是4096个地址
-
在写任何一个地址之前,如果该地址的值不是0xFF,必须先擦除对应的扇区(sector),然后再写。
-
最大支持写操作的单元是page(页)一个扇区4K字节
-
根据要写的起始地址,确定要写的起始区域的扇区(Sector)号以及在起始扇区(Sector)中的偏移量。
-
根据要写的起始地址和字节数,确定要写的数据是否跨扇区(Sector)。
-
确定好要操作的扇区(Sector)以及扇区(Sector)的地址范围。
-
对每个扇区(Sector),先遍历要写的地址区域保存的数据是不是0xff,如果都是,就不用擦除。如果有不是0xff的区域,先读出里面的数据,保存在缓存W25QXX_BUFFER,然后擦除里面的内容。然后把这个sector要操作的数据,写到缓存。最后一次性吧缓存W25QXX_BUFFER的数据写到这个对应的扇区(Sector)。
main.c
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);
delay_init(180);
uart_init(90,115200);
usmart_dev.init(90);
LED_Init();
SDRAM_Init();
LCD_Init();
KEY_Init();
W25QXX_Init();
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)
{
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;
}
LCD_ShowString(30,150,200,16,16,"W25Q256 Ready!");
FLASH_SIZE=32*1024*1024;
POINT_COLOR=BLUE;
while(1)
{
key=KEY_Scan(0);
if(key==KEY1_PRES)
{
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);
LCD_ShowString(30,170,200,16,16,"W25Q256 Write Finished!");
}
if(key==KEY0_PRES)
{
LCD_ShowString(30,170,200,16,16,"Start Read W25Q256.... ");
W25QXX_Read(datatemp,FLASH_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;
}
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)