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

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

[复制链接]
STMCU小助手 发布时间:2021-11-4 18:44
78.1 初学者重要提示
" T1 d! A! |: c4 E) M" o  QSPI接口,可以做1线,2线或者4线使用。8 _  E7 ?( D7 J9 J4 [- t2 C" O
  注意,QSPI接口不分主从,QSPI仅用于主控。
' G/ u  H" c/ \- ?$ [  可以单独使用BANK1外接一个Flash,也可以单独使用BANK2外接一个Flash,不可以BANK1和BANK2同时独立使用。但可以两个BANK合起来做双BANK(也称双Flash,即dual flash)使用,即8线模式。0 O( o5 n* E$ {* P2 I9 \
  STM32H7可用的单线,双线,四线和八线SPI QSPI OctaFlash等涵盖各大厂商
* G: t8 m2 H6 R78.2 QSPI总线基础知识% g5 \  B1 J9 k, T
78.2.1 QSPI总线的硬件框图3 h$ u/ h+ [" S2 [4 U& ~5 s% A) w' B: F
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解QSPI的基本功能,然后再看手册了解细节。% s1 e5 ~! W' @0 e

4 e. f" H" ^% tBANK1外接Flash" S+ Y+ n5 c! Y5 X: K- b; y+ {/ M7 U
0 c, H; M+ H% E* D
f04c8d70b5dfdaf87e9a1a4f54b38e55.png

. `, H  P9 K' r/ s2 `; M. B
: Q$ u0 ]% ]) m# d, ~( W% GBANK1和BANK2都外接Flash:
4 i/ @- w! N0 y" u) H* K% @* C, Z- j8 r- x' Q; `
60f4042c5098f3ba9a7e40219c023175.png

- T2 O" x# H: f2 D4 A# @1 b2 z, Y) F7 e; e& W7 j9 n- J
通过这个框图,我们可以得到如下信息:% Z' n4 I) \4 F6 I
8 Z; o+ p. I, e/ V& s" X- N2 C
  quadspi_ker_ck时钟输入6 _$ a8 n' `/ a" ^
内核时钟。4 W) r- n8 |2 Q
1 }3 T4 q0 [, k0 o: w( l
  quadspi_hclk时钟输入
; C% D$ D8 ~, B' J) l" [为寄存器提供时钟。
# g7 n% q* F7 z8 O! @
( s  l5 `/ u  z* L2 k; P4 A* U  quadspi_it输出信号
) `+ j! i0 K  n- sQSPI全局中断。
# d2 ~% {8 o. c' q. P: `/ Y5 B
6 v4 o( f8 Q" f1 E0 @+ x1 G! ?# w  quadspi_ft_trg输出信号' d& `- O5 p+ K& n
MDMA的QSPI FIFO阀值触发信号
) _! j. k* x' a( e) P
6 a* v% c& S- l' h4 k( O& u  quadspi_tc_trg输出信号- `& n/ H9 F2 ]% N7 ?  E* R
MDMA的QSPI传输完成触发信号
" x5 R* r7 u! f
. b6 x* c) Q( x& \" B9 ?& m  CLK
- B, w. s& g* A: R# e4 z8 N为外接Flash提供的时钟。为外接的两块Flash同时提供时钟。
1 E0 L2 d: h! l/ f4 S' y2 E/ q% `" X
  BK1_IO0/SO. \$ o& M+ {5 h( r# [
在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash1使用。
3 R( }2 Q( X0 {7 [7 @% L! f' I$ E4 `, R0 u1 w
  BK1_IO1/SI3 ?2 {( c/ U$ `- l
在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash1使用。
/ I$ p7 I* I0 `2 z% r5 Y. h
, ~4 y* w1 w3 m/ K: T& z  BK1_IO2/ }4 ^1 J, v+ d' L- a
在4线模式中作为双向IO,供Flash1使用。3 D% F, m! X# ^* u6 C: W
8 v* \: Y% k& h# g5 `+ g9 h; r
  BK1_IO3' N, u7 Y' A5 N) m7 S3 M7 [
在4线模式中作为双向IO,供Flash1使用。$ K7 y+ a0 s* E8 l3 |( {) i

6 `; E. p5 y4 @# @  BK12_IO0/SO& k/ [6 j8 `$ i/ S2 C; ^. j& _1 h
在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash2使用。  K. U( T5 s5 x0 V$ j# T2 N
/ U  e$ n: P) B; z. w8 O; x
  BK2_IO1/SI
7 y9 K" U' r- h/ G9 r6 E# i在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash2使用。  F! L$ _" X; X0 K$ o
2 ~/ C9 e" [" ?2 F7 z6 W
  BK2_IO2
" p- m) q8 p" Y0 P- ~在4线模式中作为双向IO,供Flash2使用。
: m3 B( j( G/ q6 s% d
2 N0 ~6 [9 D+ w  BK2_IO3
  K7 t9 C, b7 P2 M在4线模式中作为双向IO,供Flash2使用。: w9 b% u. v9 y

4 ?% A2 Y  R$ w' Z  BK1_nCS1 W0 o* h- G2 ^# y
片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash2。
# q5 q9 s$ q2 N: k" C  g3 w* L( R+ P: U5 V! F' x
  BK2_nCS' P, a, \8 a  K8 F: {. J
片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash1。* l  e% ]9 t( `6 y9 E9 i

- H+ \7 ~* ]! s78.2.2 QSPI的时钟源- I! i6 c$ V, F& ~9 W
这个知识点在初学的时候容易忽视,所以我们这里整理下。2 J* r$ p+ n# I0 u6 A" V
  k/ ^( X- i6 W& C& E
STM32H7主频在400MHz下,QSPI的最高时钟是200MHz,可以选择的时钟源如下:4 h3 g  _6 W% V

# @/ R& n3 W# a) H3 n1 {
60a21420cdf6bbfc171b77ef44ebcf28.png

% K% s7 K9 [& V8 K8 o0 N* v% O* ]: L
12523b301f01c6108162699ca2ad5685.png

/ C0 J6 y& n! ^6 T0 B; z
; K! c" G9 F, @8 P  G3 g* Y
. n; y1 q3 u2 h% \我们的程序中默认是采用的HCLK3作为QSPI时钟。
" y, k. D) V, b: q5 c0 G; a3 M2 z
78.2.3 QSPI 命令序列  Z: ?: I- H+ c; `9 [
QSPI的命令序列主要包括以下几个阶段:指令阶段、地址阶段、交替字节阶段、空指令阶段和数据这五个阶段,任一阶段均可跳过,但至少要包含指令、地址、交替字节或数据阶段之一。9 T& `3 Y4 i6 h& }0 U' i

& r) n' Q8 X0 _" ?- q4 E) M
2cb087bbc794898408c6160acfd426e4.png

+ V; K' @3 w- {- {- j( h) D1 W: S: N, h! O0 g
  指令阶段
# L2 P0 c4 A: v) z" O/ \在此阶段,将命令(8位指令)发送到Flash,允许发送任何值。用户可以简单地将所需的命令写在指令字段中。根据软件和硬件配置,可以1线,2线或者4线方式发送。在某些只发送地址的案例中,指令阶段可以跳过。1 [' b* C$ f: g

, E: p, L6 C8 t 地址阶段
% Y0 H" y% h: J: \* m/ T1 s在此阶段,将地址发送到Flash,从指定的地址读取或写入数据。 地址阶段是完全可配置的,允许发送1、2、3或4个字节的地址。在间接模式和自动轮询模式下,用户可以简单地将所需的地址写入QUADSPI_AR寄存器。据软件和硬件配置,可以1线,2线或者4线方式方式发送。 在一些不需要地址的情况下,可以跳过地址阶段。
) p& o9 y' Y* v- u1 a2 W
( e: e- l6 [4 d6 q+ \1 h( A  交替字节阶段
; ~8 n4 n; N5 U4 b$ @2 P; nQSPI接口支持的一个额外阶段,具有更大的灵活性。它是通常用于控制操作模式。交替字节阶段是完全可配置的,并允许发送一,二,三或四字节。$ ]  g+ V% q% y6 E; a

' V3 d1 O) ]' O; s7 @+ D  空周期阶段" a% T' n. Q9 l! ]
在高速时钟下运行时,此阶段可以确保有足够的“周转”时间从输出模式切换到输入模式。
5 g! u( c8 v! s) \9 x
% V5 o$ G" s" d$ I/ O  数据阶段
6 l- u* [* j+ e5 n& `这个阶段实现数据的收发。* i8 k8 ~) F, e5 l: G- Z

% C) h& _* B4 l4 u, X$ G8 X78.2.4 QSPI的1线,2线,4线,SDR和DDR模式7 R7 X. I" u8 ?' s- U! L: q3 v
这里所说的线是指通信阶段使用的数据线个数。1 |& _9 t1 g& w6 j2 Y

% Z' @# A9 K- U2 o
213a38369fe04824fa8640f515beb2fc.png

" x* M% t- @. H
" O$ c! d2 w% i! r6 F3 l* u) b1线(SingleSPI,虽然是一发一收,但属于1线方式)$ g0 [* T$ d; P/ e/ b$ i
发送用的数据线BK1_IO0/SO(BK2_IO0/SO),接收用的数据线BK1_IO1/SI(BK2_IO1/SI)
& a9 r- X6 A: L5 m0 B3 @8 Y4 P4 g4 u% M
1线模式下,所有线处于的状态:( |9 Q. ^' a7 _+ ~, v! S6 Z
5 e  l' p. u7 A$ Z
(1)  BK1_IO0 / SO(BK2_IO0 / SO)处于输出模式。
) F  K# y! O9 T/ b6 f( z
0 |1 Y, Y" o  [) Y; D! G/ G (2) BK1_IO1 / SI(BK2_IO1 / SI)处于输入模式(高阻抗)。
  r" l: a' {1 V2 _( `7 n* H
+ }. v9 @  U9 m$ u6 E) l (3) BK1_IO2(BK2_IO2)处于输出模式并强制置0。
* ~+ N2 o: C0 V0 o/ w) W, ~/ G$ m! m* k0 I' s* v# e
(4)  BK1_IO3(BK2_IO3)处于输出模式并强制置1。0 [! g: I7 l6 i) ]% \* H
5 V  B: |9 L$ l
7c6105bc6d18539b680aeeed7ec93aed.png
. \! D- \7 N% K  M9 k3 [+ x& S; H% c
5 Z% k+ X5 i6 P: o
  2线(Dual-SPI). r; W2 L( ?$ A) Q2 s5 I  ?
同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1)做输入输出。
; N& I5 U- v% W: S- X- X: N% Y$ K* a) Y- [3 g% O
2线模式下,所有线处于的状态:' [  k8 O) _" `$ i' E
0 k* R1 @0 }' T0 m5 n9 O4 K* I! n
(1) BK1_IO0 (BK2_IO0 )和BK1_IO1(BK2_IO1)读取时处于输入(高阻)。其它情况下为输出。- L8 v$ D. D* }
9 _- f' Q/ Z' g% F4 w
(2) BK1_IO2(BK2_IO2)处于输出模式并强制置0。: D5 Y. Q0 W  d7 h! O7 i2 {' [; d$ x

4 ?1 O9 j  e" r$ s" I (3) BK1_IO3(BK2_IO3)处于输出模式并强制置12 {# z: v6 O3 b3 o2 \' f
4 R! l" U' G& h2 e

7 b5 Z5 [5 m, N9 h. I9 Q2 |) }; x# @* \! ~# l
4线(Quad-SPI)
* z# C$ c3 c2 F' D/ b同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)做输入输出。5 L  n# e$ b( x, i
; I, ~. b7 @3 u0 D! ]6 w6 [* H
4线模式下,当读取数据时,所有线处于输入(高阻),其它情况作为输出。
, u' l' z/ m& d% R
9 v" r* A1 i4 x1 N+ ]: Z& K2 Q
9d022cbcfd5fb3f3950421c3312e505f.png

& B2 {7 R2 k% P* h8 z( N& s
, d9 m8 H- ^' ?/ x$ y  SDR
% ^. Q4 B1 _. `' [- u/ R在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号仅在 CLK的下降沿发生转变。. y0 w; X! c/ h! o5 a

- @0 u2 ~  e8 ^  DDR/ C" H8 ]; M* o) o5 i7 O$ i& u
在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号在CLK的上升沿和下降沿发生转变。; Z/ x  g4 f2 f; p8 y8 @
) ]4 i; F# l; B7 ^( s! E$ T
  双BANK(双Flash)% I9 }& X  w' k+ `+ Q% _
双闪存就是将QSPI的两个BANK分别接一个QSPI Flash,然后时钟公用,片选公用(也可以不公用),从而实现8线模式。4 F5 l1 ]  f, o7 {7 Y1 v/ E8 k7 m

) U7 F& [- B; j8 C5 Q
d28d743492529e4d88e9b64567fe52b4.png

5 z+ }) |. v3 F
6 P- X$ I6 z$ {, b7 F78.2.5 QSPI间接模式,查询模式和内存映射; l. p( o4 ?  o( K
QSPI支持在以下三种模式下工作:8 P! m( V* \+ P
+ y4 F) F. ^9 @7 ^! j* k0 T
1、  间接模式:+ [4 z( W  x& H5 E

& K0 N, J6 T) P' b7 P: }这里所谓的间接模式是指寄存器方式访问外设,就跟我们操作串口外设一样。间接模式主要用于以下场合:: T/ B0 L, }6 Z

" J) J4 r6 Q9 L: f! m. P  }: H  用于读取,写入,擦除和配置QSPI Flash。/ ]; C6 ^) U+ D3 J1 i
  如果不需要AHB总线访问 QSPI Flash(在内存映射模式用)。
! T# F% _+ i: Y# s: f, R( K  CPU或者DMA通过QSPI数据寄存器执行所有操作。
2 ^  E8 G* ^# K1 h; g! z6 X( @  X' l& ]
8 f: C: {8 |! |% C) A- i
在间接模式下,所有操作均通过QSPI寄存器执行,含读取和写入操作都由软件管理。 QSPI接口类似于经典的SPI接口。传输的数据通过数据寄存器与FIFO。在在此模式下,可以从大容量的外部Flash读取数据或向外部Flash写入数据,可以支持到4GB容量。
. }8 ?0 G9 J8 o. j8 J
- O! a6 I0 ]9 }% \! ]如果进行擦除或编程操作,则必须使用间接模式,并且所有操作必须由软件处理。在这种情况下,建议使用状态轮询模式,然后轮询闪存内部的状态寄存器以了解何时编程或擦除操作完成。* R, T  W% p6 V. `4 t+ W
6 _1 a/ g) q! a- E3 Y- |& X
% ]: P, P# n: ~5 t. e
& b# E( A; o& h' b
2、  状态轮询模式
% |5 u3 x9 @4 {4 K- m* u. x9 T+ z; o. \: C
在以下情况下使用状态轮询模式:
3 M8 S" o2 y0 {6 I0 L; p3 G
7 x* G0 A+ s: Y9 X* f2 r2 a  读取QSPI Flash状态寄存器。6 m  @6 p) g- l& |; `0 [
  在操作结束时自动轮询状态寄存器。
5 W3 e4 i) ]2 s4 h0 e6 G可以自动轮询内存中的指定寄存器并减轻CPU负担,例如检查擦除操作何时完成。QSPI也支持定期查询QSPI Flash,并且可以屏蔽返回的数据位,将所选位与所需值进行比较,结果比较可以通过下面两种方式处理:
& S4 H: ^4 [4 [! ?3 z8 k& t; {4 b
  AND与操作模式:如果所有选定位都匹配,则产生中断。
6 e7 X6 g2 N4 c, r OR或操作模式:如果所选位之一匹配,则产生中断$ {* I' h! G* U
# i5 J7 |+ J& A
' M& W9 c3 w+ x9 o. B* w& [) i  ?
发生匹配时,QSPI可以自动停止。
3 s7 v' J' E* ~' Z+ J: W5 k* `. u+ Q) D" C. ~/ K! s! l7 d/ D
5 g- s( k  [8 s0 \7 U+ p$ a: k

  O; ?5 G, G! \3、  内存映射模式0 Y- T" m% K+ P+ x- o
0 [- F. J1 S/ u  E) r
在以下情况下使用内存映射模式:! e/ I$ ]/ u% t. M- I5 L& h
: ?3 w' Z$ h3 }6 }0 C/ y3 Z5 {
  用于阅读操作。
% P% i7 t# \! y5 Y# U* R  像使用内部Flash一样使用外部QSPI Flash, 任何AHB总线主控都可以自主读取数据。6 B# R; D  |, u  b7 q1 i8 J3 b
  用于从外部QSPI Flash执行代码。
; }; ^0 J' i- ?: a9 i' L7 Z* q$ E+ `! c4 Q

9 n* |8 z  V' E  V5 ^QSPI接口能够管理多达256 MB的内存,在内存映射模式下地址范围是0x9000 0000到0x9FFF FFFF。' O$ T4 R; ]; e, y  ?3 z

6 T7 r, K1 N3 b7 Q! _" s78.3 QSPI总线的HAL库用法9 U6 c* ^( u  }: I7 ?  u
78.3.1 QSPI总线结构体QUADSPI_TypeDef; Y1 K* ^9 p( V; t: x
QSPI总线相关的寄存器是通过HAL库中的结构体QUADSPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
/ Z. ?2 R0 O, q  K6 k& x1 C" T" V( e! L
8 Z& k4 O1 P5 I0 `! ?
  1. typedef struct
    * [6 G/ u. L) K* G$ W* A! k8 [8 n
  2. {3 B' e9 O( W" H& D9 B0 a5 v
  3.   __IO uint32_t CR;       /*!< QUADSPI Control register,                           Address offset: 0x00 */% ~. `5 u) J% A, `/ Q9 ~6 `
  4.   __IO uint32_t DCR;      /*!< QUADSPI Device Configuration register,              Address offset: 0x04 */  g9 s( R5 \. _' b. q5 B% a/ r! H
  5.   __IO uint32_t SR;       /*!< QUADSPI Status register,                            Address offset: 0x08 */
    . ^% ]+ n1 u4 G" X9 Y3 v# n
  6.   __IO uint32_t FCR;      /*!< QUADSPI Flag Clear register,                        Address offset: 0x0C */
    ) Z- s  H4 Z# B$ ^% b, ]- S- g
  7.   __IO uint32_t DLR;      /*!< QUADSPI Data Length register,                       Address offset: 0x10 */
    . n0 U6 s7 K( e# X2 L
  8.   __IO uint32_t CCR;      /*!< QUADSPI Communication Configuration register,       Address offset: 0x14 */4 ]) s, |# t* c- j" o
  9.   __IO uint32_t AR;       /*!< QUADSPI Address register,                           Address offset: 0x18 */8 K" z% U, g) g. q
  10.   __IO uint32_t ABR;      /*!< QUADSPI Alternate Bytes register,                   Address offset: 0x1C */9 J3 m+ j% `  p1 U3 Y
  11.   __IO uint32_t DR;       /*!< QUADSPI Data register,                              Address offset: 0x20 */. N# A/ d0 L! r$ l7 U$ H$ {
  12.   __IO uint32_t PSMKR;    /*!< QUADSPI Polling Status Mask register,               Address offset: 0x24 */
    , {5 O- k8 f( s# B2 C
  13.   __IO uint32_t PSMAR;    /*!< QUADSPI Polling Status Match register,              Address offset: 0x28 */7 i3 P2 V; a# w1 b' A9 Q
  14.   __IO uint32_t PIR;      /*!< QUADSPI Polling Interval register,                  Address offset: 0x2C */
      b% K4 ^" R, L" f: g
  15.   __IO uint32_t LPTR;     /*!< QUADSPI Low Power Timeout register,                 Address offset: 0x30 */
    + Q- q4 b8 z/ z2 N4 B4 {
  16. } QUADSPI_TypeDef;
复制代码
/ e& _( @6 `6 S4 Y
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。" a) n! |9 R9 N6 n/ F7 i( G9 x
/ b* K$ o) w6 e1 ]# h  K! f6 r1 A
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:- J% i. k% M7 |7 G0 z0 Q, x
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */7 M1 Y7 c' r1 o; q
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

% e  t" P# H7 t2 k下面我们看下QSPI的定义,在stm32h743xx.h文件。, @7 @9 u5 e% _  w; v  W3 M. G2 k
* s4 {* l( w5 E; ]
  1. #define QSPI_BASE ((uint32_t)0x90000000) /*!< Base address of : QSPI memories  accessible over AXI */
    ( F5 q. W. t: r; }- ^9 d
  2. ' D9 C) n2 ^9 Y% A
  3. #define PERIPH_BASE           (0x40000000UL)
    - |% s0 \; x. u/ Z; T
  4. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)
    9 o. J7 v+ `, Z0 ], Y# A: O) d
  5.   y8 V" O  Y7 L+ |, A% b- N, F
  6. #define QSPI_R_BASE           (D1_AHB1PERIPH_BASE + 0x5000)' [( d9 p) x5 b) l  M9 Q$ D- [+ v
  7. #define DLYB_QSPI_BASE        (D1_AHB1PERIPH_BASE + 0x6000)! ^/ }/ @3 c: v2 y

  8. 3 M2 ?1 u$ @0 d+ m+ f" _8 g/ D& E
  9. #define QUADSPI               ((QUADSPI_TypeDef *) QSPI_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x520050003 L/ [6 ^( X, ~0 w: c
  10. #define DLYB_QUADSPI          ((DLYB_TypeDef *) DLYB_QSPI_BASE)
复制代码
: r& f& H7 O& ]* u% y
我们访问QSPI的CR寄存器可以采用这种形式:QUADSPI->CR= 0。
  j* ?. w3 ]  M
5 \+ w; ^8 N" [) a0 h/ V4 B0 e78.3.2 QSPI总线初始化结构体QSPI_InitTypeDef
; [4 L- h9 M7 \3 n' Y下面是QSPI总线的初始化结构体:. x  j- {1 ~3 ~" }
) k% N: W* {1 G2 ?  E
  1. typedef struct
    # x" o- {/ ^0 L2 s
  2. {
    0 B6 C0 S. h+ h. S& u
  3.   uint32_t ClockPrescaler;     
    + o* @# c( Y( l6 R. J
  4.   uint32_t FifoThreshold;      + ]) ~+ J0 u# z* I
  5.   uint32_t SampleShifting;   
    1 c  Z6 s# U- L+ _- t* \& |
  6.   uint32_t FlashSize;         
    ( N: I5 r4 v/ Y5 Q% p  P
  7.   uint32_t ChipSelectHighTime;
    4 Z! s% ~- U. s2 V, s) ^
  8.   uint32_t ClockMode;         
    % ?! b' w& s7 a5 |9 n- M
  9.   uint32_t FlashID;           5 M3 J  `. ^5 `! d* Q
  10.   uint32_t DualFlash;                                          
    # ]8 i  }; {' L, q
  11. }QSPI_InitTypeDef;
复制代码
4 z2 Y/ ?6 _4 i
下面将结构体成员逐一做个说明:- m4 m7 \1 V  }8 G& ^
, M1 @4 Y9 h, {# o/ u: [3 o+ N
  ClockPrescaler- F$ [* J2 O5 X  }
设置时钟分频,参数范围0到255。特别注意,这里是针对HCLK3作为QSPI时钟来说的。' S: G% @0 ?# t+ x5 J

/ J( @/ ~1 e9 [+ u( \) {* m  FifoThreshold* l+ P$ G$ E" [! R
用于设置FIFO阀值,仅用于间接模式,参数范围1到32,单位字节。) N7 V; ]4 t* K7 K

0 N5 q0 U; [9 \2 K% E/ o& C  SampleShifting
( J3 ^2 v4 ~1 Z% V  E! q8 K( W" f1 wQUADSPI在FLASH驱动信号后可以选择再过半个CLK周期后才对FLASH数据采样,这有利于推迟数据采样。支持的参数如下:
  Z% p; F; p( r6 h7 ^. n# M8 ~/ W; r3 I4 k
#define QSPI_SAMPLE_SHIFTING_NONE      ((uint32_t)0x00000000U)       " v% V7 R0 ]6 l, Q* [
#define QSPI_SAMPLE_SHIFTING_HALFCYCLE ((uint32_t)QUADSPI_CR_SSHIFT)
  }9 j( `- v; B$ `- H4 P( M. d  FlashSize" u& ^+ c% B) b7 t# `6 G: _* v" V8 J
Flash大小是2^(FlashSize + 1),单位字节。0 [6 f6 O2 G* f/ G
) V7 U- @. y# T3 W' z
间接模式下,最大支持的Flash大小是4GB,内存映射模式,最大支持256MB。
& f/ G+ j( s+ b+ R2 i
1 W+ N" M/ k  l8 H6 P
  1. #define SPI_POLARITY_LOW       (0x00000000UL). a& k) \+ J/ d+ F: B/ f# R
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码

/ {% g( W! D) b1 q/ j  ChipSelectHighTime
0 _5 a2 d/ |- g/ p. m/ n命令之间的CS片选至少保持的高电平时钟周期ChipSelectHighTime+1。支持的参数如下:9 ]% r" b4 n" i+ \6 ?2 }

* o6 r4 L! h) I0 r, `
  1. #define QSPI_CS_HIGH_TIME_1_CYCLE      ((uint32_t)0x00000000U)                             
    , H5 n# j( S+ i7 P, M. i
  2. #define QSPI_CS_HIGH_TIME_2_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0)                     
      f- {: o& O& Z3 a/ C
  3. #define QSPI_CS_HIGH_TIME_3_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_1)                     
    ! {$ S" s7 m0 R8 u9 z0 e& q
  4. #define QSPI_CS_HIGH_TIME_4_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0 | QUADSPI_DCR_CSHT_1) 2 f* }* O6 s: n6 q
  5. #define QSPI_CS_HIGH_TIME_5_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2)                     
    8 K9 {9 x" |+ d4 I% m
  6. #define QSPI_CS_HIGH_TIME_6_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_0)
    : r+ }* _, ]% a/ u9 u  q+ P: P' P
  7. #define QSPI_CS_HIGH_TIME_7_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_1) . e, G7 [1 K9 @
  8. #define QSPI_CS_HIGH_TIME_8_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT)   
复制代码
                5 B; q1 U' f" ]5 \8 y
  FlashID. M- R7 K; N9 N8 Y7 _+ f1 f
用于选择要操作的BANK,即用BANK1还是BANK2操作Flash。7 P& `' O: P: Y( G: |- g
) z) `; T" a( W2 N% C
  1. #define QSPI_FLASH_ID_1                ((uint32_t)0x00000000)      
    5 Q5 Z5 Q  T9 o! J. u
  2. #define QSPI_FLASH_ID_2                ((uint32_t)QUADSPI_CR_FSEL)
复制代码
1 \  R$ q: O+ s2 z
  DualFlash
: R- C, l0 Q' W8 b! ^- g7 Z1 Z用于选择是否使用双BANK。
- e5 o% J0 A5 a9 i6 `
* L( q) G& G4 _* ?3 O7 T7 v' h
  1. #define QSPI_DUALFLASH_ENABLE          ((uint32_t)QUADSPI_CR_DFM) /*!<Dual-flash mode enabled*/
    8 B$ R2 C3 N: \( I% Q
  2. #define QSPI_DUALFLASH_DISABLE         ((uint32_t)0x00000000)     /*!<Dual-flash mode disabled*/
复制代码

, n) H$ z4 G0 V+ `6 b  Q, k78.3.3 QSPI总线句柄结构体QSPI_HandleTypeDef
" q" K& i6 Z4 |0 \* V下面是QSPI总线的初始化结构体:
2 k0 X. }7 t& @1 j+ u. P  w0 ]# ?& H
  1. typedef struct
    + G7 i3 E+ F0 d2 Y3 ^
  2. {7 H9 A  y- A% }% U& Y7 J
  3.   QUADSPI_TypeDef            *Instance;        /* QSPI registers base address        */+ G6 _# q  W( U' ]3 t  A0 s
  4.   QSPI_InitTypeDef           Init;             /* QSPI communication parameters      */
    5 }8 I, H  X2 s- v4 F2 M4 F
  5.   uint8_t                    *pTxBuffPtr;      /* Pointer to QSPI Tx transfer Buffer */
    " G) X9 ?& T- K) D- q
  6.   __IO uint32_t              TxXferSize;       /* QSPI Tx Transfer size              */- L5 v5 Z+ G" n9 T( Q- B1 H. s
  7.   __IO uint32_t              TxXferCount;      /* QSPI Tx Transfer Counter           */
    " L! a8 R7 }4 a: ~0 `3 Q; k6 d
  8.   uint8_t                    *pRxBuffPtr;      /* Pointer to QSPI Rx transfer Buffer */
    . w- f  o. E+ S2 l) j) _7 Z1 w
  9.   __IO uint32_t              RxXferSize;       /* QSPI Rx Transfer size              *// w9 x7 E% s* h5 g  r7 b( a$ g
  10.   __IO uint32_t              RxXferCount;      /* QSPI Rx Transfer Counter           */' X+ K2 @7 @6 s# K) r
  11.   MDMA_HandleTypeDef         *hmdma;           /* QSPI Rx/Tx MDMA Handle parameters  */
    * ?7 n& H. |; e" c. t2 {, }& ~
  12.   __IO HAL_LockTypeDef       Lock;             /* Locking object                     */
    , [7 p5 l+ D# o) s
  13.   __IO HAL_QSPI_StateTypeDef State;            /* QSPI communication state           *// W3 p5 E+ s1 Z- N6 v' R
  14.   __IO uint32_t              ErrorCode;        /* QSPI Error code                    *// {$ G+ G% h! ]( M9 C1 S4 [
  15.   uint32_t                   Timeout;          /* Timeout for the QSPI memory access */
      ~5 ]% r: M  K2 f
  16. }QSPI_HandleTypeDef;
复制代码
3 ?  `# B- W4 P1 o2 O. P% {4 {
下面将结构体成员做个说明:, W5 K/ }3 r0 @' P6 q% @
; ?0 ?! J- V- }, }) U2 ]
  QUADSPI_TypeDef   *Instance
( l' S: B$ k$ s  }8 e6 z5 F" V" W这个参数是寄存器的例化,方便操作寄存器,比如使能QUADSPI。4 q' i* _& {$ z4 V8 N! z
" M8 K( ^0 p! z& @% o
SET_BIT(QUADSPI ->CR,  QUADSPI_CR_EN)。+ Y2 D# E7 O- S/ o  L- P7 o  R

2 u* o. h. O! ?; N* \' s, `9 ?" g, W  QSPI_InitTypeDef  Init
* G5 E; e. |$ z, |* s这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。
+ F' j' ~8 i! ]. M% X/ p! V2 Z5 |( V; L. r7 s& U
  MDMA_HandleTypeDef          *hmdma& G6 y% w( z4 \  t
用于QSPI句柄关联MDMA句柄,方便操作调用。
" S3 b( t; r8 M  G+ K# P- }% L: |# k2 z6 F5 `) D
  其它参数( t( R% b9 `2 ^& c, Z
其它参数基本都是在函数内部调用,用户基本不用管。
4 k* D+ I+ f# ^  H- m+ m. p1 e- R2 I* ?; ]4 Z8 \# n- a
78.3.4 QSPI命令结构体QSPI_CommandTypeDef
" }) L/ L1 K/ {' f下面是QSPI总线的命名结构体:
7 \, R8 c* F; {0 T6 X+ p! c' C5 g- Q( `; p( o; z# P: k
  1. typedef struct
    & ?* H9 v7 ^. q/ g
  2. {
    ( Y8 r+ d+ |+ |, N( G
  3.   uint32_t Instruction;        4 x/ S8 k0 n" a9 V. j* Z  O
  4.   uint32_t Address;           4 A4 D4 s4 j% W5 d
  5.   uint32_t AlternateBytes;     
    # S# V4 F  H: g  U3 G- P. ~
  6.   uint32_t AddressSize;      
    6 n& z5 E; g; }
  7.   uint32_t AlternateBytesSize;
    / z# O& _" Y0 w7 j# K) Z! u
  8.   uint32_t DummyCycles;      
    7 B2 T0 n8 O7 x/ n
  9.   uint32_t InstructionMode;  + r; `! S: V$ B% R, @
  10.   uint32_t AddressMode;      
    2 j+ ^0 ]0 V5 J, X* l5 k
  11.   uint32_t AlternateByteMode;   X8 R  P2 y! `4 [
  12.   uint32_t DataMode;         & r2 J& g0 r* e6 b. l8 g- q. ?
  13.   uint32_t NbData;          9 H, q& n. q- c3 F% O' t/ X
  14.   uint32_t DdrMode;           8 T1 l1 T: B4 N; S
  15.   uint32_t DdrHoldHalfCycle;  1 A0 M+ n* f( x8 k  m5 U: _
  16.   uint32_t SIOOMode;         
    ! F7 D; J. d$ U  j. Z8 B
  17. }QSPI_CommandTypeDef;
复制代码

: R, E; u  Q7 T/ C/ w; O0 O下面将结构体成员逐一做个说明:* N; I7 a7 ?5 d# E

; i+ {9 t% a" A' Z9 _  O  Instruction# ^1 W) v; t% B+ v' m8 P- h) ^  m
设置要发送的指令,参数范围0x00到0xFF。5 B# J5 {6 Z. z' p, k0 S1 y6 W% f
& N! ~& x8 i; Q6 @5 D- h
  Address0 t1 z8 v5 P: N4 S' y0 }+ ?' i
设置要发送的地址,地址由是1个字节到4个字节来表示,参数范围0x0 到 0xFFFFFFFF。6 F7 i2 @9 d, S& r5 F2 [

& p8 h+ k' r# m  AddressSize/ C1 J$ e3 J. L4 \6 r+ T
地址大小,即表示此地址需要的字节数,支持的参数如下:, E& p$ b9 {8 ~/ A$ c+ X* h8 S

0 [/ W! y$ y! c, {  Z
  1. #define QSPI_ADDRESS_8_BITS            ((uint32_t)0x00000000)           /*!<8-bit address*/% ]: C" A- d6 t) `8 E; R" l
  2. #define QSPI_ADDRESS_16_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_0) /*!<16-bit address*/
    ' f; P$ F7 g+ j* j! o5 z: G
  3. #define QSPI_ADDRESS_24_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_1) /*!<24-bit address*/8 m1 ~- s, q% D# \6 j9 E
  4. #define QSPI_ADDRESS_32_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE)   /*!<32-bit address*/
复制代码

' Y4 U5 `* Y* }4 ]) M- @  AlternateBytesSize
  K% R1 @0 n" r- o* Z: b$ M交替字节大小,支持的参数如下:
6 b6 G  ]( a3 k6 V8 d4 R( E/ S. l8 E; S) l6 p5 |3 X5 s! b
  1. #define QSPI_ALTERNATE_BYTES_8_BITS    ((uint32_t)0x00000000)           /*!<8-bit alternate bytes*/
    + I& v" F0 }; t
  2. #define QSPI_ALTERNATE_BYTES_16_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_0) /*!<16-bit alternate bytes*/: m! z6 p9 S! w2 V0 ~8 E
  3. #define QSPI_ALTERNATE_BYTES_24_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_1) /*!<24-bit alternate bytes*/
    8 K" u. x! G* g2 |/ v$ C
  4. #define QSPI_ALTERNATE_BYTES_32_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE)   /*!<32-bit alternate bytes*/
复制代码

! n6 S1 m! ]' y" [& F% N& Q, ~  DummyCycles3 L1 M+ l/ c3 v, ^; ?) R
执行空周期个数,参数范围0到31:
1 m0 V% @9 O# p% L4 }& Z1 H. F' V: I8 p: Q( E7 B
  InstructionMode; _+ A) X% n+ N  A4 B3 g1 H/ [. i
指令阶段需要几线模式:
* ~" l1 F) D: q1 y! d# O. t# ?5 [7 o: d
  1. #define QSPI_INSTRUCTION_NONE          ((uint32_t)0x00000000)          /*!<No instruction*/
    ( D& O" Z1 U& V
  2. #define QSPI_INSTRUCTION_1_LINE        ((uint32_t)QUADSPI_CCR_IMODE_0) /*!<Instruction on a single line*/( K! E3 f4 _7 l1 ^- T% B3 |
  3. #define QSPI_INSTRUCTION_2_LINES       ((uint32_t)QUADSPI_CCR_IMODE_1) /*!<Instruction on two lines*/
    : u* _' M% l$ l
  4. #define QSPI_INSTRUCTION_4_LINES       ((uint32_t)QUADSPI_CCR_IMODE)   /*!<Instruction on four lines*/
复制代码
( S/ X; F: C7 s2 {
  AddressMode1 u) p9 F0 Y( r4 q" Q
地址阶段需要几线模式:# O1 R7 h+ j2 m8 _2 v; p, D7 U+ m

! J+ z6 v+ d" w) T
  1. #define QSPI_ADDRESS_NONE              ((uint32_t)0x00000000)           /*!<No address*/
    % _2 @4 r+ n2 g8 X
  2. #define QSPI_ADDRESS_1_LINE            ((uint32_t)QUADSPI_CCR_ADMODE_0) /*!<Address on a single line*/
    1 ?6 T! }! |9 L
  3. #define QSPI_ADDRESS_2_LINES           ((uint32_t)QUADSPI_CCR_ADMODE_1) /*!<Address on two lines*/
      T# a- {7 x% K  u& q$ s
  4. #define QSPI_ADDRESS_4_LINES           ((uint32_t)QUADSPI_CCR_ADMODE)   /*!<Address on four lines*/
复制代码
+ p5 b3 D. `& V/ {6 S; l
  AlternateByteMode
% U) v8 ]% }$ ?交替字节阶段需要几线模式:' q8 k/ I' D9 l5 @. A8 X7 B/ }( k

+ W/ h8 [% g: x9 C/ O2 A' J
  1. #define QSPI_ALTERNATE_BYTES_NONE      ((uint32_t)0x00000000)           /*!<No alternate bytes*/5 s- W! n6 ^+ \+ o+ D! |7 B
  2. #define QSPI_ALTERNATE_BYTES_1_LINE    ((uint32_t)QUADSPI_CCR_ABMODE_0) /*!<Alternate bytes on a single line*/+ S! l2 F1 O5 U8 [) S
  3. #define QSPI_ALTERNATE_BYTES_2_LINES   ((uint32_t)QUADSPI_CCR_ABMODE_1) /*!<Alternate bytes on two lines*/
    + d  Q1 P6 k5 y: l
  4. #define QSPI_ALTERNATE_BYTES_4_LINES   ((uint32_t)QUADSPI_CCR_ABMODE)   /*!<Alternate bytes on four lines*/
复制代码
) Y# S$ ^4 [& _( m) r
  DataMode: C. ^1 Q( g. u8 l
数据阶段需要几线模式:
. Y; A5 f+ ]1 W. p! W- K2 _' s) z- L0 N( V$ t
  1. #define QSPI_DATA_NONE                 ((uint32_t)0X00000000)           /*!<No data*/
    7 x" ^% i% v/ E; J
  2. #define QSPI_DATA_1_LINE               ((uint32_t)QUADSPI_CCR_DMODE_0) /*!<Data on a single line*/
    + `$ {6 g! O9 `6 Z. h. O- p, b
  3. #define QSPI_DATA_2_LINES              ((uint32_t)QUADSPI_CCR_DMODE_1) /*!<Data on two lines*/- |3 D5 w/ e  L! g' G; Q
  4. #define QSPI_DATA_4_LINES              ((uint32_t)QUADSPI_CCR_DMODE)   /*!<Data on four lines*/
复制代码

7 i3 d9 I* g. |' p/ |9 I4 a. o  NbData
6 k9 r7 j% j9 K7 a要传输的数据大小,参数范围0 到 0xFFFFFFFF,如果设置为0表示不定长,直到存储器末尾。
/ G4 u, |" M7 Z7 }  @+ H5 h0 N" g. S( W& r1 t/ h/ K
  DdrMode
& A. A; [! C% s. \' q用于设置是否使能DDR模式。数据阶段,交替字节阶段和数据传输阶段可以使用DDR模式。支持的参数如下:
! _$ [0 {) T8 ~" A$ T9 Z1 w2 M1 h! w" ?+ k
  1. #define QSPI_DDR_MODE_DISABLE          ((uint32_t)0x00000000)       /*!<Double data rate mode disabled*/; q" A- J8 O7 a: r6 }) S: g9 i
  2. #define QSPI_DDR_MODE_ENABLE           ((uint32_t)QUADSPI_CCR_DDRM) /*!<Double data rate mode enabled*/
复制代码

2 r; b) C2 S" K& _  DdrHoldHalfCycle3 E* Y# j: ?/ \& \7 g
DDR模式下,用于设置延迟半个时钟周期再做数据输出。
: f6 R8 `+ S0 C' H+ f% H9 g' d8 [2 {- m: A) u! ?4 ]/ D
  1. #define QSPI_DDR_HHC_ANALOG_DELAY      ((uint32_t)0x00000000)      % K+ g6 }! P- E4 M; l5 O: L* n3 w
  2. #define QSPI_DDR_HHC_HALF_CLK_DELAY    ((uint32_t)QUADSPI_CCR_DHHC)
复制代码
' o7 ^  a  r: k6 C. ~/ O* m0 U0 n
  SIOOMode( n) a- c9 p, f4 \+ b
设置仅发送一次指令还是每次操作都发送指令,支持的参数如下:2 O  E7 U% y1 b/ @; X

9 A4 I+ E) m  ]
  1. #define QSPI_SIOO_INST_EVERY_CMD       ((uint32_t)0x00000000)     # s9 Q! e# R/ I$ L) m6 B9 [5 k" V
  2. #define QSPI_SIOO_INST_ONLY_FIRST_CMD  ((uint32_t)QUADSPI_CCR_SIOO)
复制代码

" F, w: }4 t) s) Q- H  f3 w78.3.5 QSPI自动查询结构体QSPI_AutoPollingTypeDef
( f& h( X: X- [/ \' C1 {" e8 [下面是QSPI总线自动查询结构体:; f$ X: X' d. U5 U% A
6 ]# p* M' w* K/ i- i8 _) z& Y$ z
  1. typedef struct
    , F  d- _& t4 o3 i% R$ F
  2. {% \5 j, x, q8 h: m
  3.   uint32_t Match;             # T1 ?+ I/ e1 `) X# b/ V
  4.   uint32_t Mask;            
    ( d, T( d9 }2 C2 i% |$ |& Y# G6 @
  5.   uint32_t Interval;         2 G& w0 [( W( T* w
  6.   uint32_t StatusBytesSize;    3 Y1 s4 A8 O! U5 z) _7 Z# ]$ a
  7.   uint32_t MatchMode;       5 J" d1 E& o3 d
  8.   uint32_t AutomaticStop;     # L7 A" L* `* D
  9. }QSPI_AutoPollingTypeDef;
复制代码

6 }. j: I! b& Y3 I4 V: x下面将结构体成员逐一做个说明:
1 h% q+ T7 y) z3 b  I0 a1 H% n3 v& F* ]" r" {  B. G: U
  Match
; J9 L" g, F/ u' {$ x参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器的值与此参数成员值做匹配。参数范围0x0 到 0xFFFFFFFF。
6 S% ^  a- ^$ @2 R
# [7 ?* \, w8 o6 u* w  Mask" E9 u" t3 U  r# I
用于设置屏蔽位,比如Mask = 0x01,表示仅保留bit0的数值,其它bit忽略。参数范围0x0 到 0xFFFFFFFF。7 e6 R7 c$ e0 z) L/ G  P+ x( m* T

. @4 S2 [# F" B2 m8 M* A6 |3 O  Interval
- S, y8 ^# v; U, G% h3 a指定自动轮询阶段两次读取之间的时钟周期数。参数范围0 到 0xFFFF。0 v' h& ?( g  L* K$ U/ @3 Z

) W0 d0 [% d; o  StatusBytesSize4 U  U% a. L/ u0 N  X0 ]1 f
用于设置状态寄存器大小,参数范围1到4个字节。
$ [  f# _6 `( n/ ]4 v/ @/ ~  ]4 z0 b" c5 k2 l. E
  MatchMode
  r+ N( f! @  H参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器完全与参数成员Match一样(与操作的含义)或者任意一个bit的值与参数成员Match中一个bit的值一样(或操作的含义),比如Mask = 0x01,Match=0x00,MatchMode=与操作,表示不断查询状态寄存器bit0,等待其为0。
# O8 Q* l* w, R
$ u* u/ S8 h) Z1 [MatchMode支持的参数成员如下:
' f/ B9 G3 I- \; b0 H
  H7 h/ P5 K% C$ `3 ^4 D
  1. #define QSPI_MATCH_MODE_AND            ((uint32_t)0x00000000)     /*!<AND match mode between unmasked bits*/
      _  L& v& P1 u  F/ n; @7 w$ M
  2. #define QSPI_MATCH_MODE_OR             ((uint32_t)QUADSPI_CR_PMM) /*!<OR match mode between unmasked bits*/
复制代码
: n6 r/ P( d/ L# @# R
  AutomaticStop
' C, q7 U7 v  X+ V5 ^8 k3 @1 q当与参数成员Match匹配时,自动停止检测。+ B" }- H  t1 t/ E# m

" C1 s% Q7 l9 n78.3.6 QSPI内存映射结构体QSPI_MemoryMappedTypeDef2 M( G9 u0 E1 h: e/ F) x' X, T
下面是QSPI总线的内存映射结构体:( X# I" D  u% e) |8 k

. w; L9 N5 Y/ R0 g
  1. typedef struct
    9 A9 F+ W' N" O) [2 p* m
  2. {
    8 {9 A& Q; ?  C% m$ `5 F! `
  3.   uint32_t TimeOutPeriod;   
    . F" K* V. L+ t, a- o& c) F
  4.   uint32_t TimeOutActivation;  1 e& a4 W: r$ p6 ?( \" F8 A9 Z
  5. }QSPI_MemoryMappedTypeDef;  
复制代码

2 S' ^, f) k3 r& l. c) F下面将结构体成员逐一做个说明:
: ?% t  Y  {: P) y
* x7 a+ T) i9 \! {  TimeOutPeriod
$ i6 ~; U  f2 h7 |2 q) IFIFO满时,释放芯片选择之前要等待的时钟周期数。参数范围0到0xFFFF。
4 k% Z7 i$ E! Q# }, G# F: [2 ]5 g) K" d; \+ [0 z3 C
  TimeOutActivation
# b9 c1 v, _, Q指定是否启用超时计数器以释放芯片选择,支持的参数成员如下:
7 D, S: @2 c5 w9 Y5 b( {" U) `, J4 T! _+ k7 T. g- J1 Q0 y5 V  }
  1. #define QSPI_TIMEOUT_COUNTER_DISABLE   ((uint32_t)0x00000000)     " _$ L- s6 N+ S
  2. #define QSPI_TIMEOUT_COUNTER_ENABLE    ((uint32_t)QUADSPI_CR_TCEN)
复制代码
: t4 W% e6 H# ^/ m% [5 q
78.4 QSPI总线源文件stm32h7xx_hal_qspi.c7 s( R$ t" X9 @/ I
此文件涉及到的函数较多,这里把几个常用的函数做个说明:% ^8 Q" J5 e1 r+ D3 X! f4 ?
9 e9 Y1 i" F( d' F
  HAL_QSPI_Init3 o* s- P: V/ b
  HAL_QSPI_DeInit) f2 ]# U5 e1 F8 v* h) z- j
  HAL_QSPI_Command# g- |! l3 ^+ i- P+ n# l
  HAL_QSPI_Command_IT
. B( f" m6 o3 Y, S: y. O  HAL_QSPI_AutoPolling
) F$ }) I2 _) E$ B9 j  HAL_QSPI_AutoPolling_IT) p& T! H7 ^4 x$ Y' W- {
  HAL_QSPI_Transmit6 p* y$ }7 M5 W1 O- V3 C
  HAL_QSPI_Receive( ?9 k3 n; H+ ?: T, N+ m! |* f
  HAL_QSPI_Transmit_DMA
2 _2 I  u- e" C5 s$ @3 j  HAL_QSPI_Receive_DMA, s$ p+ n; Z5 `, u! A
  HAL_QSPI_MemoryMapped
/ _9 x# S0 R8 I* T! T& {0 g+ @1 s78.4.1 函数HAL_QSPI_Init
4 i. I4 D3 f4 ^函数原型:
; R8 D* T: R& ?% V. i/ f0 n
. P$ H5 K1 n5 ?+ B, V, w0 T% D
  1. HAL_StatusTypeDef HAL_QSPI_Init(QSPI_HandleTypeDef *hqspi)
    & h/ q9 q$ g! u2 x' z9 ~" \
  2. {
    " C& `) l" W) s& W) w( B1 g
  3.   HAL_StatusTypeDef status;. B6 |  e4 F1 D2 P  z. t5 d. Z
  4.   uint32_t tickstart = HAL_GetTick();& H" @1 P* ~0 t

  5. 7 S% ]+ b5 S6 B0 i
  6.   /* 检测句柄是否有效 */
    + B  H7 T0 h% K! d' X
  7.   if(hqspi == NULL)5 p, f. Q& ~  V1 L1 s
  8.   {
    , K' m7 ^* x. j3 A; F* F
  9.     return HAL_ERROR;3 {6 o$ B1 z6 m* W% m, Y
  10.   }
    ) ]* q. A! G  P6 q5 R" a+ o
  11. 8 j$ Z$ ?, B* o$ Y
  12.   /* 检查参数是否有效 */# S1 ~7 D$ l0 ?
  13.   assert_param(IS_QSPI_ALL_INSTANCE(hqspi->Instance));& @' N: l& c7 l- [/ {, S' f: i6 @
  14.   assert_param(IS_QSPI_CLOCK_PRESCALER(hqspi->Init.ClockPrescaler));
    % u, ?  R" t9 I( g# s
  15.   assert_param(IS_QSPI_FIFO_THRESHOLD(hqspi->Init.FifoThreshold));
    $ Z* `/ @! u- v) \
  16.   assert_param(IS_QSPI_SSHIFT(hqspi->Init.SampleShifting));1 j8 i0 M6 _0 ?7 ?' K
  17.   assert_param(IS_QSPI_FLASH_SIZE(hqspi->Init.FlashSize));% v8 ?4 F7 y  Y, o: w% V8 ^* @/ y
  18.   assert_param(IS_QSPI_CS_HIGH_TIME(hqspi->Init.ChipSelectHighTime));* Q" E! ~( s, @( ~# [" t" _
  19.   assert_param(IS_QSPI_CLOCK_MODE(hqspi->Init.ClockMode));) U. j# ~# L" z! |# t6 w3 c
  20.   assert_param(IS_QSPI_DUAL_FLASH_MODE(hqspi->Init.DualFlash));
    6 z+ G' Q* O& W$ d% }& e
  21. * W% Z% E# q# D+ w
  22.   if (hqspi->Init.DualFlash != QSPI_DUALFLASH_ENABLE ), G# D7 Z5 v* e1 i: @# s. S; N# j; F
  23.   {2 N. Z, d$ t- p( }: g6 b* Z
  24.     assert_param(IS_QSPI_FLASH_ID(hqspi->Init.FlashID));
    # g/ S/ }5 Y2 h1 x1 I
  25.   }* R& ]: M9 I; F& ]

  26. 4 ?. I, v" N7 o+ U( I! r
  27.   if(hqspi->State == HAL_QSPI_STATE_RESET)
    ; R' p4 j: @) v- i- N3 r$ E
  28.   {
    & d4 s; U  |8 M/ a
  29. 1 R9 M, J& j; l. v; w5 t2 d& H
  30. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1)
    ! T  B7 `" c3 @! x! [
  31.     /* 复位状态,设置默认的回调 */
    1 M% ?" d$ A. _9 d; R( W) t, q* W" J$ t
  32.     hqspi->ErrorCallback         = HAL_QSPI_ErrorCallback;
    1 M; P. r4 A* n/ N/ z" u" ~
  33.     hqspi->AbortCpltCallback     = HAL_QSPI_AbortCpltCallback;. O, S5 M4 W8 {9 V
  34.     hqspi->FifoThresholdCallback = HAL_QSPI_FifoThresholdCallback;' M( m5 i. z; d! W2 ^5 {$ v% s' o9 L
  35.     hqspi->CmdCpltCallback       = HAL_QSPI_CmdCpltCallback;1 Y" f: o$ A5 ~
  36.     hqspi->RxCpltCallback        = HAL_QSPI_RxCpltCallback;
    7 y6 S, n/ `2 w" c$ D1 A
  37.     hqspi->TxCpltCallback        = HAL_QSPI_TxCpltCallback;2 H0 `9 @, q" m+ S
  38.     hqspi->StatusMatchCallback   = HAL_QSPI_StatusMatchCallback;
    8 b6 ^8 a8 P: V
  39.     hqspi->TimeOutCallback       = HAL_QSPI_TimeOutCallback;" F& K  ?7 r' J! h- T
  40. 4 J6 x0 f$ Q% O; C! h/ Z* L" A# B
  41.     if(hqspi->MspInitCallback == NULL)
      Z! f9 z% B2 R3 {: b, H
  42.     {
    $ j/ ], X+ S$ W) l9 U
  43.       hqspi->MspInitCallback = HAL_QSPI_MspInit;
    4 {' }7 }& n) _, J  K- b! {- m
  44.     }1 t) k- L3 A, w- R8 W6 u

  45. & E2 a  j7 n5 l, t9 S" y3 F. D3 O
  46.     /* 初始化底层硬件 */
    - g9 L8 u. y0 t8 g$ V
  47.     hqspi->MspInitCallback(hqspi);6 f" v8 j6 O  k. D" d4 D' I
  48. #else
    $ p/ A6 W1 w4 Y" s8 E6 ?1 J( {& h
  49.     /* 初始化: GPIO, CLOCK */
    % t" h6 F* ^; |0 Y
  50.     HAL_QSPI_MspInit(hqspi);  f( o2 Y, b. Q  |  C) R
  51. #endif2 r2 b& K4 ?! q2 Q

  52. . A1 K% _0 n& N/ u8 H1 [
  53.     /* 配置QSPI内存访问默认的溢出时间 */
    & f, j. v; N. \8 K6 B1 b8 I
  54.     HAL_QSPI_SetTimeout(hqspi, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
    - y. D+ _( n( r. g
  55.   }
    6 E! H0 e: S! z
  56. ; g$ V# V2 m8 h5 Z$ J) q7 S' t( e
  57.   /* 配置QSPI FIFO阀值 */
      k/ E2 J, B* [: Y9 c3 [! M
  58.   MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_FTHRES,+ K) @" l/ r  K5 \* j
  59.              ((hqspi->Init.FifoThreshold - 1U) << QUADSPI_CR_FTHRES_Pos));' M# W( z4 _% @; F$ {9 A, o
  60. 0 c0 f. I# h  e
  61.   /* 等BUSY标志复位 */5 e& g, s5 J) Q
  62.   status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);
    - H+ R) H, N( Z1 z3 l6 R3 W

  63. 3 L' ?  b/ l" I
  64.   if(status == HAL_OK)
    0 s5 ^2 d. t3 A  J, J. G: Y6 f: N
  65.   {* f* D, o1 `4 \4 S& q7 J0 R
  66.     /* 配置QSPI时钟分频和采样延迟 */
    $ w) K/ A; l3 n
  67. MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PRESCALER | QUADSPI_CR_SSHIFT | QUADSPI_CR_FSEL |' Z; }2 A6 `8 f& w: I4 G/ T; A
  68. QUADSPI_CR_DFM),
    + Y9 ]$ K: g- j4 M2 U( p1 _
  69.                ((hqspi->Init.ClockPrescaler << QUADSPI_CR_PRESCALER_Pos) |
    : @1 ~' H( s8 p2 N
  70.                 hqspi->Init.SampleShifting  | hqspi->Init.FlashID | hqspi->Init.DualFlash));
    / U4 U! J' ^% H' L

  71. 1 b) P) ^  H1 F$ s! A
  72.     /* 配置QSPI Flash大小,CS片选高电平时间和时钟模式 */
    . B  W- _, ]5 t9 f' c, d' l$ V1 Y
  73.     MODIFY_REG(hqspi->Instance->DCR, (QUADSPI_DCR_FSIZE | QUADSPI_DCR_CSHT | QUADSPI_DCR_CKMODE),: ~5 U9 l: w( d% R
  74.                ((hqspi->Init.FlashSize << QUADSPI_DCR_FSIZE_Pos) |) N4 l, r6 p2 b0 C' F: [
  75.                 hqspi->Init.ChipSelectHighTime | hqspi->Init.ClockMode));7 O5 Y* F2 \6 B7 Z' f# Y; g$ w* z

  76. 9 k! m. L, @$ V( J5 e  t& h. t6 ^
  77.     /* 时钟QSPI外设 */
    * v/ R% q" q3 p' _2 d7 r/ ]; T0 W! d3 G
  78.     __HAL_QSPI_ENABLE(hqspi);9 W+ C; B& Q( z
  79. 0 ]" e5 ?! O: l% E# u9 ^
  80.     /* 设置QSPI无错误代码 */5 x+ j: R3 M# U7 ?; K
  81.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;( G% ]9 M/ v8 b8 s! V! m

  82. / b% [1 h9 {0 _4 E. ^
  83.     /* 初始化QSPI状态就绪 */3 E2 N! U8 y0 v' O" m
  84.     hqspi->State = HAL_QSPI_STATE_READY;' \" P/ g+ |0 w9 }
  85.   }
    1 p" m) Q8 ?5 l5 N# p

  86. 2 }5 D3 R* a9 j) F% |+ h; s
  87.   /* 返回状态信息 */( J$ n' K/ G; o# [( ^# K  M
  88.   return status;8 B$ ]& q1 M+ h2 b8 c( k6 |( C
  89. }
复制代码

- t( h8 e' A4 ?1 X; k+ Z- v5 A函数描述:
! `  W, S; r7 U! R- M4 S( N0 T& T) ]5 u$ c8 w
此函数用于初始化QSPI。
" C0 q, h( U- c0 i/ v7 X6 e# Y) F1 `- l$ I9 m' p# k# g9 I
函数参数:: c" l# q- [( D7 R( p; Z
& @/ ]9 l4 \9 Z% e5 A( D
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,详见本章3.3小节。" Z2 y% g$ V# S
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
3 M% ~( q5 R  R) J# b/ l注意事项:
/ W' O/ L+ T8 A
3 D+ {: X* U8 I, q+ q+ R7 K/ B函数HAL_QSPI_MspInit用于初始化QSPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。5 U7 b" h" B& F4 ]) g  d
如果形参hqspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量QSPI_HandleTypeDef SpiHandle。
% w  a6 {/ R! z4 q# G5 A* q! S! R对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_QSPI_STATE_RESET  = 0x00U。
9 g5 n% @. M* m2 S. c* f$ t( u# k$ u
解决办法有三1 x3 K. Z5 _; [% G

, L! z7 f+ ~; l) M+ O方法1:用户自己初始化QSPI和涉及到的GPIO等。
2 w9 G3 @( F! {' t4 h) ?# F; h
! o& C( z/ ?) B3 q$ R0 k方法2:定义QSPI_HandleTypeDef QspiHandle为全局变量。7 L/ E& @) Y! X( j( x
8 {" ^( M) v4 O4 R* X
方法3:下面的方法' R' U: [. }, _* e4 P5 G" X! e+ X

3 {8 e1 B! t+ }- }5 x
  1. if(HAL_QSPI_DeInit(&QspiHandle) != HAL_OK)& V! Q# E8 V! @! m
  2. {+ k2 e" a1 v8 h6 d+ u
  3.     Error_Handler();
    3 ]4 x/ w1 q+ O1 f' v& c. ~
  4. }  - O, T7 U8 }5 |6 d1 H  r1 n
  5. if(HAL_QSPI_Init(&QspiHandle) != HAL_OK)
    * ?) q, W; m. W2 S5 C" B2 d* B' Y
  6. {8 K3 n' T- z. x: `
  7.     Error_Handler();
    4 W* C, j, }( u4 f  M5 X, e) o
  8. }
复制代码
' e) l; p1 U2 w: o2 ]- Q" e) q! b
使用举例:# J6 e( _0 a6 [$ e/ G8 N% u

+ e% c0 m9 t1 J0 F6 y5 k2 C. C
  1. /*
    * y8 e+ G! P0 E* h+ f8 W+ z3 ]
  2. *********************************************************************************************************
    * W7 Y( l* U; k# U3 ^( N1 r/ _
  3. *    函 数 名: bsp_InitQSPI_W25Q256
    * D6 K2 Y  `+ t& p' A
  4. *    功能说明: QSPI Flash硬件初始化,配置基本参数
    . i2 W% Q! `) D1 z. l; g# r; a
  5. *    形    参: 无5 B0 V' Y$ H) L4 {4 }! q% ~
  6. *    返 回 值: 无% \2 M. R% ~* }7 F
  7. *********************************************************************************************************
    % L  q- [+ e+ k; V3 w0 |$ D
  8. */
    - k, R# a3 `# G9 ?  B4 y7 g) j, b
  9. void bsp_InitQSPI_W25Q256(void)
    9 q7 Z: y9 E: I) d. O1 m
  10. {
    3 d$ E0 i& r( a' D! P" Q
  11.     /* 复位QSPI */
    4 E# k* G% I# w( g8 D
  12.     QSPIHandle.Instance = QUADSPI;% x* l/ _& V3 U2 Y% r3 h
  13.     if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)
    : P: {3 o, S% f
  14.     {; K2 ~+ F. }. L. D& b
  15.         Error_Handler(__FILE__, __LINE__);' @2 ]3 C7 [! k* ^& z) `7 b0 n
  16.     }0 Q2 U1 C$ ^4 U: k
  17. : X% C; Q! L" N8 w+ e3 G& X2 {
  18.     /* 设置时钟速度,QSPI clock = 200MHz / (ClockPrescaler+1) = 100MHz */
    . @& @+ P' J4 [" n& n
  19.     QSPIHandle.Init.ClockPrescaler  = 1;  
    / V9 @2 a: x! L8 v7 j1 a

  20. . L( V' c7 J7 K7 r/ a8 Q
  21.     /* 设置FIFO阀值,范围1 - 32 */; c4 [% u  O( a3 B1 s5 v0 i
  22.     QSPIHandle.Init.FifoThreshold   = 32;
    5 i' z/ s) {8 T: W; B
  23. 3 J2 x: S8 _4 x  \3 [2 ^
  24.     /*
    & S' A* F- z2 W" z- F$ s! Z& o
  25.         QUADSPI在FLASH驱动信号后过半个CLK周期才对FLASH驱动的数据采样。
    # J9 E: w7 z$ m# C; ~
  26.         在外部信号延迟时,这有利于推迟数据采样。1 \& m# L9 w% G* k+ y- M
  27.     */
    % ?# G' l! h# i% m/ c, w
  28.     QSPIHandle.Init.SampleShifting  = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
    $ k" r* `7 m! x1 |) \3 b) Q4 |
  29. 1 \8 C/ ~& a" w/ J
  30.     /*Flash大小是2^(FlashSize + 1) = 2^25 = 32MB */
    " I9 l+ }" f' @( C0 j  i6 X
  31.     //QSPI_FLASH_SIZE - 1; 需要扩大一倍,否则内存映射方位最后1个地址时,会异常。
    5 u1 F% F/ C3 A- P2 p
  32.     QSPIHandle.Init.FlashSize       = QSPI_FLASH_SIZE; $ z; a- s. {& Y

  33. ; _; P- g3 w, o" o
  34.     /* 命令之间的CS片选至少保持2个时钟周期的高电平 */" f# A6 u3 Q' B8 S" B
  35.     QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;' @5 w) t. `/ G+ r+ _; `
  36. : Y1 O$ X/ J( E: Q
  37.     /*
    ) t3 n- f! N+ _4 J4 I
  38.        MODE0: 表示片选信号空闲期间,CLK时钟信号是低电平
    & f, }' S4 U. a9 ~* a
  39.        MODE3: 表示片选信号空闲期间,CLK时钟信号是高电平0 P7 {- H/ _  z1 t7 n
  40.     */
    2 Q# y3 u7 p4 P+ U7 x
  41.     QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
    % [2 p9 Z. n" S, Y
  42. 0 K4 E9 c+ ]( L- j0 ^1 ]" f2 }
  43.     /* QSPI有两个BANK,这里使用的BANK1 */
    4 E1 p% q, x. f" z; d/ d
  44.     QSPIHandle.Init.FlashID   = QSPI_FLASH_ID_1;
    4 b- s, `7 F" B' x- k

  45. + F* D; H' p- w; r1 i4 }
  46.     /* V7开发板仅使用了BANK1,这里是禁止双BANK */
    2 C) J% H$ I% ^( D1 T
  47.     QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE;; b- f6 m& d; F6 T) n' w3 y
  48. $ |) t0 J9 O$ }. D7 o
  49.     /* 初始化配置QSPI */9 f4 ^# x( G* X
  50.     if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)$ ?( Q7 b  n3 ?, g
  51.     {
    3 U0 V& O9 G6 U$ o
  52.         Error_Handler(__FILE__, __LINE__);; K2 {5 W1 J7 O8 D
  53.     }    ; k* ?1 H9 z, Y! f2 K
  54. }
复制代码
8 k- C1 K2 _7 ?4 W) T
78.4.2 函数HAL_QSPI_DeInit5 K& i) V1 a( s" e* ^
函数原型:5 D+ _( M3 ^0 b" m

3 [1 |% R6 {7 a7 I  {  ?1 z9 L
  1. HAL_StatusTypeDef HAL_QSPI_DeInit(QSPI_HandleTypeDef *hqspi)
    * m! v4 u& X( m: o  E
  2. {
    " u. }: x" y! \! t
  3.   /* 检测QSPI句柄 */
    5 W+ x* B; c3 t+ I) i& j0 U% Z# }
  4.   if(hqspi == NULL)( \: F3 b& {" f
  5.   {
    * f# ]1 o7 o, D, K* z, Y0 R
  6.     return HAL_ERROR;
    1 l" v  s" e$ U! c: i# l% ~: |# l5 _
  7.   }
    + _/ c2 v) @; p: ?) H
  8. 5 ^5 t6 b9 c1 V5 j
  9.   /* 禁止QSPI外设时钟 */2 @+ H3 s8 `7 B7 b9 L
  10.   __HAL_QSPI_DISABLE(hqspi);
    ! f! t9 E7 Y# k4 Q3 Y+ ?9 B

  11.   o% u! a/ p4 N, \. k/ s# A
  12. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1)3 h4 D$ Z+ [' u  o" o
  13.   if(hqspi->MspDeInitCallback == NULL). `; j! k7 }$ q9 m3 v
  14.   {# V$ f/ V, n! C( W1 u7 f$ F8 P8 e
  15.     hqspi->MspDeInitCallback = HAL_QSPI_MspDeInit;6 _! c' }8 T7 {; M
  16.   }* ]0 h# X  v% X
  17. % K. q1 h) f9 B  P
  18.   /* 复位硬件底层 */
    / m3 }/ s1 z4 M) d2 c
  19.   hqspi->MspDeInitCallback(hqspi);
    9 g5 T. L; E! H) P
  20. #else
    7 P8 B; @: O8 \, X' b2 B
  21.   /* 复位: GPIO, CLOCK, NVIC... */! [, l- F" J0 B: e! C6 i1 }
  22.   HAL_QSPI_MspDeInit(hqspi);, y+ I% s. Y( Q7 p) L# a0 c
  23. #endif$ O4 m- s+ w; N. q0 _

  24. 2 I) g1 m5 T' H3 \# R2 s
  25.   /* 设置无错误 Set QSPI error code to none */& \( e& e& O4 e. H% i2 u
  26.   hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    3 ~; S0 ?( n. A- H3 b
  27. 0 }0 ]* y( ]$ I% {
  28.   /* 设置QSPI状态为复位 */
    2 J2 ^) R9 b" L9 A9 y
  29.   hqspi->State = HAL_QSPI_STATE_RESET;
    + }& P; L- a+ g  d* `9 o" l

  30. $ N5 y, O& S# y+ K3 q, A0 N
  31.   return HAL_OK;" t( i) L8 W. f% z  W
  32. }
复制代码

. n& @5 o8 }$ b6 h( Z4 @! u# t函数描述:
- R7 a/ j& _' l! f/ G' V2 c) }( I1 n- M
用于复位QSPI总线初始化。$ z9 R- R$ m  S4 o
5 X* [" p3 l0 q* V7 q9 T
函数参数:
( j" {* a& N2 L2 G5 n
: f# H' A- s; D! m+ R' x5 ~  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
) X7 }$ x  z+ N# k# Q  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
% T2 F# k  R1 ?( x; l- Z; \9 e' m8 d78.4.3 函数HAL_QSPI_Command
- M8 r8 k) r! }( p" j; k函数原型:, j3 a1 M* j; P4 n: x2 f

/ H( I  r. U5 Y8 l
  1. HAL_StatusTypeDef HAL_QSPI_Command(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, uint32_t Timeout)9 G% f/ T6 B. ]1 O& n
  2. {
      Z" H7 r7 E! Z6 h
  3.   HAL_StatusTypeDef status;
    , K8 L6 }0 c3 k" E- L" a# x
  4.   uint32_t tickstart = HAL_GetTick();
    2 _4 @- L+ m$ ^

  5. 7 Z7 S! W; x3 y3 D" B2 H5 D, k
  6.   /* 检测参数 */
    6 a3 \& g. S4 q# a4 C/ a4 S/ \
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));& Q2 C2 S% M* A9 f5 M2 p
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)3 V* C$ K' F+ ?- a$ R% C
  9.   {$ Y2 U- x  }, ?0 o
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    1 H1 f0 d; e9 b9 Q( d6 U: a6 z1 b
  11.   }8 `* L) R8 n8 x; s# j
  12. ! [1 K$ n9 B6 U9 ]1 h4 y* H, k4 m
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));8 x# A$ @( N4 ?, T2 s0 b
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)9 n1 [( q, P4 D3 P' ?( g; K
  15.   {
    3 o8 j% e$ U0 s  Q" y- u
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));0 F$ P$ @- |, }5 b7 i" }- r
  17.   }7 Y0 ~2 d1 [- [  }- U: R
  18. 1 B- x% L  {, Y
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));+ v1 N; [( f/ H  b! V/ ?
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)" g. n8 {6 k1 }. J
  21.   {
    * v# T1 C2 q/ j, h
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
    3 I1 e" l$ `/ s6 O) O4 g% h7 ~
  23.   }
    7 [# y  r* Z" N

  24. , b5 d/ f1 D$ `- @6 h% O
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    : {9 f8 e2 E7 @- |/ K# k
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));/ F% M/ a) [6 M5 y) V7 Z$ @, U/ x

  27. * [) B% y2 v2 l2 [8 T& k! Y
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    $ H* H: ~  D# v
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));. a/ s, t8 {7 ]6 L2 @5 L' |
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));
    ; M- {  J3 F* x  K5 A+ t
  31. 3 A0 I% e4 ~/ w% G5 Y
  32.   /* 上锁 */9 j% C6 z3 Q& c2 h( g7 [
  33.   __HAL_LOCK(hqspi);
      B. y( R+ G7 z7 }- j
  34. 4 e* U* M7 K! _, d+ m
  35.   if(hqspi->State == HAL_QSPI_STATE_READY)
    $ z0 N5 X( n' d" D' u& h
  36.   {- B& m- a* j- ]4 H7 |
  37.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    - V3 i3 U* E  p" w" ^8 L7 H
  38. 4 i; z: I% p9 Z/ M
  39.     /* 更新QSPI状态 */. v! x: M/ d( W, L& U7 ~
  40.     hqspi->State = HAL_QSPI_STATE_BUSY;& u/ \1 D# [  b
  41. 3 B% G) U- D7 B: j; h2 Q
  42.     /* 等待BUSY标志复位 */
    4 f4 \" Y7 b( \' G+ c
  43.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);: @1 `/ e4 L- ~
  44. 9 G7 w/ j2 r" O8 ?$ Q# t
  45.     if (status == HAL_OK)- W- {/ D: S: z8 [
  46.     {$ g! g" t$ @$ Y) Q. ]
  47.       /* 配置QSPI  */
    % h7 Q9 j- z, G7 g
  48.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);6 }7 O6 r5 i/ y

  49. 0 I, ^  v0 C9 p5 Q
  50.       if (cmd->DataMode == QSPI_DATA_NONE)( ]1 L( l2 a& U8 _& K
  51.       {8 G) Y1 E1 Q: a" A. I/ M
  52.         /* 没有数据阶段时,配置完成后立即开始传输,所以请等到TC标志设置并返回到空闲状态 */8 K$ @/ V" N1 w2 I. L/ o6 l" W# P
  53.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);, p3 k- k' ?' O. W# X$ q
  54. 9 i& U, O1 y  ^% x4 U  B) y3 \. c
  55.         if (status == HAL_OK)
    ' u) t' g- x3 n- V' R4 B
  56.         {
    ' t" _9 N1 f/ V+ a5 d% R' J9 T
  57.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);
    ) ]: M0 ^; c' g# P6 l- R5 G6 I
  58. # ?( j8 k) j; `7 j% I
  59.           /* QSPI就绪 */
    ; I; h3 \8 s* G( J% o
  60.           hqspi->State = HAL_QSPI_STATE_READY;8 ?0 O1 k4 u9 f6 M7 b
  61.         }2 S; d8 k+ r- c/ V
  62.       }/ }5 c* x# E: Q9 e1 u# k
  63.       else
    7 G$ S( E2 F& ~) Q! ]9 {6 i1 z
  64.       {' F5 ]! ~: [4 X: d& Y& W3 _& D. A# I
  65.         /* QSPI就绪 */
    + h7 H; X: N' A% I9 [  k
  66.         hqspi->State = HAL_QSPI_STATE_READY;  k/ a3 t2 ]% `: ?- w! ]
  67.       }
    " ]+ w* r* e9 N( u4 O( `/ f
  68.     }
    3 k" \" l& v. \$ \
  69.   }
    ( w) l+ }3 _! p" j6 Q1 p. s
  70.   else/ k, f6 q5 R' a! a# B8 D/ \& _: g
  71.   {
    ; C, y8 q1 x! H$ T" F0 z3 e
  72.     status = HAL_BUSY;. t8 A! \2 d* o0 q  s
  73.   }0 l) O. O0 j9 f# _
  74. $ G- f8 d+ _% {' K/ Q* q% Z
  75.   /* 解锁 */
    5 `5 G2 Y/ N1 L
  76.   __HAL_UNLOCK(hqspi);
    5 F9 m( E! @5 D; d3 ?) |7 H
  77. 1 [' N& X1 G, o. j3 U  ^) _+ p
  78.   /* 返回函数状态 *// o  J$ P6 y& i. T' P$ p" S) l
  79.   return status;2 a) n4 z) i3 a  c' D
  80. }
复制代码
# D' k  D) J4 I8 h" T! C& C
函数描述:
# c+ \/ w( n6 Y+ R5 a! @! v  q3 v6 m* Q$ @& A- Z+ [
此函数主要用于为QSPI Flash发送操作命令,查询方式。
1 K3 n  ~- K4 X
7 [2 g6 b+ T% R# Y3 K2 h函数参数:7 |: u: Z, _! E- {: u

, ]5 `9 b5 L; g! ^9 Q3 [7 Y  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
( L' Z% `2 L0 K  B$ S  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
9 e5 O1 v7 q/ j& R0 f+ U/ p; z  第3个参数是溢出时间,单位HAL库时间基准,一般我们设置的是1ms。
: {) z6 O" N* o: g  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
& B( _7 H2 A3 B; l7 ~( `使用举例:
" G1 u) z; G7 \& C$ G8 ^% q* X4 E5 Y7 Z, z) B7 h& i. ?
  1. /*. Q0 e1 ?6 _7 u3 ?
  2. *********************************************************************************************************+ ]- F6 K! }" w0 D7 n1 a' w2 H4 P; w) A
  3. *    函 数 名: QSPI_WriteEnable
    8 T0 N1 P1 _( |0 g1 C' N3 I
  4. *    功能说明: 写使能/ L& @6 C6 o% N- Y; `+ o
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。1 n( @, w# c0 N! M( W/ G0 Q
  6. *    返 回 值: 无: i$ m! z0 K$ ]7 U7 A: t
  7. *********************************************************************************************************
    ; K  p- U: z9 J5 k
  8. */- t% K9 J: w; Z! ]* ?
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)3 Y: m; `$ q( ]) `# E
  10. {' W* y9 {0 P; h( m* k/ z; l4 e$ g
  11.     QSPI_CommandTypeDef     sCommand = {0};; l$ f& d* ^7 o5 b# i5 {
  12. , w& q. F3 _4 @0 r
  13.     /* 基本配置 */
    - S/ ~# K# Y# d8 }2 f& W
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    % l. Z8 x7 N! a2 f
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */* ?1 u" b6 Z, a  O& q5 j/ Z
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    8 v  n0 Z) g3 N( [- {
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */" Q- I' s3 @0 T9 s
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */1 w. r% f$ _* n2 I2 K4 k$ p
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */
    # p) O* G0 ^* K, J  P! b
  20. ! w6 r% _: i/ b% q7 F
  21.     /* 写使能 */; ]# C& ~/ @2 `
  22.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */+ c* m$ d+ c" ~" B2 e
  23.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */- f8 B$ F- [0 B0 p
  24.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */0 r7 S; V% V1 C8 U0 E2 Q$ V
  25.     sCommand.DummyCycles       = 0;                 /* 空周期  */
    % d, d7 e% V. v9 C" @" @

  26. & G$ W) L, ]  K* @  [) r
  27.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)$ u. Y6 ], a1 D9 @+ c& a3 w9 `
  28.     {
    5 W* m, B: A7 S1 b5 _' x% j0 V" b, V
  29.         Error_Handler(__FILE__, __LINE__);
      K# w7 v/ n% o
  30.     }   
    1 g+ ?8 {8 ^8 m  _- F
  31. }
复制代码

% n* R6 y1 S" S, n: `78.4.4 函数HAL_QSPI_Command_IT
6 m) ]$ n# Q2 ?函数原型:  [) S+ _( F+ M7 e
! _: D6 b1 M% ?4 V! `9 t
  1. HAL_StatusTypeDef HAL_QSPI_Command_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd), H  U+ w1 Y' `3 Y7 P4 x5 X
  2. {  r, Y. ?; w/ ?/ G0 O  P3 l
  3.   HAL_StatusTypeDef status;
    7 m4 Z$ ^) U" F8 R+ @+ o
  4.   uint32_t tickstart = HAL_GetTick();
    3 B: C* i2 P! X( x3 R
  5. 9 C+ T( z( w2 [8 I* T( P
  6.   /* 检测参数 */
    ; L% Z/ [) r" }, q/ a
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    5 }, N0 P1 r# h9 b4 K
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE); L& ~$ g. Z. Z" A. ?$ b
  9.   {
    ; W: d. f) v5 h4 U& t* L
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    ) w! K6 r" \! |. @9 \+ Q5 B. D
  11.   }: v0 H- ~/ \) Y% s% h( J& s% \

  12. $ r( C) ?; R+ R3 R: |! t
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));3 X! x( [/ U9 n' U' @( M6 z
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
    ; ?6 g* ~0 S6 U7 }# o" x
  15.   {2 |6 i( w& s2 M# L3 @* o( G
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));9 n0 O+ o( _4 y8 i
  17.   }' {, K0 x& w/ ~8 \) m0 B
  18. $ [1 C; g7 l1 j
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
      E4 q0 {; D$ l( v+ K
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE): Z. }- J( A. k" S) d
  21.   {  j! \6 ?- B9 k2 G- Y
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));$ {% h8 w/ K  h9 I
  23.   }" f, o6 w) g% L$ `. R$ u8 Q+ i

  24. ! n; S% v! D9 f- g# u
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    0 v5 S& R! ^* P7 t$ z( y" ^
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    ; f5 _6 \) f4 f. x8 a
  27. ) ^4 E0 b6 A; V/ G1 K* _
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));. J8 k/ _+ u: ?4 x; \, M7 o& R
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));0 J4 P$ g5 u  c3 L
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));' N& ~7 q; g( c; `) N9 s
  31. / R3 S3 ]0 [4 c# Z0 H
  32.   /* 上锁 */
    $ c: P1 X" B" e1 b) b
  33.   __HAL_LOCK(hqspi);, {9 M) ~- _+ J; p' C* J

  34. & P$ @$ f6 V- i" p: w2 S1 w
  35.   if(hqspi->State == HAL_QSPI_STATE_READY)" _+ d6 t" z. n; L+ B4 C( c
  36.   {1 V6 K( ~- c9 p  j* D9 @
  37.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;" p: `6 F3 B' z( h9 q

  38. & a% N0 Z" ?. X1 }+ h. D* ]' G
  39.     /* QSPI忙 */  @( ~( Z( G# N  I  z) S3 p1 S8 u
  40.     hqspi->State = HAL_QSPI_STATE_BUSY;- ?& i& ?+ k( X3 \% w& U5 p7 {

  41. ( o! x/ h  W  {: g
  42.     /* 等待BUSY标志复位 */
    5 u# d& V2 W( ^+ Y7 z( X4 G
  43.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);% T9 w) X' Z6 X- ]7 v. Q
  44. * \7 n- z2 B  w
  45.     if (status == HAL_OK)2 v7 V9 k& ^2 T& a0 x! {* a
  46.     {
    / ]3 l) q, y6 z
  47.       if (cmd->DataMode == QSPI_DATA_NONE)
    3 A+ x3 s" X% L- q! K7 D7 Y
  48.       {! l& O1 C! I( d3 N$ h9 a+ y. R
  49.         /* 清除中断 */
    , ~, |+ Z* R- E
  50.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_TC);
    ' W. _3 ]. j% D; h5 I
  51.       }# E/ w- b# V6 z# S5 u& d
  52. - w5 Y& y# J, Z  G
  53.       /* 调用所有配置函数 */
    ' q% `* R" @; h. v9 ]( T
  54.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);6 {  A7 y0 q" c+ K0 U8 U% s* d5 G
  55. ( I- o& j' a9 W. Y5 q* Z
  56.       if (cmd->DataMode == QSPI_DATA_NONE)! l* N" C7 U' z3 m8 C& a1 P
  57.       {" g+ H9 J( B& g/ v1 K" y  \
  58.         /* 无数据阶段,配置完毕后,立即开始传输,所以机会TC和TE中断 */2 E4 q5 x9 H( @8 k
  59.         /* 解锁 /
    ' t( L$ [8 F, {' y. Q
  60.         __HAL_UNLOCK(hqspi);; H8 }! }1 i7 c+ s; p

  61. " b: }4 T' }" y" X) T1 N5 v) ]
  62.         /* 使能TE(Transfer Error)和TC中断 */. h' u1 I% ]) e6 d, W
  63.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE | QSPI_IT_TC);8 j2 g! e& V8 y/ T
  64.       }
    - P/ ~+ `/ Y* d9 _
  65.       else
      h$ s/ e" d& I8 W
  66.       {
    4 j) O' @6 S( D
  67.         /* 更正QSPI状态 Update QSPI state */1 C8 y- T. l1 b- V: b! ]
  68.         hqspi->State = HAL_QSPI_STATE_READY;" V+ Y% d. G: \, o& B
  69. , U: I) F( z# u4 `' Z- z0 E# H! J
  70.         /* 上锁 */
    6 x" y) e# `) J7 Q8 x# }
  71.         __HAL_UNLOCK(hqspi);
    , f, O$ S* O9 @5 I# Z
  72.       }. l! M/ [3 H: m3 k3 ^& ^6 ^
  73.     }
    6 l4 Z7 E9 K, z4 {* ^
  74.     else
    . g7 i- z- E1 Y: J! J( x
  75.     {
    5 j& \( C. j% T4 n: J5 Q
  76.       /* 解锁 */5 k) M2 A9 q  y& h! I9 o
  77.       __HAL_UNLOCK(hqspi);+ F0 d: s" G4 C: f3 I
  78.     }( H  k: O8 h! f/ h% F
  79.   }3 b. a/ @% O+ Z% b4 G: v+ e* v
  80.   else* I! R' A% C! H4 F
  81.   {$ l' W* X! w- B  J! p
  82.     status = HAL_BUSY;
    3 n9 F1 |- C. m

  83. 1 |! H; e2 ^3 I' r" }2 K
  84.     /* 解锁 */# N3 P4 t$ Y2 F& b( N! F3 J
  85.     __HAL_UNLOCK(hqspi);+ u2 C$ p' r1 E6 I, B/ M
  86.   }
    ) K- k+ H( E& \# r+ N; N9 g
  87. 4 |( u2 G* l6 R3 |0 B! F0 N
  88.   /* 返回状态 */
    ) C$ }# @* d. n% u& R
  89.   return status;) N  B$ T* z, v7 G: O/ M# W
  90. }
复制代码

) t# O4 F( G" A0 t- O函数描述:
( B" a5 G+ z/ p- M
8 J8 @2 s9 \8 A6 M2 O此函数主要用于为QSPI Flash发送操作命令,中断方式。: r9 u. N) R0 W) v8 l9 w1 z+ m+ w+ d
, M: t+ |' i8 e9 c+ y3 H/ F
函数参数:* J2 M3 K" i" i

, z; l, |, F' P7 v" c: W8 e  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。+ x7 q3 C* l+ A
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
, x2 R* ?* I2 H3 x  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。$ ]! o; j! Z  I# ?/ y
使用举例:2 P9 O6 _! ~; d* M2 L) V
# \% t- H) b- b4 q- H
  1. /*/ d+ i! v& O- g# _2 P2 ]! e7 g1 a
  2. *********************************************************************************************************, W% B1 R  N" l+ Y" f( h; r* m
  3. *    函 数 名: QSPI_WriteEnable
    " i, p( q* l; T5 q, w8 K3 \1 t
  4. *    功能说明: 写使能
    8 C/ O9 x0 ^7 ]
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。
    2 m; n' u, g4 E# H, Z$ i2 B
  6. *    返 回 值: 无" J/ ], W: u6 }& n  _$ A4 X
  7. *********************************************************************************************************
    ! V. c* u3 s9 m
  8. */
    . a. |& @0 ~" l' z8 G
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)' F. A, i* b& R
  10. {
    # m" G6 R3 j2 L' M7 e0 U
  11.     QSPI_CommandTypeDef     sCommand = {0};. r& z% f6 q6 R' F, \& M" X$ ~

  12. - R6 f+ Y2 ~1 U, b6 S2 |
  13.     /* 基本配置 */" [6 ?  Y' C) l4 }' m, f! t
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    # O" [4 I+ }6 O3 @& g
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    " H" }6 e, V- c  E3 n5 _
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    / B1 m1 n3 _% E$ _, X) i; i3 v- x* }
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR *// L8 [) b% L! {+ t+ B. v
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */" E9 d. q% N- {
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */) I9 p- `) V: G' Z8 ~
  20. ; [3 T$ Q* g) y6 D7 h  Z4 j9 t/ X
  21.     /* 写使能 */0 X$ g! ~# N  J% {/ d: V  R
  22.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */
    9 v( H! C) n+ d3 w% w' f7 i
  23.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */
    0 a" R" Z  I: v8 P* w  G( v" k0 i0 x
  24.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */
    ' j. n3 ~) s; `7 X3 e
  25.     sCommand.DummyCycles       = 0;                 /* 空周期  */1 E4 V" t) F6 Y) C; \9 U

  26. ; e& ~4 e$ W& i0 o" u: L3 N
  27.     if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK)& D7 Q7 i- \8 q! i
  28.     {4 q3 X3 g2 p% e5 q7 f' E7 m
  29.         Error_Handler(__FILE__, __LINE__);  ]! W5 @! K: m$ e8 \" P  |& y
  30.     }    ) H* r" M+ N" H2 P
  31. }
复制代码
$ w+ @9 Q' m( Y; }
78.4.5 函数HAL_QSPI_AutoPolling
* I$ g' E6 U+ ]1 g- F  i$ x4 {8 K函数原型:' R( y; Q1 V9 v. p/ O

# B1 {: g+ e8 B8 E6 l2 g" \& J5 s
  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg, uint32_t Timeout)0 C* {- t( Y8 e9 K! [# J2 E- I
  2. {/ Q" {* B+ v, S. C3 l- T- d
  3.   HAL_StatusTypeDef status;
    + d2 B9 p  U" N2 x
  4.   uint32_t tickstart = HAL_GetTick();
    " D, K/ V$ p9 P/ w

  5. ( I; s, e6 @( Z, F$ |
  6.   /* 检查参数 */
    ' h  N% H3 Z5 b  W
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    , e$ S! v. f* W8 K4 u
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
    3 _9 I- g( s  e/ C6 [+ ]
  9.   {
    ) N" V0 k' G, g4 p
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    5 g$ n4 ^' l: s. |
  11.   }
    6 L1 p/ M' f4 M0 ~  }, E
  12. ) O* i) K' z; {
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
    8 c0 `/ s3 W: j
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
    - B8 P1 G2 [% C: S: T
  15.   {
    # m( H( M$ D& _) @. _
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
    " i: `+ V- W) P! g# s# }( B
  17.   }, R/ L* i" E# H/ k4 Z. D1 J4 \

  18. . B$ `( N7 v) E, L, }
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    ! @+ t+ }6 C/ Q' l( x( p+ {( W
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    ' a% _; c) d" K7 j8 q# x$ O
  21.   {+ u& V: g3 o5 g# B3 f
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));# V8 \* U5 o! v) W! C2 g! V7 |9 L
  23.   }
    6 z; D4 M9 v, y# L
  24. - x( a' }+ V4 q/ |
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    & e( h  x( c5 X& R" L2 D& z# ~9 B
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));' V& h6 |3 \. X* o" R, P
  27. 0 _- P# M( X# A6 k7 }: g+ f
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    . D( E& r/ A1 J& C
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));7 ^8 D! j4 ~. \
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));' p+ V4 K  C1 m$ _

  31.   C/ ?. t$ U, ~1 o
  32.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));" ]& d3 w2 n" t
  33.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));
    : |% p% ]7 `! F$ P; ^
  34.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));3 I. x& X0 A7 t6 g: P; J
  35. $ N8 k, G* d5 ~( ]1 B
  36.   /* 上锁 */3 q/ l8 R4 }$ d6 C
  37.   __HAL_LOCK(hqspi);% N4 k7 I; t7 {2 i
  38. . a) ~0 ?7 O7 @: ~! E7 O  L! U, w
  39.   if(hqspi->State == HAL_QSPI_STATE_READY): F5 \  u% n0 O0 K7 k! y2 ?8 O. o
  40.   {/ c/ V  T% @# [. C1 r
  41.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;: d& Z( Z+ F) G! n: j' x+ P+ }4 z
  42. # U" G4 r0 f: Z% J5 _% @" G) @2 E2 J
  43.     /* 更新状态 */
    3 H8 p% R' Q) n& y. }
  44.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;: ~( l$ R6 O3 p/ U
  45. 8 }! U/ I" J" b' G) y% d, E
  46.     /* 等待BUSY复位标志 */# E! d2 p, k. J0 }
  47.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);
    3 J- }/ E. G# Z% M, W6 ~+ A- r

  48. 2 _/ `5 k: J4 g) q
  49.     if (status == HAL_OK)8 c1 n/ `) H7 c; E
  50.     {
    . A4 Z: ]$ n! p1 s7 r- Y
  51.       /* 配置QSPI匹配位 */% _: d  S+ I; A& i* a( O
  52.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);
    7 K$ P: v+ J" {0 C- C- s

  53. ! B3 P. u5 o6 W% O
  54.       /* 配置QSPI屏蔽位 */6 U+ T+ O+ J5 N
  55.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);: K' I; N- _) K3 B7 e8 H
  56. * K' G  Q6 D, A. g
  57.       /* 配置查询时间间隔 */
    & k, Y3 K, j7 h  N; b& X1 y
  58.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);
    + E# h# X1 ?: C9 T# `
  59. " t+ i: ^* b2 [- e1 T* k: Z
  60.       /* 配置匹配模式,使能自动停(否则阻塞方式无限等待) */
    ! u& u9 {( W8 _' }/ m  I
  61.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),) ^+ `& ?! `( {2 P! p
  62.                (cfg->MatchMode | QSPI_AUTOMATIC_STOP_ENABLE));9 Z* ~4 r5 ^2 G" S3 Y1 F. q

  63. / g% `3 J4 g4 R1 @
  64.       /* 调用配置函数 */; ^5 Q" @1 A& g! C2 `7 Y
  65.       cmd->NbData = cfg->StatusBytesSize;
    , r* l9 {/ g, z9 n! d( L* y
  66.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);
    / o+ v6 G1 r7 g% K7 v& C+ b$ G1 t5 n
  67. ; j3 }& d3 }  t' y% c: c' b
  68.       /* 等待SM标志 */
    6 F2 @! k2 D0 U9 `
  69.       status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_SM, SET, tickstart, Timeout);7 G! g: @  X) Q5 f. t" u- z

  70. # h* U& H* G) z* c! M
  71.       if (status == HAL_OK)) O( U, B0 R6 |0 |- g2 m. l0 j" ?: e
  72.       {
    7 B  b3 c( J; s
  73.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_SM);
    6 J  \) j. H4 Z! s9 Z& ~) f+ {. A

  74. ! I3 ~# Z6 ?, O3 S: f6 k; I* Y
  75.         /* 更新状态 */2 j$ a2 M; R9 R1 D
  76.         hqspi->State = HAL_QSPI_STATE_READY;' \. K3 E) V0 c5 i$ }8 c5 @5 U
  77.       }
    % A& F; n! ]; c  j1 W* k7 @
  78.     }
    8 S4 l6 S$ K8 j# @7 m" m0 D5 o
  79.   }
    , M, m# C: U/ l. P5 e6 p
  80.   else0 i# T  l& m% P( u5 x6 v% Z
  81.   {
    + F0 J& ?- \& I. ]- @# j
  82.     status = HAL_BUSY;
    ( Z9 |/ R5 B5 K/ _; }
  83.   }- ^" ]( T! ^- T2 E. M+ j
  84. " ^! s( l! @9 X
  85.   /* 解锁 */+ L2 P3 n* \$ C/ _+ X/ d/ x: o% U
  86.   __HAL_UNLOCK(hqspi);
    " U2 @, A  i4 O0 i9 h; J' F' u

  87. ; q7 ]1 S3 B9 _* Z. ]- {
  88.   /* 返回状态 */3 n9 l( E, N3 J6 E1 C( O
  89.   return status;
    9 p2 D! a7 U$ ^* F* g3 H
  90. }
复制代码

1 ^7 K) L; J$ d2 _5 L# M函数描述:9 ?4 K$ @" M, C& O  C
0 P( S# B& G; ^2 j- A# b
用于状态标志查询,函数采用的查询方式。1 C. S- @, E# G+ w, A+ r% E
/ A4 j) M* h# ]1 k
函数参数:
, F8 y1 u% p4 |6 q9 G
, Y' E7 z6 y9 o& T7 `# i* A1 l  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
; g" ]. Z' d5 Q' b  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。$ @* ]0 G3 B- u1 @2 f" N; h
  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。/ O2 j. {7 u% _  k& |
  第4个参数是溢出时间,单位HAL库时间基准,单位1ms。( |0 o# h  q/ K! H6 k; H
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
6 h. I; f! Q0 p3 d* {- [& p使用举例:0 t. v4 n# e. n7 L6 H. F
0 B7 I' a! a+ s6 ~. v- K2 W
  1. /*0 V+ M% C5 U0 A# [
  2. *********************************************************************************************************' D4 y( x. R1 z0 G
  3. *    函 数 名: QSPI_AutoPollingMemReady
    9 R6 |+ _0 U/ {3 ^) M
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用. Z9 K  x- p5 ]+ `3 _
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄3 ~) t$ t* l: d# h
  6. *    返 回 值: 无
    8 t- Y0 N' b0 Y6 F* T9 W3 B
  7. *********************************************************************************************************& C) e0 N, {+ b3 ~- ?+ ~$ d
  8. */6 j& B* ]+ K. E' i2 ]9 O6 Y
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)6 {0 k# h& \2 b- X: R0 N) @% S
  10. {
    ) M3 q8 L1 c) x6 _; u- N6 |7 [5 r
  11.     QSPI_CommandTypeDef     sCommand = {0};
    8 Y6 S: ~3 ?8 W! g/ G
  12.     QSPI_AutoPollingTypeDef sConfig = {0};
    / n% x  f: ?/ @' b
  13. ( a/ C2 _9 R$ S
  14.   f* ?3 C# Z" o3 W% U
  15.     /* 基本配置 */
    - p6 I3 W  l! Q
  16.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    5 _! l/ _! q7 L& P
  17.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    7 ~# U+ p1 `, s* J5 l3 l1 D* e* o- f
  18.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    9 o& \. N& }$ y4 f6 Z0 O( {! n2 q
  19.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    / I2 j6 n( ^8 e0 t
  20.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */8 A$ c0 V5 ~4 p& k7 v8 p- o
  21.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */1 F0 F  o- H( g: v7 N! s1 a4 p! Y

  22. + h- }& d: K" c' K6 ?5 M9 l  ], U9 X- D
  23.     /* 读取状态*/
    $ D$ c* r+ V7 m3 f
  24.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */3 [6 C) \7 A: [/ `4 V
  25.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */
    8 ^" P; y2 n& |4 a' S, l3 j1 u
  26.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */
    : j0 j+ ], a3 q- D
  27.     sCommand.DummyCycles       = 0;                   /* 无需空周期 */( U; w) F# c$ ]/ q+ s

  28. 9 I4 q* u( t9 K8 r- n1 B
  29.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */! l! W* |: h: a1 f1 f2 `
  30.     sConfig.Mask            = 0x01;
    ; Q- F9 m+ p/ F3 l- V
  31.     sConfig.Match           = 0x00;3 p; d  ]( e( x- [3 ^1 R# G1 n
  32.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;( s; r: O# Q" R6 E7 B9 n7 Y1 i
  33.     sConfig.StatusBytesSize = 1;
    ( p! y* v9 A; F% d
  34.     sConfig.Interval        = 0x10;; H& R5 a! R" H; l6 E) `, W
  35.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;8 E6 L3 a2 p1 S* h6 |
  36. : U/ p9 h" j) o: O" P
  37.     if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, 10000) != HAL_OK)
    2 L! S7 g( n; q! }; t0 l
  38.     {4 P1 ~$ y0 `3 s; o4 @6 _6 X4 l
  39.         Error_Handler(__FILE__, __LINE__);
    1 Q7 F8 W, D+ N* z% u4 M- X
  40.     }
    " i% q  @! |' d; b
  41. }
复制代码
6 D) S9 t9 l+ R3 a
78.4.6 函数HAL_QSPI_AutoPolling_IT
% @! U5 F$ c0 c1 C" P% [函数原型:
5 k, r4 w; U3 ~6 ?) y6 D, {
* A8 Y6 X1 T5 I0 Q, ^- E
  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg); F: m* g5 k0 ~1 D' K3 @
  2. {5 |+ e0 Y* Y; \+ u9 |' k* D) k
  3.   HAL_StatusTypeDef status;0 K7 M, X. J4 p
  4.   uint32_t tickstart = HAL_GetTick();( S6 A0 H; D( x$ f7 Y

  5. 3 o' l1 H" w4 Y# S9 G# {5 m+ ?
  6.   /* 检查参数 */4 }" C0 Q. a  B( {+ j
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    * x" |( r1 s4 W/ f/ f5 D: H
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)- ~( ^6 q5 h, M- L
  9.   {
    5 X& n$ i2 A/ u: U7 n3 o
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));5 [) h( D3 Q" V% \; V7 f
  11.   }
    4 n% k5 I/ e" h" H! S

  12. 6 a- m; @, G# Z; i& b
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));6 U  T8 g4 r- B: B% y- ?7 ?
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)9 Q9 R  d% ~) l; |
  15.   {
    + l4 ^% ?* n- D' m3 ?* P4 A
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));6 e1 A7 D; `$ Y( k- a
  17.   }
    1 L2 q, G' J/ J; E. d- p
  18. ( @3 t8 G; s" m2 }4 m# {. R+ ]6 Z4 M
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    ) [# a. }4 {! V! [& i
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    $ q; I2 ~# w! U5 b5 J
  21.   {! V, T/ p9 s$ v' Z
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));1 V8 r) Z2 C2 Q' z
  23.   }# R! A  \' Z8 @3 N, y: s4 T( c1 J

  24. 4 ]5 ]7 O& E: W& h1 J
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    ! b# Y) b& S! O4 R( t" U& J
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));. K- t& D6 ?  O2 s5 D

  27. . z  F0 I" e" C& t# j/ |
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));/ f0 E$ ?/ V. I- C  x2 J* I& ]0 T$ S: q
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
    # z& }5 f7 i# }/ N
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));
    9 ?2 o! W" i3 p% [1 P& l
  31. ( x7 |2 V% {; G
  32.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));
    6 X+ }$ b0 [2 r8 L
  33.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));+ T+ R' q$ I+ {1 q+ o
  34.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));
    ( `2 n5 R5 v9 h5 f5 n; S- D
  35.   assert_param(IS_QSPI_AUTOMATIC_STOP(cfg->AutomaticStop));
    1 b2 _7 r& O$ y3 q: S* T
  36. ( U3 _# H/ U  j. R' V
  37.   /* 上锁 */
    4 j* i2 E& w, K% D0 |
  38.   __HAL_LOCK(hqspi);5 w/ ~- l# I9 b+ z# V2 ]
  39. 5 Y" n7 M2 u/ ]. P
  40.   if(hqspi->State == HAL_QSPI_STATE_READY)+ C, q8 s  G: S3 A5 h/ G7 X* z5 b
  41.   {
    5 f! J# M5 |! R# ]$ P3 h9 [4 O
  42.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    ; U! e9 S  G/ K; E2 l4 B0 ]. s
  43. : L+ y7 }/ \& h. v5 m# @" r
  44.     /* 更新状态 */4 O  U6 @9 r& H
  45.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;
    ; \9 J9 ?, r6 e8 e% J
  46. ; R6 i' @0 R  H/ t2 L. y$ l
  47.     /* 等BUSY标志复位 */( x/ M# N1 Y. C. C5 r) r
  48.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);
    & h7 L! W3 q4 u3 A+ Z2 d
  49.   @/ ?" b3 F, N' Z/ [) S
  50.     if (status == HAL_OK)
    % ]4 q$ o+ ^# H2 ~+ |3 j/ y) b) c1 S, X0 J+ {
  51.     {! q& ?- l! S5 d: ^
  52.       /* 配置匹配值 */* Q! z* n; K( ^" W' h! H+ D
  53.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);
    # h, ~) T9 u) x5 P% n- T" |5 z5 d0 v# [
  54. 3 k; C% i  u+ d8 Y! m( P- y8 K
  55.       /* 配置屏蔽值 */- |! Q. J6 I. w) P% F; r8 T* \
  56.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);' r: w/ h+ N$ i& b; j2 A5 y5 K
  57. # r0 G7 S! ?" ?2 C; `9 U
  58.       /* 配置查询间隔 */
    1 D# t& {/ L* r7 Q$ R( T* n1 u
  59.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);
    : a( Z& j8 H  h) U+ A! l* T
  60. & K, c& H0 P5 X) [
  61.       /* 配置匹配模式和自动停止位 */
    5 T  S: q. z6 e$ D( u8 `9 n
  62.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),
    ' Q) E4 U5 x+ i& L! \5 B
  63.                (cfg->MatchMode | cfg->AutomaticStop));( f4 a9 c& e6 r' `" v

  64. $ X* r) g& a6 i# h
  65.       /* 清标志 */# {: G/ e7 ~& L: h% N
  66.       __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_SM);
    9 B; N% h3 _( P! h; N' F# g
  67. + G% P  F9 `  [
  68.       /* 调用配置函数 */, n: c* D  |$ X. A1 S& r3 R. R3 l
  69.       cmd->NbData = cfg->StatusBytesSize;
    % p4 X: f6 `! v
  70.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);
    . k4 y  D; F. K; U/ g

  71.   m* B( g0 W- z0 \
  72.       /* 解锁 */
    9 u; m4 ]* i8 ]0 t* D8 A
  73.       __HAL_UNLOCK(hqspi);9 ]2 F( L  D5 b5 U% q
  74. * q. B) _1 h6 K3 a# H" y
  75.       /* 使能SM(status match)和TE(Transfer Error)标志 */) ]/ _7 h; F" |
  76.       __HAL_QSPI_ENABLE_IT(hqspi, (QSPI_IT_SM | QSPI_IT_TE));7 o( H9 Y" K  ^; c' A3 s8 m, S2 u

  77. - j8 y$ i6 J3 w7 u9 M/ I
  78.     }4 s' }8 F. }7 N- W" x# c9 P$ d; F
  79.     else) L' V, F# @: J6 K! {9 c& d
  80.     {
    6 H4 d* D0 V1 W3 \5 X
  81.       /* 解锁 */+ ?4 f/ x/ l3 ]2 w
  82.       __HAL_UNLOCK(hqspi);
      m. O4 K' l+ Y
  83.     }; p& s. ?& |6 r) B
  84.   }. a: e) d3 T3 C2 {% u& i# X
  85.   else
    5 P  }6 b' A$ s$ `
  86.   {
    0 I+ T" G# ~/ O0 u$ M% i
  87.     status = HAL_BUSY;- Z! y% n+ `8 {( l0 Z) S% _" ]4 C
  88. ( \5 }1 j+ w* K3 ]& E1 _
  89.     /* 解锁 */
    1 C8 F1 \4 X4 X- s1 o
  90.     __HAL_UNLOCK(hqspi);. y( ^$ o' z  v; e8 i$ d
  91.   }
    8 w# p! X' C& e. m7 D

  92. ; T9 j' |& Y3 o
  93.   /* 返回函数状态 */) h1 p: C9 e' {) c6 _6 B( }
  94.   return status;
    * u2 @2 k2 t% z7 b# W) V$ v" \
  95. }
复制代码
- U. {* p* i9 d+ V& L1 C7 G
函数描述:
1 F4 @  W; b: h  Y9 D! ~
6 E; Z3 b2 O! Z" \) Z$ {8 s& Y# w, E用于状态标志查询,函数采用的中断方式。
3 P" G, u9 n( m- v- z$ N2 B: V
函数参数:  o/ p+ H: j% I. e$ ?. \
- _. s3 {& A9 n" ^7 ~/ @/ ?" V) k
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。; ]+ Z9 p3 j, N1 V3 H
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
" L0 G( D- D" M& S6 D# y6 a* y) `7 Z  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。% w9 a! ]* W/ H/ C, x+ A6 {; q5 i
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。2 T' M7 |/ O: q3 j9 Z  p
使用举例:
+ @& U4 v" N) B9 m# U
8 Q. p! F9 i- {- g& H7 I+ `) E/ s
  1. /*& Q+ O) T: f% B  W3 ]
  2. *********************************************************************************************************4 [  G+ N+ q& t/ U0 {
  3. *    函 数 名: QSPI_AutoPollingMemReady
    1 T2 V# L- J, Q5 d
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用
    , K; p( Z4 P' c5 ?) ?+ z
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄. [6 [  K! e6 ^+ b8 {
  6. *    返 回 值: 无% S( }" A/ v9 y" |
  7. *********************************************************************************************************
    & U. G9 M& ]5 T; c3 A
  8. */
    * [8 v. T- f$ T. b* N7 |
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)' R: B6 B1 Q- G- `& B
  10. {( v2 W+ L- [! h/ K8 k1 T9 e
  11.     QSPI_CommandTypeDef     sCommand = {0};
    5 A( X: h5 O# C4 j  r5 l) |# p5 E
  12.     QSPI_AutoPollingTypeDef sConfig = {0};
    , w  f0 j0 Q' k# w1 P
  13. 7 V/ g& [& F5 ~. \+ K, r
  14. 6 ~/ ]' N. J8 [  ?( \' q7 o
  15.     /* 基本配置 */
    ; _/ g/ N6 n" V7 X- [1 C
  16.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    # Z3 Z: L( ~: z+ ~' F, r
  17.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */* R4 |* l; a9 `; G, J) |$ A
  18.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    0 l' y$ T, S* V7 ~+ g
  19.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    " Q( B, x4 W: E% Q  x: z: d" k
  20.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
    & j+ e: L# J. w
  21.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */' r. v# y! B$ G3 Q( I$ q% m% u+ B
  22. # j. ~0 m& ]4 y) E. {+ x
  23.     /* 读取状态*/
    % o  b! c+ @7 P2 Z3 h5 b
  24.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */8 ?) c* j( g8 q. Z8 g2 ?9 Z
  25.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 *// n+ U, b* e/ v+ L4 E6 U* x
  26.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */
    5 U$ n1 D  ^. |6 J
  27.     sCommand.DummyCycles       = 0;                   /* 无需空周期 */# x5 k  \: m; L( Z

  28. * r+ _: l0 C+ @  j2 Z9 ^6 B
  29.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */: F, A3 z; O1 b- e/ @+ _
  30.     sConfig.Mask            = 0x01;
    " T1 m, t" H/ B8 k2 T, `+ \
  31.     sConfig.Match           = 0x00;
    , f. W/ Q! [6 o2 e& Z
  32.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
      ^% e, X- F/ i7 r9 {! L9 N' D
  33.     sConfig.StatusBytesSize = 1;
    - v3 w1 e& C! |$ G2 j# g+ @
  34.     sConfig.Interval        = 0x10;
    ) ?" ^2 [2 i8 J3 f5 S
  35.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;
    7 m  S$ H. @2 [' l5 J( `

  36. ) M3 E, ^& M; e# L- T$ P7 \! L
  37.     if (HAL_QSPI_AutoPolling_IT(&QSPIHandle, &sCommand, &sConfig) != HAL_OK)& V6 |* C0 j1 V/ J& H/ }/ O
  38.     {
    " {0 ]3 @# u: D
  39.         Error_Handler(__FILE__, __LINE__);
      \: X7 @1 u+ X4 ~% {, w
  40.     }% k' r4 S: _5 L  e3 z. i
  41. }
复制代码
% J2 J, l" u: y8 U
78.4.7 函数HAL_QSPI_Transmit3 z# H) q4 p2 Q5 c$ L' l. `
函数原型:+ v# I$ P4 h  t5 R7 d. G
1 X+ e# A3 q# o5 g; D8 `* M2 g3 z
  1. HAL_StatusTypeDef HAL_QSPI_Transmit(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)1 Z& v2 V0 w. ^" L8 k1 h2 {+ y
  2. {% B* {* Z& n. W0 c
  3.   HAL_StatusTypeDef status = HAL_OK;% N/ e4 a5 @" G
  4.   uint32_t tickstart = HAL_GetTick();# Q$ w# i# j, c& ^. t8 H
  5.   __IO uint32_t *data_reg = &hqspi->Instance->DR;
    0 H4 P* T# \$ T6 V( t0 r8 O  \4 I( b

  6. 2 H3 A# K$ t# F& X( {
  7.   /* 上锁 */
    + r$ k  M& I. \5 P: c
  8.   __HAL_LOCK(hqspi);9 B8 _% A% ]$ E6 s* [, Y

  9. ) v& m5 a* g9 R/ e. o& V
  10.   if(hqspi->State == HAL_QSPI_STATE_READY)5 c) e* y% E) q% Y
  11.   {
    ( P8 A9 K1 k% t
  12.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;+ T6 ~  N  x  `, L) P
  13. ; k% }! w" n) `# c  w/ R1 q/ e6 t
  14.     if(pData != NULL )
    5 I* Z& y# H1 N6 P% G, L
  15.     {
    ; \. u% _0 z: \0 k) L# d/ ^
  16.       /* 更新状态 */
    + D4 t9 G6 R& k4 o; ]' c
  17.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;* r) T- K3 M4 @

  18. : N$ w( X% r' X
  19.       /* 配置发送 */) H* W! l6 G8 s9 Z1 K6 C
  20.       hqspi->TxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;/ j$ {* ?; g4 Q4 q/ V
  21.       hqspi->TxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;
    6 H$ A6 ~  o- P9 G& [  s
  22.       hqspi->pTxBuffPtr = pData;
    ; U  u4 F; o; i- @" U

  23. ' t- w8 g. v5 T" o2 i5 T
  24.       /* 配置QSPI,间接模式 */9 r2 i- U; G6 ?& M" f2 ~
  25.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    . w' f" x: B. m/ w, S  I

  26. : d, U  \% ]3 f, T9 Z4 K" V7 Z
  27.       while(hqspi->TxXferCount > 0U)
    : ?: A3 m1 H; F% h, T
  28.       {3 [: E: u$ s% U% f* d
  29.         /* 等待FT标志 */. R$ G% |+ h) m: Q( c
  30.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_FT, SET, tickstart, Timeout);
    + W8 [6 [9 {, w* M) j
  31. ; p# P$ c0 [( ?& ^
  32.         if (status != HAL_OK)  i) I2 }2 m2 o$ M. j. v
  33.         {
    + e5 Q; u/ {& ?1 ~
  34.           break;$ z# O+ v$ O- m1 t0 h( ]
  35.         }$ H% |' {; ~0 |' n1 V/ E
  36. / q& w6 Y. B. E% \! R" c- e4 w
  37.         *((__IO uint8_t *)data_reg) = *hqspi->pTxBuffPtr;7 Y* y# R+ o0 A' r/ s3 d
  38.         hqspi->pTxBuffPtr++;
      g9 t' N+ [2 P5 m
  39.         hqspi->TxXferCount--;
    , C- x5 n9 o9 ^0 x) e% {
  40.       }
    0 M9 O0 W! @  l8 u' N, }, v
  41. 6 K- A1 T. r% l. }
  42.       if (status == HAL_OK)
    ( F5 C% \- u8 h# A+ u4 n3 n( e
  43.       {
    ( p0 Z# C- S, B" E, J$ Q$ m$ w
  44.         /* 等待TC标志 */- R( R+ ^+ F- B6 e3 a. j
  45.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);
    5 q( a0 I) W6 L1 v8 Y8 p+ ^2 V
  46. & S  C+ X9 B) c: V5 u5 _% n
  47.         if (status == HAL_OK)
    & g; K* }: C; U. U  Z: d7 d
  48.         {
    . G5 P, p% j5 v1 K7 H7 y
  49.           /* 清楚传输完成 */
    ) w. o+ x, `/ k( q! o: [5 c1 z7 X3 D4 b
  50.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);
      ?/ \* L6 W3 {# d% T3 Q
  51. 0 j3 Q& E, L/ z& D5 ^1 b" l, e
  52.         }
    ( C1 a- ^# j4 ]- `
  53.       }2 [, m* C; J9 f8 x

  54. 7 k' ~4 ]* u! [
  55.       /* 更新 */. y( |& J/ Z& Y7 h: R
  56.       hqspi->State = HAL_QSPI_STATE_READY;  Y5 |" T; b. m( M3 n
  57.     }
    % G, Y0 V0 h( [$ K
  58.     else9 U% b8 J% C! w
  59.     {
    " Q& ^( `5 I, B3 i3 [4 ^
  60.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;! Q4 a+ v( d- w
  61.       status = HAL_ERROR;
    3 x* ^1 r4 R4 B/ `# D
  62.     }# D  ~" W; I# M% ]$ q6 ]# ?' Z
  63.   }
    0 x# e; r4 }' i2 m" Q  s! ]
  64.   else" G( q6 k6 Q% \& X; G% E$ a
  65.   {0 V, H' Q1 i6 q! S
  66.     status = HAL_BUSY;
    " G8 z% D1 g: O5 |- v
  67.   }
    4 {; p/ v% t: \  D- d

  68. . e% C5 ^5 [" M( T6 l  n( D
  69.   /* 解锁 */
    " d8 r$ @2 k- F8 b- T5 G- b
  70.   __HAL_UNLOCK(hqspi);  [" B3 z6 H+ h; v3 X+ j& L
  71. % M5 x" y1 ~8 A8 c
  72.   return status;" B2 k% s$ w7 e9 ~6 N' y
  73. }
复制代码
6 r$ `8 D2 U! U4 s$ p; K
函数描述:! D: f+ |9 c6 }

; H; I5 n* j" K' I0 Y7 U8 |8 ^此函数用于QSPI接口数据发送,函数采用查询方式。: H; f3 ?/ o* l- S6 t: m' Y

( Q/ d3 f0 @) g0 |函数参数:
- }2 O1 B2 W8 b9 v7 z# u# C: ]" {; v
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。" T3 D6 ~9 Y6 H; V% o. y$ k* s
  第2个参数是要发送的数据地址。- N3 E# t' W7 C* v. H
  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。; k$ @4 r( H2 f2 a
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。# r, X% `/ M+ s
使用举例:" i# q5 L9 K6 u- a3 n  w# S; G
+ l: d- m, U& H) }2 W- v% i9 N
  1. /*9 B5 A, [2 d$ P- w! X$ f
  2. *********************************************************************************************************6 z$ b, Y# l5 U& N! K
  3. *    函 数 名: QSPI_WriteBuffer: S3 h1 Q7 w5 h3 U$ F( n! h
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入
    ( f7 X' ^1 {8 N2 t
  5. *    形    参: _pBuf : 数据源缓冲区;
    / [1 K/ ]5 T8 V, B" g4 g4 O% F
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。
    8 J+ `. `* ~6 M( ~0 E" N4 p5 M
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。
    ! w$ V# E, O* ~% T2 |/ a) S
  8. *    返 回 值: 1:成功, 0:失败5 w$ |( X0 x* i3 }
  9. *********************************************************************************************************
    ; V+ u! v: S+ g
  10. */# P6 F2 f4 D' A0 D3 t/ j
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
    - W4 Y8 f2 l& k' c! J
  12. {5 n' \% d" x# d. x. X6 ^
  13.     QSPI_CommandTypeDef sCommand={0};
    # W; a5 ]* l* N3 b/ w
  14. 8 K0 R' d; Q# }+ @3 }
  15.     /* 写使能 */% ]8 u3 ~9 R. a$ ~' J5 d5 S
  16.     QSPI_WriteEnable(&QSPIHandle);    1 }9 ?$ C! u2 W" E/ i

  17. 3 ~( S5 I% }( V+ r# @
  18.     /* 基本配置 */
    $ V3 N: H6 q& _% }4 k3 c9 {
  19.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */, v3 Q: k# F9 f+ Y+ H
  20.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    + v: t+ w+ b3 k$ ?7 \! P) C( i
  21.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */5 N5 D, U4 h& @/ J' t
  22.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */, \$ H' `  }1 d! N. x$ w
  23.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */7 L: c) |* \. `
  24.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */   
    3 G& E% _  J: w. x

  25. ) w8 n7 T5 |8 A, x3 Z5 l9 y
  26.     /* 写序列配置 */
    2 D8 W( h; g. j( P% w- |
  27.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */
    + O/ R* _' I5 y; g4 ?
  28.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */+ H. j/ X+ r( ~  r- R+ M
  29.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */+ r" [/ q& n, [
  30.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
    4 P# e4 m/ U3 B% p/ h# V) g
  31.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   
    6 M! T$ Q2 Q  o3 d' b
  32.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 */
    ; u, v: t! V5 q% }

  33. ' D$ @. o' [& S) l/ h. ^
  34.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)% [* [9 _) j3 `2 I7 x+ J  A
  35.     {
    ( `$ y" S& S0 h; s/ |4 E, X  B
  36.         //return 0;( a& ^5 M- v0 N# ^/ m
  37.         Error_Handler(__FILE__, __LINE__);
    ' N8 ]* ?) u2 |
  38.     }' A0 I5 ?: G! C$ G! K
  39. 4 z- N6 Q- N' P! g
  40.     /* 启动传输 */0 L: E, x' P" @' T$ D4 H( n+ s
  41.     if (HAL_QSPI_Transmit(&QSPIHandle, _pBuf, 10000) != HAL_OK)  C$ W* d" y0 A0 e3 o$ x9 l
  42.     {0 Z7 ]8 X  k4 A& T* O7 T+ G
  43.         //return 0;
    ! f+ F( p: n8 K# W5 r2 w1 c7 s
  44.         Error_Handler(__FILE__, __LINE__);
    ! h* ~$ ]' K) d4 _0 Y

  45. 8 c+ R+ d( I' j
  46.     }
    7 }* J! J5 ~2 }' K" [

  47. ; d( j% I- ~; U. h# S7 e. r
  48.     QSPI_AutoPollingMemReady(&QSPIHandle);   
    . E* Y' i+ v4 k3 y  V$ L
  49.   n) P, x4 C/ y: ^' r7 r
  50.     return 1;. e! E. @/ ?: A! z% F
  51. }
复制代码

  _4 r! h1 r4 i" ^; F8 r7 d$ o7 t78.4.8 函数HAL_QSPI_Receive2 L& s# o1 P* f5 G+ e
函数原型:8 `, P6 F# |* Y2 M5 D; ^7 D

6 k" z: A- m8 @' P5 C- t
  1. HAL_StatusTypeDef HAL_QSPI_Receive(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)
    2 o2 {  f8 u( _( ^; x& W9 J# v
  2. {6 p, b/ i* y% ^
  3.   HAL_StatusTypeDef status = HAL_OK;$ m5 }( b5 j0 f; L- f' W, f
  4.   uint32_t tickstart = HAL_GetTick();
    6 |5 A  }# v; D& T* ?
  5.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);
      q; O  ]" x$ P0 b1 |/ F5 f  [
  6.   __IO uint32_t *data_reg = &hqspi->Instance->DR;5 N5 v6 ~1 M, Z3 O9 D5 W
  7. ; P: w5 {2 a2 X: ?" M) |
  8.   /* 上锁 */
    # G- Z& S  Q, }# g# g0 q
  9.   __HAL_LOCK(hqspi);
    1 v" V. \; U& w3 E- C

  10. 1 E: D' h& ]2 B! P0 Z6 G( U% J; |
  11.   if(hqspi->State == HAL_QSPI_STATE_READY)
    - X% e4 `# x1 ]7 E4 ]" `( m
  12.   {
    ! f0 O4 d) C: E; t5 J; o
  13.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;- `5 k$ _/ Z% m+ b% J* u2 k
  14. 0 m( M) b& m% d( N/ e
  15.     if(pData != NULL )
    , u/ f( E) P0 ]! k
  16.     {
    " n& X( E; a* y% B
  17.       /* 更新状态 */
    ( ?8 i2 e& V5 g. P$ o
  18.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;
    8 L9 w' e9 X! ]8 Q/ O
  19. ; m; k1 y3 V( G( K* t* j
  20.       /* 配置接收 */3 M" q9 {, q0 F
  21.       hqspi->RxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;* d1 a$ e6 E! |2 B3 C4 A' p
  22.       hqspi->RxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;' {3 B6 M; y& Q# }  _  c3 i
  23.       hqspi->pRxBuffPtr = pData;7 J. t, n% x3 b2 z" c* F

  24. * u: U" _2 G: k7 D" U
  25.       /* 配置QSPI,间接模式 */
    ( n" d% C2 Y) k; ^8 C7 {; I8 M
  26.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);
    8 [/ z9 u. o% u" ?4 |

  27. + K# f! }1 n+ |7 Y* }* U- P
  28.       /* 启动传输 */
    , v/ p. L1 c: [' N, r: w' Y% o$ ^
  29.       WRITE_REG(hqspi->Instance->AR, addr_reg);/ e% J% X) i# r' A
  30. ' R4 A/ N  ^1 Z
  31.       while(hqspi->RxXferCount > 0U)' k+ k2 y3 U; s9 }& U  |) M, ^7 }
  32.       {* K8 v1 ]0 o3 h, B5 i- ]% p2 @* E
  33.         /* 等FT和TC标志 */, I+ N% {/ D' r. t1 p
  34.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, (QSPI_FLAG_FT | QSPI_FLAG_TC), SET, tickstart, Timeout);  u3 i, `$ }/ Z& @' H

  35. 6 B8 C0 q) l: Y' @9 R7 `. ]
  36.         if  (status != HAL_OK)( e3 n: n8 u% `" D4 V& U
  37.         {
    6 f# R$ G) O" G1 D: v
  38.           break;
    + r* o1 N1 ], W8 A) @: |
  39.         }$ N9 I" o  I6 u. F% B
  40. " x9 _+ l1 R# F9 h6 u
  41.         *hqspi->pRxBuffPtr = *((__IO uint8_t *)data_reg);
    ; i6 T) W9 D0 ]  q
  42.         hqspi->pRxBuffPtr++;9 w, C; w/ K& s* p8 D
  43.         hqspi->RxXferCount--;; J* a& U) F1 H) ^$ U. J
  44.       }0 q+ y$ \" o+ [& p, }. T
  45. 5 {3 ~: @/ J6 U! C% K5 r( Y6 x
  46.       if (status == HAL_OK). _( N4 y% i. I' Y
  47.       {
    9 ~: D% n9 Q9 k8 z, u: q3 H2 H
  48.         /* 等待TC标志 */" n( N; U9 P3 [" z( V
  49.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);6 k* h" n% [" P' e2 R3 ?5 {

  50. $ F. l# g6 s/ x& u* o( d  m3 @
  51.         if  (status == HAL_OK)( |1 k+ `% V8 t3 `$ \& F1 |
  52.         {" d2 S6 y6 v( {
  53.           /* 清楚传输完成bit */2 l  ?, G0 {# B. u
  54.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);+ B! k* P$ A7 B; M; G3 x

  55. 8 p( u1 L9 `4 x) w/ p3 V; m
  56.         }- O8 u( {: h: z& H; M
  57.       }
    % W# ?% u+ x: {& W) S$ d7 a

  58. - m! j( U8 }7 q2 |
  59.       /* 更新QSPI状态 */  _1 k# A6 N0 {; m! O- J& i
  60.       hqspi->State = HAL_QSPI_STATE_READY;
    1 {- [$ Z) B0 F* b" t# U
  61.     }
    $ K5 ~8 H3 k- |* e) P! k
  62.     else
    1 s8 e( _6 I; [
  63.     {
    8 ?( m; R) t. q) V$ y# q  H
  64.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;% }- o1 Y  f$ O8 m( q3 ?
  65.       status = HAL_ERROR;
    % I" k: y6 q# ~% J+ ~) w- B
  66.     }
    & W! v4 A: D2 x, M0 ?( h% G
  67.   }
    5 W6 P. d4 T/ I4 ~% }- u3 ]2 d9 L
  68.   else
    # a7 ~6 X" c( G6 i
  69.   {) J5 a$ f" V" }# N- e5 ?
  70.     status = HAL_BUSY;& m: W6 _7 j( G- N. M: q# h2 s3 p
  71.   }  }* w' V( Q9 _4 l  \+ I
  72. 2 j, x; r9 s- b2 Q! r* T
  73.   /* 解锁 */
    # \: o6 s0 `( R" d( I" _! d
  74.   __HAL_UNLOCK(hqspi);
    + z; G2 @  w6 ]

  75. + F+ }0 Z" _1 R( B5 \/ w
  76.   return status;
    $ e* _! E$ n: j
  77. }
复制代码

/ e- v% E1 f; v1 x函数描述:
3 o7 B/ j) h; X) D, f4 W- P" [/ O+ _9 {, T" `1 c$ V0 Y) ]* N
此函数用于QSPI接口数据接收,函数采用查询方式。
- S3 G- k# d/ T" M
. S& V' ~9 @  v0 j; \; j: a函数参数:
% W% [( |) V8 T: d/ b1 t+ k; y+ B+ l, p" ]# u+ x5 f
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
2 T, W; U' }7 {  第2个参数是要接收的数据地址。; i2 f, F+ d( `
  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。5 x" A  M+ I- J5 e) s
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
7 Y* Z3 Z" e& F5 g- ^使用举例:
$ K2 M: Q- I9 ^. |% s- O
6 H0 ?  r0 E! t* M, k
  1. /*
    $ m6 Y. Y, Z( ^3 ?6 g* N/ m
  2. *********************************************************************************************************
    ' G8 D3 A5 u& I5 }9 L1 Y
  3. *    函 数 名: QSPI_ReadBuffer
    % q# i1 ?9 @; J. |
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。
    ( Y; Q9 b0 u/ D( P. I* y
  5. *    形    参: _pBuf : 数据源缓冲区。# ?, C8 G) A) f1 l, Q6 p
  6. *              _uiReadAddr :起始地址。# u; i# J$ ~8 q1 M3 Y7 v1 {( V  N
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
    + {6 {3 c  m5 e5 ~- ]- u
  8. *    返 回 值: 无
    / f$ z' B1 b% n% n, F
  9. *********************************************************************************************************
    5 ~, w( {$ w) _* a: ?
  10. */( X8 R8 S! _6 p6 b( a5 }1 b1 {
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
    * Y' c0 J( Y# O
  12. {7 }! F; q1 g/ ^* L/ m

  13. 3 z# I$ `: n( M( K7 h1 E
  14.     QSPI_CommandTypeDef sCommand = {0};
    5 X/ V% v* b4 x, N
  15. 5 z' ~6 W8 J' W4 H

  16. 6 T8 D: {. `; t- n8 e
  17.     /* 基本配置 */
    ) Q3 Z+ ?! a6 ?  j/ b
  18.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */
    " ^7 g0 }8 L& w
  19.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */# q/ C  f! \' t3 h- v
  20.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 */$ v- u) ^% s# i/ S8 S9 @
  21.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */
    . i: r! ^( s7 F* V$ q  U
  22.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */* t' x3 x0 j& R. V, T% l# e7 n
  23.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */   
    8 V( ^, r. J9 A2 \- t! e

  24. $ j8 ^4 o* J9 s
  25.     /* 读取数据 */( i& y1 h5 U1 `
  26.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */4 F" J& W8 G4 e# W* _5 R. r: l  @- B
  27.     sCommand.DummyCycles = 6;                    /* 空周期 */  j0 c, T& y2 e/ w/ z
  28.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */
    : p5 b- ~- h2 d/ T# C) I4 N1 V! t
  29.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */
    * ?" y$ q' T% [* ]: ^3 T
  30.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */ 9 K$ Q$ l7 o- M$ ]
  31.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */ 1 x3 n! b. h' P# \1 D& C( B! l$ W- X
  32. ) }1 E5 P5 ?/ t: U8 b# h! t1 B
  33.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
    . F( E- h. c  d9 y3 C4 @
  34.     {) |: Q: q) a6 x/ M+ J
  35.         Error_Handler(__FILE__, __LINE__);
    ( H: i: f$ X+ {
  36.     }4 [7 `4 I! T* h/ h, B
  37. : H* }. g3 `- b
  38.     /* 读取 */
    / @% ], V+ z5 ~. J# c
  39.     if (HAL_QSPI_Receive(&QSPIHandle, _pBuf, 10000) != HAL_OK)( x" V! E5 N, |: l8 x
  40.     {
    3 i4 X* N# E5 N. F  o
  41.         Error_Handler(__FILE__, __LINE__);; x* u$ F4 U& E4 ]
  42.     }    / {8 z& Z3 o5 C2 {. G
  43. }
复制代码
/ X4 i1 H8 B0 j; X2 m
78.4.9 函数HAL_QSPI_Transmit_DMA
6 t- w4 Q5 L) W. D) v7 S" K" x函数原型:/ G. c2 A! e1 Y6 J* l) K8 s% g- ]
8 i7 e2 h& v; z& i; I* @
  1. HAL_StatusTypeDef HAL_QSPI_Transmit_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData)5 r1 ^+ V9 z8 i3 b4 S: I: I! x& D
  2. {
    ) F, F" B! k3 E/ i
  3.   HAL_StatusTypeDef status = HAL_OK;
    8 O$ e) O  w$ u' `# Q
  4.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);
      z( I+ y, W6 W7 x0 l" C

  5. $ V% u- o0 b: k* T9 k
  6.   /* 上锁 */
    3 d. q* i# e( q7 L( ~. b
  7.   __HAL_LOCK(hqspi);
    ) ^$ s' N; D! X' l
  8. , d+ W7 D# Q# d
  9.   if(hqspi->State == HAL_QSPI_STATE_READY)* z1 s- _% X7 I# U4 P  l
  10.   {( X) n2 p3 L0 ?3 g
  11.     /* 无错误 */3 b1 j# M, K9 ^
  12.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    ) e8 j. k' o! R8 i
  13. : a1 \& @9 D% L- a. H. D
  14.     if(pData != NULL )
    " A- t/ r. z# h4 }" Y' X
  15.     {
    1 L6 z8 D8 ?, X1 q! d5 U- p1 h) D
  16.       /* 配置发送字节数 */! c( l, g4 c* X6 r1 t
  17.       hqspi->TxXferCount = data_size;
    " ~' ]( v3 F6 `) j
  18. ! J& V& I( J1 U! q+ m
  19.         /* 设置QSPI状态 */
    7 v5 {; l9 a- ]/ ?5 Y# `
  20.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;7 W# |( u# x& z  H6 s( D  b5 B* A

  21. 9 @5 K) C) t" P1 \1 k* S
  22.         /* 清除中断标志 */
    $ N6 J+ _5 q' d8 l# ]" Y$ t
  23.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));
    7 R; i, R* F1 x' M) {: F: _3 v  t" W

  24. 2 @/ i8 v/ b1 x) L& a* i& H0 s0 V
  25.         /* 配置发送 */" e( E1 q9 E5 r
  26.         hqspi->TxXferSize = hqspi->TxXferCount;$ ^8 t! W: K/ V: r3 `9 |& p
  27.         hqspi->pTxBuffPtr = pData;2 ?2 @. b% r) F* i
  28. " k. X! N+ {% I" \9 v) N0 m
  29.         /* 配置间接写模式 */
    1 V" g3 S9 C8 L8 F7 @+ }
  30.         MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);% w  T' z) O! O: E
  31. 3 C4 |0 p$ D; y
  32.         /* 设置MDMA发送完回调 */
    4 x6 x& B% S5 E/ k
  33.         hqspi->hmdma->XferCpltCallback = QSPI_DMATxCplt;  G. u7 S. N1 i4 \' f* n
  34. ! q# R: n4 K' g
  35.         /* 设置MDMA错误回调 */" @- x  y/ _8 t4 j2 Y5 [+ t
  36.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;
    : y. l6 t; o# j7 v/ x
  37. - R) y+ o, z4 X
  38.         /* 设置MDMA终止传输回调为NULL */& N& [+ J$ L" Z/ V2 k$ R0 a
  39.         hqspi->hmdma->XferAbortCallback = NULL;
    4 @$ J5 e' J, b! p; k1 o
  40. 3 e8 }' `6 D! L( E0 V8 R% U# |
  41.         /* MDMA的目的地址是QSPI DR寄存器,设置禁止递增 */
    ! m0 m/ c) t: n
  42.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) ,MDMA_DEST_INC_DISABLE);
    2 [+ F, k7 p4 t) u

  43.   X0 F: _5 J" I7 H
  44.         /* 更新MDMA源地址配置 */0 g3 B# E# L! N& _, z
  45.         if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_BYTE): i- E3 f# P+ o( w8 T% R7 t% y3 a
  46.         {) ]* E6 J  T8 s3 k
  47.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_BYTE);, z1 c2 |) j5 m( G& A7 p
  48.         }
    2 ?( q0 R6 Q3 e! P& @6 Z
  49.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_HALFWORD)1 o, w* M. ]4 R% m* |
  50.         {+ t5 {8 e6 O- q7 K9 y2 }+ w
  51.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) ,
    2 k' M6 r7 W8 n  l% N' z
  52. MDMA_SRC_INC_HALFWORD);
    1 g" f+ F. D- k- O: ?5 a
  53.         }+ d+ I: Z9 h# a* t
  54.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_WORD)
    " f* {5 H# f9 B5 S5 |
  55.         {) h, y( o7 n+ C% }: ]& h0 F2 x
  56.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_WORD);
    8 z1 U9 I' Y, W; R- W$ ?' w: g3 ]
  57.         }
    . y# N3 _# q% j6 \. f& c
  58.         else
    / u$ s+ a  H3 B5 |# s! H: c5 F
  59.         {
    % f  T, M/ g3 i+ R" P' `
  60.           /* 配置错误 */* o) O/ e/ F9 c* C; W3 C
  61.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;' D' O. P' U* j) }" D
  62.           status = HAL_ERROR;% F- \* H( O2 @) K. x4 E  l
  63.         }4 _& m/ o5 H2 _" J) ]

  64. : p; n3 O. q8 B) U* o9 t/ H
  65.         /* 使能QSPI MDMA发送 */0 l# W$ M. ~; V( Z" k9 x
  66.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)pData, (uint32_t)&hqspi->Instance->DR,& ^) O  s2 u) D# c" O! s7 j
  67. hqspi->TxXferSize, 1) == HAL_OK)/ s) N. r  _: e9 Q; _2 D
  68.         {
    2 W3 O6 b! C3 u9 |) A$ S
  69.           /* 解锁 */
    2 W  I) |) r6 p$ h0 k! T
  70.           __HAL_UNLOCK(hqspi);
    - G8 s  ~/ C1 k$ A8 G) u5 A
  71. 6 G$ k5 Z: C2 {$ v- P$ T' O) D
  72.           /* 使能QSPI传输错误中断 */& V9 [1 h/ ^, w$ C  d4 I0 s
  73.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);: F+ l- M7 g3 A) A

  74. ; K: [/ f4 x" ^8 y. X4 X9 ~5 T
  75.           /* 使能MDMA传输 */2 N3 a; x+ }9 m" K# S2 Q1 x
  76.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);* X6 ]) E" N! L1 M7 Q* N. @
  77.         }
    8 N/ D5 x' k. B" m' I! j0 ?7 c3 ?
  78.         else9 K' V$ |: g, b7 I
  79.         {6 H& M( b2 v( ]6 F0 i" \
  80.           status = HAL_ERROR;
    5 M7 n. N$ A. ]5 j6 O4 _
  81.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
    - b$ h$ b) c" y0 L* @4 B, Y0 f& B) {
  82.           hqspi->State = HAL_QSPI_STATE_READY;
    * E% ^4 Q1 E4 D5 e
  83. 8 p0 d. U8 M8 o# F+ ]8 O
  84.           /* 解锁 */# N: n+ P  e) Q' }
  85.           __HAL_UNLOCK(hqspi);# I* F& s. V' @1 }( F
  86.         }+ Y0 i& |6 l& T1 l3 w/ p
  87.     }
    ( {6 U# J% _$ _/ e
  88.     else
    ! }; @2 |5 n. C% o7 U& O
  89.     {
    # t- z  ~8 m9 {0 r. P% Z
  90.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;+ G+ c6 C# P: v2 `, x7 l: Q' b
  91.       status = HAL_ERROR;$ D3 y, w# s, a
  92. 1 m! o) B; M$ I" s, H4 a
  93.       /* 解锁 */
    4 Y& S% @5 i1 U% O5 v* B6 a5 x
  94.       __HAL_UNLOCK(hqspi);
    ; S7 W5 s& T$ E+ g( }; i% ?
  95.     }3 v6 F& Q5 v& T; Y8 r
  96.   }3 G$ M7 e( g3 F% M% r: {# H" R
  97.   else
    9 `0 N8 s/ J; I
  98.   {6 Q1 \6 _2 c) S
  99.     status = HAL_BUSY;$ u9 V* q7 Y7 g/ @9 i# I

  100. 1 j- i  G3 {/ G5 y& ~) X* C
  101.     /* 解锁 */
    4 }" \, j$ L$ l& a" S0 d6 T6 F
  102.     __HAL_UNLOCK(hqspi);8 d/ m6 O0 A* }7 K0 E
  103.   }
    ( [$ Q& I: }$ x% M5 Z! v' S
  104. ( i: v8 x- O. c/ o$ b% }5 y# D
  105.   return status;* K  z3 Q# _4 ~2 I
  106. }
复制代码
. t) i& M; W" r  p5 X; a5 ~
函数描述:( ~! l6 I* {/ _; i' w# S
& _% S- W2 v) e' |6 t' D# K
此函数用于QSPI接口数据发送,函数采用DMA方式。
7 I8 R6 s5 h0 N8 ]9 @$ d+ A1 ]+ ~' B( A3 m
函数参数:
- L9 h9 Y+ Q0 r' h, ~
; W$ o9 i5 y3 H  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。' m- ^6 X6 ?* |1 r
  第2个参数是要接收的数据地址。" r7 ?* t3 h! `: b
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
6 }. x! Y2 C- K" ~5 }% O0 c使用举例:
. [2 E+ N. J, D. V5 p
. k1 A! R/ E6 p3 v7 a+ A
  1. /** A4 V' q; B0 j* f6 X
  2. *********************************************************************************************************
    2 Q% M- i4 S# F: F: t
  3. *    函 数 名: QSPI_WriteBuffer
    $ l) E4 o4 S) y8 ?& R& F
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入
    - ^3 v% W( G" N$ b
  5. *    形    参: _pBuf : 数据源缓冲区;' K: |9 `8 P) A' l, x/ U* [% i
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。3 h# g* |" h: ^9 \; W0 K0 z3 D8 F4 S
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。
    & O! l. h1 @  t7 k" J
  8. *    返 回 值: 1:成功, 0:失败% ]* C& N" U3 k4 X( }. C3 }
  9. *********************************************************************************************************1 k9 _8 D( q* U+ u' u: Q7 b% ~
  10. */
    / i) q$ d1 |* t, |& w
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)3 h! O. l  O& Z/ h" `/ p- P( H5 i
  12. {( m8 I+ v, Z9 C& t
  13.     QSPI_CommandTypeDef sCommand={0};4 p  T' O  f& F+ J  K0 ~

  14. % K7 |* x+ ^$ H) T6 N9 L7 I0 F
  15.     /* 写使能 */" a" e1 Z2 |( `% R
  16.     QSPI_WriteEnable(&QSPIHandle);    , E* y6 }# K; g8 ~) c9 c

  17. 1 o. `3 F* h: s& x
  18.     /* 基本配置 */
    : J: H6 T) u! n
  19.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 *// b) X4 Q/ u" x. F9 h
  20.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    + I* A+ \% Z9 X) k9 k
  21.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    5 d, K8 ?" o: a% v% n# q, w0 z
  22.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    6 @; s2 `9 o' [( H3 q8 ]" `  b* q. p
  23.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
    . K+ ]* ]9 s' j
  24.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */    + [" }( P$ @0 o+ o8 o7 `. P$ u' ]

  25. $ x- n, G0 ]$ n: N. H* J
  26.     /* 写序列配置 */) q* C9 ?. t5 C8 x" H
  27.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */
    ) f  p. t- L  J- c$ w% s
  28.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */5 Z# }5 U0 I3 c: B# o: x
  29.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */
    ; ?% q  Y0 O4 s0 ^, A( ]4 J6 e4 Q
  30.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */7 I! r( \8 c. T8 w$ X
  31.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   5 t" s( `4 q8 e. b
  32.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 */. F  Y* a. D; r+ S9 V* n1 U# R
  33. ( f) @. {+ Y$ B) E* L
  34.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK). k: U& z0 H. {( `- o
  35.     {" h2 k" O0 H$ f8 O; P
  36.         //return 0;
    2 M4 W; }! k6 }# g, ?: z
  37.         Error_Handler(__FILE__, __LINE__);7 h+ p8 R" q( q
  38.     }" r7 S% r3 @  ^, W# T, K

  39. " r' H1 H9 ]  o: p$ a4 c# j! S
  40.     /* 启动传输 */
    . \1 j! w, E9 |9 T! v9 o
  41.     if (HAL_QSPI_Transmit_DMA(&QSPIHandle, _pBuf) != HAL_OK)# C' o6 ?6 @' m  V, i
  42.     {' `6 e- I, {* G7 [6 b( L
  43.         //return 0;
    % h3 c3 Z- q9 X4 u' q$ k
  44.         Error_Handler(__FILE__, __LINE__);' p7 M8 G* }3 L& y1 H
  45.     }
    # E: u3 I: W; g8 j7 n
  46. - d' O" g% R# i, R
  47.     QSPI_AutoPollingMemReady(&QSPIHandle);   
    . Z  E. M/ `2 v# W( G9 e: ?0 [

  48. 6 p. w- x) s+ V6 m7 G8 C  s
  49.     return 1;) s* f6 H& H% ^; G8 ~
  50. }
复制代码

& V9 K* M" G3 K7 ?8 x4 E2 t78.4.10   函数HAL_QSPI_Receive_DMA
8 ], R3 }) E2 l4 b$ H0 c; h函数原型:# X- G' }7 W$ L% Q( n4 I

, C. D1 F* n. r( `6 P$ R" F
  1. HAL_StatusTypeDef HAL_QSPI_Receive_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData)$ @% o5 l& ~6 c) R: U4 w/ I
  2. {
    2 f2 D7 {$ p% k8 J* J+ f' [/ P$ `
  3.   HAL_StatusTypeDef status = HAL_OK;
    8 F( H  ~2 }) T" G
  4.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);8 P1 B, A# f" q5 \- T6 U0 N
  5.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);+ R; u  J- N& C" N3 Z# }' g0 t

  6. , P3 b( h$ h7 h2 |& ~2 B1 b
  7.   /* 上锁 */) u6 }) c& n/ E  ]) E: s
  8.   __HAL_LOCK(hqspi);0 j/ c( ?% ~, G: s  q% y; y

  9. 8 @. y+ f* G6 `- z) K, a
  10.   if(hqspi->State == HAL_QSPI_STATE_READY)) ?; e7 i/ z$ E; @& J4 H6 ~
  11.   {
    " ^  A0 z  l; {# I2 C+ b$ r
  12.     /* 无错误 */
    # i5 S* h/ B; X: u4 H0 q2 `, w
  13.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    $ u$ R; C: m4 l! Q  j, l8 R
  14. % _# y1 w2 J: S  p! E
  15.     if(pData != NULL )
    7 v2 u7 V; b" y) O6 M' q& h! o
  16.     {
    : @: T8 X4 K6 i7 E
  17.       /* 配置接收 */
    ' [& y" x" m( y  v1 M6 `
  18.       hqspi->RxXferCount = data_size;
    0 \! [4 C+ _0 v+ b% ]
  19.         /* 更新状态 */( _" [& `% d, T2 n9 q
  20.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;
    ; g! X& C( F! _3 J6 ?
  21. 6 f! P7 _* h: i/ \  n
  22.         /* 清除中断标志 *// w! z: X7 i- o$ V8 B
  23.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));' L4 a! T0 c% o& Y2 C" F

  24. 1 s6 c$ l$ ~% ^
  25.         /* 配置接收 Configure */
    ' z, r3 B" x7 U  ?+ J
  26.         hqspi->RxXferSize = hqspi->RxXferCount;
    ) @& p) g. ?6 j9 W# D
  27.         hqspi->pRxBuffPtr = pData;( M; S3 F+ J. G1 S

  28. 9 A6 V- X5 A) h/ ?/ Z. l$ K
  29.         /* 设置接收完成中断 */
    3 ~+ i4 M* y/ l& v, M
  30.         hqspi->hmdma->XferCpltCallback = QSPI_DMARxCplt;2 K3 O7 F1 V: }1 q0 D4 B/ @1 i6 [

  31. ) ^( D- P! j" W3 j3 T7 g
  32.         /* 设置MDMA错误回调 */
    / o8 B  C- J3 @2 \9 R2 Q
  33.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;
    3 w6 i$ o3 T9 ~! }0 C$ K2 f3 A2 `

  34. : M  S3 r6 O2 i, h4 ?0 Q/ ^& Y
  35.         /* 置空MDMA终止回调 */
    8 G/ I) J5 F0 k% Y$ d6 r
  36.         hqspi->hmdma->XferAbortCallback = NULL;
    ) u+ l& w% R+ B! H! Q" S# B

  37. ) [" {/ K% J6 x$ g; G: _( Q( W6 E# ]3 u
  38.       /* 接收模式下,MDMA的源地址是QSPI DR,要禁止地址自增 */" Y3 M; U2 {" E0 d+ K
  39.       MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_DISABLE);
    . X. ^  H2 u" z

  40. - d0 p- U7 A  ]- \& h6 H( v
  41.       /* 更新目的地址配置 */
    / j: s. s' b; B. r9 @* D/ v
  42.       if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_BYTE)* u" \: l  X) ~
  43.       {
    1 i1 B4 u9 }! `! m- R  N! h
  44.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_BYTE);2 j+ o4 O9 H5 a( Z1 @1 {# Z
  45.       }$ o3 l( `! b5 ~! ?# W8 [
  46.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_HALFWORD)- r; x4 Z$ A/ k' K3 e0 C  U
  47.       {) ]& @4 [3 U' p: U, O0 _5 j
  48.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) ,
    ) b" e9 ]/ v3 Y8 N
  49. MDMA_DEST_INC_HALFWORD);" x. h# t: p! z5 J8 P6 Q5 N+ [
  50.       }
    1 G2 Z7 P2 n8 |. F
  51.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_WORD)2 s. _% c  u+ ^4 M4 i! g$ F, {
  52.       {
    # I# C) e3 u& b9 K
  53.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_WORD);
    - O, f+ q1 t, z
  54.       }, V& n$ I7 Q6 C  t
  55.       else" d. l8 L( T9 ?3 F% x4 T
  56.       {. P6 _/ x: w4 j5 P! v
  57.        /* 配置错误 */
    + h4 d! S# K$ E$ U. f/ l
  58.         hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;; [7 x  ?  J) ?7 K6 L" l
  59.         status = HAL_ERROR;6 R! Q0 w% }- Y$ b4 z; s, q9 c5 |
  60.       }
    ( ?1 Z+ ^3 ?) i: [! Z7 T
  61.           /* 配置CCR寄存器,间接读 */4 b" h( \2 F" F/ \$ v
  62.           MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);, \& @0 W+ G. G, o: {: Y, a

  63. 7 P7 T' {! l; W2 f
  64.           /* 启动传输 */( m- }! s  j& x# v$ b" p
  65.           WRITE_REG(hqspi->Instance->AR, addr_reg);
    + _6 d5 N0 P+ }. D. C
  66. . a; v0 q5 F" U; c
  67.         /* 使能MDMA */" }4 z( h' B* Y* a
  68.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)&hqspi->Instance->DR, (uint32_t)pData,- T( o, ]% D5 B- r2 }. `+ o3 \! Y( r
  69. hqspi->RxXferSize, 1) == HAL_OK), Z7 o2 F, M- k4 ~% B2 p
  70.         {7 [# q" p5 {6 r
  71.           /* 解锁 */" _0 b; t, F& a/ O
  72.           __HAL_UNLOCK(hqspi);
    6 \4 G0 z% }* ?! u* E# I6 @

  73. 1 t% U) |/ t# H- J& g
  74.           /* 使能传输错误中断 */
      I7 Y& ~  s9 A2 G  I4 G
  75.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);
    ) g* O$ \% y8 W- F8 _
  76. " c4 M' m: @5 Z1 N6 c0 I
  77.           /* 使能MDMA传输 */
    $ |$ y) k" c6 c- P
  78.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);; T0 k, P# x3 \; ^
  79.         }; }2 y$ ^+ P8 o0 t! d( v
  80.         else
    1 J0 p& q( ^, r3 v' k
  81.         {
    / b9 ?8 I/ `4 O
  82.           status = HAL_ERROR;
    ) o% q0 r) {6 k8 u
  83.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
    7 v$ A0 W1 ~3 J
  84.           hqspi->State = HAL_QSPI_STATE_READY;; t, R: [$ x# W+ b# c' R% s

  85. 6 k% }0 w$ F" k( h9 |% X9 h# N1 }
  86.           /* 解锁 */
    ) R. v! p; L( p, v; ]
  87.           __HAL_UNLOCK(hqspi);& b) n& V' @- |. N4 O
  88.         }! x8 N1 V) e( e1 m. {8 E  Q
  89.     }3 V9 |( h2 n" W5 i* u
  90.     else+ b# n6 U5 |' [$ }. R0 D# N) V
  91.     {
    ! F$ I; O. ?; l4 J# h( Q
  92.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
    $ w, ]3 \8 Z( P# q# Q4 {
  93.       status = HAL_ERROR;' N$ \* y9 ^  T7 C

  94. # a4 B1 |. K  ~' h2 n* S7 S( H
  95.       /* 解锁 */: |% O# [: U+ Z; D9 |1 g& M% e! G) m( T
  96.       __HAL_UNLOCK(hqspi);
      _, ?+ p2 o( `0 Y
  97.     }
    ( E4 H# u; w2 j* [% ~8 `
  98.   }7 n8 _( ?" K2 Z8 F) X
  99.   else* _+ C4 f( ~! @! w+ U, T6 J
  100.   {8 J- i+ f! j( U1 B
  101.     status = HAL_BUSY;8 P2 p; \7 c3 L, ]5 k- X0 w

  102. / L! m# m. |8 o$ Y0 T5 O
  103.     /* 解锁 */
    % c( O* Q) c8 i+ _
  104.     __HAL_UNLOCK(hqspi);
    1 k0 x+ }/ ]4 e( d
  105.   }
    7 n1 _& {6 M  h3 T$ h
  106. $ U# T4 m! B! P# n" Y6 F1 B) w+ S& c0 E
  107.   return status;& m1 Y; V) N/ }/ v6 V$ `- \1 R
  108. }
复制代码
/ F4 J, k" f9 l( k8 K  v
函数描述:
0 l' k5 T6 z/ f2 W) N6 e$ R( ~1 F/ h$ c
此函数用于QSPI接口数据接收,函数采用DMA方式。
& o$ V$ x! E0 d
1 x9 Y8 }# {7 n* _- u- G8 l函数参数:# s9 A& _7 E7 M8 n% n

1 a+ k; k$ b" J6 T+ g) F- f" e* v7 l2 J  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。$ T* x' q9 C  ^
  第2个参数是要接收的数据地址。
  _* T9 `6 {5 r, Q) y  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。! b/ u- g0 ]1 x5 v: m
使用举例:. h: R. I/ n! X% |2 |9 [
& r( i' I# X! c  m; f
  1. /*
    7 I: R5 Y9 x7 {
  2. *********************************************************************************************************
    - B3 d& S9 Q7 q5 \: b; |+ X$ o
  3. *    函 数 名: QSPI_ReadBuffer
    8 W) a) D! b1 w5 ]1 P% }( L% m
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。4 ]8 i, t6 D! N  o) f
  5. *    形    参: _pBuf : 数据源缓冲区。* @) v5 ~* U+ S4 I. l, t
  6. *              _uiReadAddr :起始地址。
    4 p+ Z% W$ A2 U7 |7 A8 A
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
    5 D1 X  \! H- q8 m
  8. *    返 回 值: 无
    + C/ g2 y" @! U
  9. *********************************************************************************************************
    6 k' T2 n5 u! x8 R
  10. */) W& c3 d* ]' p1 q$ x
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)5 O* w, R; b; _/ |
  12. {
    : P7 H! [/ e3 `* W4 e
  13. 7 ?; ~! Z4 V- O* S7 X" b6 R
  14.     QSPI_CommandTypeDef sCommand = {0};
    + t9 a( ?" ~8 ?
  15. ( _- [- ?# M# j0 X

  16. / f$ p/ c$ p4 P# m3 V* A8 ]
  17.     /* 基本配置 */
    9 ^0 w7 d7 B" c( h6 o
  18.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */; x0 G" _, i( f2 s- [: [
  19.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */, J! ]/ B! q1 N" x" O$ F5 ~+ L
  20.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 *// ~6 u5 k# O/ u* k+ I: l2 Y
  21.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */) r) Y% H* n; T) {  M3 F$ s
  22.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */3 w# z, ~# a6 w% F
  23.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */    0 h, }9 H/ F8 V3 j1 D, f
  24. ' N# T' B& M/ A( A4 s
  25.     /* 读取数据 */
    : r6 G5 j) ~: W/ o) E1 D4 w  z
  26.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */- k- i/ s/ Z4 |
  27.     sCommand.DummyCycles = 6;                    /* 空周期 */; U$ I2 ~3 u+ u* C
  28.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */3 C! M7 f' K5 d4 Y+ R* e5 D4 s
  29.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */
      v% b1 r) u/ s( I; U
  30.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */
    : w+ U$ p: b6 i) E3 ?) a
  31.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */
    2 q! [9 i- n4 k0 d. O- a8 [

  32. # ?( B8 m4 o" B% `& E8 x
  33.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
    ' S8 _! w  [0 z5 V
  34.     {
    & {: J: n. ~; N  m( Q' L! ?' c5 Y
  35.         Error_Handler(__FILE__, __LINE__);
    + H8 _, X$ @; F# q& C
  36.     }
    8 d& [! a, {+ R$ W# L  [: ^
  37. + i$ B5 s' M6 v
  38.     /* 读取 */
    6 F- e2 J, T, k3 K% c. O, o
  39.     if (HAL_QSPI_Receive_DMA(&QSPIHandle, _pBuf) != HAL_OK)
    ' N8 i1 X. U# O' o! V
  40.     {
    ' w  s) y8 c: }! z4 E6 Z# j- A% C
  41.         Error_Handler(__FILE__, __LINE__);1 I- W. v8 ?: x8 a. H6 a8 |
  42.     }    6 V/ M! f5 ?- C7 R' W
  43. }
复制代码
  I9 M- Q$ P5 [% P% h
78.4.11   函数HAL_QSPI_MemoryMapped
% k9 ]0 S5 n" |2 K. s0 z函数原型:2 W6 |1 s) R# p; D/ F/ U1 D# ?
# _4 L! H: t' V. Z6 J
  1. HAL_StatusTypeDef HAL_QSPI_MemoryMapped(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_MemoryMappedTypeDef *cfg)
    3 L/ v% \: h$ X) y1 S
  2. {
    + y3 y& {* F8 D7 h) V5 a
  3.   HAL_StatusTypeDef status;
      e  S: [) S2 E7 I
  4.   uint32_t tickstart = HAL_GetTick();- \3 j# g- z" w+ }/ H/ C. b
  5. - q: V4 y3 j  a
  6.   /* 检查参数 */$ G" _7 L5 ]4 F- r
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));) |0 C% E6 B' B8 _1 V/ \/ Z
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)3 d0 w8 n9 L7 g: |" G$ E/ `1 g
  9.   {- M! ^2 T% l6 ^
  10.   assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));. S9 c9 Y9 L3 H: X% E1 e0 V2 C
  11.   }$ ?7 e+ t2 y1 B7 B) o

  12. % x5 i, P4 X' p" P9 x! I* N
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));2 p3 h3 W, d+ ~5 m3 u
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
    " S, P6 W  Q. f" K* A
  15.   {
    - V0 ~# t- W2 P8 S9 o* f8 E  X
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
    ' Q1 h" ^8 p% S4 e
  17.   }6 R6 B  u6 C4 f/ O0 `

  18. : Z3 N/ K1 B6 R: y5 H
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));" d6 x! D. n- E6 O
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    8 y8 m  ~9 m1 y0 O+ V( Z
  21.   {
    & ]" n5 v# Q, ]6 q- N1 O, f% a
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
    & j* V. a7 s* R8 p/ q" {0 M
  23.   }* G) T3 Y+ ~' [6 {1 W, F4 l5 U5 m

  24. $ H3 T. B! Z1 d
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    . E5 q* [' Y; V! d+ }3 T
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));1 s6 q( K0 P6 L2 p5 o

  27. ; A  @; ^  K1 f+ R7 w, W: Q
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    ! S, a3 [4 U" h* N$ w+ ?; T
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));0 {* ]5 Q/ |2 C* A! |, w
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));
    7 @7 Y5 {% {" b; @
  31. 6 R8 j1 |! G2 s. Z/ O
  32.   assert_param(IS_QSPI_TIMEOUT_ACTIVATION(cfg->TimeOutActivation));
    # X4 I- v/ D0 q. S3 F# t1 f2 V1 Y

  33. ! j* O3 r. m. q
  34.   /* 上锁 */& V. p( T- k0 b
  35.   __HAL_LOCK(hqspi);, W1 M* m4 }7 s5 _( B& ^

  36. ' N3 |% o# \+ c: x# q# t
  37.   if(hqspi->State == HAL_QSPI_STATE_READY)
    " c# g; W* }7 T( X& Y
  38.   {
    + Y4 A5 p' `$ {+ C
  39.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    ! u: A7 h( u9 s/ W
  40. # ]" Z3 n' H6 a  m  G3 T
  41.     /* 更新状态 */5 c( J/ ]' a0 s$ N2 N
  42.     hqspi->State = HAL_QSPI_STATE_BUSY_MEM_MAPPED;1 F1 ~" B9 C7 q# s3 G9 n2 q
  43. ! a, N/ M9 }) P) Q1 @
  44.     /* 等待BUSY标志复位 */+ U2 C, }/ c0 [' E  [! l% u
  45.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);9 m; \) x: d" T" M* h& B2 o
  46. : n8 K) Z  J: X& S+ r
  47.     if (status == HAL_OK)3 c. u. n7 }6 _+ s5 X
  48.     {" V+ w: H. N$ E$ r- A3 L  a
  49.       /* 配置QSPI CR寄存器溢出时间计数 */
    * `! E# j1 X  I1 R4 K  ?3 w& G
  50.     MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_TCEN, cfg->TimeOutActivation);
    # o  Q5 Q/ D$ M9 R: t
  51. + b" I: ]" t- `% g( a, u
  52.     if (cfg->TimeOutActivation == QSPI_TIMEOUT_COUNTER_ENABLE)
    4 A8 p( `3 D2 i8 U9 p; i2 j
  53.       {0 O/ p2 ~1 B- K' V2 D! f
  54.         assert_param(IS_QSPI_TIMEOUT_PERIOD(cfg->TimeOutPeriod));- o, X& `4 B# M0 G6 B; O1 P
  55. , _4 L" m. w2 Z0 v+ f* \% _) l' U; r
  56.         /* 配置溢出时间 */
    % t- k  K# ]3 H1 `( k0 |. H- E4 e# i
  57.         WRITE_REG(hqspi->Instance->LPTR, cfg->TimeOutPeriod);& j6 H0 f. b( v# H- d; P
  58. : Y* h9 t, O) |5 Q7 z3 x2 Z3 I
  59.         /* 清楚中断标志 */
    # S9 E% |$ b" q) J: y6 s- j
  60.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TO);
    ) _/ G8 W$ Z6 v* n! i  [/ w( j

  61. . l& a9 J0 ]+ u
  62.         /* 使能QSPI溢出中断 */
    * A# x8 k0 t* y, ]5 D
  63.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TO);
    $ p  ^/ p: ]/ L
  64.       }# E5 V  U% ~& J, ?9 O0 g8 x; U
  65. , P( l. r0 O6 i( I4 x
  66.       /* 调用配置函数 */
    $ P; {8 [: M9 P# J2 i
  67.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_MEMORY_MAPPED);
    7 O7 r' P( u$ a
  68.     }# I6 M: ~1 S; s5 O! s
  69.   }
    2 `( r% B7 v% K& C9 V  {4 [
  70.   else
    2 `9 f7 ~0 x1 `. C
  71.   {
    $ K+ d% B1 {3 M1 O. d
  72.     status = HAL_BUSY;0 J. H! U0 O8 `1 \0 u! |6 l
  73.   }* ]) W- f: Q" Y9 O- o' t3 Q, V6 p
  74. 6 x  n! C3 ]% C; U( H4 c5 t
  75.   /* 解锁 */
    : a2 `( h' t& B: h1 Z* v' j
  76.   __HAL_UNLOCK(hqspi);
    9 I7 G! G2 L+ L5 @% c$ M8 W+ y

  77. * n' R: ^: [/ d! S
  78.   /* 返回状态 */* S, I1 X: |' s: h, g" S
  79.   return status;
    9 r- d1 Z! P% o% L
  80. }
复制代码
8 @+ q5 x9 R, [6 ]- }- o
函数描述:
( B9 A0 p4 O$ ]7 V1 |& J6 Q1 M
' Z0 Q( y' A& m用于QSPI内存映射设置。
% M  i* N0 C/ H$ v6 G- h# [
/ U0 ]1 t; O- Z# F( {9 K0 N6 D) C! R+ C函数参数:5 X" Z  l. Y1 q' u! L% q( N

3 Q5 L- w% b2 W& U2 O# k  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
0 f9 D, C5 P8 Q+ P5 S  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。$ Y% B: }' M- T: ^/ Z, q  t
  第3个参数是QSPI_MemoryMappedTypeDef类型结构体变量,详见本章3.6小节。% J# K, b) Y3 x
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。+ X8 g8 w1 I8 |5 Z: d  q& f* O) T
使用举例:; i* P. l; x9 X
; d+ c& r0 w( O& s* W* Z7 w& o2 Y+ I
  1. /*$ d9 d( ]+ d/ i2 D) a$ j( L# x
  2. *********************************************************************************************************
    ) F# O7 \* ]' E$ N% B. J
  3. *    函 数 名: QSPI_MemoryMapped
    6 k+ K) R& T1 k3 W
  4. *    功能说明: QSPI内存映射,地址 0x90000000/ N9 c4 X* `- a
  5. *    形    参: 无
    % K6 b3 v8 M6 Z0 Q# ]
  6. *    返 回 值: 无2 w9 a% p) A9 G: ^/ ?3 P$ W' r* F) a; Y
  7. *********************************************************************************************************
    $ P+ @9 L: n, ?
  8. */
    ( w, R; G7 Q; Y9 E$ R
  9. void QSPI_MemoryMapped(void)
    0 U$ O6 N0 x  i. C
  10. {
    : U" S, O- u$ K- y. l& z/ ]: c
  11.     QSPI_CommandTypeDef s_command = {0};
    7 K5 u8 j7 ~: x
  12.     QSPI_MemoryMappedTypeDef s_mem_mapped_cfg = {0};- I2 [6 W8 }# w+ y0 A, u

  13. 6 o$ _* k- g; A; Y
  14.     /* 基本配置 */
    7 Y% m; }: _! C7 g' O- k/ D
  15.     s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;      /* 1线方式发送指令 */
    . l! M) M/ Q+ [2 [6 X
  16.     s_command.AddressSize = QSPI_ADDRESS_32_BITS;             /* 32位地址 */
    6 N3 F* I# ]$ Q( ^
  17.     s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    2 Y# l3 l4 E  i, P5 g
  18.     s_command.DdrMode = QSPI_DDR_MODE_DISABLE;                /* W25Q256JV不支持DDR *// B8 T: w9 }$ z& R
  19.     s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;   /* DDR模式,数据输出延迟 */
    3 M) j/ e* k1 u& m
  20.     s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次传输都发指令 */# L" G6 l& p: M* r
  21. 3 D+ N8 e5 u7 R- u
  22.     /* 全部采用4线 */
    - y3 Z  Q7 p. R$ t- \: n
  23.     s_command.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 快速读取命令 */$ U/ ~5 C! u0 u, U7 n8 w
  24.     s_command.AddressMode = QSPI_ADDRESS_4_LINES;                 /* 4个地址线 */' ?. z' K4 T% D9 w# k5 w* j+ V! f
  25.     s_command.DataMode = QSPI_DATA_4_LINES;                       /* 4个数据线 */
    3 c9 ~3 z8 w& {1 u2 Y
  26.     s_command.DummyCycles = 6;                                    /* 空周期 */
      I( H& L" ?( h- {! p$ b% f: W% \
  27. 7 t4 v8 D: T0 P" C5 Y0 \# @, |2 {7 X2 B
  28.     /* 关闭溢出计数 */# O' f" R: O. G: p. L9 s$ k- U* N
  29.     s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;; a. m; A! V+ b0 q0 F9 z7 s4 R* Q
  30.     s_mem_mapped_cfg.TimeOutPeriod = 0;3 r: w1 D  g1 q/ [( W

  31. 8 c  T6 ~! Y$ ~- \3 p  K. `' @
  32.     if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)
    % Q. q6 s" E" x
  33.     {
    - e. q3 A3 v6 h' D  y
  34.        Error_Handler(__FILE__, __LINE__);* q* r9 `# M- g4 a
  35.     }
    % z/ O' n4 n, v9 Q- r4 Z* R
  36. }
复制代码

% d0 V* S! x# ?3 r+ W3 ^3 p78.5 总结, E, @' T7 _3 ?8 O
本章节就为大家讲解这么多,要熟练掌握QSPI总线的查询,中断和DMA方式的API用法。0 l* k4 c3 U; Y& }9 q. G0 V! Y
: {) |* J  m1 h, i6 ^3 K5 C9 S2 I

6 j' {% f! D4 o9 ?
74f88e781c0aa6369a48d73fb7dbe7d9.png
赞 收藏 评论0 发布时间:2021-11-4 18:44

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版