-
2021-05-03 11:38:45
头文件
#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 #define W25QXX_CS PAout(4) //指令表 #define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg 0x05 #define W25X_WriteStatusReg 0x01 #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 0x09 #define W25X_Enable_Rest 0x66 #define W25X_Rest_Device 0x99 #define W25X_Enter_4_Addres 0xb7 #define W25X_Read_4_Addres 0x13 #define W25X_Write_4_Addres 0x02 #define W25X_Exit_4_Addres 0xe9 void W25QXX_Init(void); u16 W25QXX_ReadID(void); //读取FLASH ID u8 W25QXX_Read_SR(void); //读取状态寄存器 void W25QXX_Write_SR(u8 sr); //写状态寄存器 void W25QXX_Write_Enable(void); //写使能 void W25QXX_Write_Disable(void); //写保护 void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u32 NumByteToWrite); void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u32 NumByteToRead); //读取flash void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u32 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); //唤醒 void W25XX_Reset_With_Soft(void);//软件复位W25qXX #endif
访问W25Q256的所有地址(32MB)需要使用4字节地址,使用3字节地址只能访问16MB的空间,根据需要开启
.c文件
#include "spi.h" #include "w25qxx.h" u16 W25QXX_TYPE=W25Q256; //默认是W25Q32 #define ENABLE_W25Q258 1//要使用W25Q256的32MB空间时,设置1,否则为0 //软件复位W25qXX void W25XX_Reset_With_Soft(void){ W25QXX_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_Enable_Rest); //发送允许复位命令 W25QXX_CS=1; //取消片选 W25QXX_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_Rest_Device); //发送允许复位命令 W25QXX_CS=1; //取消片选 } #if ENABLE_W25Q258 //进入4字节地址模式 void W25QXX_Enter_4Byte(){ W25QXX_CS=0; SPI1_ReadWriteByte(W25X_Enter_4_Addres); W25QXX_CS=1; } //退出4字节地址模式 void W25QXX_Exit_4Byte(){ W25QXX_CS=0; SPI1_ReadWriteByte(W25X_Exit_4_Addres); W25QXX_CS=1; } #endif void W25QXX_Init(void) { //管脚初始化 GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); W25QXX_CS=1; SPI1_Init(); SPI1_SetSpeed(SPI_BaudRatePrescaler_2); //进入4字节模式 #if ENABLE_W25Q258 W25QXX_Enter_4Byte(); #endif W25QXX_TYPE=W25QXX_ReadID(); } /******************************************************************************** //读取W25QXX的状态寄存器 //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 *******************************************************************************/ u8 W25QXX_ReadSR(void) { u8 byte=0; W25QXX_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令 byte=SPI1_ReadWriteByte(0Xff); //读取一个字节 W25QXX_CS=1; //取消片选 return byte; } /******************************************************************************** //写W25QXX状态寄存器 //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!! *******************************************************************************/ void W25QXX_Write_SR(u8 sr) { W25QXX_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_WriteStatusReg); //发送写取状态寄存器命令 SPI1_ReadWriteByte(sr); //写入一个字节 W25QXX_CS=1; //取消片选 } /******************************************************************************** //W25QXX写使能 //将WEL置位 *******************************************************************************/ void W25QXX_Write_Enable(void) { W25QXX_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_WriteEnable); //发送写使能 W25QXX_CS=1; //取消片选 } /******************************************************************************** //W25QXX写禁止 //将WEL清零 *******************************************************************************/ void W25QXX_Write_Disable(void) { W25QXX_CS=0; //使能器件 SPI1_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; SPI1_ReadWriteByte(0x90);//发送读取ID命令 SPI1_ReadWriteByte(0x00); SPI1_ReadWriteByte(0x00); SPI1_ReadWriteByte(0x00); Temp|=SPI1_ReadWriteByte(0xFF)<<8; Temp|=SPI1_ReadWriteByte(0xFF); W25QXX_CS=1; return Temp; } /******************************************************************************** //读取SPI FLASH //在指定地址开始读取指定长度的数据 //pBuffer:数据存储区 //ReadAddr:开始读取的地址(24bit)(W25Q256为(32bit)) //NumByteToRead:要读取的字节数(最大65535) *******************************************************************************/ void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u32 NumByteToRead) { u32 i; W25QXX_CS=0; //使能器件 // SPI1_ReadWriteByte(W25X_ReadData); #if ENABLE_W25Q258 SPI1_ReadWriteByte(W25X_ReadData); //发送4字节地址读取命令 SPI1_ReadWriteByte((u8)((ReadAddr)>>24)); //发送32bit地址 #else SPI1_ReadWriteByte(W25X_ReadData); //发送普通读指令 #endif SPI1_ReadWriteByte((u8)((ReadAddr)>>16)); //发送24bit地址 SPI1_ReadWriteByte((u8)((ReadAddr)>>8)); SPI1_ReadWriteByte((u8)ReadAddr); for(i=0;i<NumByteToRead;i++) { pBuffer[i]=SPI1_ReadWriteByte(0XFF); //循环读数 } W25QXX_CS=1; } /******************************************************************************** //SPI在一页(0~65535)内写入少于256个字节的数据 //在指定地址开始写入最大256字节的数据 //pBuffer:数据存储区 //WriteAddr:开始写入的地址(24bit)(W25Q256为(32bit)) //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!! *******************************************************************************/ void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u32 NumByteToWrite) { u32 i; W25QXX_Write_Enable(); //SET WEL W25QXX_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_PageProgram); //发送写页命令 #if ENABLE_W25Q258 //发送读取命令 SPI1_ReadWriteByte((u8)((WriteAddr)>>24)); //发送32bit地址 #endif SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址 SPI1_ReadWriteByte((u8)((WriteAddr)>>8)); SPI1_ReadWriteByte((u8)WriteAddr); for(i=0;i<NumByteToWrite;i++)SPI1_ReadWriteByte(pBuffer[i]);//循环写数 W25QXX_CS=1; //取消片选 W25QXX_Wait_Busy(); //等待写入结束 } /******************************************************************************** //无检验写SPI FLASH //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败! //具有自动换页功能 //在指定地址开始写入指定长度的数据,但是要确保地址不越界! //pBuffer:数据存储区 //WriteAddr:开始写入的地址(24bit)(W25Q256为(32bit)) //NumByteToWrite:要写入的字节数(最大65535) //CHECK OK *******************************************************************************/ void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u32 NumByteToWrite) { u32 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)(W25Q256为(32bit)) //NumByteToWrite:要写入的字节数(最大65535) *******************************************************************************/ u8 W25QXX_BUFFER[4096]; void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u32 NumByteToWrite) { u32 secpos; u32 secoff; u32 secremain; u32 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; //使能器件 SPI1_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; //使能器件 SPI1_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令 #if ENABLE_W25Q258 //发送读取命令 SPI1_ReadWriteByte((u8)((Dst_Addr)>>24)); #endif SPI1_ReadWriteByte((u8)((Dst_Addr)>>16)); //发送24bit地址 SPI1_ReadWriteByte((u8)((Dst_Addr)>>8)); SPI1_ReadWriteByte((u8)Dst_Addr); W25QXX_CS=1; //取消片选 W25QXX_Wait_Busy(); //等待擦除完成 } /******************************************************************************** //等待空闲 *******************************************************************************/ void W25QXX_Wait_Busy(void) { while((W25QXX_ReadSR()&0x01)==0x01); // 等待BUSY位清空 } /******************************************************************************** //进入掉电模式 *******************************************************************************/ void W25QXX_PowerDown(void) { u16 Time_i=0xffff; W25QXX_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_PowerDown); //发送掉电命令 W25QXX_CS=1; //取消片选 while(Time_i--); //等待TPD } /******************************************************************************** //唤醒 *******************************************************************************/ void W25QXX_WAKEUP(void) { u16 Time_i=0xffff; W25QXX_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB W25QXX_CS=1; //取消片选 while(Time_i--); //等待TRES1 }
对于4字节读取时,根据芯片手册,使用Read_Data(03h)也可以访问4字节地址,测试后也确实可以
当然 也可以使用专门的4地址读指令Read_Date_with_4_Byte_Address(13h)
这里我使用的是Read_Date_with_4_Byte_Address(13h)
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u32 NumByteToRead) { u32 i; W25QXX_CS=0; //使能器件 // SPI1_ReadWriteByte(W25X_ReadData); #if ENABLE_W25Q258 SPI1_ReadWriteByte(W25X_ReadData); //发送4字节地址读取命令 SPI1_ReadWriteByte((u8)((ReadAddr)>>24)); //发送32bit地址 #else SPI1_ReadWriteByte(W25X_ReadData); //发送普通读指令 #endif SPI1_ReadWriteByte((u8)((ReadAddr)>>16)); //发送24bit地址 SPI1_ReadWriteByte((u8)((ReadAddr)>>8)); SPI1_ReadWriteByte((u8)ReadAddr); for(i=0;i<NumByteToRead;i++) { pBuffer[i]=SPI1_ReadWriteByte(0XFF); //循环读数 } W25QXX_CS=1; }
更多相关内容 -
W25Q80, W25Q16, W25Q32数据手册
2020-07-02 00:08:051. W25Q80 (8M-bit)、W25Q16 (16M-bit)和W25Q32 (32M-bit)串行闪存为空间、引脚和电源有限的系统提供了存储解决方案。25Q系列提供的灵活性和性能远远超过普通的串行闪存设备。他们是理想的代码隐藏到RAM,执行代码... -
华邦 W25Q80 数据手册
2018-05-28 18:27:25华邦 W25Q80英文版数据手册,注意是英文版,是英文版! -
W25Q80NA.zip
2019-10-15 21:06:56W25Q80NA Verilog仿真模型用于QSPI/SPI外设的仿真和调试。 -
W25Q80_datasheet.pdf
2019-11-08 11:13:14W25Q80 SPI FLASH系列的文档,很详细哦 好用哦多看看哦 -
基于W25Q80BL的FPGA配置控制器的设计与验证.pdf
2021-07-13 12:48:04基于W25Q80BL的FPGA配置控制器的设计与验证.pdf -
Arduino SPI + SPI Flash芯片W25Q80BV
2021-04-19 17:02:52W25Q80BV是台湾华邦电子(Winbond)生产的8M-bit串行flash芯片。主要特性有: 工作电压:2.5 ~ 3.6 V 功耗:读写(active)时4mA,低功耗(power-down)时<1μA 容量:8M-bit/1M-byte,包含4096个页(每页大小...W25Q80BV是台湾华邦电子(Winbond)生产的8M-bit串行flash芯片。主要特性有:
- 工作电压:2.5 ~ 3.6 V
- 功耗:读写(active)时4mA,低功耗(power-down)时<1μA
- 容量:8M-bit/1M-byte,包含4096个页(每页大小256字节)
- 接口:Standard/Dual/Quad SPI,支持时钟频率最高104MHz
- 支持以4/32/64k-bytes为单位进行Sector/Block擦除
- 一次写入最多256字节
- 软件/硬件写保护功能
- 大于10万次擦除/编程寿命
- 大于20年的数据保存时间
- 封装:SOIC/USON/WSON/PDIP
管脚定义
与Arduino的连接
采用工作于3.3V的Pro Mini版本进行简单调试,接法如下。
其中HOLD脚须上拉接到3.3V,否则器件无法正常工作;WP脚可以浮空。W25Q80BV Pro Mini (3.3V/8MHz)
VCC <------> 3.3V
GND <------> GND
/CS <------> SS (D10)
DI <------> MOSI (D11)
DO <------> MISO (D12)
CLK <------> SCK (D13)
功能调试
-
与I2C不同,利用SPI库操作时,读和写都用同一个函数SPI.transfer()实现。
-
读取时,可以任意地址、任意长度进行读取。
-
与EEPROM不同,SPI Flash写入前,需要对写入的存储空间进行擦除(Erase)操作,否则写入不成功。芯片支持Chip Erase(整片擦除)、Block Erase(32K bytes/64K bytes块擦除)和Sector Erase(4K bytes扇区擦除)。
-
当写操作对应的地址空间到达page的边界,再继续写入时目的地址会自动roll over到本页的起始位置。
测试代码
1 /* 2 communication with W25Q80BV (1 MBYTE SPI FLASH) using Arduino Pro Mini 3.3V/8MHz 3 Reference: http://www.instructables.com/id/How-to-Design-with-Discrete-SPI-Flash-Memory/?ALLSTEPS 4 */ 5 6 // the SPI bus uses pins 10 (SS), 11 (MOSI), 12 (MISO), and 13 (SCK) 7 8 #include <SPI.h> 9 10 #define READ_JEDEC_ID 0x9F 11 #define READ_STATUS_1 0x05 12 #define READ_DATA 0x03 13 #define WRITE_ENABLE 0x06 14 #define PAGE_PROGRAM 0x02 15 #define CHIP_ERASE 0xC7 16 17 byte pageBuffer[256]; 18 char str[] = "An apple a day keeps the doctor away."; //short than 256 19 20 void setup() 21 { 22 SPI.begin(); 23 SPI.setDataMode(SPI_MODE0); 24 SPI.setBitOrder(MSBFIRST); 25 Serial.begin(9600); 26 27 ReadID(); 28 EraseChip(); 29 WritePage(0x1234, str, sizeof(str)); 30 } 31 32 void loop() 33 { 34 ReadPage(0x1234, pageBuffer, sizeof(str)); 35 36 for(int i = 0; i < sizeof(str); i++) 37 { 38 Serial.print(char(pageBuffer[i])); 39 } 40 Serial.println(); 41 42 delay(2000); 43 } 44 45 void CheckBusy() 46 { 47 digitalWrite(SS, HIGH); 48 digitalWrite(SS, LOW); 49 SPI.transfer(READ_STATUS_1); 50 while(SPI.transfer(0) & 0x01); 51 digitalWrite(SS, HIGH); 52 } 53 54 void ReadID() 55 { 56 digitalWrite(SS, HIGH); 57 digitalWrite(SS, LOW); 58 SPI.transfer(READ_JEDEC_ID); 59 byte manuID = SPI.transfer(0); 60 byte memoType = SPI.transfer(0); 61 byte capa = SPI.transfer(0); 62 digitalWrite(SS, HIGH); 63 64 Serial.print("Manufacturer ID: "); Serial.println(manuID, HEX); 65 Serial.print("Memory Type: "); Serial.println(memoType, HEX); 66 Serial.print("Capacity : "); Serial.println(capa, HEX); 67 68 CheckBusy(); 69 } 70 71 void ReadPage(word pageNumber, byte pageBuffer[], int length) 72 { 73 // pageNumber: 16-bit data 74 digitalWrite(SS, HIGH); 75 digitalWrite(SS, LOW); 76 SPI.transfer(READ_DATA); 77 SPI.transfer((pageNumber >> 8) & 0xFF); 78 SPI.transfer(pageNumber & 0xFF); 79 SPI.transfer(0); 80 for(int i = 0; i < length; i++) 81 { 82 pageBuffer[i] = SPI.transfer(0); 83 } 84 digitalWrite(SS, HIGH); 85 CheckBusy(); 86 } 87 88 void WritePage(word pageNumber, char pageBuffer[], int length) 89 { 90 digitalWrite(SS, HIGH); 91 digitalWrite(SS, LOW); 92 SPI.transfer(WRITE_ENABLE); 93 digitalWrite(SS, HIGH); 94 digitalWrite(SS, LOW); 95 SPI.transfer(PAGE_PROGRAM); 96 SPI.transfer((pageNumber >> 8) & 0xFF); 97 SPI.transfer(pageNumber & 0xFF); 98 SPI.transfer(0); 99 for(int i = 0; i < length; i++) 100 { 101 SPI.transfer(byte(pageBuffer[i])); 102 } 103 digitalWrite(SS, HIGH); 104 CheckBusy(); 105 } 106 107 void EraseChip() 108 { 109 digitalWrite(SS, HIGH); 110 digitalWrite(SS, LOW); 111 SPI.transfer(WRITE_ENABLE); 112 digitalWrite(SS, HIGH); 113 digitalWrite(SS, LOW); 114 SPI.transfer(CHIP_ERASE); 115 digitalWrite(SS, HIGH); 116 CheckBusy(); 117 }
View Code
读取芯片的ID信息,向W25Q80BV写入一段字符串,再将写入的信息反复读出:
参考资料
W25Q80BV datasheet - Winbond
Arduino - SPI
Designing with Discrete SPI Flash Memory - Instructables
Flash芯片硬件特性转载于:https://www.cnblogs.com/zlbg/p/4246721.html
-
STM32 QSPI驱动W25Q80FLASH不成功问题记录
2021-03-24 18:33:06最近使用STM32的QSPI驱动W25QXX系列Flash时遇到的一个现象:原子的例程,同样的程序驱动W25Q16JVSIQ没有任何问题,但是驱动W25Q80DVSIG的时候读不到芯片ID,读写数据也都不成功。 问题排查 于是网上搜索了很多相关的...问题描述
最近使用STM32的QSPI驱动W25QXX系列Flash时遇到的一个现象:原子的例程,同样的程序驱动W25Q16JVSIQ没有任何问题,但是驱动W25Q80DVSIG的时候读不到芯片ID,读写数据也都不成功。
问题排查
于是网上搜索了很多相关的问题,确定大概的方向:W25Q80DVSIG上状态寄存器2的QE位没有置1导致,而W25Q16JVSIQ出厂时默认QE位已经置1(也许后缀为Q的型号就是QE出厂置1的意思,未验证,但手册上有提及)
既然出厂时没有帮我们把QE位置1,那我们就自己将它置1就好了。步骤也不难,无非就是先把状态寄存器的写保护位WEL置1,关掉写保护,再把状态寄存器2读出来,读出来的值第2位 置1后再写回状态寄存器2就行了。但问题就在于,原子的例程里初始化FLASH的时候已经有将QE位 置1的代码了。。。
问题解决
经过调试以及研读芯片手册,发现问题所在。
以上几张图是原子例程参照W25Q32(或其他型号)手册写的指令表,这没什么问题,当我找到W25Q80DV芯片手册的指令表时,问题就突显出来了。
W25Q80DV的写入状态寄存器指令只有一条:“0x01”,而W25Q32JV(或其他大部分型号)不同状态寄存器的写入指令是不同的(01h/31h)。W25Q80DV是一条指令就把状态寄存器1和2一起写入:“01h S7-S0 S15-S8”,指令后的第一个字节是状态寄存器1的写入值,第二个字节是状态寄存器2的写入值。所以只要稍微修改一下程序就可以用了,修改如下:
以上就是这次QSPI驱动W25Q80不成功的问题记录以及解决方法,如果有疑问或者有不同见解的朋友欢迎评论区一起交流! -
W25Q80和GD25Q80
2018-09-29 15:45:22W25Q80: 8M-bit 1024KB 80MHz clock operation 共有16个Block,每个Block有16个扇区,每个扇区4KB,每一页256个字节 每个设备有64位唯一ID GD25Q80: 8M-bit 1024KB 120MHz 快速阅读 共有16个Block,...二者同为SPI-Flash,前者为华邦公司产品,后者是GD公司产品。
W25Q80:
- 8M-bit 1024KB
- 80MHz clock operation
- 共有16个Block,每个Block有16个扇区,每个扇区4KB,每一页256个字节
- 每个设备有64位唯一ID
GD25Q80:
- 8M-bit 1024KB
- 120MHz 快速阅读
- 共有16个Block,每个Block有16个扇区,每个扇区4KB,每一页256个字节
- 每个设备有128位唯一ID
引脚:(二者引脚完全兼容)
寄存器:
W25Q80 状态寄存器(S15~S0)
BUSY:FLASH正在擦除或者正在写入
TB:Top/Bottom写保护位,与BP[2:0]构成更多组合
SEC:扇区保护位,与BP[2:0]构成更多组合
SRP0:状态寄存器保护位
这5位决定写保护的范围
GD25Q80 状态寄存器(S15~S0)
SUS:只读位,该位在擦除、编程、暂停指令后置1 个人感觉这位没什么用
CMP:与BP[4:0]构成更多的组合 默认置0,与W25q80保持兼容
HPM:该位置1表示FLASH当前是高性能模式 一般不用
LB:OTP位,写1,安全寄存器变为永久只读 一般不用
这6位决定写保护范围,其实除了S14,剩下的和W25Q80寄存器是一样的,都是S2~S6共5位
那么S14是什么东西呢?上文讲了,S14即CMP,CMP=0或1 时 只是保护的范围不同罢了
比如当CMP=0,S6~S2= 00010 时 写保护区域为 0E0000H-0FFFFFH 128KB(与W25Q80一样)
当CMP=1时,S6~S2=00010时 写保护区域为 000000H-0DFFFFH 896KB
默认CMP=0,即与W25Q80保持兼容。
指令表:
以下指令二者是一样的,实际上GD32Q80多了很多指令,比如和安全寄存器相关的编程,擦除,读取三条指令,但是通常我们也只会用到以下指令。
#define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg 0x05 #define W25X_WriteStatusReg 0x01 #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
值得注意的是,二者厂商的ID和设备ID是不同的,原子例程有个死循环验证厂商和设备ID,如果用的是GD25系列的Flash需要改下相关宏定义。
华邦的厂商和设备ID(不是芯片唯一ID)一般是 0xEFXX,GD是0xC8XX(XX由不同容量决定)。
综上所述,二者可以互相替换。
-
华邦存储器W25Q80, W25Q16, W25Q32系列的spi通讯
2020-04-16 21:06:43华邦存储器W25Q80, W25Q16, W25Q32系列与stm32f1系列单片机的spi通讯 2020.4.9 spi通讯在配置好之后一定要开启spi使能,和串口的配置是一样的 2020.4.13 华邦存储器的spi通讯调试完成。 总结,在调试的过程中出现了... -
解读Datasheet系列:W25Q80DV(华邦 SPI Flash)
2018-06-13 17:12:37本文只对 W25Q80DV 数据手册的一部分进行解读,其涵盖的内容基本足够开发标准 SPI 接口的 Linux 驱动和裸板驱动。完整的 Datasheet 下载: https://download.csdn.net/download/luckydarcy/10443182 一般描述 ... -
Linux 驱动 SPI Flash(W25Q80DV)
2018-06-13 19:21:27W25Q80DV 是 Winbond 的一款 SPI Flash,容量大小为 8M bit。如果还没看 W25Q80DV 的数据手册,赶紧去看! https://blog.csdn.net/lu_embedded/article/details/80682374 本文描述的是在 i.MX6q 硬件平台上... -
w25q80dv 英文手册..
2022-03-21 11:43:36w25q80dv 手册 -
DS1302N DS2460 RS485 CH340G W25Q80B 原理图库封装库(AD集成库)39个合集.zip
2021-08-26 11:04:59DS1302N DS2460 RS232 RS485 CH340G W25Q80B ALTIUM原理图库封装库(AD集成库)39个合集,PcbLib+SchLib格式,Altium Designer原理图库+PCB封装库, Library Component Count : 39 Name Description ---------------... -
Flash_W25Q80数据手册.pdf
2021-11-05 17:16:39Flash_W25Q80数据手册 -
W25Q80源代码
2013-04-17 22:31:03通过产品测试,运行稳定数据手册W25Q80_IcpdfCom_207315.pdf -
W25Q80NE verilog Model
2018-01-17 15:59:06W25Q80NE verilog Model SPI Flash 仿真模型,verilog 仿真模型,SPI端口,支持多种读写操作操作 -
NRF52832与W25Q80通信
2019-03-30 21:15:00void W25Q80_FLASH_PageWrite(unsigned char* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) { W25Q80_WriteEnable(); //发送FLASH写使能命令 nrf_gpio_pin_clear(SPI_SS_PIN); //片选有效 W25Q80_... -
w25q128 verilog仿真模型
2019-04-23 16:22:11w25q128 官方verilog仿真模型,有助于开发QSPI外设IP,用于QSPI/SPI外设的仿真和调试。 -
[学习笔记]STM32F1软件SPI读写W25Qx源码(寄存器、标准库、HAL库)
2021-07-11 21:20:34[学习笔记]STM32F1软件SPI读写W25Qx源码(寄存器、标准库、HAL库) -
利用rt-thread系统spi设备驱动w25q
2021-10-22 15:26:25一、W25Q简介 W25Q64是华邦公司推出的大容量SPI FLASH产品,其容量为64Mb。该25Q系列的器件在灵活性和性能方面远远超过普通的串行闪存器件。W25Q64将8M字节的容量分为128个块,每个块大小为64K字节,每个块又分为16... -
LPCOpen-keil-lpc43xx:带有Keil的NXP LPC43xx的LPCOpen库
2021-05-23 00:49:07LPCOpen-keil-lpc43xx 适用于LPC43xx的NXP LPCOpen,将Keil移植到Micromint Bambino。 恩智浦LPCOpen平台提供了使用恩智浦微控制器及其外围设备的启动代码,设备驱动程序和代码示例。 通用API可以与所有NXP ARM ... -
W25Q16BV中文数据手册
2016-01-19 13:52:57最新的W25Q16BV闪存中文数据手册(W25Q16BV(16M位)串行闪存,该W25Q16BV阵列是由每256字节可编程8,192页.最多256个字节,2.7到3.6V电源) -
w25q64中文数据手册
2016-01-09 16:03:39W25Q80(8M-bit),W25Q16(16M-bit)和W25Q32(32M-bit)是为系统提供一个最小的空间、引脚和功耗的存储器解决方案的串行Flash存储器。25Q系列比普通的串行Flash存储器更灵活,性能更优越。基于双倍/四倍的SPI,它们能够... -
RT_threadのQSPI总线设备驱动W25Q
2022-03-19 21:23:58本文仅仅记录使用RTT的QSPI总线设备驱动W25Q -
【STM32】通过RTThread驱动W25QXXX
2022-04-11 11:09:34} else { /* 方式1:使用 rt_spi_send_then_recv()发送命令读取ID */ rt_spi_send_then_recv(spi_dev_w25q, &w25x_read_id, 1, id, 5);//先发送后接收数据id rt_kprintf("use rt_qspi_send_then_recv() read w25q ... -
STM32cubeide/STM32cubeMX USB链接W25QXX做U盘
2022-04-21 11:32:15STM32cubeide/STM32cubeMX USB链接W25QXX做U盘,使用HAL库 -
CC2640R2F BLE5.0 CC2640R2F SPI驱动实现
2017-08-07 09:58:45SPI驱动 这一节我们详细讲解TI CC13x0/CC26x0 SDK开发平台 基于TI-RTOS的SPI驱动实现,主要了解SPI驱动的分层实现、驱动接口,以及结合开发板板载SPIFlash调试通过驱动。 概述 ...SPI(Serial Perripheral ...