• STM32F103标准库开发---SPI实验---W25Qxx系列外部Flash芯片


    STM32F103标准库开发—SPI实验----基本原理
    STM32F103标准库开发—SPI实验----底层驱动程序


    一、W25Qxx系列芯片----简介

    W25Qxx 系列 Flash 存储器可以为用户提供存储解决方案。擦写周期多达10W次,可将数据保存达20年之久,支持2.7~3.6V的电压,支持标准的SPI,还支持双输出/四输出的SPI,最大SPI时钟可达80Mhz
    W25Qxx 系列 Flash 存储器是为系统提供一个最小空间、最少引脚,最低功耗的串行Flash存储器,比普通的串行Flash存储器更灵活,性能更优越。
    功耗低,正常工作状态下电流消耗0.5mA,掉电状态下电流消耗1uA。

    1. 存储结构

    W25Qxx 系列 Flash 存储器的存储结构
    相同点:

    • 1块 = 16扇区 = 64k字节,1扇区 = 16页 = 4k字节,1页 = 256字节。
    • 只有三种擦除方式:扇区擦除块擦除全片擦除
    • 写操作一次可以写1~256字节,最多一次写一页256字节。

    不同点: 容量和内存空间地址不同,具体如下表所示:

    芯片型号总容量总块数内存空间地址
    W25Q808M(bit)—1M(字节)160x000000~0x0FFFFF(24bit)
    W25Q1616M(bit)—2M(字节)320x000000~0x1FFFFF(24bit)
    W25Q3232M(bit)—4M(字节)640x000000~0x3FFFFF(24bit)
    W25Q6464M(bit)—8M(字节)1280x000000~0x7FFFFF(24bit)
    W25Q128128M(bit)—16M(字节)2560x000000~0xFFFFFF(24bit)
    W25Q256256M(bit)—32M(字节)5120x00000000~0x01FFFFFF(32bit)
    W25Q512512M(bit)—64M(字节)10240x00000000~0x03FFFFFF(32bit)

    2. 引脚接口

    下面只介绍标准SPI接口,接口如下图所示:
    在这里插入图片描述

    1. 片选引脚:/CS
      (1)当CS引脚为高电平时,芯片被禁能,DO引脚高阻态,不能进行读写操作。
      (2)当CS引脚为低电平时,芯片被使能,能进行读写操作。
         上电后,执行一条新指令之前必须使CS引脚先有一个下降沿。

    2. 数据输出引脚:DO(IO1)
      标准SPI模式: CLK上升沿捕获地址和命令,下降沿输出数据
      QSPI模式: 双向数据传输 IO1。

    3. 写保护引脚:/WP(IO2)
      标准SPI模式:
      写保护引脚可以被用来保护状态寄存器不被意外改写。
      (1)当WP引脚为高电平时,芯片写保护失能,可以正常写入数据
      (2)当WP引脚为低电平时,芯片写保护使能,不可以正常写入数据
      QSPI模式: 双向数据传输 IO2。

    4. 地:GND
      电源地

    5. 数据输入引脚:DI(IO0)
      标准SPI模式:
      数据、地址和命令从DI引脚送到芯片内部,在CLK引脚的上升沿捕获。
      QSPI模式: 双向数据传输 IO0。

    6. 串行时钟引脚:CLK
      SPI时钟引脚,为输入输出提供时序。

    7. 保持引脚:/HOLD(IO3)
      标准SPI模式:
      当CS引脚为低电平时
      (1)当HOLD为低电平时,DO引脚处于高阻态状态,而且也会忽略DIO和CLK引脚上的信号。
      (2)当HOLD为高电平时,芯片恢复正常工作。
      QSPI模式: 双向数据传输 IO3。

    8. 电源:VCC
      电源正极

    3. 原理图

    在这里插入图片描述

    4. 内部结构框架图

    请添加图片描述

    5. 型号ID

    W25Qxx 系列 Flash 存储器支持 JEDEC 标准,具有唯一的 64 位识别序列号,方便区别芯片型号,具体如下表所示:

    芯片型号芯片ID(64bit)
    W25Q800xEF13
    W25Q160xEF14
    W25Q320xEF15
    W25Q640xEF16
    W25Q1280xEF17
    W25Q2560xEF18
    W25Q5120xEF19

    二、W25Qxx系列芯片----工作原理

    1. SPI 运行方式

    W25Qxx系列芯片支持以下两种SPI通信方式:
    模式0: CPOL = 0,CPHA = 0
    模式3: CPOL = 1,CPHA = 1

    2. W25Qxx系列芯片----状态寄存器

    注:这里是记录所有W25Qxx系列芯片的状态寄存器,有些型号的状态寄存器,没有全部功能。

    状态寄存器1

    S7S6S5S4S3S2S1S0
    SRPSECTBBP2BP1BP0WELBUSY
    读/写读/写读/写读/写读/写读/写只读只读

    S0----总线忙标志位(BUSY)
    在执行页编程、扇区擦除、块区擦除、芯片擦除以及写状态寄存器指令时,该位被硬件自动置1。这时候,除了读状态寄存器指令外的所有操作指令都会被芯片忽略。
    当芯片执行完这些指令后,硬件会自动将该位清0,表示芯片器件可以接收其他的指令。

    S1----写保护位(WEL)
    执行完写使能指令后,该位置1
    芯片掉电后和执行写禁能、页编程、扇区擦除、块区擦除以及芯片擦除指令都会进入写保护状态该位置0

    S2、S3、S4----块区保护位(BP2、BP1、BP0)
    这3个位默认状态为0,即块区处于未保护状态。可以利用“写状态寄存器”指令对这几个位进行置1来达到块区保护的目的。块区保护状态为:没有保护、部分保护和全部保护状态。
    当状态寄存器的SRP位为1或读写保护管脚(/WP)为低电平时,这3个位不可被更改。

    S5----底部和顶部块保护位(TB)
    此位默认值为0,可以利用“写状态寄存器”指令对这个位进行置1或清零。
    当TB = 0时,表示保护位从顶部开始;
    当TB = 1时,表示保护位从底部开始。
    当状态寄存器的SRP位为1或读写保护管脚(/WP)为低电平时,这个位不可被更改。

    S6----扇区/块保护(SEC)
    此位默认值为0,可以利用“写状态寄存器”指令对这个位进行置1或清零。
    当SEC = 0时,表示每次保护的区域大小为4K;
    当SEC = 1时,表示每次保护的区域大小为64K。

    状态寄存器2

    S15S14S13S12S11S10S9S8
    SUSCMPLB3LB2LB1预留QESRL
    只读读/写读/写读/写读/写读/写读/写

    S7、S8----状态寄存器保护位(SRP、SRL)
    这两个位的默认值为0,可以利用“写状态寄存器”指令对这个位进行置1或清零。
    这两位和读写保护管脚(/WP)决定了状态寄存器写保护的方式。
    状态寄存器写保护的方式有:软件保护,硬件保护、电源锁定或一次性可编程(OTP)保护。

    S9----快速SPI通讯使能(QE)
    此位默认值为0,可以利用“写状态寄存器”指令对这个位进行置1或清零。
    当QE = 0时,设置为标准速度模式或快速模式,保持管脚(/HOLE)和读写保护管脚(/WP)启用;
    当QE = 1时,设置为高速模式,保持管脚(/HOLE)和读写保护管脚(/WP)被设置为IO2和IO3功能使用。

    S10、S11、S12、S13----安全寄存器锁位(LB3、LB2、LB1)
    LB3-1的默认状态为0,安全寄存器被解锁。
    可以使用写状态寄存器指令将LB3-1单独设置为1。
    LB3-1是一次性可编程(OTP),一旦它设置为1,相应的256字节安全寄存器将成为永久只读。

    S14----补码保护位(CMP)
    它与SEC、TB、BP2、BP1和BP0位结合使用,为阵列保护提供更大的灵活性。
    一旦CMP设置为1,之前SEC、TB、BP2、BP1和BP0设置的阵列保护将被逆转。例如:
    当CMP=0时,一个最高64KB的块可以被保护,而数组的其他部分则不受保护;
    当CMP=1时,最上面的64KB块将成为不受保护的,而数组的其余部分将成为只读的。
    默认设置为CMP=0。

    S15----暂停状态位(SUS)
    在执行**擦除/程序暂停(75h)指令后设置为1。
    通过
    擦除/程序恢复 (7Ah)**指令以及下电、上电周期将SUS状态位清除为0。

    状态寄存器3

    S23S22S21S20S19S18S17S16
    HOLD/RSTDRV1DRV0预留预留WPSADPADS
    读/写读/写读/写读/写读/写只读

    S16----当前地址模式(ADS)
    表示设备当前运行的地址模式。
    当ADS=0时,设备处于3字节地址模式,
    当ADS=1时,设备处于4字节地址模式。

    S17----启动时地址模式(ADP)
    决定设备上电或复位时的初始地址模式,该位仅在上电或设备复位初始化期间使用。
    当ADP=0(出厂默认)时,设备将启动到3字节地址模式,扩展地址寄存器必须用于访问超过128Mb的内存区域。当ADP=1时,设备将直接启动到4字节地址模式。

    S18----写保护方案(WPS)
    当WPS=0时,设备将使用CMP、SEC、TB、BP[2:0]位的组合来保护存储阵列的特定区域。
    当WPS=1时,设备将使用单独块锁来保护任何单独的扇区或块。
    设备上电或复位后,所有单个块锁定位的缺省值为1。

    S22、S21 ---- 输出信号强度(DRV1、DRV0)
    在这里插入图片描述

    S23----HOLD/RST引脚功能选择
    当HOLD/RST=0(出厂设置)时,引脚为/HOLD。
    当HOLD/RST=1时,引脚为/RESET。
    但是,只有当QE=0时,/HOLD或/RESET函数才可用。
    QE设置为1时,关闭/HOLD和/RESET功能,引脚为专用数据I/O引脚。

    3. W25Qxx系列芯片----常用操作命令

    (1)单字节操作

    单字节操作,只往芯片中写入1字节的操作命令,具体代码如下:

    void W25QXX_Write_Enable(void) //写使能 
    {
    	W25QXX_CS(0);				 //拉低片选CS引脚---使能芯片
    	W25QXX_ReadWriteByte(0x06);  //写入1字节操作命令
    	W25QXX_CS(1);				 //拉高片选CS引脚---关闭芯片	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    操作命令 如下表所示:

    指令名称指令数据(hex)功能
    Write Enable0x06写操作启用
    Volatile SR Write Enable0x50易失性状态寄存器的写启用
    Write Disable0x04写操作禁用
    Set Read Parameters0xC0设置读取参数
    Chip Erase0xC7/0x60擦除芯片
    Global Block/Sector Lock0x7E全局块/扇区上锁
    Global Block/Sector Unlock0x98全局块/扇区解锁
    Erase / Program Suspend0x75擦除/程序挂起
    Erase / Program Resume0x7A擦除/程序恢复
    Power-down0xB9断电
    Release Power-down0xAB解除断电
    Enter 4-Byte Address Mode0xB7输入4字节地址模式
    Exit 4-Byte Address Mode0xE9退出4字节地址模式
    Enter QPI Mode0x38开启QSPI模式
    Exit QPI Mode0xFF退出QSPI模式
    Enable Reset0x66使能复位
    Reset Device0x99复位

    注:如果想要实现其他功能,替换操作指令数据,便可实现功能。

    (2)双字节操作

    双字节操作,先往芯片中写入1字节的操作命令,接下来是读取/写入的字节数据。
    具体代码如下:

    //读取1字节数据
    uint8_t W25QXX_ReadSR(void)//读取状态寄存器
    {
    	uint8_t  data=0;
    	W25QXX_CS(0);            		 //拉低片选CS引脚---使能芯片
    	W25QXX_ReadWriteByte(0x05);  	 //写入1字节操作命令
    	data=W25QXX_ReadWriteByte(0Xff); //读取1字节数据
    	W25QXX_CS(1);                    //拉高片选CS引脚---取消片选
    	return data;
    }
    
    //写入1字节数据
    void W25QXX_WriteSR(uint8_t data)//写状态寄存器
    {
    	W25QXX_CS(0);            	//拉低片选CS引脚---使能芯片
    	W25QXX_ReadWriteByte(0x01); //写入1字节操作命令
    	W25QXX_ReadWriteByte(data); //写入1字节数据
    	W25QXX_CS(1);               //拉高片选CS引脚---取消片选
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    操作命令 如下表所示:

    指令名称指令数据(hex)写入/读取的数据(hex)功能
    Read Status Register-10x05(S7-S0)读状态寄存器1
    Write Status Register-10x01(S7-S0)写状态寄存器1
    Read Status Register-20x35(S15-S8)读状态寄存器2
    Write Status Register-20x31(S15-S8)写状态寄存器2
    Read Status Register-30x15(S23-S16)读状态寄存器3
    Write Status Register-30x11(S23-S16)写状态寄存器3
    Read Extended Addr. Reg0xC8(EA7-EA0)读扩展地址寄存器
    Write Extended Addr. Reg0xC5(EA7-EA0)写扩展地址寄存器

    注:如果想要实现其他功能,替换操作指令数据,便可实现功能。

    (3)读取ID操作

    具体代码如下:

    uint16_t W25QXX_ReadID(void)//读取芯片ID
    {
    	uint16_t ID = 0;	  
    	W25QXX_CS(0);				//拉低片选CS引脚---使能芯片    
    	W25QXX_ReadWriteByte(0x90);	//发送读取ID命令	    
    	W25QXX_ReadWriteByte(0x00); 	    
    	W25QXX_ReadWriteByte(0x00); 	    
    	W25QXX_ReadWriteByte(0x00); 	 			   
    	ID|=W25QXX_ReadWriteByte(0xFF)<<8;  
    	ID|=W25QXX_ReadWriteByte(0xFF);	 
    	W25QXX_CS(1);				 //拉高片选CS引脚---取消片选   
    	return ID;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    操作命令 如下表所示:

    指令名称指令数据(hex)字节1字节2字节3字节4字节5功能
    Device ID0xAB0x000x000x00(ID7-ID0)读取设备ID
    Manufacturer/Device ID0x900x000x000x00(MF7-MF0)(ID7-ID0)读取制造商+设备ID
    JEDEC ID0x9F(MF7-MF0)(ID15-ID8)(ID7-ID0)读取全部ID
    Read Unique ID0x4B0x000x000x000x00(UID63-0)读取唯一ID号

    注:如果想要实现其他功能,替换操作指令数据,便可实现功能。

    (4)带地址操作

    带地址操作主要分两种:
    3字节地址:W25Qxx系列芯片都可以使用。
    4字节地址:只有W25Q256和W25Q512可用。

    • 3字节地址
      具体代码如下:
    //读取数据
    void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   
    { 						    
    	W25QXX_CS(0);	                        //拉低片选CS引脚---使能芯片
        W25QXX_ReadWriteByte(0x03);    			//发送读取命令  
        W25QXX_ReadWriteByte((uint8_t)((ReadAddr)>>16));   //发送24bit地址    
        W25QXX_ReadWriteByte((uint8_t)((ReadAddr)>>8));   
        W25QXX_ReadWriteByte((uint8_t)ReadAddr);   
        for(uint16_t i=0;i<NumByteToRead;i++)//可读多个数据
    	{ 
           pBuffer[i]=W25QXX_ReadWriteByte(0XFF);    //循环读数  
        }
    	W25QXX_CS(1);				    	      
    }  
    
    //写入数据
    void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
    {
        W25QXX_Write_Enable();                  	//写使能
    	W25QXX_CS(0);                            	//使能器件   
        W25QXX_ReadWriteByte(0x02);   //发送页写命令   
        W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址    
        W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>8));   
        W25QXX_ReadWriteByte((uint8_t)WriteAddr);   
        for(uint16_t i=0;i<NumByteToWrite;i++)//可写多个数据,最多256个字节一页数据
    	{
    		W25QXX_ReadWriteByte(pBuffer[i]);//循环写数  
    	}
    	W25QXX_CS(1);                            	//取消片选 
    	W25QXX_Wait_Busy();					   		//等待写入结束
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    操作命令 如下表所示:

    指令名称指令数据(hex)地址1地址2地址3数据1数据2功能
    Read Data0x03A23-A16A15-A8A7-A0(D7-D0)(D7-D0)读取数据
    Fast Read0x0BA23-A16A15-A8A7-A00x00(D7-D0)快速读取数据
    Page Program0x02A23-A16A15-A8A7-A0(D7-D0)(D7-D0)页写数据
    Sector Erase (4KB)0x20A23-A16A15-A8A7-A0扇区擦除
    Block Erase (32KB)0x52A23-A16A15-A8A7-A0半块擦除
    Block Erase (64KB)0xD8A23-A16A15-A8A7-A0整块擦除
    Read SFDP Register0x5AA23-A16A15-A8A7-A00x00(D7-D0)
    Erase Security Register0x44A23-A16A15-A8A7-A0擦除安全寄存器
    Program Security Register0x42A23-A16A15-A8A7-A0(D7-D0)(D7-D0)编辑安全寄存器
    Read Security Register0x48A23-A16A15-A8A7-A00x00(D7-D0)读取安全寄存器
    Erase Security Register0x3DA23-A16A15-A8A7-A0(L7-L0)读块锁
    Individual Block Lock0x36A23-A16A15-A8A7-A0单块上锁
    Individual Block Unlock0x39A23-A16A15-A8A7-A0单块解锁
    • 4字节地址
      具体代码如下:
    //启用4字节地址模式	
    void W25QXX_Enter_4Byte()
    {
    	W25QXX_CS(0);				 //拉低片选CS引脚---使能芯片
    	W25QXX_ReadWriteByte(0xB7);  //写入1字节操作命令
    	W25QXX_CS(1);				 //拉高片选CS引脚---关闭芯片
    }
    
    //退出4字节地址模式	
    void W25QXX_Exit_4Byte()
    {
    	W25QXX_CS(0);				 //拉低片选CS引脚---使能芯片
    	W25QXX_ReadWriteByte(0xE9);  //写入1字节操作命令
    	W25QXX_CS(1);				 //拉高片选CS引脚---关闭芯片
    }
    
    //读取数据
    void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   
    { 						    
    	W25QXX_CS(0);	                        //拉低片选CS引脚---使能芯片
        W25QXX_ReadWriteByte(0x13);    			//发送4字节地址读取命令  
        W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>24));//发送32bit地址 
        W25QXX_ReadWriteByte((uint8_t)((ReadAddr)>>16));     
        W25QXX_ReadWriteByte((uint8_t)((ReadAddr)>>8));   
        W25QXX_ReadWriteByte((uint8_t)ReadAddr);   
        for(uint16_t i=0;i<NumByteToRead;i++)//可读多个数据
    	{ 
           pBuffer[i]=W25QXX_ReadWriteByte(0XFF);    //循环读数  
        }
    	W25QXX_CS(1);				    	      
    }  
    
    //写入数据
    void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
    {
        W25QXX_Write_Enable();                  //写使能
    	W25QXX_CS(0);                            //使能器件   
        W25QXX_ReadWriteByte(0x12);   			//发送4字节地址页写命令   
        W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>24));//发送32bit地址 
        W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>16));    
        W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>8));   
        W25QXX_ReadWriteByte((uint8_t)WriteAddr);   
        for(uint16_t i=0;i<NumByteToWrite;i++)//可写多个数据,最多256个字节一页数据
    	{
    		W25QXX_ReadWriteByte(pBuffer[i]);//循环写数  
    	}
    	W25QXX_CS(1);                            	//取消片选 
    	W25QXX_Wait_Busy();					   		//等待写入结束
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    注:如果想要实现4字节地址,需要启用4字节地址模式。

    操作命令 如下表所示:

    指令名称指令数据(hex)地址1地址2地址3地址4数据1数据2功能
    Read Data with 4-Byte Address0x13A31-A24A23-A16A15-A8A7-A0(D7-D0)(D7-D0)读取4字节地址数据
    Fast Read with 4-Byte Address0x0BA31-A24A23-A16A15-A8A7-A00x00(D7-D0)快读4字节地址数据
    Page Program with 4-Byte Address0x12A31-A24A23-A16A15-A8A7-A0(D7-D0)(D7-D0)页写4字节地址数据
    Sector Erase (4KB) with 4-Byte Address0x21A31-A24A23-A16A15-A8A7-A0扇区擦除4字节地址数据
    Block Erase (64KB) with 4-Byte Address0xDCA31-A24A23-A16A15-A8A7-A0整块擦除4字节地址数据

    STM32F103标准库开发—目录

  • 相关阅读:
    高效回顾深度学习DL、CV、NLP
    基于微信小程序的土地租赁的设计与实现
    go语言实现LeetCode59 螺旋矩阵Ⅱ
    为什么进行压力测试? 有哪些方法?
    <C++> 异常
    【工程应用六】 继续聊一聊高效率的模板匹配算法(分水岭助威+蒙版提速)。
    Python中prettytable库
    基于JavaSwing开发扫雷小游戏(不同版本) 课程设计 大作业
    Python爬虫实战系列4:天眼查公司工商信息采集
    错误的robots文件设置对SEO的影响
  • 原文地址:https://blog.csdn.net/MQ0522/article/details/126195451