你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7的QSPI总线基础知识和HAL库API

[复制链接]
STMCU小助手 发布时间:2021-11-4 18:44
78.1 初学者重要提示
  QSPI接口,可以做1线,2线或者4线使用。
  注意,QSPI接口不分主从,QSPI仅用于主控。
  可以单独使用BANK1外接一个Flash,也可以单独使用BANK2外接一个Flash,不可以BANK1和BANK2同时独立使用。但可以两个BANK合起来做双BANK(也称双Flash,即dual flash)使用,即8线模式。
  STM32H7可用的单线,双线,四线和八线SPI QSPI OctaFlash等涵盖各大厂商
78.2 QSPI总线基础知识
78.2.1 QSPI总线的硬件框图
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解QSPI的基本功能,然后再看手册了解细节。

BANK1外接Flash

f04c8d70b5dfdaf87e9a1a4f54b38e55.png


BANK1和BANK2都外接Flash:

60f4042c5098f3ba9a7e40219c023175.png


通过这个框图,我们可以得到如下信息:

  quadspi_ker_ck时钟输入
内核时钟。

  quadspi_hclk时钟输入
为寄存器提供时钟。

  quadspi_it输出信号
QSPI全局中断。

  quadspi_ft_trg输出信号
MDMA的QSPI FIFO阀值触发信号

  quadspi_tc_trg输出信号
MDMA的QSPI传输完成触发信号

  CLK
为外接Flash提供的时钟。为外接的两块Flash同时提供时钟。

  BK1_IO0/SO
在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash1使用。

  BK1_IO1/SI
在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash1使用。

  BK1_IO2
在4线模式中作为双向IO,供Flash1使用。

  BK1_IO3
在4线模式中作为双向IO,供Flash1使用。

  BK12_IO0/SO
在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash2使用。

  BK2_IO1/SI
在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash2使用。

  BK2_IO2
在4线模式中作为双向IO,供Flash2使用。

  BK2_IO3
在4线模式中作为双向IO,供Flash2使用。

  BK1_nCS
片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash2。

  BK2_nCS
片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash1。

78.2.2 QSPI的时钟源
这个知识点在初学的时候容易忽视,所以我们这里整理下。

STM32H7主频在400MHz下,QSPI的最高时钟是200MHz,可以选择的时钟源如下:

60a21420cdf6bbfc171b77ef44ebcf28.png


12523b301f01c6108162699ca2ad5685.png



我们的程序中默认是采用的HCLK3作为QSPI时钟。

78.2.3 QSPI 命令序列
QSPI的命令序列主要包括以下几个阶段:指令阶段、地址阶段、交替字节阶段、空指令阶段和数据这五个阶段,任一阶段均可跳过,但至少要包含指令、地址、交替字节或数据阶段之一。

2cb087bbc794898408c6160acfd426e4.png


  指令阶段
在此阶段,将命令(8位指令)发送到Flash,允许发送任何值。用户可以简单地将所需的命令写在指令字段中。根据软件和硬件配置,可以1线,2线或者4线方式发送。在某些只发送地址的案例中,指令阶段可以跳过。

地址阶段
在此阶段,将地址发送到Flash,从指定的地址读取或写入数据。 地址阶段是完全可配置的,允许发送1、2、3或4个字节的地址。在间接模式和自动轮询模式下,用户可以简单地将所需的地址写入QUADSPI_AR寄存器。据软件和硬件配置,可以1线,2线或者4线方式方式发送。 在一些不需要地址的情况下,可以跳过地址阶段。

  交替字节阶段
QSPI接口支持的一个额外阶段,具有更大的灵活性。它是通常用于控制操作模式。交替字节阶段是完全可配置的,并允许发送一,二,三或四字节。

  空周期阶段
在高速时钟下运行时,此阶段可以确保有足够的“周转”时间从输出模式切换到输入模式。

  数据阶段
这个阶段实现数据的收发。

78.2.4 QSPI的1线,2线,4线,SDR和DDR模式
这里所说的线是指通信阶段使用的数据线个数。

213a38369fe04824fa8640f515beb2fc.png


1线(SingleSPI,虽然是一发一收,但属于1线方式)
发送用的数据线BK1_IO0/SO(BK2_IO0/SO),接收用的数据线BK1_IO1/SI(BK2_IO1/SI)

1线模式下,所有线处于的状态:

(1)  BK1_IO0 / SO(BK2_IO0 / SO)处于输出模式。

(2) BK1_IO1 / SI(BK2_IO1 / SI)处于输入模式(高阻抗)。

(3) BK1_IO2(BK2_IO2)处于输出模式并强制置0。

(4)  BK1_IO3(BK2_IO3)处于输出模式并强制置1。

7c6105bc6d18539b680aeeed7ec93aed.png


  2线(Dual-SPI)
同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1)做输入输出。

2线模式下,所有线处于的状态:

(1) BK1_IO0 (BK2_IO0 )和BK1_IO1(BK2_IO1)读取时处于输入(高阻)。其它情况下为输出。

(2) BK1_IO2(BK2_IO2)处于输出模式并强制置0。

(3) BK1_IO3(BK2_IO3)处于输出模式并强制置1



4线(Quad-SPI)
同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)做输入输出。

4线模式下,当读取数据时,所有线处于输入(高阻),其它情况作为输出。

9d022cbcfd5fb3f3950421c3312e505f.png


  SDR
在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号仅在 CLK的下降沿发生转变。

  DDR
在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号在CLK的上升沿和下降沿发生转变。

  双BANK(双Flash)
双闪存就是将QSPI的两个BANK分别接一个QSPI Flash,然后时钟公用,片选公用(也可以不公用),从而实现8线模式。

d28d743492529e4d88e9b64567fe52b4.png


78.2.5 QSPI间接模式,查询模式和内存映射
QSPI支持在以下三种模式下工作:

1、  间接模式:

这里所谓的间接模式是指寄存器方式访问外设,就跟我们操作串口外设一样。间接模式主要用于以下场合:

  用于读取,写入,擦除和配置QSPI Flash。
  如果不需要AHB总线访问 QSPI Flash(在内存映射模式用)。
  CPU或者DMA通过QSPI数据寄存器执行所有操作。


在间接模式下,所有操作均通过QSPI寄存器执行,含读取和写入操作都由软件管理。 QSPI接口类似于经典的SPI接口。传输的数据通过数据寄存器与FIFO。在在此模式下,可以从大容量的外部Flash读取数据或向外部Flash写入数据,可以支持到4GB容量。

如果进行擦除或编程操作,则必须使用间接模式,并且所有操作必须由软件处理。在这种情况下,建议使用状态轮询模式,然后轮询闪存内部的状态寄存器以了解何时编程或擦除操作完成。



2、  状态轮询模式

在以下情况下使用状态轮询模式:

  读取QSPI Flash状态寄存器。
  在操作结束时自动轮询状态寄存器。
可以自动轮询内存中的指定寄存器并减轻CPU负担,例如检查擦除操作何时完成。QSPI也支持定期查询QSPI Flash,并且可以屏蔽返回的数据位,将所选位与所需值进行比较,结果比较可以通过下面两种方式处理:

  AND与操作模式:如果所有选定位都匹配,则产生中断。
OR或操作模式:如果所选位之一匹配,则产生中断


发生匹配时,QSPI可以自动停止。



3、  内存映射模式

在以下情况下使用内存映射模式:

  用于阅读操作。
  像使用内部Flash一样使用外部QSPI Flash, 任何AHB总线主控都可以自主读取数据。
  用于从外部QSPI Flash执行代码。


QSPI接口能够管理多达256 MB的内存,在内存映射模式下地址范围是0x9000 0000到0x9FFF FFFF。

78.3 QSPI总线的HAL库用法
78.3.1 QSPI总线结构体QUADSPI_TypeDef
QSPI总线相关的寄存器是通过HAL库中的结构体QUADSPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:

  1. typedef struct
  2. {
  3.   __IO uint32_t CR;       /*!< QUADSPI Control register,                           Address offset: 0x00 */
  4.   __IO uint32_t DCR;      /*!< QUADSPI Device Configuration register,              Address offset: 0x04 */
  5.   __IO uint32_t SR;       /*!< QUADSPI Status register,                            Address offset: 0x08 */
  6.   __IO uint32_t FCR;      /*!< QUADSPI Flag Clear register,                        Address offset: 0x0C */
  7.   __IO uint32_t DLR;      /*!< QUADSPI Data Length register,                       Address offset: 0x10 */
  8.   __IO uint32_t CCR;      /*!< QUADSPI Communication Configuration register,       Address offset: 0x14 */
  9.   __IO uint32_t AR;       /*!< QUADSPI Address register,                           Address offset: 0x18 */
  10.   __IO uint32_t ABR;      /*!< QUADSPI Alternate Bytes register,                   Address offset: 0x1C */
  11.   __IO uint32_t DR;       /*!< QUADSPI Data register,                              Address offset: 0x20 */
  12.   __IO uint32_t PSMKR;    /*!< QUADSPI Polling Status Mask register,               Address offset: 0x24 */
  13.   __IO uint32_t PSMAR;    /*!< QUADSPI Polling Status Match register,              Address offset: 0x28 */
  14.   __IO uint32_t PIR;      /*!< QUADSPI Polling Interval register,                  Address offset: 0x2C */
  15.   __IO uint32_t LPTR;     /*!< QUADSPI Low Power Timeout register,                 Address offset: 0x30 */
  16. } QUADSPI_TypeDef;
复制代码

这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。

__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

下面我们看下QSPI的定义,在stm32h743xx.h文件。

  1. #define QSPI_BASE ((uint32_t)0x90000000) /*!< Base address of : QSPI memories  accessible over AXI */

  2. #define PERIPH_BASE           (0x40000000UL)
  3. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)

  4. #define QSPI_R_BASE           (D1_AHB1PERIPH_BASE + 0x5000)
  5. #define DLYB_QSPI_BASE        (D1_AHB1PERIPH_BASE + 0x6000)

  6. #define QUADSPI               ((QUADSPI_TypeDef *) QSPI_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52005000
  7. #define DLYB_QUADSPI          ((DLYB_TypeDef *) DLYB_QSPI_BASE)
复制代码

我们访问QSPI的CR寄存器可以采用这种形式:QUADSPI->CR= 0。

78.3.2 QSPI总线初始化结构体QSPI_InitTypeDef
下面是QSPI总线的初始化结构体:

  1. typedef struct
  2. {
  3.   uint32_t ClockPrescaler;     
  4.   uint32_t FifoThreshold;      
  5.   uint32_t SampleShifting;   
  6.   uint32_t FlashSize;         
  7.   uint32_t ChipSelectHighTime;
  8.   uint32_t ClockMode;         
  9.   uint32_t FlashID;           
  10.   uint32_t DualFlash;                                          
  11. }QSPI_InitTypeDef;
复制代码

下面将结构体成员逐一做个说明:

  ClockPrescaler
设置时钟分频,参数范围0到255。特别注意,这里是针对HCLK3作为QSPI时钟来说的。

  FifoThreshold
用于设置FIFO阀值,仅用于间接模式,参数范围1到32,单位字节。

  SampleShifting
QUADSPI在FLASH驱动信号后可以选择再过半个CLK周期后才对FLASH数据采样,这有利于推迟数据采样。支持的参数如下:

#define QSPI_SAMPLE_SHIFTING_NONE      ((uint32_t)0x00000000U)      
#define QSPI_SAMPLE_SHIFTING_HALFCYCLE ((uint32_t)QUADSPI_CR_SSHIFT)
  FlashSize
Flash大小是2^(FlashSize + 1),单位字节。

间接模式下,最大支持的Flash大小是4GB,内存映射模式,最大支持256MB。

  1. #define SPI_POLARITY_LOW       (0x00000000UL)
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码

  ChipSelectHighTime
命令之间的CS片选至少保持的高电平时钟周期ChipSelectHighTime+1。支持的参数如下:

  1. #define QSPI_CS_HIGH_TIME_1_CYCLE      ((uint32_t)0x00000000U)                             
  2. #define QSPI_CS_HIGH_TIME_2_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0)                     
  3. #define QSPI_CS_HIGH_TIME_3_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_1)                     
  4. #define QSPI_CS_HIGH_TIME_4_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0 | QUADSPI_DCR_CSHT_1)
  5. #define QSPI_CS_HIGH_TIME_5_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2)                     
  6. #define QSPI_CS_HIGH_TIME_6_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_0)
  7. #define QSPI_CS_HIGH_TIME_7_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_1)
  8. #define QSPI_CS_HIGH_TIME_8_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT)   
复制代码
               
  FlashID
用于选择要操作的BANK,即用BANK1还是BANK2操作Flash。

  1. #define QSPI_FLASH_ID_1                ((uint32_t)0x00000000)      
  2. #define QSPI_FLASH_ID_2                ((uint32_t)QUADSPI_CR_FSEL)
复制代码

  DualFlash
用于选择是否使用双BANK。

  1. #define QSPI_DUALFLASH_ENABLE          ((uint32_t)QUADSPI_CR_DFM) /*!<Dual-flash mode enabled*/
  2. #define QSPI_DUALFLASH_DISABLE         ((uint32_t)0x00000000)     /*!<Dual-flash mode disabled*/
复制代码

78.3.3 QSPI总线句柄结构体QSPI_HandleTypeDef
下面是QSPI总线的初始化结构体:

  1. typedef struct
  2. {
  3.   QUADSPI_TypeDef            *Instance;        /* QSPI registers base address        */
  4.   QSPI_InitTypeDef           Init;             /* QSPI communication parameters      */
  5.   uint8_t                    *pTxBuffPtr;      /* Pointer to QSPI Tx transfer Buffer */
  6.   __IO uint32_t              TxXferSize;       /* QSPI Tx Transfer size              */
  7.   __IO uint32_t              TxXferCount;      /* QSPI Tx Transfer Counter           */
  8.   uint8_t                    *pRxBuffPtr;      /* Pointer to QSPI Rx transfer Buffer */
  9.   __IO uint32_t              RxXferSize;       /* QSPI Rx Transfer size              */
  10.   __IO uint32_t              RxXferCount;      /* QSPI Rx Transfer Counter           */
  11.   MDMA_HandleTypeDef         *hmdma;           /* QSPI Rx/Tx MDMA Handle parameters  */
  12.   __IO HAL_LockTypeDef       Lock;             /* Locking object                     */
  13.   __IO HAL_QSPI_StateTypeDef State;            /* QSPI communication state           */
  14.   __IO uint32_t              ErrorCode;        /* QSPI Error code                    */
  15.   uint32_t                   Timeout;          /* Timeout for the QSPI memory access */
  16. }QSPI_HandleTypeDef;
复制代码

下面将结构体成员做个说明:

  QUADSPI_TypeDef   *Instance
这个参数是寄存器的例化,方便操作寄存器,比如使能QUADSPI。

SET_BIT(QUADSPI ->CR,  QUADSPI_CR_EN)。

  QSPI_InitTypeDef  Init
这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。

  MDMA_HandleTypeDef          *hmdma
用于QSPI句柄关联MDMA句柄,方便操作调用。

  其它参数
其它参数基本都是在函数内部调用,用户基本不用管。

78.3.4 QSPI命令结构体QSPI_CommandTypeDef
下面是QSPI总线的命名结构体:

  1. typedef struct
  2. {
  3.   uint32_t Instruction;        
  4.   uint32_t Address;           
  5.   uint32_t AlternateBytes;     
  6.   uint32_t AddressSize;      
  7.   uint32_t AlternateBytesSize;
  8.   uint32_t DummyCycles;      
  9.   uint32_t InstructionMode;  
  10.   uint32_t AddressMode;      
  11.   uint32_t AlternateByteMode;
  12.   uint32_t DataMode;         
  13.   uint32_t NbData;         
  14.   uint32_t DdrMode;           
  15.   uint32_t DdrHoldHalfCycle;  
  16.   uint32_t SIOOMode;         
  17. }QSPI_CommandTypeDef;
复制代码

下面将结构体成员逐一做个说明:

  Instruction
设置要发送的指令,参数范围0x00到0xFF。

  Address
设置要发送的地址,地址由是1个字节到4个字节来表示,参数范围0x0 到 0xFFFFFFFF。

  AddressSize
地址大小,即表示此地址需要的字节数,支持的参数如下:

  1. #define QSPI_ADDRESS_8_BITS            ((uint32_t)0x00000000)           /*!<8-bit address*/
  2. #define QSPI_ADDRESS_16_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_0) /*!<16-bit address*/
  3. #define QSPI_ADDRESS_24_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_1) /*!<24-bit address*/
  4. #define QSPI_ADDRESS_32_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE)   /*!<32-bit address*/
复制代码

  AlternateBytesSize
交替字节大小,支持的参数如下:

  1. #define QSPI_ALTERNATE_BYTES_8_BITS    ((uint32_t)0x00000000)           /*!<8-bit alternate bytes*/
  2. #define QSPI_ALTERNATE_BYTES_16_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_0) /*!<16-bit alternate bytes*/
  3. #define QSPI_ALTERNATE_BYTES_24_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_1) /*!<24-bit alternate bytes*/
  4. #define QSPI_ALTERNATE_BYTES_32_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE)   /*!<32-bit alternate bytes*/
复制代码

  DummyCycles
执行空周期个数,参数范围0到31:

  InstructionMode
指令阶段需要几线模式:

  1. #define QSPI_INSTRUCTION_NONE          ((uint32_t)0x00000000)          /*!<No instruction*/
  2. #define QSPI_INSTRUCTION_1_LINE        ((uint32_t)QUADSPI_CCR_IMODE_0) /*!<Instruction on a single line*/
  3. #define QSPI_INSTRUCTION_2_LINES       ((uint32_t)QUADSPI_CCR_IMODE_1) /*!<Instruction on two lines*/
  4. #define QSPI_INSTRUCTION_4_LINES       ((uint32_t)QUADSPI_CCR_IMODE)   /*!<Instruction on four lines*/
复制代码

  AddressMode
地址阶段需要几线模式:

  1. #define QSPI_ADDRESS_NONE              ((uint32_t)0x00000000)           /*!<No address*/
  2. #define QSPI_ADDRESS_1_LINE            ((uint32_t)QUADSPI_CCR_ADMODE_0) /*!<Address on a single line*/
  3. #define QSPI_ADDRESS_2_LINES           ((uint32_t)QUADSPI_CCR_ADMODE_1) /*!<Address on two lines*/
  4. #define QSPI_ADDRESS_4_LINES           ((uint32_t)QUADSPI_CCR_ADMODE)   /*!<Address on four lines*/
复制代码

  AlternateByteMode
交替字节阶段需要几线模式:

  1. #define QSPI_ALTERNATE_BYTES_NONE      ((uint32_t)0x00000000)           /*!<No alternate bytes*/
  2. #define QSPI_ALTERNATE_BYTES_1_LINE    ((uint32_t)QUADSPI_CCR_ABMODE_0) /*!<Alternate bytes on a single line*/
  3. #define QSPI_ALTERNATE_BYTES_2_LINES   ((uint32_t)QUADSPI_CCR_ABMODE_1) /*!<Alternate bytes on two lines*/
  4. #define QSPI_ALTERNATE_BYTES_4_LINES   ((uint32_t)QUADSPI_CCR_ABMODE)   /*!<Alternate bytes on four lines*/
复制代码

  DataMode
数据阶段需要几线模式:

  1. #define QSPI_DATA_NONE                 ((uint32_t)0X00000000)           /*!<No data*/
  2. #define QSPI_DATA_1_LINE               ((uint32_t)QUADSPI_CCR_DMODE_0) /*!<Data on a single line*/
  3. #define QSPI_DATA_2_LINES              ((uint32_t)QUADSPI_CCR_DMODE_1) /*!<Data on two lines*/
  4. #define QSPI_DATA_4_LINES              ((uint32_t)QUADSPI_CCR_DMODE)   /*!<Data on four lines*/
复制代码

  NbData
要传输的数据大小,参数范围0 到 0xFFFFFFFF,如果设置为0表示不定长,直到存储器末尾。

  DdrMode
用于设置是否使能DDR模式。数据阶段,交替字节阶段和数据传输阶段可以使用DDR模式。支持的参数如下:

  1. #define QSPI_DDR_MODE_DISABLE          ((uint32_t)0x00000000)       /*!<Double data rate mode disabled*/
  2. #define QSPI_DDR_MODE_ENABLE           ((uint32_t)QUADSPI_CCR_DDRM) /*!<Double data rate mode enabled*/
复制代码

  DdrHoldHalfCycle
DDR模式下,用于设置延迟半个时钟周期再做数据输出。

  1. #define QSPI_DDR_HHC_ANALOG_DELAY      ((uint32_t)0x00000000)      
  2. #define QSPI_DDR_HHC_HALF_CLK_DELAY    ((uint32_t)QUADSPI_CCR_DHHC)
复制代码

  SIOOMode
设置仅发送一次指令还是每次操作都发送指令,支持的参数如下:

  1. #define QSPI_SIOO_INST_EVERY_CMD       ((uint32_t)0x00000000)     
  2. #define QSPI_SIOO_INST_ONLY_FIRST_CMD  ((uint32_t)QUADSPI_CCR_SIOO)
复制代码

78.3.5 QSPI自动查询结构体QSPI_AutoPollingTypeDef
下面是QSPI总线自动查询结构体:

  1. typedef struct
  2. {
  3.   uint32_t Match;            
  4.   uint32_t Mask;            
  5.   uint32_t Interval;         
  6.   uint32_t StatusBytesSize;   
  7.   uint32_t MatchMode;      
  8.   uint32_t AutomaticStop;     
  9. }QSPI_AutoPollingTypeDef;
复制代码

下面将结构体成员逐一做个说明:

  Match
参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器的值与此参数成员值做匹配。参数范围0x0 到 0xFFFFFFFF。

  Mask
用于设置屏蔽位,比如Mask = 0x01,表示仅保留bit0的数值,其它bit忽略。参数范围0x0 到 0xFFFFFFFF。

  Interval
指定自动轮询阶段两次读取之间的时钟周期数。参数范围0 到 0xFFFF。

  StatusBytesSize
用于设置状态寄存器大小,参数范围1到4个字节。

  MatchMode
参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器完全与参数成员Match一样(与操作的含义)或者任意一个bit的值与参数成员Match中一个bit的值一样(或操作的含义),比如Mask = 0x01,Match=0x00,MatchMode=与操作,表示不断查询状态寄存器bit0,等待其为0。

MatchMode支持的参数成员如下:

  1. #define QSPI_MATCH_MODE_AND            ((uint32_t)0x00000000)     /*!<AND match mode between unmasked bits*/
  2. #define QSPI_MATCH_MODE_OR             ((uint32_t)QUADSPI_CR_PMM) /*!<OR match mode between unmasked bits*/
复制代码

  AutomaticStop
当与参数成员Match匹配时,自动停止检测。

78.3.6 QSPI内存映射结构体QSPI_MemoryMappedTypeDef
下面是QSPI总线的内存映射结构体:

  1. typedef struct
  2. {
  3.   uint32_t TimeOutPeriod;   
  4.   uint32_t TimeOutActivation;  
  5. }QSPI_MemoryMappedTypeDef;  
复制代码

下面将结构体成员逐一做个说明:

  TimeOutPeriod
FIFO满时,释放芯片选择之前要等待的时钟周期数。参数范围0到0xFFFF。

  TimeOutActivation
指定是否启用超时计数器以释放芯片选择,支持的参数成员如下:

  1. #define QSPI_TIMEOUT_COUNTER_DISABLE   ((uint32_t)0x00000000)     
  2. #define QSPI_TIMEOUT_COUNTER_ENABLE    ((uint32_t)QUADSPI_CR_TCEN)
复制代码

78.4 QSPI总线源文件stm32h7xx_hal_qspi.c
此文件涉及到的函数较多,这里把几个常用的函数做个说明:

  HAL_QSPI_Init
  HAL_QSPI_DeInit
  HAL_QSPI_Command
  HAL_QSPI_Command_IT
  HAL_QSPI_AutoPolling
  HAL_QSPI_AutoPolling_IT
  HAL_QSPI_Transmit
  HAL_QSPI_Receive
  HAL_QSPI_Transmit_DMA
  HAL_QSPI_Receive_DMA
  HAL_QSPI_MemoryMapped
78.4.1 函数HAL_QSPI_Init
函数原型:

  1. HAL_StatusTypeDef HAL_QSPI_Init(QSPI_HandleTypeDef *hqspi)
  2. {
  3.   HAL_StatusTypeDef status;
  4.   uint32_t tickstart = HAL_GetTick();

  5.   /* 检测句柄是否有效 */
  6.   if(hqspi == NULL)
  7.   {
  8.     return HAL_ERROR;
  9.   }

  10.   /* 检查参数是否有效 */
  11.   assert_param(IS_QSPI_ALL_INSTANCE(hqspi->Instance));
  12.   assert_param(IS_QSPI_CLOCK_PRESCALER(hqspi->Init.ClockPrescaler));
  13.   assert_param(IS_QSPI_FIFO_THRESHOLD(hqspi->Init.FifoThreshold));
  14.   assert_param(IS_QSPI_SSHIFT(hqspi->Init.SampleShifting));
  15.   assert_param(IS_QSPI_FLASH_SIZE(hqspi->Init.FlashSize));
  16.   assert_param(IS_QSPI_CS_HIGH_TIME(hqspi->Init.ChipSelectHighTime));
  17.   assert_param(IS_QSPI_CLOCK_MODE(hqspi->Init.ClockMode));
  18.   assert_param(IS_QSPI_DUAL_FLASH_MODE(hqspi->Init.DualFlash));

  19.   if (hqspi->Init.DualFlash != QSPI_DUALFLASH_ENABLE )
  20.   {
  21.     assert_param(IS_QSPI_FLASH_ID(hqspi->Init.FlashID));
  22.   }

  23.   if(hqspi->State == HAL_QSPI_STATE_RESET)
  24.   {

  25. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1)
  26.     /* 复位状态,设置默认的回调 */
  27.     hqspi->ErrorCallback         = HAL_QSPI_ErrorCallback;
  28.     hqspi->AbortCpltCallback     = HAL_QSPI_AbortCpltCallback;
  29.     hqspi->FifoThresholdCallback = HAL_QSPI_FifoThresholdCallback;
  30.     hqspi->CmdCpltCallback       = HAL_QSPI_CmdCpltCallback;
  31.     hqspi->RxCpltCallback        = HAL_QSPI_RxCpltCallback;
  32.     hqspi->TxCpltCallback        = HAL_QSPI_TxCpltCallback;
  33.     hqspi->StatusMatchCallback   = HAL_QSPI_StatusMatchCallback;
  34.     hqspi->TimeOutCallback       = HAL_QSPI_TimeOutCallback;

  35.     if(hqspi->MspInitCallback == NULL)
  36.     {
  37.       hqspi->MspInitCallback = HAL_QSPI_MspInit;
  38.     }

  39.     /* 初始化底层硬件 */
  40.     hqspi->MspInitCallback(hqspi);
  41. #else
  42.     /* 初始化: GPIO, CLOCK */
  43.     HAL_QSPI_MspInit(hqspi);
  44. #endif

  45.     /* 配置QSPI内存访问默认的溢出时间 */
  46.     HAL_QSPI_SetTimeout(hqspi, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
  47.   }

  48.   /* 配置QSPI FIFO阀值 */
  49.   MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_FTHRES,
  50.              ((hqspi->Init.FifoThreshold - 1U) << QUADSPI_CR_FTHRES_Pos));

  51.   /* 等BUSY标志复位 */
  52.   status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);

  53.   if(status == HAL_OK)
  54.   {
  55.     /* 配置QSPI时钟分频和采样延迟 */
  56. MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PRESCALER | QUADSPI_CR_SSHIFT | QUADSPI_CR_FSEL |
  57. QUADSPI_CR_DFM),
  58.                ((hqspi->Init.ClockPrescaler << QUADSPI_CR_PRESCALER_Pos) |
  59.                 hqspi->Init.SampleShifting  | hqspi->Init.FlashID | hqspi->Init.DualFlash));

  60.     /* 配置QSPI Flash大小,CS片选高电平时间和时钟模式 */
  61.     MODIFY_REG(hqspi->Instance->DCR, (QUADSPI_DCR_FSIZE | QUADSPI_DCR_CSHT | QUADSPI_DCR_CKMODE),
  62.                ((hqspi->Init.FlashSize << QUADSPI_DCR_FSIZE_Pos) |
  63.                 hqspi->Init.ChipSelectHighTime | hqspi->Init.ClockMode));

  64.     /* 时钟QSPI外设 */
  65.     __HAL_QSPI_ENABLE(hqspi);

  66.     /* 设置QSPI无错误代码 */
  67.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;

  68.     /* 初始化QSPI状态就绪 */
  69.     hqspi->State = HAL_QSPI_STATE_READY;
  70.   }

  71.   /* 返回状态信息 */
  72.   return status;
  73. }
复制代码

函数描述:

此函数用于初始化QSPI。

函数参数:

  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,详见本章3.3小节。
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
注意事项:

函数HAL_QSPI_MspInit用于初始化QSPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
如果形参hqspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量QSPI_HandleTypeDef SpiHandle。
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_QSPI_STATE_RESET  = 0x00U。

解决办法有三

方法1:用户自己初始化QSPI和涉及到的GPIO等。

方法2:定义QSPI_HandleTypeDef QspiHandle为全局变量。

方法3:下面的方法

  1. if(HAL_QSPI_DeInit(&QspiHandle) != HAL_OK)
  2. {
  3.     Error_Handler();
  4. }  
  5. if(HAL_QSPI_Init(&QspiHandle) != HAL_OK)
  6. {
  7.     Error_Handler();
  8. }
复制代码

使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_InitQSPI_W25Q256
  4. *    功能说明: QSPI Flash硬件初始化,配置基本参数
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_InitQSPI_W25Q256(void)
  10. {
  11.     /* 复位QSPI */
  12.     QSPIHandle.Instance = QUADSPI;
  13.     if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)
  14.     {
  15.         Error_Handler(__FILE__, __LINE__);
  16.     }

  17.     /* 设置时钟速度,QSPI clock = 200MHz / (ClockPrescaler+1) = 100MHz */
  18.     QSPIHandle.Init.ClockPrescaler  = 1;  

  19.     /* 设置FIFO阀值,范围1 - 32 */
  20.     QSPIHandle.Init.FifoThreshold   = 32;

  21.     /*
  22.         QUADSPI在FLASH驱动信号后过半个CLK周期才对FLASH驱动的数据采样。
  23.         在外部信号延迟时,这有利于推迟数据采样。
  24.     */
  25.     QSPIHandle.Init.SampleShifting  = QSPI_SAMPLE_SHIFTING_HALFCYCLE;

  26.     /*Flash大小是2^(FlashSize + 1) = 2^25 = 32MB */
  27.     //QSPI_FLASH_SIZE - 1; 需要扩大一倍,否则内存映射方位最后1个地址时,会异常。
  28.     QSPIHandle.Init.FlashSize       = QSPI_FLASH_SIZE;

  29.     /* 命令之间的CS片选至少保持2个时钟周期的高电平 */
  30.     QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;

  31.     /*
  32.        MODE0: 表示片选信号空闲期间,CLK时钟信号是低电平
  33.        MODE3: 表示片选信号空闲期间,CLK时钟信号是高电平
  34.     */
  35.     QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;

  36.     /* QSPI有两个BANK,这里使用的BANK1 */
  37.     QSPIHandle.Init.FlashID   = QSPI_FLASH_ID_1;

  38.     /* V7开发板仅使用了BANK1,这里是禁止双BANK */
  39.     QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE;

  40.     /* 初始化配置QSPI */
  41.     if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
  42.     {
  43.         Error_Handler(__FILE__, __LINE__);
  44.     }   
  45. }
复制代码

78.4.2 函数HAL_QSPI_DeInit
函数原型:

  1. HAL_StatusTypeDef HAL_QSPI_DeInit(QSPI_HandleTypeDef *hqspi)
  2. {
  3.   /* 检测QSPI句柄 */
  4.   if(hqspi == NULL)
  5.   {
  6.     return HAL_ERROR;
  7.   }

  8.   /* 禁止QSPI外设时钟 */
  9.   __HAL_QSPI_DISABLE(hqspi);

  10. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1)
  11.   if(hqspi->MspDeInitCallback == NULL)
  12.   {
  13.     hqspi->MspDeInitCallback = HAL_QSPI_MspDeInit;
  14.   }

  15.   /* 复位硬件底层 */
  16.   hqspi->MspDeInitCallback(hqspi);
  17. #else
  18.   /* 复位: GPIO, CLOCK, NVIC... */
  19.   HAL_QSPI_MspDeInit(hqspi);
  20. #endif

  21.   /* 设置无错误 Set QSPI error code to none */
  22.   hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;

  23.   /* 设置QSPI状态为复位 */
  24.   hqspi->State = HAL_QSPI_STATE_RESET;

  25.   return HAL_OK;
  26. }
复制代码

函数描述:

用于复位QSPI总线初始化。

函数参数:

  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
78.4.3 函数HAL_QSPI_Command
函数原型:

  1. HAL_StatusTypeDef HAL_QSPI_Command(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, uint32_t Timeout)
  2. {
  3.   HAL_StatusTypeDef status;
  4.   uint32_t tickstart = HAL_GetTick();

  5.   /* 检测参数 */
  6.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
  7.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
  8.   {
  9.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
  10.   }

  11.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
  12.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
  13.   {
  14.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
  15.   }

  16.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
  17.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
  18.   {
  19.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
  20.   }

  21.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
  22.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));

  23.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
  24.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
  25.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));

  26.   /* 上锁 */
  27.   __HAL_LOCK(hqspi);

  28.   if(hqspi->State == HAL_QSPI_STATE_READY)
  29.   {
  30.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;

  31.     /* 更新QSPI状态 */
  32.     hqspi->State = HAL_QSPI_STATE_BUSY;

  33.     /* 等待BUSY标志复位 */
  34.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);

  35.     if (status == HAL_OK)
  36.     {
  37.       /* 配置QSPI  */
  38.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);

  39.       if (cmd->DataMode == QSPI_DATA_NONE)
  40.       {
  41.         /* 没有数据阶段时,配置完成后立即开始传输,所以请等到TC标志设置并返回到空闲状态 */
  42.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);

  43.         if (status == HAL_OK)
  44.         {
  45.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);

  46.           /* QSPI就绪 */
  47.           hqspi->State = HAL_QSPI_STATE_READY;
  48.         }
  49.       }
  50.       else
  51.       {
  52.         /* QSPI就绪 */
  53.         hqspi->State = HAL_QSPI_STATE_READY;
  54.       }
  55.     }
  56.   }
  57.   else
  58.   {
  59.     status = HAL_BUSY;
  60.   }

  61.   /* 解锁 */
  62.   __HAL_UNLOCK(hqspi);

  63.   /* 返回函数状态 */
  64.   return status;
  65. }
复制代码

函数描述:

此函数主要用于为QSPI Flash发送操作命令,查询方式。

函数参数:

  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
  第3个参数是溢出时间,单位HAL库时间基准,一般我们设置的是1ms。
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: QSPI_WriteEnable
  4. *    功能说明: 写使能
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
  10. {
  11.     QSPI_CommandTypeDef     sCommand = {0};

  12.     /* 基本配置 */
  13.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
  14.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
  15.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
  16.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
  17.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
  18.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */

  19.     /* 写使能 */
  20.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */
  21.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */
  22.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */
  23.     sCommand.DummyCycles       = 0;                 /* 空周期  */

  24.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  25.     {
  26.         Error_Handler(__FILE__, __LINE__);
  27.     }   
  28. }
复制代码

78.4.4 函数HAL_QSPI_Command_IT
函数原型:

  1. HAL_StatusTypeDef HAL_QSPI_Command_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd)
  2. {
  3.   HAL_StatusTypeDef status;
  4.   uint32_t tickstart = HAL_GetTick();

  5.   /* 检测参数 */
  6.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
  7.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
  8.   {
  9.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
  10.   }

  11.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
  12.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
  13.   {
  14.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
  15.   }

  16.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
  17.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
  18.   {
  19.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
  20.   }

  21.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
  22.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));

  23.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
  24.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
  25.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));

  26.   /* 上锁 */
  27.   __HAL_LOCK(hqspi);

  28.   if(hqspi->State == HAL_QSPI_STATE_READY)
  29.   {
  30.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;

  31.     /* QSPI忙 */
  32.     hqspi->State = HAL_QSPI_STATE_BUSY;

  33.     /* 等待BUSY标志复位 */
  34.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);

  35.     if (status == HAL_OK)
  36.     {
  37.       if (cmd->DataMode == QSPI_DATA_NONE)
  38.       {
  39.         /* 清除中断 */
  40.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_TC);
  41.       }

  42.       /* 调用所有配置函数 */
  43.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);

  44.       if (cmd->DataMode == QSPI_DATA_NONE)
  45.       {
  46.         /* 无数据阶段,配置完毕后,立即开始传输,所以机会TC和TE中断 */
  47.         /* 解锁 /
  48.         __HAL_UNLOCK(hqspi);

  49.         /* 使能TE(Transfer Error)和TC中断 */
  50.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE | QSPI_IT_TC);
  51.       }
  52.       else
  53.       {
  54.         /* 更正QSPI状态 Update QSPI state */
  55.         hqspi->State = HAL_QSPI_STATE_READY;

  56.         /* 上锁 */
  57.         __HAL_UNLOCK(hqspi);
  58.       }
  59.     }
  60.     else
  61.     {
  62.       /* 解锁 */
  63.       __HAL_UNLOCK(hqspi);
  64.     }
  65.   }
  66.   else
  67.   {
  68.     status = HAL_BUSY;

  69.     /* 解锁 */
  70.     __HAL_UNLOCK(hqspi);
  71.   }

  72.   /* 返回状态 */
  73.   return status;
  74. }
复制代码

函数描述:

此函数主要用于为QSPI Flash发送操作命令,中断方式。

函数参数:

  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: QSPI_WriteEnable
  4. *    功能说明: 写使能
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
  10. {
  11.     QSPI_CommandTypeDef     sCommand = {0};

  12.     /* 基本配置 */
  13.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
  14.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
  15.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
  16.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
  17.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
  18.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */

  19.     /* 写使能 */
  20.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */
  21.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */
  22.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */
  23.     sCommand.DummyCycles       = 0;                 /* 空周期  */

  24.     if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK)
  25.     {
  26.         Error_Handler(__FILE__, __LINE__);
  27.     }   
  28. }
复制代码

78.4.5 函数HAL_QSPI_AutoPolling
函数原型:

  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg, uint32_t Timeout)
  2. {
  3.   HAL_StatusTypeDef status;
  4.   uint32_t tickstart = HAL_GetTick();

  5.   /* 检查参数 */
  6.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
  7.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
  8.   {
  9.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
  10.   }

  11.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
  12.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
  13.   {
  14.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
  15.   }

  16.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
  17.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
  18.   {
  19.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
  20.   }

  21.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
  22.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));

  23.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
  24.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
  25.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));

  26.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));
  27.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));
  28.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));

  29.   /* 上锁 */
  30.   __HAL_LOCK(hqspi);

  31.   if(hqspi->State == HAL_QSPI_STATE_READY)
  32.   {
  33.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;

  34.     /* 更新状态 */
  35.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;

  36.     /* 等待BUSY复位标志 */
  37.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);

  38.     if (status == HAL_OK)
  39.     {
  40.       /* 配置QSPI匹配位 */
  41.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);

  42.       /* 配置QSPI屏蔽位 */
  43.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);

  44.       /* 配置查询时间间隔 */
  45.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);

  46.       /* 配置匹配模式,使能自动停(否则阻塞方式无限等待) */
  47.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),
  48.                (cfg->MatchMode | QSPI_AUTOMATIC_STOP_ENABLE));

  49.       /* 调用配置函数 */
  50.       cmd->NbData = cfg->StatusBytesSize;
  51.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);

  52.       /* 等待SM标志 */
  53.       status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_SM, SET, tickstart, Timeout);

  54.       if (status == HAL_OK)
  55.       {
  56.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_SM);

  57.         /* 更新状态 */
  58.         hqspi->State = HAL_QSPI_STATE_READY;
  59.       }
  60.     }
  61.   }
  62.   else
  63.   {
  64.     status = HAL_BUSY;
  65.   }

  66.   /* 解锁 */
  67.   __HAL_UNLOCK(hqspi);

  68.   /* 返回状态 */
  69.   return status;
  70. }
复制代码

函数描述:

用于状态标志查询,函数采用的查询方式。

函数参数:

  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。
  第4个参数是溢出时间,单位HAL库时间基准,单位1ms。
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: QSPI_AutoPollingMemReady
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)
  10. {
  11.     QSPI_CommandTypeDef     sCommand = {0};
  12.     QSPI_AutoPollingTypeDef sConfig = {0};


  13.     /* 基本配置 */
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */

  20.     /* 读取状态*/
  21.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */
  22.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */
  23.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */
  24.     sCommand.DummyCycles       = 0;                   /* 无需空周期 */

  25.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
  26.     sConfig.Mask            = 0x01;
  27.     sConfig.Match           = 0x00;
  28.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
  29.     sConfig.StatusBytesSize = 1;
  30.     sConfig.Interval        = 0x10;
  31.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;

  32.     if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, 10000) != HAL_OK)
  33.     {
  34.         Error_Handler(__FILE__, __LINE__);
  35.     }
  36. }
复制代码

78.4.6 函数HAL_QSPI_AutoPolling_IT
函数原型:

  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg)
  2. {
  3.   HAL_StatusTypeDef status;
  4.   uint32_t tickstart = HAL_GetTick();

  5.   /* 检查参数 */
  6.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
  7.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
  8.   {
  9.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
  10.   }

  11.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
  12.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
  13.   {
  14.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
  15.   }

  16.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
  17.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
  18.   {
  19.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
  20.   }

  21.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
  22.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));

  23.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
  24.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
  25.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));

  26.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));
  27.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));
  28.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));
  29.   assert_param(IS_QSPI_AUTOMATIC_STOP(cfg->AutomaticStop));

  30.   /* 上锁 */
  31.   __HAL_LOCK(hqspi);

  32.   if(hqspi->State == HAL_QSPI_STATE_READY)
  33.   {
  34.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;

  35.     /* 更新状态 */
  36.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;

  37.     /* 等BUSY标志复位 */
  38.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);

  39.     if (status == HAL_OK)
  40.     {
  41.       /* 配置匹配值 */
  42.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);

  43.       /* 配置屏蔽值 */
  44.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);

  45.       /* 配置查询间隔 */
  46.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);

  47.       /* 配置匹配模式和自动停止位 */
  48.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),
  49.                (cfg->MatchMode | cfg->AutomaticStop));

  50.       /* 清标志 */
  51.       __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_SM);

  52.       /* 调用配置函数 */
  53.       cmd->NbData = cfg->StatusBytesSize;
  54.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);

  55.       /* 解锁 */
  56.       __HAL_UNLOCK(hqspi);

  57.       /* 使能SM(status match)和TE(Transfer Error)标志 */
  58.       __HAL_QSPI_ENABLE_IT(hqspi, (QSPI_IT_SM | QSPI_IT_TE));

  59.     }
  60.     else
  61.     {
  62.       /* 解锁 */
  63.       __HAL_UNLOCK(hqspi);
  64.     }
  65.   }
  66.   else
  67.   {
  68.     status = HAL_BUSY;

  69.     /* 解锁 */
  70.     __HAL_UNLOCK(hqspi);
  71.   }

  72.   /* 返回函数状态 */
  73.   return status;
  74. }
复制代码

函数描述:

用于状态标志查询,函数采用的中断方式。

函数参数:

  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: QSPI_AutoPollingMemReady
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)
  10. {
  11.     QSPI_CommandTypeDef     sCommand = {0};
  12.     QSPI_AutoPollingTypeDef sConfig = {0};


  13.     /* 基本配置 */
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */

  20.     /* 读取状态*/
  21.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */
  22.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */
  23.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */
  24.     sCommand.DummyCycles       = 0;                   /* 无需空周期 */

  25.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
  26.     sConfig.Mask            = 0x01;
  27.     sConfig.Match           = 0x00;
  28.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
  29.     sConfig.StatusBytesSize = 1;
  30.     sConfig.Interval        = 0x10;
  31.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;

  32.     if (HAL_QSPI_AutoPolling_IT(&QSPIHandle, &sCommand, &sConfig) != HAL_OK)
  33.     {
  34.         Error_Handler(__FILE__, __LINE__);
  35.     }
  36. }
复制代码

78.4.7 函数HAL_QSPI_Transmit
函数原型:

  1. HAL_StatusTypeDef HAL_QSPI_Transmit(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)
  2. {
  3.   HAL_StatusTypeDef status = HAL_OK;
  4.   uint32_t tickstart = HAL_GetTick();
  5.   __IO uint32_t *data_reg = &hqspi->Instance->DR;

  6.   /* 上锁 */
  7.   __HAL_LOCK(hqspi);

  8.   if(hqspi->State == HAL_QSPI_STATE_READY)
  9.   {
  10.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;

  11.     if(pData != NULL )
  12.     {
  13.       /* 更新状态 */
  14.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;

  15.       /* 配置发送 */
  16.       hqspi->TxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;
  17.       hqspi->TxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;
  18.       hqspi->pTxBuffPtr = pData;

  19.       /* 配置QSPI,间接模式 */
  20.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);

  21.       while(hqspi->TxXferCount > 0U)
  22.       {
  23.         /* 等待FT标志 */
  24.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_FT, SET, tickstart, Timeout);

  25.         if (status != HAL_OK)
  26.         {
  27.           break;
  28.         }

  29.         *((__IO uint8_t *)data_reg) = *hqspi->pTxBuffPtr;
  30.         hqspi->pTxBuffPtr++;
  31.         hqspi->TxXferCount--;
  32.       }

  33.       if (status == HAL_OK)
  34.       {
  35.         /* 等待TC标志 */
  36.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);

  37.         if (status == HAL_OK)
  38.         {
  39.           /* 清楚传输完成 */
  40.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);

  41.         }
  42.       }

  43.       /* 更新 */
  44.       hqspi->State = HAL_QSPI_STATE_READY;
  45.     }
  46.     else
  47.     {
  48.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
  49.       status = HAL_ERROR;
  50.     }
  51.   }
  52.   else
  53.   {
  54.     status = HAL_BUSY;
  55.   }

  56.   /* 解锁 */
  57.   __HAL_UNLOCK(hqspi);

  58.   return status;
  59. }
复制代码

函数描述:

此函数用于QSPI接口数据发送,函数采用查询方式。

函数参数:

  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
  第2个参数是要发送的数据地址。
  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: QSPI_WriteBuffer
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入
  5. *    形    参: _pBuf : 数据源缓冲区;
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。
  8. *    返 回 值: 1:成功, 0:失败
  9. *********************************************************************************************************
  10. */
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
  12. {
  13.     QSPI_CommandTypeDef sCommand={0};

  14.     /* 写使能 */
  15.     QSPI_WriteEnable(&QSPIHandle);   

  16.     /* 基本配置 */
  17.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
  18.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
  19.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
  20.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
  21.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
  22.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */   

  23.     /* 写序列配置 */
  24.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */
  25.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */
  26.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */
  27.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
  28.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   
  29.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 */

  30.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
  31.     {
  32.         //return 0;
  33.         Error_Handler(__FILE__, __LINE__);
  34.     }

  35.     /* 启动传输 */
  36.     if (HAL_QSPI_Transmit(&QSPIHandle, _pBuf, 10000) != HAL_OK)
  37.     {
  38.         //return 0;
  39.         Error_Handler(__FILE__, __LINE__);

  40.     }

  41.     QSPI_AutoPollingMemReady(&QSPIHandle);   

  42.     return 1;
  43. }
复制代码

78.4.8 函数HAL_QSPI_Receive
函数原型:

  1. HAL_StatusTypeDef HAL_QSPI_Receive(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)
  2. {
  3.   HAL_StatusTypeDef status = HAL_OK;
  4.   uint32_t tickstart = HAL_GetTick();
  5.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);
  6.   __IO uint32_t *data_reg = &hqspi->Instance->DR;

  7.   /* 上锁 */
  8.   __HAL_LOCK(hqspi);

  9.   if(hqspi->State == HAL_QSPI_STATE_READY)
  10.   {
  11.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;

  12.     if(pData != NULL )
  13.     {
  14.       /* 更新状态 */
  15.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;

  16.       /* 配置接收 */
  17.       hqspi->RxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;
  18.       hqspi->RxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;
  19.       hqspi->pRxBuffPtr = pData;

  20.       /* 配置QSPI,间接模式 */
  21.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);

  22.       /* 启动传输 */
  23.       WRITE_REG(hqspi->Instance->AR, addr_reg);

  24.       while(hqspi->RxXferCount > 0U)
  25.       {
  26.         /* 等FT和TC标志 */
  27.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, (QSPI_FLAG_FT | QSPI_FLAG_TC), SET, tickstart, Timeout);

  28.         if  (status != HAL_OK)
  29.         {
  30.           break;
  31.         }

  32.         *hqspi->pRxBuffPtr = *((__IO uint8_t *)data_reg);
  33.         hqspi->pRxBuffPtr++;
  34.         hqspi->RxXferCount--;
  35.       }

  36.       if (status == HAL_OK)
  37.       {
  38.         /* 等待TC标志 */
  39.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);

  40.         if  (status == HAL_OK)
  41.         {
  42.           /* 清楚传输完成bit */
  43.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);

  44.         }
  45.       }

  46.       /* 更新QSPI状态 */
  47.       hqspi->State = HAL_QSPI_STATE_READY;
  48.     }
  49.     else
  50.     {
  51.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
  52.       status = HAL_ERROR;
  53.     }
  54.   }
  55.   else
  56.   {
  57.     status = HAL_BUSY;
  58.   }

  59.   /* 解锁 */
  60.   __HAL_UNLOCK(hqspi);

  61.   return status;
  62. }
复制代码

函数描述:

此函数用于QSPI接口数据接收,函数采用查询方式。

函数参数:

  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
  第2个参数是要接收的数据地址。
  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: QSPI_ReadBuffer
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。
  5. *    形    参: _pBuf : 数据源缓冲区。
  6. *              _uiReadAddr :起始地址。
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
  8. *    返 回 值: 无
  9. *********************************************************************************************************
  10. */
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
  12. {

  13.     QSPI_CommandTypeDef sCommand = {0};


  14.     /* 基本配置 */
  15.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */
  16.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */
  17.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 */
  18.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */
  19.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */
  20.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */   

  21.     /* 读取数据 */
  22.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */
  23.     sCommand.DummyCycles = 6;                    /* 空周期 */
  24.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */
  25.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */
  26.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */
  27.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */

  28.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
  29.     {
  30.         Error_Handler(__FILE__, __LINE__);
  31.     }

  32.     /* 读取 */
  33.     if (HAL_QSPI_Receive(&QSPIHandle, _pBuf, 10000) != HAL_OK)
  34.     {
  35.         Error_Handler(__FILE__, __LINE__);
  36.     }   
  37. }
复制代码

78.4.9 函数HAL_QSPI_Transmit_DMA
函数原型:

  1. HAL_StatusTypeDef HAL_QSPI_Transmit_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData)
  2. {
  3.   HAL_StatusTypeDef status = HAL_OK;
  4.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);

  5.   /* 上锁 */
  6.   __HAL_LOCK(hqspi);

  7.   if(hqspi->State == HAL_QSPI_STATE_READY)
  8.   {
  9.     /* 无错误 */
  10.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;

  11.     if(pData != NULL )
  12.     {
  13.       /* 配置发送字节数 */
  14.       hqspi->TxXferCount = data_size;

  15.         /* 设置QSPI状态 */
  16.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;

  17.         /* 清除中断标志 */
  18.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));

  19.         /* 配置发送 */
  20.         hqspi->TxXferSize = hqspi->TxXferCount;
  21.         hqspi->pTxBuffPtr = pData;

  22.         /* 配置间接写模式 */
  23.         MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);

  24.         /* 设置MDMA发送完回调 */
  25.         hqspi->hmdma->XferCpltCallback = QSPI_DMATxCplt;

  26.         /* 设置MDMA错误回调 */
  27.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;

  28.         /* 设置MDMA终止传输回调为NULL */
  29.         hqspi->hmdma->XferAbortCallback = NULL;

  30.         /* MDMA的目的地址是QSPI DR寄存器,设置禁止递增 */
  31.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) ,MDMA_DEST_INC_DISABLE);

  32.         /* 更新MDMA源地址配置 */
  33.         if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_BYTE)
  34.         {
  35.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_BYTE);
  36.         }
  37.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_HALFWORD)
  38.         {
  39.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) ,
  40. MDMA_SRC_INC_HALFWORD);
  41.         }
  42.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_WORD)
  43.         {
  44.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_WORD);
  45.         }
  46.         else
  47.         {
  48.           /* 配置错误 */
  49.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
  50.           status = HAL_ERROR;
  51.         }

  52.         /* 使能QSPI MDMA发送 */
  53.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)pData, (uint32_t)&hqspi->Instance->DR,
  54. hqspi->TxXferSize, 1) == HAL_OK)
  55.         {
  56.           /* 解锁 */
  57.           __HAL_UNLOCK(hqspi);

  58.           /* 使能QSPI传输错误中断 */
  59.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);

  60.           /* 使能MDMA传输 */
  61.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);
  62.         }
  63.         else
  64.         {
  65.           status = HAL_ERROR;
  66.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
  67.           hqspi->State = HAL_QSPI_STATE_READY;

  68.           /* 解锁 */
  69.           __HAL_UNLOCK(hqspi);
  70.         }
  71.     }
  72.     else
  73.     {
  74.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
  75.       status = HAL_ERROR;

  76.       /* 解锁 */
  77.       __HAL_UNLOCK(hqspi);
  78.     }
  79.   }
  80.   else
  81.   {
  82.     status = HAL_BUSY;

  83.     /* 解锁 */
  84.     __HAL_UNLOCK(hqspi);
  85.   }

  86.   return status;
  87. }
复制代码

函数描述:

此函数用于QSPI接口数据发送,函数采用DMA方式。

函数参数:

  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
  第2个参数是要接收的数据地址。
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: QSPI_WriteBuffer
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入
  5. *    形    参: _pBuf : 数据源缓冲区;
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。
  8. *    返 回 值: 1:成功, 0:失败
  9. *********************************************************************************************************
  10. */
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
  12. {
  13.     QSPI_CommandTypeDef sCommand={0};

  14.     /* 写使能 */
  15.     QSPI_WriteEnable(&QSPIHandle);   

  16.     /* 基本配置 */
  17.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
  18.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
  19.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
  20.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
  21.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
  22.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */   

  23.     /* 写序列配置 */
  24.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */
  25.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */
  26.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */
  27.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
  28.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   
  29.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 */

  30.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
  31.     {
  32.         //return 0;
  33.         Error_Handler(__FILE__, __LINE__);
  34.     }

  35.     /* 启动传输 */
  36.     if (HAL_QSPI_Transmit_DMA(&QSPIHandle, _pBuf) != HAL_OK)
  37.     {
  38.         //return 0;
  39.         Error_Handler(__FILE__, __LINE__);
  40.     }

  41.     QSPI_AutoPollingMemReady(&QSPIHandle);   

  42.     return 1;
  43. }
复制代码

78.4.10   函数HAL_QSPI_Receive_DMA
函数原型:

  1. HAL_StatusTypeDef HAL_QSPI_Receive_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData)
  2. {
  3.   HAL_StatusTypeDef status = HAL_OK;
  4.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);
  5.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);

  6.   /* 上锁 */
  7.   __HAL_LOCK(hqspi);

  8.   if(hqspi->State == HAL_QSPI_STATE_READY)
  9.   {
  10.     /* 无错误 */
  11.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;

  12.     if(pData != NULL )
  13.     {
  14.       /* 配置接收 */
  15.       hqspi->RxXferCount = data_size;
  16.         /* 更新状态 */
  17.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;

  18.         /* 清除中断标志 */
  19.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));

  20.         /* 配置接收 Configure */
  21.         hqspi->RxXferSize = hqspi->RxXferCount;
  22.         hqspi->pRxBuffPtr = pData;

  23.         /* 设置接收完成中断 */
  24.         hqspi->hmdma->XferCpltCallback = QSPI_DMARxCplt;

  25.         /* 设置MDMA错误回调 */
  26.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;

  27.         /* 置空MDMA终止回调 */
  28.         hqspi->hmdma->XferAbortCallback = NULL;

  29.       /* 接收模式下,MDMA的源地址是QSPI DR,要禁止地址自增 */
  30.       MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_DISABLE);

  31.       /* 更新目的地址配置 */
  32.       if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_BYTE)
  33.       {
  34.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_BYTE);
  35.       }
  36.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_HALFWORD)
  37.       {
  38.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) ,
  39. MDMA_DEST_INC_HALFWORD);
  40.       }
  41.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_WORD)
  42.       {
  43.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_WORD);
  44.       }
  45.       else
  46.       {
  47.        /* 配置错误 */
  48.         hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
  49.         status = HAL_ERROR;
  50.       }
  51.           /* 配置CCR寄存器,间接读 */
  52.           MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);

  53.           /* 启动传输 */
  54.           WRITE_REG(hqspi->Instance->AR, addr_reg);

  55.         /* 使能MDMA */
  56.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)&hqspi->Instance->DR, (uint32_t)pData,
  57. hqspi->RxXferSize, 1) == HAL_OK)
  58.         {
  59.           /* 解锁 */
  60.           __HAL_UNLOCK(hqspi);

  61.           /* 使能传输错误中断 */
  62.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);

  63.           /* 使能MDMA传输 */
  64.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);
  65.         }
  66.         else
  67.         {
  68.           status = HAL_ERROR;
  69.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
  70.           hqspi->State = HAL_QSPI_STATE_READY;

  71.           /* 解锁 */
  72.           __HAL_UNLOCK(hqspi);
  73.         }
  74.     }
  75.     else
  76.     {
  77.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
  78.       status = HAL_ERROR;

  79.       /* 解锁 */
  80.       __HAL_UNLOCK(hqspi);
  81.     }
  82.   }
  83.   else
  84.   {
  85.     status = HAL_BUSY;

  86.     /* 解锁 */
  87.     __HAL_UNLOCK(hqspi);
  88.   }

  89.   return status;
  90. }
复制代码

函数描述:

此函数用于QSPI接口数据接收,函数采用DMA方式。

函数参数:

  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
  第2个参数是要接收的数据地址。
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: QSPI_ReadBuffer
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。
  5. *    形    参: _pBuf : 数据源缓冲区。
  6. *              _uiReadAddr :起始地址。
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
  8. *    返 回 值: 无
  9. *********************************************************************************************************
  10. */
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
  12. {

  13.     QSPI_CommandTypeDef sCommand = {0};


  14.     /* 基本配置 */
  15.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */
  16.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */
  17.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 */
  18.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */
  19.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */
  20.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */   

  21.     /* 读取数据 */
  22.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */
  23.     sCommand.DummyCycles = 6;                    /* 空周期 */
  24.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */
  25.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */
  26.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */
  27.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */

  28.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
  29.     {
  30.         Error_Handler(__FILE__, __LINE__);
  31.     }

  32.     /* 读取 */
  33.     if (HAL_QSPI_Receive_DMA(&QSPIHandle, _pBuf) != HAL_OK)
  34.     {
  35.         Error_Handler(__FILE__, __LINE__);
  36.     }   
  37. }
复制代码

78.4.11   函数HAL_QSPI_MemoryMapped
函数原型:

  1. HAL_StatusTypeDef HAL_QSPI_MemoryMapped(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_MemoryMappedTypeDef *cfg)
  2. {
  3.   HAL_StatusTypeDef status;
  4.   uint32_t tickstart = HAL_GetTick();

  5.   /* 检查参数 */
  6.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
  7.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
  8.   {
  9.   assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
  10.   }

  11.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
  12.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
  13.   {
  14.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
  15.   }

  16.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
  17.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
  18.   {
  19.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
  20.   }

  21.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
  22.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));

  23.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
  24.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
  25.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));

  26.   assert_param(IS_QSPI_TIMEOUT_ACTIVATION(cfg->TimeOutActivation));

  27.   /* 上锁 */
  28.   __HAL_LOCK(hqspi);

  29.   if(hqspi->State == HAL_QSPI_STATE_READY)
  30.   {
  31.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;

  32.     /* 更新状态 */
  33.     hqspi->State = HAL_QSPI_STATE_BUSY_MEM_MAPPED;

  34.     /* 等待BUSY标志复位 */
  35.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);

  36.     if (status == HAL_OK)
  37.     {
  38.       /* 配置QSPI CR寄存器溢出时间计数 */
  39.     MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_TCEN, cfg->TimeOutActivation);

  40.     if (cfg->TimeOutActivation == QSPI_TIMEOUT_COUNTER_ENABLE)
  41.       {
  42.         assert_param(IS_QSPI_TIMEOUT_PERIOD(cfg->TimeOutPeriod));

  43.         /* 配置溢出时间 */
  44.         WRITE_REG(hqspi->Instance->LPTR, cfg->TimeOutPeriod);

  45.         /* 清楚中断标志 */
  46.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TO);

  47.         /* 使能QSPI溢出中断 */
  48.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TO);
  49.       }

  50.       /* 调用配置函数 */
  51.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_MEMORY_MAPPED);
  52.     }
  53.   }
  54.   else
  55.   {
  56.     status = HAL_BUSY;
  57.   }

  58.   /* 解锁 */
  59.   __HAL_UNLOCK(hqspi);

  60.   /* 返回状态 */
  61.   return status;
  62. }
复制代码

函数描述:

用于QSPI内存映射设置。

函数参数:

  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
  第3个参数是QSPI_MemoryMappedTypeDef类型结构体变量,详见本章3.6小节。
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: QSPI_MemoryMapped
  4. *    功能说明: QSPI内存映射,地址 0x90000000
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void QSPI_MemoryMapped(void)
  10. {
  11.     QSPI_CommandTypeDef s_command = {0};
  12.     QSPI_MemoryMappedTypeDef s_mem_mapped_cfg = {0};

  13.     /* 基本配置 */
  14.     s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;      /* 1线方式发送指令 */
  15.     s_command.AddressSize = QSPI_ADDRESS_32_BITS;             /* 32位地址 */
  16.     s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
  17.     s_command.DdrMode = QSPI_DDR_MODE_DISABLE;                /* W25Q256JV不支持DDR */
  18.     s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;   /* DDR模式,数据输出延迟 */
  19.     s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次传输都发指令 */

  20.     /* 全部采用4线 */
  21.     s_command.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 快速读取命令 */
  22.     s_command.AddressMode = QSPI_ADDRESS_4_LINES;                 /* 4个地址线 */
  23.     s_command.DataMode = QSPI_DATA_4_LINES;                       /* 4个数据线 */
  24.     s_command.DummyCycles = 6;                                    /* 空周期 */

  25.     /* 关闭溢出计数 */
  26.     s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
  27.     s_mem_mapped_cfg.TimeOutPeriod = 0;

  28.     if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)
  29.     {
  30.        Error_Handler(__FILE__, __LINE__);
  31.     }
  32. }
复制代码

78.5 总结
本章节就为大家讲解这么多,要熟练掌握QSPI总线的查询,中断和DMA方式的API用法。


74f88e781c0aa6369a48d73fb7dbe7d9.png
收藏 评论0 发布时间:2021-11-4 18:44

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版