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

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

[复制链接]
STMCU小助手 发布时间:2021-11-4 18:44
78.1 初学者重要提示: `5 ?. B" F2 L5 T
  QSPI接口,可以做1线,2线或者4线使用。
( \* n/ q5 b; o4 C0 r  注意,QSPI接口不分主从,QSPI仅用于主控。
2 C  r5 n& t$ g) e; `- H) A  可以单独使用BANK1外接一个Flash,也可以单独使用BANK2外接一个Flash,不可以BANK1和BANK2同时独立使用。但可以两个BANK合起来做双BANK(也称双Flash,即dual flash)使用,即8线模式。, O. A- a' U; X$ o4 Z$ o  V
  STM32H7可用的单线,双线,四线和八线SPI QSPI OctaFlash等涵盖各大厂商
% y" L0 C% \  t1 Y78.2 QSPI总线基础知识  _+ A% |/ n. E) S
78.2.1 QSPI总线的硬件框图
% f* g8 U, l! Y1 Q$ c  G, H" I认识一个外设,最好的方式就是看它的框图,方便我们快速的了解QSPI的基本功能,然后再看手册了解细节。& I/ s% D" u1 S5 Q+ i3 f& u

  L7 Q0 n  e6 @, O( A$ x$ [BANK1外接Flash! Y3 n% V2 a# Y% |! q8 e! ^

0 j4 Z3 w: f* i. H5 Q- L2 r, a! [
f04c8d70b5dfdaf87e9a1a4f54b38e55.png

. h8 |1 e+ f' P# T+ r' t6 P0 ^4 D- H/ ?# y( B$ }; l, _
BANK1和BANK2都外接Flash:# R( E. Q) `( v0 }" X5 c: F& Y

/ l" N% [$ C4 C% \. o* d1 Q7 a* _
60f4042c5098f3ba9a7e40219c023175.png
+ P2 q0 k) y0 Z$ \

& V1 U: a) v- n; E  ?通过这个框图,我们可以得到如下信息:
  V: v$ h: h) L7 p: F1 Z3 e" {1 ~( I+ G: ~4 O
  quadspi_ker_ck时钟输入
- S4 _2 h2 z4 \7 x: n) U: W内核时钟。2 k: s3 t# x) @, P- F/ Y
. w2 l9 X; U% B2 J6 b" J
  quadspi_hclk时钟输入
: X* J) O4 O# \% b为寄存器提供时钟。0 V1 j2 V! z* M; m+ F8 c- @

9 _! }0 R  g/ x8 ^+ g# T# o/ F+ F  quadspi_it输出信号. Z% l! a7 _. c% i8 Q8 T& P
QSPI全局中断。
5 r  }( r  O6 L! `! E: }
7 q$ J6 A  \1 Q( Q- q6 J  quadspi_ft_trg输出信号
4 [2 a0 @; r) H1 b  P% sMDMA的QSPI FIFO阀值触发信号! }7 v3 D( F1 N. }% p3 E
  T0 p2 w) m* f
  quadspi_tc_trg输出信号
6 c$ b& ]* b9 M/ o. lMDMA的QSPI传输完成触发信号% {, Q7 {  |# C, H
" U: H9 m& L$ z( t
  CLK* K# p% Q+ |! u0 S& b( J
为外接Flash提供的时钟。为外接的两块Flash同时提供时钟。
, Y! r/ T/ _) e2 F( ^9 I7 K
8 z+ Q( }  g* N$ k: C  BK1_IO0/SO+ Y3 K+ _9 Y  B# \3 b
在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash1使用。' @9 c) g" G1 M  J( n/ \# w  v
/ u, K( q* H4 H( J5 G5 B* H
  BK1_IO1/SI3 o% z1 a2 q- A
在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash1使用。: G7 B0 r/ q) s$ {3 r* C" X
( `$ N) o6 n: ~0 K
  BK1_IO29 V2 r0 F3 y, ]0 ^3 Y1 S* m) V. ]- ^+ M  ~
在4线模式中作为双向IO,供Flash1使用。3 p# O) l$ ]2 X- m2 G- x8 x
( a: r1 D. @$ z2 t
  BK1_IO3
8 B$ E3 L: W$ s. T7 Z% [在4线模式中作为双向IO,供Flash1使用。1 J3 B; m& ?! o. `7 g
- Z) X; v3 h% \" R8 m
  BK12_IO0/SO' z% g( H1 j5 H( o* u7 L
在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash2使用。
$ f$ o6 K$ S# a( m' ?' w' I
8 p0 x) d4 @' @* L  BK2_IO1/SI
( [+ r. d- ^. \- x+ R在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash2使用。
& p) e& j* Q* k, B6 [  Z4 g6 W3 P* f3 `3 ^" b- n
  BK2_IO2
' Z# O/ c- l# ]2 l在4线模式中作为双向IO,供Flash2使用。1 L5 Z* f# e% y# S$ Q) p
1 I0 g7 n  f1 o/ b' O
  BK2_IO3% z/ o4 z! i$ _$ c  z0 [- d
在4线模式中作为双向IO,供Flash2使用。
1 l; n7 c1 ]8 {3 g) ~
  y3 m* D' _  \3 f1 y2 ^  BK1_nCS
$ _4 f) i' x8 t: Q# z2 L# p5 ]" ~片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash2。
! I9 c: f! \6 e  g3 {/ x& m7 [7 R9 e8 L
  BK2_nCS' \; }% o' M; G+ @
片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash1。& |7 \( r$ a/ t" G7 l

- F& L3 l8 O+ ~& M/ N1 Y* V78.2.2 QSPI的时钟源  B4 |0 h  H7 Q% T' e
这个知识点在初学的时候容易忽视,所以我们这里整理下。) p- w" q- d! A. N5 V6 o
' E5 f+ b) B# u  @2 R
STM32H7主频在400MHz下,QSPI的最高时钟是200MHz,可以选择的时钟源如下:
! q1 {$ J1 L9 K2 i; F. Z3 f! X* b4 p7 o. c2 `2 i- h
60a21420cdf6bbfc171b77ef44ebcf28.png
9 y6 q4 ^8 S: M9 Q$ ^  L
) {" |& y+ ~# H. R+ Z
12523b301f01c6108162699ca2ad5685.png
) Y3 b4 p( e( V$ @8 P5 R3 c( J

& R! E3 q0 P8 y; j3 `0 u) S' \; ~: h0 u4 C2 W1 S2 |
我们的程序中默认是采用的HCLK3作为QSPI时钟。; D. K9 K. w2 U, k! W- b
2 Q4 V1 W% H8 ^
78.2.3 QSPI 命令序列
# y1 _2 B' M! |0 kQSPI的命令序列主要包括以下几个阶段:指令阶段、地址阶段、交替字节阶段、空指令阶段和数据这五个阶段,任一阶段均可跳过,但至少要包含指令、地址、交替字节或数据阶段之一。. z# v* O, x1 i0 ~( @$ H

+ x6 B# ~, v: n0 v" t! ^7 Q- X
2cb087bbc794898408c6160acfd426e4.png

3 o  w8 r6 n) g5 S3 ]
4 ]1 O+ V& k, s6 o  指令阶段
: v. B) P" ~# m: l. t在此阶段,将命令(8位指令)发送到Flash,允许发送任何值。用户可以简单地将所需的命令写在指令字段中。根据软件和硬件配置,可以1线,2线或者4线方式发送。在某些只发送地址的案例中,指令阶段可以跳过。
: s1 u. c' f6 o
7 g$ j6 f) s( Q! V6 v+ Z1 S 地址阶段
. ?/ v8 u4 b$ d$ H在此阶段,将地址发送到Flash,从指定的地址读取或写入数据。 地址阶段是完全可配置的,允许发送1、2、3或4个字节的地址。在间接模式和自动轮询模式下,用户可以简单地将所需的地址写入QUADSPI_AR寄存器。据软件和硬件配置,可以1线,2线或者4线方式方式发送。 在一些不需要地址的情况下,可以跳过地址阶段。! a* J" u5 x$ p# Q: i
1 P9 k# \' A: Q2 o
  交替字节阶段
# p4 c) h. Z  o" N* UQSPI接口支持的一个额外阶段,具有更大的灵活性。它是通常用于控制操作模式。交替字节阶段是完全可配置的,并允许发送一,二,三或四字节。
# F$ B5 Z3 W; j  z. Z
$ ?2 M9 q  Z9 ?  j& r  空周期阶段
0 {$ M5 u, ^( Z9 [4 E在高速时钟下运行时,此阶段可以确保有足够的“周转”时间从输出模式切换到输入模式。
" ^5 O0 G7 s; j* y+ E
# V% E/ a  L1 h5 N  }9 u5 g/ ]  数据阶段
; Q! z! V5 l/ {这个阶段实现数据的收发。2 {1 d# ^% O, k2 r) B2 N" S
! z& {! a6 `1 J; l2 m) y# v2 n
78.2.4 QSPI的1线,2线,4线,SDR和DDR模式; }, S6 G9 i0 F" ^
这里所说的线是指通信阶段使用的数据线个数。
' t& b( v* L' V% w  J% f6 I, c, s5 u2 f6 u* |. l' y9 e
213a38369fe04824fa8640f515beb2fc.png
8 h9 [0 M3 u6 ]* U

5 A) P. _1 e5 w; i! K1线(SingleSPI,虽然是一发一收,但属于1线方式)
: w7 W) S" R; ^7 W/ ~发送用的数据线BK1_IO0/SO(BK2_IO0/SO),接收用的数据线BK1_IO1/SI(BK2_IO1/SI)
$ l' S' q* [  ?2 ?/ z. P* d3 C
; _5 {5 T" N2 v, M1线模式下,所有线处于的状态:
6 _( o3 f; ?: ^- o- J! N; |" T$ X* M0 R% D, A* z
(1)  BK1_IO0 / SO(BK2_IO0 / SO)处于输出模式。, t) T, ^' x0 Y: I1 ^5 y' A

' d' [) ^! S( e9 Q& T( [ (2) BK1_IO1 / SI(BK2_IO1 / SI)处于输入模式(高阻抗)。
& ], L( o- s% b1 R2 A7 L2 M+ U7 Z! }0 V
(3) BK1_IO2(BK2_IO2)处于输出模式并强制置0。; T' m4 j! M- i5 @1 z
5 I! c5 N; O" P1 e/ O' M
(4)  BK1_IO3(BK2_IO3)处于输出模式并强制置1。0 ~3 I# L# c, m. d/ O5 S) y
$ r3 S4 h. ^+ w: a1 s$ J, ?0 E# R% x6 ~/ ?
7c6105bc6d18539b680aeeed7ec93aed.png

& ^  ?4 h1 a( ^1 `
* [, V1 b6 F% ^9 C4 r& L; K' n6 H  2线(Dual-SPI)% W6 U; g  c5 d, q! K) \
同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1)做输入输出。7 Y0 p+ O) @; V$ `2 [6 D2 m2 f
  z, {- A2 r! ~4 \! F7 [% m
2线模式下,所有线处于的状态:8 l, g5 H4 V2 z! H6 n6 D% a% w0 ]

+ f2 k/ U7 F3 B, d( J7 U6 b; t+ W (1) BK1_IO0 (BK2_IO0 )和BK1_IO1(BK2_IO1)读取时处于输入(高阻)。其它情况下为输出。6 q5 x) ^$ E4 w2 y
5 C+ @3 }' n" E. I; X; K
(2) BK1_IO2(BK2_IO2)处于输出模式并强制置0。
! b  ~& }; E9 W9 ^% b( ^3 F; B% g; v" p
(3) BK1_IO3(BK2_IO3)处于输出模式并强制置1! w4 r$ i, _6 A8 Z! X$ ]( T

4 d( k& ^0 D! ^8 p/ @
# w. K$ p+ f% u: W

5 E  ~6 H* A8 K4 f* v4线(Quad-SPI)
: U8 s: b( }: ^) \同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)做输入输出。
% X: V/ W! O* ^- O" s" z0 ^. L( O7 h+ P3 d! @+ ?. O& }2 I9 B/ S/ ~
4线模式下,当读取数据时,所有线处于输入(高阻),其它情况作为输出。/ c( G7 f# M8 ]- u8 K( y  g2 R
- U, N. {* a# d. f$ q/ h: O9 i
9d022cbcfd5fb3f3950421c3312e505f.png

" B  B  P- @  W0 x* ?2 ~4 F4 S; M. S0 C" b& m4 _! n  f
  SDR! w' S' M" }. B! m- B' I8 b# S$ I
在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号仅在 CLK的下降沿发生转变。
" {( J7 h% W1 k/ ]& c" }1 L% C& E" D! k
  DDR
2 b: c/ Q! @3 P# Y  F. ]在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号在CLK的上升沿和下降沿发生转变。' c& x2 d" ?4 x( _4 y

9 r" B$ C7 }1 `$ y. {  双BANK(双Flash)
( H8 S2 X, O/ _, R, J- }1 `  Z双闪存就是将QSPI的两个BANK分别接一个QSPI Flash,然后时钟公用,片选公用(也可以不公用),从而实现8线模式。4 E( H" X# Z# G% U, r& N9 D8 v% j
" i+ d! o1 F  R* O& i
d28d743492529e4d88e9b64567fe52b4.png
- m6 F- p2 ~& u) g4 P0 W/ d* A
. i; \2 i5 O$ q
78.2.5 QSPI间接模式,查询模式和内存映射
6 o4 P$ z2 K/ @5 uQSPI支持在以下三种模式下工作:7 ]2 c7 Y6 V+ c( m) ^/ S
1 L2 Z- H/ x3 Y2 P& F8 P) J
1、  间接模式:
6 `$ W( e! [4 Q; b7 c/ Q0 w7 O( Z  q$ g3 n3 w3 T% a: G
这里所谓的间接模式是指寄存器方式访问外设,就跟我们操作串口外设一样。间接模式主要用于以下场合:' [  f- n/ k. x
3 M0 d. K' \8 F
  用于读取,写入,擦除和配置QSPI Flash。; g: A# x8 g! U9 ~% i1 ~* E( E3 G: q# n
  如果不需要AHB总线访问 QSPI Flash(在内存映射模式用)。
8 {( z5 I- z9 \  CPU或者DMA通过QSPI数据寄存器执行所有操作。# J+ y( w0 V; v

  o9 y4 C, ~  x) w' v% z$ h1 j+ G) S
在间接模式下,所有操作均通过QSPI寄存器执行,含读取和写入操作都由软件管理。 QSPI接口类似于经典的SPI接口。传输的数据通过数据寄存器与FIFO。在在此模式下,可以从大容量的外部Flash读取数据或向外部Flash写入数据,可以支持到4GB容量。
* x0 V. t8 U3 Q1 y$ y  z1 t2 y3 m1 O: m7 R( d' K* |
如果进行擦除或编程操作,则必须使用间接模式,并且所有操作必须由软件处理。在这种情况下,建议使用状态轮询模式,然后轮询闪存内部的状态寄存器以了解何时编程或擦除操作完成。
# m" j7 y5 x) L% W/ Y8 p# l5 J3 H1 {6 O

6 w) P. X& g! r; W4 d1 z9 C( k: v- n& l4 F/ b; P
2、  状态轮询模式' ]4 L: e3 V9 o/ ~4 O
9 ^1 `- e0 s# I% T  H; S+ @/ j2 j
在以下情况下使用状态轮询模式:
5 s2 w$ d) \2 z6 n4 p0 q8 V0 A* d, t5 W6 W! B( V# H
  读取QSPI Flash状态寄存器。, t9 ~; Y! h- N* A" Y1 P
  在操作结束时自动轮询状态寄存器。' c% e8 Z& t, h4 @/ K  y
可以自动轮询内存中的指定寄存器并减轻CPU负担,例如检查擦除操作何时完成。QSPI也支持定期查询QSPI Flash,并且可以屏蔽返回的数据位,将所选位与所需值进行比较,结果比较可以通过下面两种方式处理:
3 ]* k  G3 z# |& D( X# Q6 M, y
9 t1 P8 c  [/ N( P7 J, X, C: n  AND与操作模式:如果所有选定位都匹配,则产生中断。
2 b  H0 X, P# M  w OR或操作模式:如果所选位之一匹配,则产生中断* T5 c8 G) e7 T: ~3 s
  [, K0 I3 H3 s
. _5 @6 L% n% D- Y5 k
发生匹配时,QSPI可以自动停止。4 B3 A0 S. f" m. }7 E2 \, Q  e+ ]
8 _  m- ^) P( J4 t; g

; \) t* y8 U5 b6 G- o+ I& L) X" H# K" J
3、  内存映射模式( k3 N6 D" j( {% G( w3 D7 Z/ W
( r' U2 v* g5 g/ R' W! X
在以下情况下使用内存映射模式:
/ d/ s8 L7 A9 S" d3 _- w* N! c% Z4 d+ ]( f6 f0 f
  用于阅读操作。/ c8 K/ l( b. D8 F+ c
  像使用内部Flash一样使用外部QSPI Flash, 任何AHB总线主控都可以自主读取数据。8 j- s' j/ \7 |' b
  用于从外部QSPI Flash执行代码。
: x- m) j) i2 J4 n* R1 s2 A/ s; I9 ^$ J
+ a3 _* C) ~# H6 ?* g
QSPI接口能够管理多达256 MB的内存,在内存映射模式下地址范围是0x9000 0000到0x9FFF FFFF。# G8 e3 l4 V" e9 t; n- F" j% g
  r( N; _  b% v; K% y
78.3 QSPI总线的HAL库用法& g  s5 v0 \# z. }( p8 Y2 ~
78.3.1 QSPI总线结构体QUADSPI_TypeDef3 o( S! d5 o/ r- z0 a* ^
QSPI总线相关的寄存器是通过HAL库中的结构体QUADSPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
6 E2 U9 O: {2 t2 W$ O
  R, K( r( j% [; j4 k
  1. typedef struct
    * K- P' F/ \9 |9 ?/ C
  2. {1 o3 Z# M8 y# C0 w- K& `
  3.   __IO uint32_t CR;       /*!< QUADSPI Control register,                           Address offset: 0x00 */$ E8 w/ i  M. `9 w  V
  4.   __IO uint32_t DCR;      /*!< QUADSPI Device Configuration register,              Address offset: 0x04 */' A& a2 ?5 O4 a# |- C$ A
  5.   __IO uint32_t SR;       /*!< QUADSPI Status register,                            Address offset: 0x08 */
    ( E& L) d$ ^( {. S7 h. C% Y
  6.   __IO uint32_t FCR;      /*!< QUADSPI Flag Clear register,                        Address offset: 0x0C */
    - }& E3 n+ f! k" M
  7.   __IO uint32_t DLR;      /*!< QUADSPI Data Length register,                       Address offset: 0x10 */
    ) a! x, a& D: s9 G) O& w
  8.   __IO uint32_t CCR;      /*!< QUADSPI Communication Configuration register,       Address offset: 0x14 */! d6 e* `7 V/ ?6 T( c5 f  H' d
  9.   __IO uint32_t AR;       /*!< QUADSPI Address register,                           Address offset: 0x18 */
    0 h2 b6 u2 B5 Q' T
  10.   __IO uint32_t ABR;      /*!< QUADSPI Alternate Bytes register,                   Address offset: 0x1C */% y+ N( ~% b6 a/ G* P  G: c: g+ x
  11.   __IO uint32_t DR;       /*!< QUADSPI Data register,                              Address offset: 0x20 */" B" C1 M9 Q8 O
  12.   __IO uint32_t PSMKR;    /*!< QUADSPI Polling Status Mask register,               Address offset: 0x24 */
    1 B9 J. t/ [( A6 ?
  13.   __IO uint32_t PSMAR;    /*!< QUADSPI Polling Status Match register,              Address offset: 0x28 */; a9 S" c4 p. _4 ~6 |# C
  14.   __IO uint32_t PIR;      /*!< QUADSPI Polling Interval register,                  Address offset: 0x2C */
    ) C* l9 n- r6 t: g6 L
  15.   __IO uint32_t LPTR;     /*!< QUADSPI Low Power Timeout register,                 Address offset: 0x30 */
    % b2 {+ C6 b( d
  16. } QUADSPI_TypeDef;
复制代码

. ?# p9 X, o0 u% Z  T& Q这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。; i' c$ \1 U& ?$ K+ w. L; z, v
( s1 n/ C8 N! @7 }- F2 K4 Z
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:$ g/ F  M! j; e9 E- @" l+ v: r4 t
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */; e$ A+ p  h) q; u2 @  t% }
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
& v% J- Z  @2 K* S0 h
下面我们看下QSPI的定义,在stm32h743xx.h文件。2 L. x; z/ D- _$ c1 H
3 M  E  [7 M' ~  Y) Y4 C6 x+ E4 ^1 C
  1. #define QSPI_BASE ((uint32_t)0x90000000) /*!< Base address of : QSPI memories  accessible over AXI */
    8 Z9 y, a  w4 J+ e- E
  2. & j/ O6 ~8 U- `, r9 i
  3. #define PERIPH_BASE           (0x40000000UL)
    7 \' X! [" d, W, X( i! h
  4. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)5 e$ @" K& ?# V0 K! V# U$ j! e
  5. - S& l* t2 _8 r3 G/ @. n7 R$ Y& a8 w
  6. #define QSPI_R_BASE           (D1_AHB1PERIPH_BASE + 0x5000)% L+ D, `, `, A$ J
  7. #define DLYB_QSPI_BASE        (D1_AHB1PERIPH_BASE + 0x6000)
    8 J# R3 {. r- n# F) r7 d8 S; U( e$ S) h
  8. 2 y0 `$ v& g  U
  9. #define QUADSPI               ((QUADSPI_TypeDef *) QSPI_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52005000
    4 w  ^) y+ x6 y) N9 v
  10. #define DLYB_QUADSPI          ((DLYB_TypeDef *) DLYB_QSPI_BASE)
复制代码

( Y) K2 D1 \1 a1 q0 ^- h9 q我们访问QSPI的CR寄存器可以采用这种形式:QUADSPI->CR= 0。
( o5 h- g& R1 ~: p
( |) @% G1 t+ U! z; @$ W, ]" n* X$ M78.3.2 QSPI总线初始化结构体QSPI_InitTypeDef
1 C( r2 y$ X- w下面是QSPI总线的初始化结构体:9 T. e, q. W3 X% s! Y+ \1 f: S# K
. R4 W) ^7 Z# j" v% s" m( r6 `
  1. typedef struct
    0 ^+ s3 W# n& H$ v
  2. {
    2 H5 B8 ~* ^3 M. c  O. R6 U
  3.   uint32_t ClockPrescaler;     ; ]- H4 o  P  m; ~% q9 O7 M& a- ?
  4.   uint32_t FifoThreshold;      3 f8 u( ^; I' ?8 d( L2 j1 g
  5.   uint32_t SampleShifting;   
    % H- t& M9 z/ o! o( h
  6.   uint32_t FlashSize;          ! i, k, @+ }8 L% G9 H! _( K* L
  7.   uint32_t ChipSelectHighTime; 3 y1 m7 P9 X0 n* S* m0 g
  8.   uint32_t ClockMode;         
    : c2 S7 h* X6 b0 k; z
  9.   uint32_t FlashID;           
    ( L  F5 u) X2 u- o$ x
  10.   uint32_t DualFlash;                                          
    . [+ o& q3 z: r
  11. }QSPI_InitTypeDef;
复制代码
4 ]; G0 M2 f0 D* P/ `
下面将结构体成员逐一做个说明:$ ?4 P, `1 d5 u$ u- y8 m* |  b4 T

0 j8 K) n3 w. Z7 t; D  ClockPrescaler, X" X& f* C- q5 \1 s9 M
设置时钟分频,参数范围0到255。特别注意,这里是针对HCLK3作为QSPI时钟来说的。
* i+ N, C, i$ T" L1 e4 }' X2 T
7 T( }0 C+ p9 |7 \- G  Y6 |4 U3 R" X  FifoThreshold
* `: a$ l2 c" s+ n7 b用于设置FIFO阀值,仅用于间接模式,参数范围1到32,单位字节。/ q6 q/ r& Y' A4 O

3 K( h2 d9 h  n  SampleShifting% {6 V2 t. l" k2 z2 F4 p' X
QUADSPI在FLASH驱动信号后可以选择再过半个CLK周期后才对FLASH数据采样,这有利于推迟数据采样。支持的参数如下:
, k1 v/ D2 u* p. N, O9 z1 F3 B2 z- h
#define QSPI_SAMPLE_SHIFTING_NONE      ((uint32_t)0x00000000U)       ) w7 `+ o! r+ n$ x- G
#define QSPI_SAMPLE_SHIFTING_HALFCYCLE ((uint32_t)QUADSPI_CR_SSHIFT)
2 b% p* \* G) u9 U  FlashSize4 ?* C3 ^, r; z! \
Flash大小是2^(FlashSize + 1),单位字节。! H; `/ t) ~- b$ m

! ~5 c1 }: S, p7 l7 O间接模式下,最大支持的Flash大小是4GB,内存映射模式,最大支持256MB。, C; K" b" F+ g3 F- @
. w" C# Z  C( u4 L6 |/ C% |
  1. #define SPI_POLARITY_LOW       (0x00000000UL). Z( C6 T6 C7 ~) O
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码

1 O) ?" X( p$ k( k& N) B  ChipSelectHighTime3 |1 e2 m/ b0 ~: f; D
命令之间的CS片选至少保持的高电平时钟周期ChipSelectHighTime+1。支持的参数如下:* t: l9 ~5 k. s: B# ?
) |- {, Y; p6 L9 D
  1. #define QSPI_CS_HIGH_TIME_1_CYCLE      ((uint32_t)0x00000000U)                             
    % b" n# j5 h7 M# x
  2. #define QSPI_CS_HIGH_TIME_2_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0)                     
    0 H! o0 p3 U; L7 E2 y7 q
  3. #define QSPI_CS_HIGH_TIME_3_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_1)                      6 Q. f8 J( N) @+ |; _
  4. #define QSPI_CS_HIGH_TIME_4_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0 | QUADSPI_DCR_CSHT_1) " k) Z) Y) a8 E+ F
  5. #define QSPI_CS_HIGH_TIME_5_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2)                     8 |" k9 H' |  J* g4 M$ q
  6. #define QSPI_CS_HIGH_TIME_6_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_0)3 g, ^0 |& N( m: p1 a
  7. #define QSPI_CS_HIGH_TIME_7_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_1)
    , ]) H# o# C8 j0 |( U
  8. #define QSPI_CS_HIGH_TIME_8_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT)   
复制代码
                - V& G, t0 J! [1 @, [  E$ B
  FlashID
; q. g9 i( \' J7 ~6 s; V用于选择要操作的BANK,即用BANK1还是BANK2操作Flash。7 {9 X3 d( Q1 }' c% {

- J; r7 G$ u, @0 G4 R% X
  1. #define QSPI_FLASH_ID_1                ((uint32_t)0x00000000)      
    + `* J# T- T/ M: @1 m
  2. #define QSPI_FLASH_ID_2                ((uint32_t)QUADSPI_CR_FSEL)
复制代码
3 R5 N! R7 O$ I0 Q" B+ r5 U6 U
  DualFlash
8 {: \( x! S7 u3 }& M1 m) l用于选择是否使用双BANK。
# }# M/ n5 n7 b9 }) |( r# D% ?7 @0 d' T' z" t) s* ~1 I9 L. B
  1. #define QSPI_DUALFLASH_ENABLE          ((uint32_t)QUADSPI_CR_DFM) /*!<Dual-flash mode enabled*/, f/ C7 I8 l8 o; F# [8 _
  2. #define QSPI_DUALFLASH_DISABLE         ((uint32_t)0x00000000)     /*!<Dual-flash mode disabled*/
复制代码
. P  E  Z) ^+ O7 k/ d( K
78.3.3 QSPI总线句柄结构体QSPI_HandleTypeDef
) c! w6 X4 v. N  H下面是QSPI总线的初始化结构体:
4 B  m- `& w1 M# p3 c2 a
3 o  S) c. o: S' f8 T% Z6 l
  1. typedef struct! ~8 `) J/ E( `! R4 I. h
  2. {
    % d3 I  g9 A) F9 Z( E& W* f
  3.   QUADSPI_TypeDef            *Instance;        /* QSPI registers base address        */
    7 v9 `) e% r! [
  4.   QSPI_InitTypeDef           Init;             /* QSPI communication parameters      */
    / |" K* Q$ Z: c! [
  5.   uint8_t                    *pTxBuffPtr;      /* Pointer to QSPI Tx transfer Buffer */7 f- Y* Q! G; {: r
  6.   __IO uint32_t              TxXferSize;       /* QSPI Tx Transfer size              */, Q8 @! {& p# J8 S5 \
  7.   __IO uint32_t              TxXferCount;      /* QSPI Tx Transfer Counter           */9 m# c) m4 x7 Z7 O0 E
  8.   uint8_t                    *pRxBuffPtr;      /* Pointer to QSPI Rx transfer Buffer */
    . F" G# s+ O6 R4 r- @! `
  9.   __IO uint32_t              RxXferSize;       /* QSPI Rx Transfer size              */
    6 ?6 s' n; {/ g) F
  10.   __IO uint32_t              RxXferCount;      /* QSPI Rx Transfer Counter           */# ]7 a+ c* T7 W" J
  11.   MDMA_HandleTypeDef         *hmdma;           /* QSPI Rx/Tx MDMA Handle parameters  */* G, m: }( e& o6 O
  12.   __IO HAL_LockTypeDef       Lock;             /* Locking object                     */
    2 T: g; z1 {0 n2 g7 F* N
  13.   __IO HAL_QSPI_StateTypeDef State;            /* QSPI communication state           */! R1 U2 ]" Y" f& k! {% N! F6 E9 l
  14.   __IO uint32_t              ErrorCode;        /* QSPI Error code                    */$ K! a& j; {  Q" R+ M6 Z/ D8 Y
  15.   uint32_t                   Timeout;          /* Timeout for the QSPI memory access */
    3 g9 C4 Y) v, W0 s( V1 e2 N+ ?, s
  16. }QSPI_HandleTypeDef;
复制代码
; w6 y. A7 {" W+ O
下面将结构体成员做个说明:+ `" H0 {  q! \8 D& N. y

; V& a3 Z4 ?* P* u6 o1 F  QUADSPI_TypeDef   *Instance' W$ h& }& g# d- H9 D. J  P7 ~: V' a
这个参数是寄存器的例化,方便操作寄存器,比如使能QUADSPI。
5 x: w+ J2 p. ?& X6 U2 U- `3 ~) x, n
SET_BIT(QUADSPI ->CR,  QUADSPI_CR_EN)。; w2 F+ K8 t+ d& Q

* n3 h- W. o' C6 O# \  QSPI_InitTypeDef  Init6 D/ q- U, b+ X; ?* C; c
这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。. `: Q. i. Q  F3 l4 p
8 Z/ y7 }. G% J4 G  e
  MDMA_HandleTypeDef          *hmdma
% I0 v* _5 x. v. [用于QSPI句柄关联MDMA句柄,方便操作调用。3 n. A3 R( f& e0 l3 F: S+ ?3 B
6 k/ T7 M+ D8 G& t0 q
  其它参数
7 ?0 Q7 h: A4 e8 V其它参数基本都是在函数内部调用,用户基本不用管。4 _, U# t; L7 h) a* s4 W
' B% O" P4 f3 l6 S( X9 w  E
78.3.4 QSPI命令结构体QSPI_CommandTypeDef
, _5 ^1 }4 n* _5 x( C5 r% D) C# f下面是QSPI总线的命名结构体:
: N& _. Y1 B& y3 C+ d; A) l
& z. l2 ?) Y  }  j+ F. ~. ^# v  w. r" ]
  1. typedef struct
    ! u  [/ T+ ^2 S* [% `4 i
  2. {
    ) \! c3 `$ G8 c8 _0 u
  3.   uint32_t Instruction;        
    . d8 U+ F' [& S1 s; d; e
  4.   uint32_t Address;           " ^$ G1 f0 V  z' w( n) v
  5.   uint32_t AlternateBytes;     
    & T0 R1 S) ^- }$ p& ^4 m/ Z
  6.   uint32_t AddressSize;       : y6 {" C" M2 E( i0 A
  7.   uint32_t AlternateBytesSize; ( E; W  x. n4 I+ x- ~6 _& V0 Z
  8.   uint32_t DummyCycles;      
    ( O2 w! w" \2 r$ b: ?) I5 Y; ?* d* d  Y
  9.   uint32_t InstructionMode;  
    # t3 m  Z4 d% B/ `' r  P0 J4 \
  10.   uint32_t AddressMode;      
    / ]  [# _! l5 f, R; ^* [. \
  11.   uint32_t AlternateByteMode; $ r3 U# h. b( @
  12.   uint32_t DataMode;         ( n& ~6 w9 K, R7 N0 {3 \
  13.   uint32_t NbData;            n4 R& B: w8 W9 z* q
  14.   uint32_t DdrMode;           # L. B$ l7 p7 q, }: o
  15.   uint32_t DdrHoldHalfCycle;  5 N0 Z- S6 i0 F
  16.   uint32_t SIOOMode;         
    1 Y6 K$ ^6 {% {0 t* E& t6 h
  17. }QSPI_CommandTypeDef;
复制代码

$ p; w4 Z: c4 W) p; x. L下面将结构体成员逐一做个说明:" F' E+ D$ s$ v) U: ~% V- N

# f" \$ T" D- B+ {& @# r, L) \, J: r  Instruction
, F7 K8 S5 @, p8 [1 Q6 r8 [5 e( k设置要发送的指令,参数范围0x00到0xFF。7 k$ [7 w% `2 [3 @( z

. J; y( f" f5 j  Address. L& ]( s. u" }; A! u
设置要发送的地址,地址由是1个字节到4个字节来表示,参数范围0x0 到 0xFFFFFFFF。
9 S: h6 D' b# D4 t1 ~; L+ o7 h. q# f  U0 |6 k; u
  AddressSize+ `+ H, o2 H& s4 P3 \7 ~
地址大小,即表示此地址需要的字节数,支持的参数如下:
  `7 q  n2 j+ I0 d3 q  }
8 @/ m% F( L* J; P' @
  1. #define QSPI_ADDRESS_8_BITS            ((uint32_t)0x00000000)           /*!<8-bit address*/
    . H9 @4 s! [) M" C- D2 U
  2. #define QSPI_ADDRESS_16_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_0) /*!<16-bit address*/' {* D0 m8 q* @1 m9 ^8 h8 g% U
  3. #define QSPI_ADDRESS_24_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_1) /*!<24-bit address*/
    * I8 c0 ?# Z$ O3 L: z4 q
  4. #define QSPI_ADDRESS_32_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE)   /*!<32-bit address*/
复制代码

, m% d/ U" V- ^  AlternateBytesSize
! P+ ]& d; d5 g5 e1 x+ u交替字节大小,支持的参数如下:' _# }- J9 x3 t9 A4 \

3 J' v& y2 y/ }( a" @* t" C: {
  1. #define QSPI_ALTERNATE_BYTES_8_BITS    ((uint32_t)0x00000000)           /*!<8-bit alternate bytes*/
    ; I  I" y: g8 K; ]$ S
  2. #define QSPI_ALTERNATE_BYTES_16_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_0) /*!<16-bit alternate bytes*/& T3 @( F9 f6 M# L) C9 j+ v1 Z9 l/ Q
  3. #define QSPI_ALTERNATE_BYTES_24_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_1) /*!<24-bit alternate bytes*/0 {0 _* p' ?" [- M
  4. #define QSPI_ALTERNATE_BYTES_32_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE)   /*!<32-bit alternate bytes*/
复制代码

$ g7 S2 p& N; _/ q  DummyCycles
' s  D$ T% `) G- m5 `执行空周期个数,参数范围0到31:
; d! f2 R3 ~" [  p& x+ {9 g& f4 V2 _5 U/ }
  InstructionMode
' p6 y0 S8 D6 z/ {1 L% R指令阶段需要几线模式:
) U; l- @/ c( I( b9 B' r# Z0 H5 S9 K$ r  e' }+ l1 o
  1. #define QSPI_INSTRUCTION_NONE          ((uint32_t)0x00000000)          /*!<No instruction*/. y0 i+ u+ e4 t* a" M# g
  2. #define QSPI_INSTRUCTION_1_LINE        ((uint32_t)QUADSPI_CCR_IMODE_0) /*!<Instruction on a single line*/
    ) V$ ]& U4 J7 P$ o: E5 z4 c
  3. #define QSPI_INSTRUCTION_2_LINES       ((uint32_t)QUADSPI_CCR_IMODE_1) /*!<Instruction on two lines*/. n) @7 Z# h1 {! v
  4. #define QSPI_INSTRUCTION_4_LINES       ((uint32_t)QUADSPI_CCR_IMODE)   /*!<Instruction on four lines*/
复制代码

2 z- j9 d/ M: s+ S6 @$ d  AddressMode8 b- I, l. w  K$ w6 N
地址阶段需要几线模式:
9 }5 S6 z6 D: S
( m. N9 H* y. R
  1. #define QSPI_ADDRESS_NONE              ((uint32_t)0x00000000)           /*!<No address*/
      T# x9 a6 \1 L
  2. #define QSPI_ADDRESS_1_LINE            ((uint32_t)QUADSPI_CCR_ADMODE_0) /*!<Address on a single line*/
    ; c: F& L) ^( T+ ^+ {. P
  3. #define QSPI_ADDRESS_2_LINES           ((uint32_t)QUADSPI_CCR_ADMODE_1) /*!<Address on two lines*/
    7 U3 m/ k. }( O+ v! E1 H: M
  4. #define QSPI_ADDRESS_4_LINES           ((uint32_t)QUADSPI_CCR_ADMODE)   /*!<Address on four lines*/
复制代码
0 B. m1 O3 @7 O5 v, z5 }* U3 f9 [( d. t
  AlternateByteMode" U. [4 S# g- m
交替字节阶段需要几线模式:! x; s! ~+ t- Q. N
  _4 N  a& ^4 `7 {% B; T9 V
  1. #define QSPI_ALTERNATE_BYTES_NONE      ((uint32_t)0x00000000)           /*!<No alternate bytes*/- n# u! G  K/ I8 B; A4 t
  2. #define QSPI_ALTERNATE_BYTES_1_LINE    ((uint32_t)QUADSPI_CCR_ABMODE_0) /*!<Alternate bytes on a single line*/
    " v+ a7 s! Q/ ~) X" z) n& I
  3. #define QSPI_ALTERNATE_BYTES_2_LINES   ((uint32_t)QUADSPI_CCR_ABMODE_1) /*!<Alternate bytes on two lines*/
    2 k* e6 s: L2 H# r
  4. #define QSPI_ALTERNATE_BYTES_4_LINES   ((uint32_t)QUADSPI_CCR_ABMODE)   /*!<Alternate bytes on four lines*/
复制代码
9 `5 L" l* @( _
  DataMode
1 h  m; f8 O4 ]数据阶段需要几线模式:
7 ^2 R- e! |! H  Z8 n/ z
/ |: n. q$ R; m# G
  1. #define QSPI_DATA_NONE                 ((uint32_t)0X00000000)           /*!<No data*/
    & b) G9 d7 v. `( r! c' {2 |
  2. #define QSPI_DATA_1_LINE               ((uint32_t)QUADSPI_CCR_DMODE_0) /*!<Data on a single line*/! n  i1 r+ s- S! b2 Z) \: a
  3. #define QSPI_DATA_2_LINES              ((uint32_t)QUADSPI_CCR_DMODE_1) /*!<Data on two lines*/
    ; Q. s' A7 b' ]% J; `8 L
  4. #define QSPI_DATA_4_LINES              ((uint32_t)QUADSPI_CCR_DMODE)   /*!<Data on four lines*/
复制代码

, E8 O% @0 Z8 Y0 G, _  NbData+ c; A& v9 ]* p9 r* E0 \) o9 C$ s
要传输的数据大小,参数范围0 到 0xFFFFFFFF,如果设置为0表示不定长,直到存储器末尾。# E+ C9 n' G2 s5 Z. k4 U' S
* W( z( i3 l3 v$ q
  DdrMode4 d- C4 F$ b- B6 R5 s
用于设置是否使能DDR模式。数据阶段,交替字节阶段和数据传输阶段可以使用DDR模式。支持的参数如下:; h; x. C; l, `" Y* ~
) i% [" h  ^; o7 G
  1. #define QSPI_DDR_MODE_DISABLE          ((uint32_t)0x00000000)       /*!<Double data rate mode disabled*/3 o- H" `' e$ a+ \
  2. #define QSPI_DDR_MODE_ENABLE           ((uint32_t)QUADSPI_CCR_DDRM) /*!<Double data rate mode enabled*/
复制代码
2 B) f) S0 a: Z/ ]: F: P* u
  DdrHoldHalfCycle. i+ T9 T7 h7 V( T  F. |+ W2 @
DDR模式下,用于设置延迟半个时钟周期再做数据输出。3 [" x; p4 h2 Y4 `) |

$ |% }# L' _; K4 m( l6 }' u* f- G
  1. #define QSPI_DDR_HHC_ANALOG_DELAY      ((uint32_t)0x00000000)      
    5 v- v9 J5 g- F& i) h: T$ v; i4 ?/ k
  2. #define QSPI_DDR_HHC_HALF_CLK_DELAY    ((uint32_t)QUADSPI_CCR_DHHC)
复制代码

) X' O4 I. r  s5 S: `  SIOOMode
, o6 u! y, X/ `1 ~# M: F9 ~, S设置仅发送一次指令还是每次操作都发送指令,支持的参数如下:
4 o4 @% m2 ^4 X. [0 Z- C2 u- B* i0 ?& c* w/ ?& O' z  W
  1. #define QSPI_SIOO_INST_EVERY_CMD       ((uint32_t)0x00000000)     
    3 U% ~6 @& N% j8 H$ t. O0 u
  2. #define QSPI_SIOO_INST_ONLY_FIRST_CMD  ((uint32_t)QUADSPI_CCR_SIOO)
复制代码
" Q$ t! h8 g% M2 G0 r
78.3.5 QSPI自动查询结构体QSPI_AutoPollingTypeDef- \: U4 j' }8 A
下面是QSPI总线自动查询结构体:
3 R& J$ F. D6 I0 M+ V+ L& I
- H: K2 z: @" G6 ^+ F; h  H% A
  1. typedef struct
    , h$ e% J; Q; B& c. H
  2. {" P! G$ V; m  H" j  R
  3.   uint32_t Match;             4 e. X- H: z& G+ x8 }, c/ d
  4.   uint32_t Mask;             & G6 \, R6 t3 B/ L4 u
  5.   uint32_t Interval;         
    ' z4 O, n. f, u" J4 I' e  {  M% n
  6.   uint32_t StatusBytesSize;   
    ) \, z+ _) ^3 z( q; Q* A" ~
  7.   uint32_t MatchMode;       8 ~3 _8 M  a( O8 Y5 D9 W& x
  8.   uint32_t AutomaticStop;     
    1 o. m. P! R5 k3 {7 `9 i
  9. }QSPI_AutoPollingTypeDef;
复制代码

3 f2 a) j1 L/ e1 x下面将结构体成员逐一做个说明:
* f, Y! B- y2 p; p, \0 m
2 r1 D9 @* U; a0 G1 X7 j& U5 A  Match
. g. _2 x5 L) i+ Q3 ^) |2 d' B8 B8 Z参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器的值与此参数成员值做匹配。参数范围0x0 到 0xFFFFFFFF。
2 O- d: H' c; V) V0 [: f' U& D' }' I& F: Z
  Mask9 v( G' g" @, W
用于设置屏蔽位,比如Mask = 0x01,表示仅保留bit0的数值,其它bit忽略。参数范围0x0 到 0xFFFFFFFF。
% _! `# _  @; t1 S# a- H) \
- @# D4 V+ M" @8 Z1 B  Interval! M' R* H; P0 n. j& i. Q4 y5 k
指定自动轮询阶段两次读取之间的时钟周期数。参数范围0 到 0xFFFF。
6 u. f8 i  m% X( O& N- ^
0 o  j  }5 ^) w2 |  StatusBytesSize
  U& {1 c2 w# }% u, O/ Z# J用于设置状态寄存器大小,参数范围1到4个字节。. m1 C/ U* d. K* W
- Q1 \4 `& H' Y
  MatchMode
/ k! S3 V) K! d5 x' W. j参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器完全与参数成员Match一样(与操作的含义)或者任意一个bit的值与参数成员Match中一个bit的值一样(或操作的含义),比如Mask = 0x01,Match=0x00,MatchMode=与操作,表示不断查询状态寄存器bit0,等待其为0。
- z) L. Q1 o3 R. k: R' S- F: }' L' g; ~
MatchMode支持的参数成员如下:( f0 I- i6 }: d" ^# ~7 ^. E; t
) D1 |0 O% M3 a
  1. #define QSPI_MATCH_MODE_AND            ((uint32_t)0x00000000)     /*!<AND match mode between unmasked bits*/
    / `' T7 h0 b  k
  2. #define QSPI_MATCH_MODE_OR             ((uint32_t)QUADSPI_CR_PMM) /*!<OR match mode between unmasked bits*/
复制代码
2 a" z$ k7 {& }) f& {
  AutomaticStop
# B* Q) K% ]- R, v当与参数成员Match匹配时,自动停止检测。
' t+ T) ]% M0 R1 r% ^$ p2 Z4 C0 {( r0 Q2 R
78.3.6 QSPI内存映射结构体QSPI_MemoryMappedTypeDef) U' v0 ?' t6 ]! j2 [$ b
下面是QSPI总线的内存映射结构体:8 I1 U% L- }+ M+ H2 H, _+ [

3 k1 E! m  w' O9 W6 S
  1. typedef struct5 N: l! b' U. r$ c. \
  2. {
    " H$ I) X8 N! ?( ^( W$ q
  3.   uint32_t TimeOutPeriod;    ' V0 t; a/ _# m  O6 h
  4.   uint32_t TimeOutActivation;  6 O  ~& T; E9 E
  5. }QSPI_MemoryMappedTypeDef;  
复制代码

2 e* o5 f- b1 ?下面将结构体成员逐一做个说明:( ~4 Y. V% L* U. d$ T

3 i* w" ^( _9 }( x& ?0 ]8 y' u  TimeOutPeriod0 A  q3 N4 H+ V
FIFO满时,释放芯片选择之前要等待的时钟周期数。参数范围0到0xFFFF。. ]' r, v7 K. H& a

5 [2 f9 ]- f* V% ~( R& z  TimeOutActivation
2 h4 e& i3 v5 D* N+ S指定是否启用超时计数器以释放芯片选择,支持的参数成员如下:- P0 i' P. z( ~( W) O! R4 z
) K/ n! e& c) Q
  1. #define QSPI_TIMEOUT_COUNTER_DISABLE   ((uint32_t)0x00000000)     
    6 K4 m$ ^; d- C5 h% X& {* s4 B9 y
  2. #define QSPI_TIMEOUT_COUNTER_ENABLE    ((uint32_t)QUADSPI_CR_TCEN)
复制代码
! s$ \4 g1 F+ @) E; \
78.4 QSPI总线源文件stm32h7xx_hal_qspi.c9 N7 e4 o2 }. S8 w& O6 l# g
此文件涉及到的函数较多,这里把几个常用的函数做个说明:% \/ ~- q, C& E8 |' T: f
2 ?5 m/ q* m5 ?
  HAL_QSPI_Init
( y* s' I5 A4 s  HAL_QSPI_DeInit8 J1 L+ A- k5 x" M2 g
  HAL_QSPI_Command
! r9 _1 Q  E9 |6 H, r5 ]  HAL_QSPI_Command_IT
( ^2 D, k& j  q  HAL_QSPI_AutoPolling
8 U& {4 P2 e  v5 ~% |3 I" F2 R5 W  HAL_QSPI_AutoPolling_IT- n! ^: {0 B; B7 [( u. y
  HAL_QSPI_Transmit
0 w6 g; E8 _% n) u( Q8 S& j$ s  HAL_QSPI_Receive4 [( o$ `* x! l0 ?6 @$ X4 x, c& R
  HAL_QSPI_Transmit_DMA
$ N/ S  U% ]+ k  HAL_QSPI_Receive_DMA  B& P% y1 Q" e" S9 f! I3 V# F
  HAL_QSPI_MemoryMapped
1 g) T2 b* J; n# d78.4.1 函数HAL_QSPI_Init: P+ O. A7 u' K' r, v+ d! k: u; L
函数原型:# q0 h/ Q9 J6 o3 e0 e
9 u$ B% ^( _; [  `1 B8 @
  1. HAL_StatusTypeDef HAL_QSPI_Init(QSPI_HandleTypeDef *hqspi)" {3 \7 F; N2 f2 y! t+ P3 s2 o
  2. {  l- z5 R5 S5 A0 _) D
  3.   HAL_StatusTypeDef status;4 }. c6 {- G* }4 @1 \
  4.   uint32_t tickstart = HAL_GetTick();
    # o, L( `& C7 }$ U: M' N+ {
  5. * M- w  h0 n8 \( |
  6.   /* 检测句柄是否有效 */7 {/ Y0 B0 _( X1 U
  7.   if(hqspi == NULL)6 A+ a$ I% v0 E
  8.   {
    / \' N3 R+ d; s7 D5 `+ A9 N0 H6 y& |
  9.     return HAL_ERROR;$ z) q2 I) H0 n& J
  10.   }3 I% f+ {0 _4 x0 I, B4 ?/ N5 G

  11. / C, t. A! f4 V6 {+ i
  12.   /* 检查参数是否有效 */
    + k# U. b2 v, q( H. `/ s6 F  K
  13.   assert_param(IS_QSPI_ALL_INSTANCE(hqspi->Instance));& ?# d) l: M! b+ L, R) V2 R
  14.   assert_param(IS_QSPI_CLOCK_PRESCALER(hqspi->Init.ClockPrescaler));
    ; E' U0 M9 m) a3 U' F
  15.   assert_param(IS_QSPI_FIFO_THRESHOLD(hqspi->Init.FifoThreshold));
    * T9 D& i8 e+ e9 @* n( W' Z7 |
  16.   assert_param(IS_QSPI_SSHIFT(hqspi->Init.SampleShifting));
    + J& Y: M. p. j- @! r8 d
  17.   assert_param(IS_QSPI_FLASH_SIZE(hqspi->Init.FlashSize));& \: ^2 u, x/ R
  18.   assert_param(IS_QSPI_CS_HIGH_TIME(hqspi->Init.ChipSelectHighTime));
    ! S  Q+ c' H  c
  19.   assert_param(IS_QSPI_CLOCK_MODE(hqspi->Init.ClockMode));( u- O" U5 z; E4 K% {
  20.   assert_param(IS_QSPI_DUAL_FLASH_MODE(hqspi->Init.DualFlash));
    & Z9 z9 |0 s. Y
  21. % }0 d" B0 ^# T7 }. K3 |/ ~
  22.   if (hqspi->Init.DualFlash != QSPI_DUALFLASH_ENABLE )2 z, o" Q# s  X# O/ K$ }( C
  23.   {
    + u. a  b! N7 q
  24.     assert_param(IS_QSPI_FLASH_ID(hqspi->Init.FlashID));
    $ y' C& _6 y0 K5 x0 z& g1 L. p! S
  25.   }
    ; ]0 T/ F; }1 [
  26. , `; o  o7 y7 p5 A( c( q* q
  27.   if(hqspi->State == HAL_QSPI_STATE_RESET)
    , X; p4 a" v# P+ a0 ]
  28.   {
    9 A. e6 I! O' O# \2 U
  29. ' }9 i" t6 Y3 }  f) b( t5 i' T
  30. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1)2 H1 _& m% e  A6 j! Y* p" e+ S
  31.     /* 复位状态,设置默认的回调 */
    4 s. N$ Q$ k7 s
  32.     hqspi->ErrorCallback         = HAL_QSPI_ErrorCallback;6 \- D( C1 E$ M: d: W
  33.     hqspi->AbortCpltCallback     = HAL_QSPI_AbortCpltCallback;' h* ?9 ?- l" |5 J* S+ l3 \
  34.     hqspi->FifoThresholdCallback = HAL_QSPI_FifoThresholdCallback;
    6 {) n9 N: c8 B6 f/ I( @$ ?5 f( K2 p$ X
  35.     hqspi->CmdCpltCallback       = HAL_QSPI_CmdCpltCallback;
    $ K; M6 X- H7 V( E0 L1 x3 m6 W
  36.     hqspi->RxCpltCallback        = HAL_QSPI_RxCpltCallback;
      B8 J6 q% @! }5 S
  37.     hqspi->TxCpltCallback        = HAL_QSPI_TxCpltCallback;
    ! [! Y' X4 _9 [9 _
  38.     hqspi->StatusMatchCallback   = HAL_QSPI_StatusMatchCallback;2 G# o' x9 v- i! ^9 P2 [4 z5 B
  39.     hqspi->TimeOutCallback       = HAL_QSPI_TimeOutCallback;
    $ z% O% _& V# r+ m1 S# n
  40. ( ^) [! b: n- y9 @. Y/ k
  41.     if(hqspi->MspInitCallback == NULL)4 ~6 w" c# }# ?3 \* h) A% g8 e
  42.     {* I4 A0 M1 j- G- R
  43.       hqspi->MspInitCallback = HAL_QSPI_MspInit;7 c8 ~# R" Z2 O* O- }* L2 j6 z
  44.     }
    : \6 u. N/ S* j8 \9 X& k( F
  45. % o# H0 t0 m* N9 l! W1 @
  46.     /* 初始化底层硬件 */$ i! h4 k" v& l: k, l8 {
  47.     hqspi->MspInitCallback(hqspi);
    6 u" V* w. a! @* C
  48. #else$ y7 t% C7 L  z0 R& T
  49.     /* 初始化: GPIO, CLOCK */
    $ z5 u0 R/ Y# T. D2 \+ N# P
  50.     HAL_QSPI_MspInit(hqspi);6 Z. H! w: U9 E9 Y9 m
  51. #endif
    ; z) h  N* [- X% g# c- V1 g8 v# F- i

  52. / r3 z0 y2 o+ m# J
  53.     /* 配置QSPI内存访问默认的溢出时间 */
    8 H; k) |! F; K2 A
  54.     HAL_QSPI_SetTimeout(hqspi, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
    8 F/ v; z" X( F$ K$ @% L6 Q
  55.   }
    : {% N8 s' ?0 M2 L$ j8 K

  56. ; ?: H3 r, o0 [2 T( O$ K6 n4 t
  57.   /* 配置QSPI FIFO阀值 */7 J' X* P/ f* H7 e- H6 [) F
  58.   MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_FTHRES,
    ! H; d4 P2 Z3 s# z
  59.              ((hqspi->Init.FifoThreshold - 1U) << QUADSPI_CR_FTHRES_Pos));
    ; l; b4 f6 o0 F( {
  60. $ J1 N2 g+ u4 z# A* S% |5 Z+ \
  61.   /* 等BUSY标志复位 */
    : k7 Q9 m- r2 Q
  62.   status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);
    7 q. J1 [' @# v6 f

  63. % S& o% D/ k4 s/ \9 y* d& E/ H- V
  64.   if(status == HAL_OK)
    * R( W( L! y  q3 F2 E2 i
  65.   {
    2 s  b- I9 e& S0 l' T. M# X
  66.     /* 配置QSPI时钟分频和采样延迟 */. w" K. O. f/ P- B. ?3 a
  67. MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PRESCALER | QUADSPI_CR_SSHIFT | QUADSPI_CR_FSEL |
    # e5 f! p! f7 X
  68. QUADSPI_CR_DFM),2 a. |1 p! q) R$ e# w+ [1 \: o" R. S, `
  69.                ((hqspi->Init.ClockPrescaler << QUADSPI_CR_PRESCALER_Pos) |# J% ^7 p- S, K6 u) W  `
  70.                 hqspi->Init.SampleShifting  | hqspi->Init.FlashID | hqspi->Init.DualFlash));4 {3 W% ~- J1 H: H( \2 T

  71. ! q5 q# l2 C4 e3 G- X8 A
  72.     /* 配置QSPI Flash大小,CS片选高电平时间和时钟模式 */0 Y+ [/ ]6 z" N( h6 U) G
  73.     MODIFY_REG(hqspi->Instance->DCR, (QUADSPI_DCR_FSIZE | QUADSPI_DCR_CSHT | QUADSPI_DCR_CKMODE),
    / x  p1 A8 j3 C6 Y" h
  74.                ((hqspi->Init.FlashSize << QUADSPI_DCR_FSIZE_Pos) |
    & r) }4 j* y: ?+ X
  75.                 hqspi->Init.ChipSelectHighTime | hqspi->Init.ClockMode));
    / R" P- h* {) T& A6 |" n7 J
  76. 4 U" r. e. \& D: q9 v2 W* }* T: Q
  77.     /* 时钟QSPI外设 */2 s, O. m/ E" t$ {# {) R- O
  78.     __HAL_QSPI_ENABLE(hqspi);
    9 V: T* |, Z2 T) B* z& k" r: F0 d- @

  79. 5 F9 ?$ g& G3 }6 \9 `: Z
  80.     /* 设置QSPI无错误代码 */) w6 Q5 k5 s+ H/ t. x
  81.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    0 I3 C) h8 \7 N* N7 O

  82.   N+ e  V8 i, Y$ ]
  83.     /* 初始化QSPI状态就绪 */
    % a8 g. m, W1 ^. D6 _5 t, r. a
  84.     hqspi->State = HAL_QSPI_STATE_READY;+ d: f/ V+ n: s5 A% {8 ]. l! f
  85.   }: M- W, n" N- O5 t
  86. 1 ^' a0 y, r" c  z& c
  87.   /* 返回状态信息 */* v8 a: C, m% M; G; z( b
  88.   return status;" f; [) O! q; @0 L  O% G6 ?
  89. }
复制代码
! X/ \) |" |9 H
函数描述:; U  t9 h5 s: Z5 V
, B5 i4 S( ~$ t5 N! t, a) R0 q
此函数用于初始化QSPI。
! t+ b0 e( k& X" T' s* E
' h+ B* i! V% n1 |函数参数:# L4 Z" L  i+ E, G% B. J$ @2 G" ?! m
5 L9 D; N& h/ H! [5 L( Z
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,详见本章3.3小节。
" U9 n( R( t% O; ?1 h+ i6 R- H  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。, D6 b- L- a2 l8 T9 _. J
注意事项:
: {2 n# N) z/ C2 s' |2 R5 g; N% w& t" G
函数HAL_QSPI_MspInit用于初始化QSPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。! M3 @. B6 I1 ]' s. [) Z& [" E
如果形参hqspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量QSPI_HandleTypeDef SpiHandle。
, [) ]: w4 p4 |2 C0 _; `对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_QSPI_STATE_RESET  = 0x00U。  [9 A( |% ]0 ~$ U! Z  B% ]. b
$ b1 S% E! |, M3 n( A' {
解决办法有三
1 ^1 ~- Y( i/ o/ H% S) N
8 l: n! v4 `9 @方法1:用户自己初始化QSPI和涉及到的GPIO等。
( n/ D+ i5 j' t" s) h9 K
# R! o% j+ f/ o方法2:定义QSPI_HandleTypeDef QspiHandle为全局变量。
7 d0 k1 U3 N+ g- x6 }& W, o8 c& Z0 ]% _
方法3:下面的方法* y$ z$ J& m* Y6 m2 o$ M; Q  |3 m

+ l% n" r! _7 s7 R8 w4 f. ~
  1. if(HAL_QSPI_DeInit(&QspiHandle) != HAL_OK)
    2 C8 R2 O* L2 K0 C* y; U- b( p; e
  2. {
      G+ Y  j/ v( |
  3.     Error_Handler();7 i( A) V+ ?" P. @0 V+ P5 Q" r3 R
  4. }  5 y8 c6 e  @9 g
  5. if(HAL_QSPI_Init(&QspiHandle) != HAL_OK)/ ^& [) x. }# i
  6. {
    , E* N7 m, P& g6 s; y9 F  }
  7.     Error_Handler();8 V2 d# ~# D; [& j( T) C" x
  8. }
复制代码

/ |9 {$ {/ e8 F' }" L使用举例:
  s$ I2 K* p" Y/ E: l6 w  M. s) o
  1. /*( n' a2 l- p& d0 [. ~' C- J! S% n
  2. *********************************************************************************************************3 Q" g* o4 }) B  ^& i0 l$ [
  3. *    函 数 名: bsp_InitQSPI_W25Q2563 g. c) U2 J( @" t6 d/ Q
  4. *    功能说明: QSPI Flash硬件初始化,配置基本参数
    2 p4 \! j, B2 Y+ B( o0 d3 q
  5. *    形    参: 无% f, V- z/ F2 s, N
  6. *    返 回 值: 无
    + n5 q$ y* i9 u3 y4 j* e
  7. *********************************************************************************************************- H% H9 A3 I+ U2 \8 o  S$ L
  8. */
    ! j7 o! @* N( s$ o8 Q6 E* U) |
  9. void bsp_InitQSPI_W25Q256(void)
    ) W. ]. C. F0 p2 t/ E# N3 ?2 p; g* V
  10. {7 j" J' G. J6 o9 r* B" K( Q2 B
  11.     /* 复位QSPI */$ u, H* ]' y3 ?# h& I2 U* c
  12.     QSPIHandle.Instance = QUADSPI;  \4 [+ a0 \2 m, e& P2 N" {2 z3 u
  13.     if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)4 ]4 B: k( }  k& ~9 T
  14.     {2 j& O: s  M4 m% \6 n6 r
  15.         Error_Handler(__FILE__, __LINE__);) O4 p! _4 ]4 p% P3 s6 l- w' |* s9 \
  16.     }
      D' G) A( M) B0 |: Y! u) z$ e
  17. 8 o" b/ m' a" B( g
  18.     /* 设置时钟速度,QSPI clock = 200MHz / (ClockPrescaler+1) = 100MHz */' n$ b/ P: Q4 P2 X# `4 u
  19.     QSPIHandle.Init.ClockPrescaler  = 1;  2 G# A, t. O4 M1 d. C8 e
  20. 4 i3 p4 A2 f7 t
  21.     /* 设置FIFO阀值,范围1 - 32 */
    3 J% Q8 X. R- d; W
  22.     QSPIHandle.Init.FifoThreshold   = 32; % E; Z+ z" ]4 G' e+ y0 P' [9 R
  23. / ]0 z1 b# K( @2 p, a( y
  24.     /*
    3 J  x7 u9 A  I) ~, Q* Y0 a
  25.         QUADSPI在FLASH驱动信号后过半个CLK周期才对FLASH驱动的数据采样。: Z6 Q2 _3 g% T. l5 _1 q
  26.         在外部信号延迟时,这有利于推迟数据采样。& ~3 `4 ?; [) D8 w3 F
  27.     */
    0 E: Q) j/ I5 u' s4 {( @( }( u$ a
  28.     QSPIHandle.Init.SampleShifting  = QSPI_SAMPLE_SHIFTING_HALFCYCLE; * `7 z% U$ n" Q& c, w5 S% n" Z
  29. ' E& F0 Z. P0 x- g, T
  30.     /*Flash大小是2^(FlashSize + 1) = 2^25 = 32MB */
    4 f, U- m5 q( C& z' l! O
  31.     //QSPI_FLASH_SIZE - 1; 需要扩大一倍,否则内存映射方位最后1个地址时,会异常。
    . }1 m, K1 l5 `6 g0 `
  32.     QSPIHandle.Init.FlashSize       = QSPI_FLASH_SIZE;
    + Y8 h4 z/ A+ ]  ^: r' w' {
  33. 3 y* \# N! D0 c/ M, H0 |: L
  34.     /* 命令之间的CS片选至少保持2个时钟周期的高电平 */
    . ?& n5 B' \' R8 m. Y
  35.     QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;4 ?' g% w. R/ j1 G
  36. # r* c- V+ ~2 E! }8 u
  37.     /*
    " R; K& d; ]( v  U/ _( H
  38.        MODE0: 表示片选信号空闲期间,CLK时钟信号是低电平
    % e3 E4 V4 ]) F% Y3 m
  39.        MODE3: 表示片选信号空闲期间,CLK时钟信号是高电平* b. b" B7 H" N# l6 E6 i
  40.     */
    1 l) {% p* o3 t0 r4 K4 K
  41.     QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
    6 O) R' x* [& y, v$ ]
  42. % y. M" T- S0 Y# ~% P
  43.     /* QSPI有两个BANK,这里使用的BANK1 */
    5 D) c% p2 m; `2 I- k3 B
  44.     QSPIHandle.Init.FlashID   = QSPI_FLASH_ID_1;- F& J6 z$ d- c* }4 h$ G; s
  45. * C6 w1 a! {8 Q  M7 S" E9 K! i, H
  46.     /* V7开发板仅使用了BANK1,这里是禁止双BANK */
    " r4 Q) A3 `9 A( @, F$ g3 ~8 j5 e
  47.     QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE;* `6 v% m0 K/ V) Q+ E+ ^" z5 S+ Y
  48. 2 _! e) P7 U4 A9 ?( b
  49.     /* 初始化配置QSPI */
    # |. x; ~$ Q$ z3 ?4 o: ~
  50.     if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
    1 [, b! G9 O4 o+ [% K9 B, F
  51.     {
    & x/ P1 e$ J: _4 [- F' f3 `
  52.         Error_Handler(__FILE__, __LINE__);+ ^3 ?' e1 m. H/ W6 ~
  53.     }   
    / c/ k' }/ o4 u  a
  54. }
复制代码

. e; }4 Y" I2 M5 e3 h! o3 ]: x78.4.2 函数HAL_QSPI_DeInit
2 }1 o) L# i; U! @: p9 N8 A/ |函数原型:* S$ K% ^: P) d# B+ H; q: K

' D; R+ I% |5 v4 N* o; R
  1. HAL_StatusTypeDef HAL_QSPI_DeInit(QSPI_HandleTypeDef *hqspi)
    5 i& u9 q; O* C# s5 \' i* g
  2. {; z$ B  P% p5 O. [9 r# u) p
  3.   /* 检测QSPI句柄 */1 h) ~8 [; g* I5 S1 C" l: a" t
  4.   if(hqspi == NULL)
    - C3 _/ P) |6 j# u0 L+ p
  5.   {
    8 t# ?- b/ \# l6 G( g# X! j! N
  6.     return HAL_ERROR;. K. Y& @) D, M) p+ E% h
  7.   }
    1 C) \5 ^+ d7 R2 [0 b

  8. " W9 ~& `! }9 \4 ~& y
  9.   /* 禁止QSPI外设时钟 */$ K# z/ D9 x$ A, V- ]
  10.   __HAL_QSPI_DISABLE(hqspi);
    & E- t9 p: ]; h9 j
  11. 0 \9 c$ w3 M0 e* D9 k1 d) ?
  12. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1)% m$ [& s3 @- ]- P; K
  13.   if(hqspi->MspDeInitCallback == NULL)
    : r9 r/ F% K$ s) E' z
  14.   {
    ; w" {! q" M( Y0 A. {
  15.     hqspi->MspDeInitCallback = HAL_QSPI_MspDeInit;# }# h7 @5 N$ w8 a. B" r
  16.   }' \0 y, D: f' v4 a( q1 A) x9 w% M

  17. 1 H4 `" S: Y7 e5 D# n3 d0 w/ }
  18.   /* 复位硬件底层 */0 |( t; m/ }2 x1 y( @+ U+ }( \
  19.   hqspi->MspDeInitCallback(hqspi);
    . Y! C! L4 {4 m/ b6 c3 o4 n
  20. #else; r( _! U9 s! E& _
  21.   /* 复位: GPIO, CLOCK, NVIC... */
    % @3 B) b1 e" e1 D9 l6 \
  22.   HAL_QSPI_MspDeInit(hqspi);3 g) `2 L' B- x+ g0 {, \
  23. #endif
    / `; l. D: x& i9 b& ^

  24. , J9 x2 M% Q5 i. j
  25.   /* 设置无错误 Set QSPI error code to none */
    " I3 ?9 R$ i2 E2 X  }
  26.   hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;) ~& `& T4 g/ k4 F6 ]
  27. 5 g5 d3 U* K; |' b9 Q, b4 C
  28.   /* 设置QSPI状态为复位 */
    3 q. E, \% {9 }/ t1 a# ?" D
  29.   hqspi->State = HAL_QSPI_STATE_RESET;
    , n; Q$ Q  ~* m3 ~6 N9 k

  30. / O6 S2 G5 ?; N) G! X, e
  31.   return HAL_OK;, Q. }0 a7 Y) D  A" h
  32. }
复制代码
" P( @6 k; i& }# d
函数描述:
5 I: H: ?3 X9 B* H2 _6 g
( j: G- H  g  u用于复位QSPI总线初始化。5 Z5 i  r  P( V9 K

0 E) G7 z# w0 L6 L/ H1 e. \+ q! N( |- q函数参数:+ B) p9 a7 _" D6 I
8 o% B7 q4 E& J+ N8 e
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。5 ]6 e3 K; X4 ~8 k3 r/ O  b
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。, C8 H0 A9 o3 H, g; v9 x
78.4.3 函数HAL_QSPI_Command
) ]4 n3 E& Q' Z5 g函数原型:
7 w6 p) J. z9 U7 ^5 ~5 y; H8 Q* V/ o1 x0 a+ {3 N. `! t- f* |
  1. HAL_StatusTypeDef HAL_QSPI_Command(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, uint32_t Timeout)( L; P! r0 P" [' M( \* B
  2. {; _/ W% B6 y+ F4 o8 K  N$ ?
  3.   HAL_StatusTypeDef status;& E( \8 |2 k6 b! Z
  4.   uint32_t tickstart = HAL_GetTick();
    ' Z5 m1 o0 p, S7 v# t! P$ R
  5. 6 m. I9 O  y+ t
  6.   /* 检测参数 */
    8 c7 A1 t% H# F: M5 y
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    * _  J: z$ H& G% n/ j/ m& a& {& O/ r
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
    0 o" o! F9 y4 g0 t% E( i
  9.   {
    - K% u' p$ s- k; \, r# K
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    & z) Q. e0 D! C, ?/ _
  11.   }
    ! \# m  Q$ c. ^% \; y8 {
  12. . ^% f5 F* k( ^7 N: m
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
    3 `* K$ t# z: x+ j; m
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
    ! R8 E7 D6 _4 o
  15.   {
    ; k7 ?2 Y# K, _: s( B2 A% o
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));; @& m1 I) q3 w- D1 v+ c4 y. A
  17.   }* `' n/ |& v! Z# Z
  18. ( w/ |7 Q3 w) H- C
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));* S: s2 ?/ i9 z9 N" w# r$ D% x
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)( \0 `4 z# L/ V* F) B  _( k' \
  21.   {' G  {/ A! }& @1 n3 u
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
    ! l1 ?0 A  c7 }) L0 ~' m% j3 t5 {
  23.   }
      _" o0 d4 r# x' T( v& i. v! a
  24. / I" L; j- b# X
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));  Q2 s5 ]# K2 Y4 h$ I+ Q5 Y; ~8 _
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));" S' {7 j8 T9 z  m# _

  27. # q7 {! l* ]8 g; w7 ^* P+ ^
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    ! Y9 b- D+ D8 N- x3 w  P9 |; n
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));" H7 J8 W4 G5 O# Y0 ]. H
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));3 M. ^$ p6 M, ^, O7 _

  31. , m. a5 R% @/ [7 _
  32.   /* 上锁 */( d3 l/ k' p7 I2 y+ z8 W2 ~
  33.   __HAL_LOCK(hqspi);& t' Q9 V1 i( \/ E' B5 V

  34. 7 s( r. x3 a' d  `  K  b( N
  35.   if(hqspi->State == HAL_QSPI_STATE_READY)
    ) H, R7 K! J7 _* {. N
  36.   {" [  w+ O2 E( P5 @# [6 b9 s% T
  37.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    4 J+ I6 m1 x2 Y+ {8 X* A0 i

  38. & |2 n2 w- E/ ?' j
  39.     /* 更新QSPI状态 */
    , e) t6 X( {) r
  40.     hqspi->State = HAL_QSPI_STATE_BUSY;
    1 H. m, ?4 v- m8 j

  41. 1 e" W) h7 c" n! B
  42.     /* 等待BUSY标志复位 */
    % Z8 D, x2 `8 R- C- s+ o
  43.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);% e' r5 E$ z4 t8 V' C8 X: Z& z
  44. ) L$ u% ?$ C% i/ ~) ?
  45.     if (status == HAL_OK)" @) t5 Z! J  f! r: b4 N# S
  46.     {4 K- ?8 z  S2 p" w* u
  47.       /* 配置QSPI  */
    5 H' `3 e5 x6 S8 ~
  48.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);! i+ f1 u9 l/ N
  49. 8 ^2 l  z6 }4 q8 j$ }. }
  50.       if (cmd->DataMode == QSPI_DATA_NONE)$ Q. k2 u. n1 A+ z
  51.       {
    7 W! v, b8 w7 `& ~' j4 ^
  52.         /* 没有数据阶段时,配置完成后立即开始传输,所以请等到TC标志设置并返回到空闲状态 */( N, r4 u5 h; V5 p5 P
  53.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);% D3 L- \# B# G8 E& K, L

  54. 9 f6 M9 J0 x; f
  55.         if (status == HAL_OK)
    3 w( h$ N2 C& `
  56.         {
    5 K$ X& K  e3 R
  57.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);: S) X+ v  y. B% T: H3 L+ y

  58. ( Z2 V7 G" f7 U
  59.           /* QSPI就绪 */
    ; v3 t+ M7 ^4 X6 r2 H$ y" f
  60.           hqspi->State = HAL_QSPI_STATE_READY;
    4 N/ {) g2 c1 z, G
  61.         }
    / X' A8 @9 T5 r! G
  62.       }$ d' p2 u$ ]3 q4 f
  63.       else8 v: ?" b- l% l  n: @4 F  T
  64.       {
    1 D+ [  |+ H& X
  65.         /* QSPI就绪 */% z2 t8 R) ?0 f( v+ V, m& I) @
  66.         hqspi->State = HAL_QSPI_STATE_READY;/ U$ G5 _' F" D# j
  67.       }
    2 \, _9 H5 i& L
  68.     }, U; t% e/ l2 ~# D
  69.   }2 n! _5 s6 s$ ]4 G  ~5 g: e
  70.   else
    5 W, q& T8 t$ |/ G) ?0 M% @1 M' I" m+ ^
  71.   {
    + w7 w  }; n+ U% g8 a7 }, y
  72.     status = HAL_BUSY;& C0 B$ g; ^! j/ w
  73.   }
    $ A8 y# G. E: q( l0 s8 m

  74. 7 Q. K6 S9 d& }, S% R4 W
  75.   /* 解锁 */
    5 c+ [7 T) w5 |
  76.   __HAL_UNLOCK(hqspi);
    " E5 ~# U7 h4 B. h: y
  77. 5 ?: p+ \& y' M( r  T+ s$ c" T5 O2 X
  78.   /* 返回函数状态 */
    9 J; o: D* F$ ~2 {1 h; S( n
  79.   return status;" t- n& k9 W( @5 A0 I) I, _
  80. }
复制代码
3 x. M( w& W( i# m  l$ N
函数描述:/ S2 x( |8 N& n9 f( U. n
6 l+ _0 j9 p6 E" D
此函数主要用于为QSPI Flash发送操作命令,查询方式。) s, l( {7 C' {/ c/ r
9 v  G( ?( I! m& n! g
函数参数:( a- \) k) Q9 Q' c9 D7 i
' k6 n9 A% x- e7 \, E9 ^
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
( P8 l+ ^. L6 c5 }' V  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。* G& l4 C# B) c8 Z0 u+ V! t. E
  第3个参数是溢出时间,单位HAL库时间基准,一般我们设置的是1ms。
0 {) B1 L' m5 q$ d  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。# o1 `7 a( k/ K" Y
使用举例:" J2 Q* e" @0 r% i/ ~. n
  z" t, \4 w' B+ Q1 A
  1. /*
    . T/ }. v4 q' d
  2. *********************************************************************************************************
    % N6 B9 X& g8 U* V
  3. *    函 数 名: QSPI_WriteEnable
    ' H) \: f2 y' T. Y6 [8 R& ^
  4. *    功能说明: 写使能$ Y; C/ Y# s; J
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。& R- ]& e: R$ I7 U. R, m5 A
  6. *    返 回 值: 无' _- @; o* r" d; k' p
  7. *********************************************************************************************************
    % @. Q- P: x6 }; g8 W( X& }
  8. */
    7 w3 @  f  B; L3 U
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
    ' n$ E! f. S  Z" }0 E
  10. {3 H$ u  t: D% k* n2 U+ D7 V: A. m
  11.     QSPI_CommandTypeDef     sCommand = {0};1 ?$ b; g* H7 g+ ~% \: n9 }/ Q
  12. 6 c# k. i5 a; a. d' T
  13.     /* 基本配置 */* e( X) f9 J+ U6 s
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    - a' g8 H* x/ x0 [$ g# j% V
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */' w6 g; ~: T; X) j, B) _
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    * s+ D1 [/ h4 U: N+ q( E  c' ~
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */9 r5 Q, v3 j; t7 G1 G
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */! A: S8 P+ v4 _/ ~, t; r
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */1 F0 l+ t8 E, M3 n# {

  20. ; I, _' R- Y* C& A
  21.     /* 写使能 */
      [- ^+ l  C8 E3 s: u' L, o
  22.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */+ v- X. z; |4 |& g
  23.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */' O; i# Y# Z$ v' w$ [$ L- B
  24.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */
    ) q) }- K- h* Q$ s4 Y, G6 B
  25.     sCommand.DummyCycles       = 0;                 /* 空周期  */
    " w3 Q3 r+ z9 W. t9 q/ s! K" {- H8 y

  26. 3 S4 S! h) l* e) a# j1 @
  27.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)% j; t* v, T( q" b! E( B6 n
  28.     {8 C- ]- {, p- u, n1 C, z) F
  29.         Error_Handler(__FILE__, __LINE__);
    / j2 V& E& Z5 ~0 e+ E" r' S
  30.     }   
    , }3 T# F& l: _4 w1 `& e3 b* M) b
  31. }
复制代码

8 I2 B# @' R$ R( T& _78.4.4 函数HAL_QSPI_Command_IT
! |& Y; Q4 k+ G函数原型:; Q3 h5 O& [7 f, u& j- D

3 M' Z) _6 j% D# x
  1. HAL_StatusTypeDef HAL_QSPI_Command_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd)
    # p7 Z" q, \# j+ W7 v
  2. {
    * p1 _1 s. v: t1 `! _4 E
  3.   HAL_StatusTypeDef status;
    1 c+ h; j6 f3 B  j) V
  4.   uint32_t tickstart = HAL_GetTick();, k, O) [- u$ v! r7 L
  5. " A+ U: [2 q: C
  6.   /* 检测参数 */! o1 x1 F+ G! @! ~
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    * d; C/ M6 W' u7 s- t2 u+ P
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)0 d  ^1 D7 V' l( A. g) h( A
  9.   {  S* U0 A* H4 w1 V
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));4 }1 P7 ~7 I/ Q9 R5 X: G4 x5 I
  11.   }2 d: o) m( ^$ H4 X
  12. ' J' s: _; a" m8 d
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));- ?! n% o0 n8 S* G& ]
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)+ ~0 ~, E- m0 X' ?  [. y
  15.   {1 A7 S  k$ l# Y  a( Q4 s7 L
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
    - }/ F" L, ?# `& l) G
  17.   }
    0 S# ~; X) v- P* I+ |8 i

  18.   \5 o( l' w  r5 M2 W3 I
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));+ d2 b/ w; g5 N/ e
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE); e- y" P& j3 {0 u! M5 S& E
  21.   {
    : ?8 m& y( \+ `; h' b) k: T
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
    ! f7 R' \: ?- P4 N+ r
  23.   }2 t! I6 g5 I6 Y& z4 P; A7 Y
  24.   `4 w7 i: P/ \, J
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    " ]4 H0 {$ H! N* Y# E- Q, P
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    4 p7 V$ r: l! l
  27. 0 ?5 O; i; }1 E$ T: e3 ~6 Y) ^
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));' }. A1 f( i( X+ s! h
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
    ) ]7 `- h! J: E  w6 V; A' T& h
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));
    $ G( M: ~2 |! u% v9 Q
  31. 3 }8 c2 V: K0 Y( w% N# O
  32.   /* 上锁 */$ {" F) w6 i6 m# d' n2 m: ^
  33.   __HAL_LOCK(hqspi);
    0 ], ^; f+ M2 i% b

  34. # Z/ U+ O& R  k% h# X
  35.   if(hqspi->State == HAL_QSPI_STATE_READY)
    6 \' _  [! x8 {, }
  36.   {$ z* U9 S, ^$ c# T( Z' L, a
  37.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    ! b4 Z' W1 A/ o1 J
  38. 7 O) Z5 w; H7 \# S' i6 G- k
  39.     /* QSPI忙 */
    & l; O; A: w7 ~8 |0 }- a, M
  40.     hqspi->State = HAL_QSPI_STATE_BUSY;! p1 w/ @+ L3 N, L# b

  41. 2 ~  Y! U- e# e1 {# s9 I
  42.     /* 等待BUSY标志复位 */( B) _# M9 M4 u+ a) p
  43.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);& z( Y3 @9 _/ t) ~& C* i; _
  44. 6 v0 G$ C; h) b) e7 L
  45.     if (status == HAL_OK)
    1 I$ |/ \7 u" s
  46.     {
    4 A3 b2 z: x/ e4 c$ I% g: s
  47.       if (cmd->DataMode == QSPI_DATA_NONE)' u) F$ o7 b& m; V, D4 a( s
  48.       {, E# h) G/ w5 V% ~) h  o
  49.         /* 清除中断 */
    * [" U, B4 u7 @9 ?$ p
  50.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_TC);
    $ [* Y& i* i# p2 g3 ?
  51.       }' `2 N  A  `$ c0 m
  52. ( y9 m* l; B* W7 @- X- ^6 x! b
  53.       /* 调用所有配置函数 */
    5 ?( E! O8 Y1 y+ H/ Z# l
  54.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);' j7 a2 n; \5 R0 j7 y9 W
  55. " @& |$ @1 T) E$ @6 S
  56.       if (cmd->DataMode == QSPI_DATA_NONE)
    ; r+ x4 s/ ]! O2 o
  57.       {3 G+ W; V* G! H2 v5 O% |
  58.         /* 无数据阶段,配置完毕后,立即开始传输,所以机会TC和TE中断 */
    % ^7 q/ ^0 u. X" @1 D( [
  59.         /* 解锁 /( j' E* t3 ]8 r
  60.         __HAL_UNLOCK(hqspi);
    ' j9 f' y1 _- n; R$ ^
  61. - R* x/ Q  R# r$ Y) B8 f
  62.         /* 使能TE(Transfer Error)和TC中断 */& r1 C, w& N# _( b8 N
  63.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE | QSPI_IT_TC);
    9 H5 Z# T1 V1 E0 H0 s( e9 l
  64.       }! p3 p/ i0 O- v$ B+ S+ @2 Z
  65.       else
    2 a# V1 P) e& i
  66.       {( `3 c: h6 G; u0 K& Y+ g" N! q
  67.         /* 更正QSPI状态 Update QSPI state */
    + N) C: s1 c3 Y
  68.         hqspi->State = HAL_QSPI_STATE_READY;
    & N, g2 z& M6 l
  69. % d! y: p0 C" \) z' n6 y9 X, D1 ~
  70.         /* 上锁 */
    1 t+ Q* U/ N. a0 o0 x1 K
  71.         __HAL_UNLOCK(hqspi);
    ! _6 c% y" Y% _* G  Z
  72.       }
    " }) H) t5 G9 L8 D+ g2 @
  73.     }
    2 t6 y' n. M+ K) h- k- k; w
  74.     else
    ! P! p# q+ J* `- B2 O7 X
  75.     {
    ) u* ~: c4 b8 l6 o/ n
  76.       /* 解锁 */
    : w& W  \$ F; E( a/ u5 \
  77.       __HAL_UNLOCK(hqspi);
    7 L4 @; x9 N7 U; d3 ]) d$ ~
  78.     }1 Z" v, @* \3 I/ K, }
  79.   }. c) @! y# E4 {
  80.   else
    ' W% M% b+ b7 Q  p* u+ A
  81.   {
    5 i8 h; q/ N/ u& d
  82.     status = HAL_BUSY;- G' h4 a' Z" i3 i4 G# h5 x1 r) T
  83. 8 q4 z" X$ I# U5 S" r1 M7 S9 l
  84.     /* 解锁 */
    % P& q2 e' h% R' |( d( Y
  85.     __HAL_UNLOCK(hqspi);
    2 ~5 m* D5 m, L* @2 H% A  _4 w- j
  86.   }8 y- U( E5 B, V1 M

  87. 7 Z0 q1 o0 x0 y
  88.   /* 返回状态 */
    ! r6 @3 F. a0 V& u, r
  89.   return status;
    & B6 ?+ P: @" x, X& N& [
  90. }
复制代码

4 e7 u; }- g2 B3 T8 T函数描述:
) }8 A7 r1 z: n# B# f* v% u
7 u4 K% E2 g7 u此函数主要用于为QSPI Flash发送操作命令,中断方式。# o; X$ Z$ `2 q  Y% n

2 o( |6 q: T* s5 |* s6 v% l6 y函数参数:
3 R# d9 X1 e9 s* g9 ], E' F$ n( r, Z3 M( j) p0 g  F
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
2 L* h. U2 d8 J2 O4 ^  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。& z0 L! t* n9 s8 @% e+ P
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。% y9 j' v" o# d% X3 ]* h, F7 m2 z7 r! ~
使用举例:: q: f- ]  i) G* l. y

  b8 g# T$ x) _& t8 P, u6 N; M
  1. /*% [1 d5 Y7 @& M  P
  2. *********************************************************************************************************; w4 u: ?( y3 ?# Y9 k7 _
  3. *    函 数 名: QSPI_WriteEnable
    / S( b- W# o7 y% T% f8 }
  4. *    功能说明: 写使能
    / m5 V7 V3 T, J6 O$ [5 T2 o0 |
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。
    3 V5 }& G4 L7 b. o) `5 J
  6. *    返 回 值: 无* o9 x' k4 R+ g( g, I
  7. *********************************************************************************************************
    " b' b+ x1 K7 [
  8. */3 R5 C( R& H) e6 Q7 T
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
    & }$ ~# M; Y9 d) x: L2 `
  10. {" m: ~- q' C' w5 H
  11.     QSPI_CommandTypeDef     sCommand = {0};
    & d/ \  x( Y1 x# q, T* c7 U
  12. , w" C" |3 ^( z5 j( B
  13.     /* 基本配置 */7 O& x( d2 y' d1 A% F+ \( O
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
      s! C7 [! Y) L& ?
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */% {# j: i6 A% t
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */2 g- |' L: S/ y) a" D. {* ]9 R9 a) y2 ]
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    ; ^, D9 Z8 }( E4 I% e
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */' [) j# N' c9 M, E  ?/ [- B3 s& N& b% _
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */0 J5 m3 G& [$ v: ~

  20. ! _* ^. P: P: s# m& f# P8 `( C, h
  21.     /* 写使能 */
    4 s- w7 l  d' ~
  22.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */
    & t: J8 x1 }# m8 b
  23.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */6 u3 P! p0 @) S
  24.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */
    ) _& t! d8 u+ N% \: {7 v& e, X9 U
  25.     sCommand.DummyCycles       = 0;                 /* 空周期  */8 a0 h* ^- C, E' V% s

  26. - C% U) Y9 z4 d$ |2 l; C
  27.     if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK)" @/ ?& U$ a" w. j/ K
  28.     {
    8 L, y- H( o7 P5 n' L* X
  29.         Error_Handler(__FILE__, __LINE__);
    3 ^1 _1 q& {. T+ C
  30.     }    % d/ [; x3 q- y2 Z% t& E
  31. }
复制代码

1 }3 Y6 H2 ]8 k1 I, Z8 S  s( \78.4.5 函数HAL_QSPI_AutoPolling* s6 N% d( Q1 T' p+ c
函数原型:
1 l+ B: f/ a. ]7 Z4 N- b
( @- M' ?& v7 g! x$ C& B
  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg, uint32_t Timeout)& g+ w8 {" M: `6 b) a! X; ^- J
  2. {2 c* B; U3 U! q  z) B4 p
  3.   HAL_StatusTypeDef status;; `0 O" x1 p. N; n" m# G
  4.   uint32_t tickstart = HAL_GetTick();) W" i5 \' u% i6 K) |

  5. 1 I! [% t& m3 J; P1 ]& T# s
  6.   /* 检查参数 *// b  U6 ^) J3 I; i3 b; Q
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));! p4 z3 `4 B( O( R+ s" p
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)$ H) _- j8 \. U- H0 @% A
  9.   {& J" i$ ?3 P8 n  l; A
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    : o$ G1 h! }& Z3 c. T
  11.   }
    ( [5 j7 r5 {) P5 t
  12. 3 r6 a0 u6 U' o7 o7 s# h# w
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));: T) q$ H7 E. ?$ f" |
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)) r. {8 V" _( `2 @
  15.   {7 v% {* f8 J/ s$ b' l
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));- U5 ]- V. F% ?. }
  17.   }
    ( O1 v: P1 T9 `, y7 M  G
  18. & C# Y- G( V0 J' S8 f
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));: u# {8 p/ r% [$ ]9 x2 i  u
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)0 c4 O6 G+ |+ }& B
  21.   {& t* O+ f" I' D; w5 K- l7 J# Y
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
    : j' Y: }; i" S% M( q3 Z1 w8 \
  23.   }
    1 e1 o/ n7 P* c" |4 m
  24. : K1 k/ o4 W& p+ I8 T1 D" W
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));: ]7 [/ \) H, _6 L) v
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    0 H( Y9 J9 r9 g$ a+ L" ]2 e
  27. + j1 n1 o* [* ^6 z' q
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));, |6 t( L" r5 x
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));! v! ]4 R% Q5 B' R
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));
    ) L6 P& J' X! ~- n" r
  31. 1 |8 u$ _6 K6 n& p* j
  32.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));0 p6 v" c; C+ S" `  v8 p
  33.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));
    , y2 y4 d' ?! {! E+ V5 n- n9 T
  34.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));
    % l1 \0 [! \+ H

  35. , {' R1 I, ?5 \; k
  36.   /* 上锁 */8 _8 o: H6 A; l% k
  37.   __HAL_LOCK(hqspi);) E* N6 B% b, _! ?* a7 C, w
  38. 4 @/ C9 T) X5 B% B- u! M
  39.   if(hqspi->State == HAL_QSPI_STATE_READY)
    5 ^0 y/ Z4 x5 s3 d8 w* W" t3 n3 a
  40.   {. d* I; z( H& X1 U) S/ d; a
  41.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;% }# G% ?. t4 B5 {$ X) W) }

  42. 5 e& v) r! y7 ~; ^# q
  43.     /* 更新状态 */
    5 h* m; L- T, \: e  t
  44.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;
    8 O# E2 ]; p( v; M

  45. : n- B/ z' d$ m0 M
  46.     /* 等待BUSY复位标志 */
    * P: x( G9 s7 e. F* i, k
  47.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);" n8 u2 F: o8 J* w3 W2 _3 X
  48. 6 h; z% a3 m  U7 Z' y5 |
  49.     if (status == HAL_OK)
    5 O" W, d2 H5 U1 W0 n2 l) b; v
  50.     {
    $ y0 o, z. ]+ @
  51.       /* 配置QSPI匹配位 */
      O+ l" C, j& k/ z
  52.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);6 f+ N& m8 U3 z; [

  53. * Q) l5 v. b* i
  54.       /* 配置QSPI屏蔽位 */" r% j  l: a2 A& a2 J: a
  55.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);
      L0 x" G8 i# ~9 A6 S
  56. 2 ^* b: J2 @& ?8 F' l7 q
  57.       /* 配置查询时间间隔 */% l1 [7 ^6 }0 M4 D, u( b. {
  58.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);
    * ?) ^' G% \" b# y, B2 u9 c. [" E

  59. + `- ]  O( _  C: e
  60.       /* 配置匹配模式,使能自动停(否则阻塞方式无限等待) */
    / F$ P2 |% N& ~4 j
  61.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),
    , z. r% v+ ^. V; r' ]7 e9 k
  62.                (cfg->MatchMode | QSPI_AUTOMATIC_STOP_ENABLE));
    - j5 F0 v- t# L+ k2 z  B" D
  63. ; z8 K3 z$ q4 ~/ F; ~
  64.       /* 调用配置函数 */- Y+ B% ?, N/ c' A" h
  65.       cmd->NbData = cfg->StatusBytesSize;
    0 U" D# c7 k; T: N
  66.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);/ p2 n% h* M5 `  X8 J# F

  67. 4 Y. i$ s, m1 {& y
  68.       /* 等待SM标志 */
    $ t# E4 o2 e7 [) V( x. i) l: ]0 ?$ U
  69.       status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_SM, SET, tickstart, Timeout);# ~9 w9 F% u2 A

  70. ! c1 q0 s( m6 Y0 ?; e& G
  71.       if (status == HAL_OK)
    ! q7 C5 l! b& r; E( h" ~# S; `
  72.       {1 u8 W* o- X. g! @  D% o3 g# U7 j( s
  73.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_SM);
    7 U0 K+ Y* d# M6 H5 k3 q( R0 }

  74. 7 C( A1 W2 Z+ r" q
  75.         /* 更新状态 */$ J, T" m8 K5 ~# [9 u0 m/ `
  76.         hqspi->State = HAL_QSPI_STATE_READY;
    : N, \0 @# u7 h
  77.       }
    4 b/ _! v) h8 E- |
  78.     }
      ?1 V; z, s+ f* Q" b2 N/ w/ V
  79.   }
    $ n# s2 |+ R" X+ L8 W
  80.   else
    5 j; `5 V9 W  ~1 ?: L6 [4 ~
  81.   {5 Q2 `4 C7 M, {$ i$ j2 O4 S
  82.     status = HAL_BUSY;, Y2 l) a$ C5 L8 C' r% J7 Z
  83.   }
    % H, p2 r) N2 K, H1 D2 n

  84. ( X1 {; `& c! Q8 m7 E3 g
  85.   /* 解锁 */
    - X( S5 b8 N9 E6 E
  86.   __HAL_UNLOCK(hqspi);8 d  ^) k; m% Z" ~/ m- d

  87. 1 p7 _5 g3 t0 E: f* }2 y6 V
  88.   /* 返回状态 */( H2 o# e, L0 J  G1 I+ n
  89.   return status;
    6 X& C  R( p" a& s. Q& E5 h, V; z8 f
  90. }
复制代码

8 V  O0 V  s0 c+ g  E- Z/ K* \函数描述:- W+ p; V8 O8 Q3 n5 f
# n5 d7 [5 H: }  d# p1 f
用于状态标志查询,函数采用的查询方式。' H3 q- y( f1 A/ P6 Y  z
% q  q& E7 Q$ i
函数参数:
* |5 Q6 W& D0 X- O, I; o5 ?) K
0 e; K' C# S/ Q: U( s% G, R2 X  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。2 q3 b% w% N' |' G5 K+ i! R' k
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
" P1 B6 }- R! g: ^  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。( z/ E3 Z, V- |+ z" B
  第4个参数是溢出时间,单位HAL库时间基准,单位1ms。4 G7 O% S, Y& j- m, k4 n0 R9 h( y
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。' E( b, D6 u* o0 \/ t9 f
使用举例:# [2 I  C, W5 O+ j0 B4 ^! |) _7 o/ ]
* W8 Z: K- \2 s2 V! a! f$ C+ u' ~9 D
  1. /*4 i+ H" t: p/ P
  2. *********************************************************************************************************% u& |, f. H! p/ Y
  3. *    函 数 名: QSPI_AutoPollingMemReady( E: I. `! e) I% H7 x; K+ ?5 O
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用
    0 p  t0 P, W% ?& l
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄
    & j$ k! {" i' h: d, |! t
  6. *    返 回 值: 无  j' R  I' s0 E# ~
  7. *********************************************************************************************************
    2 Q/ c- F$ }9 S. B7 Z& _8 @: l! V6 `% O/ r
  8. *// ~- h2 j5 E' g7 V) Z
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)7 C  I/ i, v' X9 `2 s! K: k
  10. {
    6 {6 {, w6 Q. J. j  O+ C. P6 M4 L
  11.     QSPI_CommandTypeDef     sCommand = {0};) [5 m$ }+ a8 J! t) B' M
  12.     QSPI_AutoPollingTypeDef sConfig = {0};
    8 k7 s- L( f  A; Y& k- v
  13. ' P' }6 ^- V$ N+ L4 ?% _
  14. 7 o. r$ S8 ~( {0 ~: c& c
  15.     /* 基本配置 */; R, K. ~" ]/ R6 M5 p+ S. ~! w% q
  16.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    $ i4 I$ ?) W  Z0 q
  17.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    1 V8 l& e: y7 v$ a! U2 y; w6 m: |
  18.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    - L. m+ v5 K8 f6 Z
  19.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */' x- G% f2 b# Y0 Z9 ]& ]
  20.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */8 K( p: S# K- q* c, `# R
  21.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */7 q3 r$ c0 ]* |- U" z

  22. 1 \' O: K# x8 W3 J( q
  23.     /* 读取状态*/7 i. T9 c+ Z! x# u* {) K
  24.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */$ K6 J# y8 H4 C3 I! f% ]" U
  25.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */, {' O1 Q2 d; ^) G
  26.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */
    . `8 G6 o# V& n1 U6 H' R
  27.     sCommand.DummyCycles       = 0;                   /* 无需空周期 */* [: ?7 _9 ]: h: u/ O. ~

  28. - i% I6 U3 `6 M9 m) i
  29.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
    1 X" k' X/ R+ A9 ^/ @: p
  30.     sConfig.Mask            = 0x01;' n9 ]1 o) T9 a9 [9 @4 O
  31.     sConfig.Match           = 0x00;
    5 t1 k5 a$ j2 s  D8 M8 T2 z
  32.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;- z; W# M; {) s8 f8 i6 z
  33.     sConfig.StatusBytesSize = 1;
    7 ]8 n& g8 `3 m; W( r3 K& K: y
  34.     sConfig.Interval        = 0x10;6 ^  A( U9 ]: [- _% r6 Z
  35.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;* e3 R! @. @1 K* X7 S5 U" D* `8 v
  36. 0 S$ |9 b; Y. E
  37.     if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, 10000) != HAL_OK)
    ; _8 S; _& K" H/ V2 y9 ~7 {; t) `; L
  38.     {
    / `* v- Z+ y% v; g4 I. ]" |
  39.         Error_Handler(__FILE__, __LINE__);
    * G- N; v& W% }$ w
  40.     }
    3 q! s6 t  _% |: `
  41. }
复制代码

2 H, w4 r, ?8 m' r' N78.4.6 函数HAL_QSPI_AutoPolling_IT( s, T7 J+ j) ?" `
函数原型:
& n0 k5 x  y7 D7 U/ V. S7 i/ Y
* s: R- V# Z( G
  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg)* _% l* B( P$ [# B& w! T
  2. {
    $ r% u; M" L  z8 B$ h3 Q# @3 y
  3.   HAL_StatusTypeDef status;, @# J. g# P6 y  I, Z# ~' O5 i
  4.   uint32_t tickstart = HAL_GetTick();# @8 p1 X8 q9 w+ Y, }* e* e' I% Q+ T
  5. 6 ~1 g7 o2 E: H9 ?* X6 J% x& }
  6.   /* 检查参数 */
    " N, {' o% U4 X4 P5 u
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));2 m$ \  r- U" w# {1 a, @
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
    - V) p* t+ d* x% \, F* x2 J
  9.   {
    $ s+ D, V) g, Y6 K
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    9 ?7 Q- k8 n+ ?
  11.   }
    - B6 E1 y; V2 K" E* Q
  12. 4 l. P4 c7 o) Z
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
    6 B/ G6 r: V' z
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
    ! N* F% |" m( P$ M9 E
  15.   {9 K5 j4 i( u% x
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));) A8 ?0 M  Q. q  R3 _; j  ^2 O
  17.   }
    ) d( a2 }5 O' b- h& E6 w; d8 M
  18. " v! Q7 U# J# D; l  K2 p4 g& k: v& t
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));& o) R4 S/ A4 k8 u3 n- c  b
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    8 J$ p* q# i! p. f
  21.   {
    $ A8 z3 F" N4 h3 B
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
    $ t3 Z$ H$ i, ~# y, e5 `/ D
  23.   }  N* o9 Q8 S6 R" v9 D7 I. f

  24. 6 r5 ~; b9 u1 I2 h8 d
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));2 h( D' \* c+ b8 _
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    " g; ^$ l; H; E& [$ A& Z' v
  27. * q/ y( |" t6 m* E
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    6 T! G  L4 l* I1 \( [4 b
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));6 ^6 C" C# T9 `2 p* t
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));
    * K' E/ D" G: B5 S6 i
  31. ' U7 E3 D! N: w% P. ^9 s; q% E
  32.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));+ m; ?7 z/ H7 m/ V
  33.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));  P# ?- d; `2 O; l8 ]
  34.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));
    6 O8 ~& _. B/ M
  35.   assert_param(IS_QSPI_AUTOMATIC_STOP(cfg->AutomaticStop));4 R! N: G* P& D& q

  36. % s5 Y( ~( @; M$ z& `; s$ a& d. s  Q
  37.   /* 上锁 */
      ]9 c) j1 J" J! D
  38.   __HAL_LOCK(hqspi);: G- x/ e! }% T0 D2 O' \. |/ H

  39.   U! h# h7 K, I
  40.   if(hqspi->State == HAL_QSPI_STATE_READY)
    # |& K5 r! U9 c' l
  41.   {  h" Z+ y! H  ~
  42.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    7 Q; v8 D9 U1 B! N* \. U/ s

  43. 3 }% l5 X6 v9 S& q: r" {
  44.     /* 更新状态 */
    $ Y+ A! s* ?5 U
  45.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;
    * a9 d, I* i% L4 g) J/ w

  46. 3 X1 P8 d5 i- ?2 @! Y4 p
  47.     /* 等BUSY标志复位 */, c5 F- n* N6 Q1 {5 b( {
  48.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);4 j$ a. s+ s# T; I% O* @9 {1 C8 W

  49. ! F: m. O/ J* q, g" B
  50.     if (status == HAL_OK)3 y% }$ @8 }+ u
  51.     {
    7 j* g" P: v. X3 ]0 p
  52.       /* 配置匹配值 */0 |8 K8 J% U  G: J& ^# F
  53.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);
    " y8 m( w* g+ `: A8 v) X

  54. + e6 S/ n: h6 S1 [# p% D! I2 n
  55.       /* 配置屏蔽值 */: t1 k$ U( w9 a
  56.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);
    ; W) i1 J& g, ^! O6 W! \

  57. ) a6 {$ L4 H+ p" w
  58.       /* 配置查询间隔 */+ o/ }: g3 [, Y9 j. ]5 ^( Z
  59.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);" H* M) B% O2 g- D- b" `

  60. ) D8 O) x3 U( C/ g+ f# ?! G
  61.       /* 配置匹配模式和自动停止位 */
    4 @, i$ F* q' h0 m0 O) H. n. i
  62.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),9 m% \' l: U2 a3 ^( s" n. W( ]
  63.                (cfg->MatchMode | cfg->AutomaticStop));
    + ~  ]9 H, z8 y6 I& [8 I

  64. ! U! ]/ X6 |* ^& q1 I
  65.       /* 清标志 */) N" T0 `6 a+ O3 b& t, v
  66.       __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_SM);
    " \; S/ i* m3 p7 Y) |6 C) T1 _4 r# p
  67. + S. v) n/ D# h' ^* w5 g0 E
  68.       /* 调用配置函数 */
    , s$ S( S; t+ ?0 z
  69.       cmd->NbData = cfg->StatusBytesSize;+ Y1 j& b4 @% Y; h5 W
  70.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);
    5 D2 ?8 ?* Z! `. s

  71. & |. ~6 |0 r9 B, J
  72.       /* 解锁 */$ J' _/ o- |* K+ |
  73.       __HAL_UNLOCK(hqspi);9 o' O- i# l. y/ z8 H( Q5 O( U# C

  74. * J. o5 Y# P2 ?: e: @, U
  75.       /* 使能SM(status match)和TE(Transfer Error)标志 */
    + A8 \0 T- }& x3 v
  76.       __HAL_QSPI_ENABLE_IT(hqspi, (QSPI_IT_SM | QSPI_IT_TE));' j" `4 c7 w$ ~4 h9 y
  77. 9 F; n$ Y% X# M9 X4 q
  78.     }) H  l3 {* A$ B1 ~* x# U. n7 C
  79.     else$ X; b! R# X) ?( P
  80.     {/ Y# [% G. f; R: v
  81.       /* 解锁 */
    ) L& J& B, V4 l& Y3 I
  82.       __HAL_UNLOCK(hqspi);
    7 U6 o4 L# ~8 I: {
  83.     }
    # K4 v' V5 I: w! d& U$ i, {9 I, l9 F
  84.   }
    8 m! S- [, R8 {
  85.   else
    ( ?" c1 ^% A- A& M9 J
  86.   {7 [; @) O; z" n, P
  87.     status = HAL_BUSY;% |/ r8 A6 K" l. |" F9 F; w- t6 X

  88. $ _' p% `3 w/ d' k7 {
  89.     /* 解锁 */
    / W/ {' C9 W4 e4 D, }
  90.     __HAL_UNLOCK(hqspi);4 t" v  Z7 E4 P/ I4 ~& I
  91.   }& B& K. B7 ?- I' @) m

  92. 7 d  F# t3 W  M! y  W* e  p
  93.   /* 返回函数状态 */
    2 s) L0 `  E% r+ E
  94.   return status;7 y$ a) P; ^5 V4 z
  95. }
复制代码
! F9 @) |8 a, u  g
函数描述:8 O; q( E" v& Q4 J) p3 D6 Y% t( D3 t
2 ?8 C! v& I8 H
用于状态标志查询,函数采用的中断方式。
- K" x& r* r* b  `1 O$ I7 L6 k) b% a
0 k6 o& L& p" x. i+ M函数参数:
, R. D* \. F2 Y1 a8 |
0 w+ H' i$ p, x! s  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。2 v3 S& n+ g$ Q0 S3 q
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。  t1 d. x& I$ `7 I
  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。6 L" P: p% D8 a1 B! w* C3 f6 M
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。! i) g& b; }1 b: n1 D/ P: Q
使用举例:
; w, l$ ]; N' w" c' B# ?* ~# z  [2 V7 G/ w
  1. /*: a/ C7 g5 _; N
  2. *********************************************************************************************************& m* ?  r2 B- \4 v
  3. *    函 数 名: QSPI_AutoPollingMemReady
    $ _3 o6 p, U) Q: `' O$ z$ J) a
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用
    * e; |  X# ?2 [
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄1 `$ ~+ x0 h! p" a- O7 E8 Q/ f, F% P
  6. *    返 回 值: 无
    ( Y2 O0 x4 h5 S- O6 J
  7. *********************************************************************************************************( S. ~6 K, @7 U4 H8 ^5 i9 o7 I
  8. */; D+ ]) g& G% b1 s+ ?! e% i
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)7 C- J9 B& A' ]: W# z
  10. {
    $ k. s" V( k6 G3 |1 r& L
  11.     QSPI_CommandTypeDef     sCommand = {0};
    , R% c- l( x) Z( A7 \
  12.     QSPI_AutoPollingTypeDef sConfig = {0};
    $ b" t  B. \( L
  13. ) f5 o6 Z1 e( {

  14. 8 o. }( W' _2 L7 J9 z
  15.     /* 基本配置 */
    & C) q9 l" ]1 m/ N4 v
  16.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */" X4 t4 _0 x$ ?; g- j5 G) F
  17.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */2 D) H. F1 D4 x% D6 f! x
  18.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
      l" z! }: b) w' t. w
  19.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    8 a2 \! W+ Y  Q
  20.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */! \, _! l# z/ q# V  y
  21.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */+ w) f6 ^8 B; x, b3 J% n

  22. 6 o# W4 C. d' S8 G* X. t
  23.     /* 读取状态*/
    ' j: Z* \; Z/ v# Q# r+ v1 x: z
  24.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */
    1 j/ T8 t% q/ @% Y
  25.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */5 S* G/ x; V  K+ N( ^
  26.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */6 x- i  l3 F& ~' O' A
  27.     sCommand.DummyCycles       = 0;                   /* 无需空周期 */
    ; n  p) `" j. J0 M6 U/ ?

  28. ' ^: d+ e4 _, `) B; T
  29.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
    . T# C" o$ c' H+ ]2 W1 @
  30.     sConfig.Mask            = 0x01;1 B8 d0 M& `" D- U
  31.     sConfig.Match           = 0x00;
    8 Q* J, W% E3 f
  32.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;" U2 u: j- Y% E4 I5 p# s, `
  33.     sConfig.StatusBytesSize = 1;
    # a" e) ^$ u# e. O
  34.     sConfig.Interval        = 0x10;2 ?6 k/ t: s2 e6 \1 N
  35.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;  p+ d. x1 K) \' J
  36. 7 D/ x& h4 ]# t  S7 U  m; p) e
  37.     if (HAL_QSPI_AutoPolling_IT(&QSPIHandle, &sCommand, &sConfig) != HAL_OK)
    5 W1 i0 {2 s- }. g3 B+ G; N
  38.     {
    ' c+ A- J( L+ p
  39.         Error_Handler(__FILE__, __LINE__);; h9 ?4 c6 @1 |9 @5 L: a  z; W( H
  40.     }
    7 t9 g/ \3 d4 y- r0 ^$ F9 h, V+ @
  41. }
复制代码

3 ~9 X/ z7 _2 ~9 p78.4.7 函数HAL_QSPI_Transmit
8 z3 l/ G: ]1 _3 {6 n6 ^. z* ?函数原型:8 V  M! B7 d2 Y# c0 m. i

9 g+ H# S% W$ J* [" x* z# Y* n- `# y
  1. HAL_StatusTypeDef HAL_QSPI_Transmit(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)
      g& P+ |- g% ^$ a
  2. {
    6 m; d7 d. ~4 E+ d, z+ p
  3.   HAL_StatusTypeDef status = HAL_OK;, P2 s1 W2 \/ ~% Q3 [1 _- c
  4.   uint32_t tickstart = HAL_GetTick();; s8 D* r+ A8 Y! l8 T8 |  R9 f; v
  5.   __IO uint32_t *data_reg = &hqspi->Instance->DR;4 |: f8 m6 q) u: g
  6. 4 n1 u; p5 Z+ W2 D
  7.   /* 上锁 */$ ?1 j; F( e$ O! x
  8.   __HAL_LOCK(hqspi);
    3 g- T) l* }3 U% N

  9. 3 _0 M2 X+ p! n- }
  10.   if(hqspi->State == HAL_QSPI_STATE_READY)
    ; @  i2 M& W7 r- c7 c7 R
  11.   {
    , O9 @2 K6 F/ i7 I- p
  12.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;, l. f! P: U& L: ^% C0 b

  13. ( C5 |8 c& ^" j1 r) x5 |) a# p2 U
  14.     if(pData != NULL )
    3 k( I: T+ R2 d; g. M' ?
  15.     {
    + w/ p9 T6 H# f2 t  |
  16.       /* 更新状态 */
    " G+ `) U7 Q. {, X; t9 `
  17.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;
    , I# ~: K. {+ T' j! e* w

  18. 1 M/ Y& S/ _5 @) K# k- `8 a
  19.       /* 配置发送 */: t, ~$ d5 W, a1 b0 |
  20.       hqspi->TxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;
    ; Z2 P# W' V( h# d4 o# U* R, V! y
  21.       hqspi->TxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;5 }% m1 ]. D' e% _  d. E
  22.       hqspi->pTxBuffPtr = pData;
    9 H/ t0 }) Y7 N- b  Y

  23. 9 g& V: p7 ]4 o3 b' `/ }
  24.       /* 配置QSPI,间接模式 */
    + u  b: J8 L+ n# j
  25.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    4 j  z1 [. ^9 `4 C7 L, k3 K( D
  26. ' c5 p8 F; @5 `) n
  27.       while(hqspi->TxXferCount > 0U)5 y# p7 ?. ], v% U: ~$ H; L# ?
  28.       {: d7 I" n# q( N# N) l- i; B0 H
  29.         /* 等待FT标志 */
    - P1 A, c7 b  b+ E6 S2 @
  30.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_FT, SET, tickstart, Timeout);& ~* A6 Q  E9 |6 S: o) K
  31. 2 Q# ~- A* K2 U* R( u$ v
  32.         if (status != HAL_OK)4 ~1 e, v$ D( g- i
  33.         {
    % F! ?6 G, d5 H# i
  34.           break;$ O7 C/ Z& R5 Q1 T
  35.         }9 u) x1 O; K6 I0 i" I; ^; h

  36.   N0 I. r! v0 V# y4 O. m
  37.         *((__IO uint8_t *)data_reg) = *hqspi->pTxBuffPtr;
    % d2 F# D( t0 ^. d
  38.         hqspi->pTxBuffPtr++;) M2 o3 G& Q8 d) ~" B
  39.         hqspi->TxXferCount--;1 W5 b" |  m( Z% q$ a* H3 b
  40.       }
    3 c) f+ e' \* z: H( Z
  41. ) r8 u8 z9 F3 Y, U2 h
  42.       if (status == HAL_OK)0 E3 h/ Q$ J) o+ _* ]7 x
  43.       {* ^$ L, I5 ?4 k8 W  Y* l3 q
  44.         /* 等待TC标志 */
    6 b2 k9 l7 F$ p* j8 R9 s
  45.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);! w3 Q; m( t0 J# v

  46. & f3 J" Y( f, o' \
  47.         if (status == HAL_OK)
    : \$ b; d8 }  g4 v4 v5 O* z
  48.         {
    $ m5 N% e- P& D+ z
  49.           /* 清楚传输完成 */
    * z: N/ C2 y- q" D: K2 N1 @
  50.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);
    3 k2 P6 t6 ^6 z  R! t' C

  51. ! ^; Z# P; i6 Q( f
  52.         }' P/ x+ y' e2 H
  53.       }% p0 V5 ]7 o. M" J' F* T

  54. + d; J) K. N4 z+ q/ v
  55.       /* 更新 */. \2 K- d9 L( M4 X
  56.       hqspi->State = HAL_QSPI_STATE_READY;2 \1 ]( w' a3 i# a
  57.     }
    7 F  I' h! {3 \5 b& j  d
  58.     else. t3 v: n& K* Z, S3 D
  59.     {
    + H% a$ V) ]5 H  p- F, h" r+ v
  60.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
    * w1 x4 z2 A# H9 u) K( Q! W/ R
  61.       status = HAL_ERROR;
    * H- H! j# T- K
  62.     }
    4 s# `8 F- q5 [: D0 m' o; ?; M
  63.   }
    ; L, C* ]; j2 Y7 ?
  64.   else
    4 L8 Y6 f/ ?5 f! q
  65.   {" R+ I1 [* d- v: m5 R+ f
  66.     status = HAL_BUSY;3 K$ T2 h* d7 x% ~
  67.   }" x6 t- y& i8 h) T4 o: `3 ?, N
  68. 2 n) f; x- J  o9 s: L4 h
  69.   /* 解锁 */6 q' `, \% j9 ]; W9 |8 i4 L2 n
  70.   __HAL_UNLOCK(hqspi);- J8 ~% O1 g: }: j+ j  q

  71. 0 _7 c9 t0 e7 c9 M5 J9 K" m
  72.   return status;
    ! Z9 A# T8 M5 I' J
  73. }
复制代码
' c9 s5 w" m2 G( H
函数描述:
1 u6 ~3 ]/ w' o9 K% a: d: H
9 F" o4 _6 z+ u1 h: x% N此函数用于QSPI接口数据发送,函数采用查询方式。
9 E3 r7 T& `& w+ ?2 ?  b5 e* a0 Q
- X; u/ H& e& ^5 A函数参数:8 F9 [* D( B1 r0 }
* w: n8 C$ r# t+ I: X6 b
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
( Z  k; Y# X" Y  第2个参数是要发送的数据地址。8 ~6 N! Y8 @( `9 y  v% ]
  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。
$ u: N7 i2 t: t1 M- B, w* D- w  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
' G+ U; ~  u* x0 q使用举例:
6 Y# E+ Y: o. C& j3 f5 H  ?) K9 E2 _7 F: N$ o; g. D
  1. /*
    - i: B7 h: H$ v2 }8 g
  2. *********************************************************************************************************
    * ?* P8 _! I% h0 h
  3. *    函 数 名: QSPI_WriteBuffer& Q" \3 n6 \& J. F- ^
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入3 p4 x0 Y- [* U8 z: }. ]
  5. *    形    参: _pBuf : 数据源缓冲区;
    & P; A4 i' ?8 y9 h" K2 S* H: l
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。
    & j  W. }4 |3 f3 R; {
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。8 _' M3 w# A2 p- K
  8. *    返 回 值: 1:成功, 0:失败
    3 A9 v6 K- T7 Q! J
  9. *********************************************************************************************************
    $ O  {% Y' J, ~& f2 M! L- A
  10. */5 Y; |2 b! E* @9 `
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
    6 ?; }9 C! ~: n% K! u
  12. {" @! i& s9 l9 W$ Y& M  Z
  13.     QSPI_CommandTypeDef sCommand={0};  F0 m2 |: M9 |1 Z

  14. ! \# O7 ~( N8 v' A% W
  15.     /* 写使能 */1 p4 r9 s5 i. Q- x. |5 N* N
  16.     QSPI_WriteEnable(&QSPIHandle);    ( A4 X6 W% H$ F. G3 E

  17. ' N2 I# ^) i+ V/ Y$ @
  18.     /* 基本配置 */
    , j& O: T1 g0 w
  19.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    : v- ]/ v6 Z5 L* c& X
  20.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    % }  T7 |/ S2 Z9 _( `2 H, n+ k1 ^% C: H
  21.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    ) n  c# X. a6 B  D5 }1 e4 Y: o
  22.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */+ N' K7 m. ~0 s3 M
  23.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */4 I2 [+ M  _2 i5 r( ?% }8 [! A
  24.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */    ( _8 D3 b1 G' `" U+ J; t
  25. : V! K4 s  J5 ~, E2 B; a4 M
  26.     /* 写序列配置 */
    % M: I0 Z: V8 ]3 n  J0 ~
  27.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */
    2 Z0 U( t# P; m! `; G
  28.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */
    . ~, d* H1 ^0 L6 O$ e' }; t* X* m& H
  29.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */
    . k4 D, b& V! K, g3 ]* g. n
  30.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
    * y- j" W8 @/ c
  31.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   
    5 a* b! f5 b1 i  x* @9 N( W, y) }
  32.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 */8 w6 y6 R$ S' h* U7 n& b
  33. / n. @) k3 Y4 A0 M
  34.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
    8 X0 M! Y6 w/ K; j4 U( G
  35.     {: S/ p# I& ^8 H
  36.         //return 0;5 |6 n  o5 y9 w* s# g
  37.         Error_Handler(__FILE__, __LINE__);
    + E' C( T6 N$ \5 n- Y
  38.     }4 O( v: Z/ f6 t1 O
  39. # {* u1 s4 z: e9 n6 ?: n4 C
  40.     /* 启动传输 */
    ; p7 ^$ R+ _2 `9 U
  41.     if (HAL_QSPI_Transmit(&QSPIHandle, _pBuf, 10000) != HAL_OK)8 z5 ~( e- [  }* f' i
  42.     {
    * J% L8 C8 N0 a& a% @  |! f. _$ Q
  43.         //return 0;
    * w5 C% w" O2 |) q9 L1 Z
  44.         Error_Handler(__FILE__, __LINE__);
    % Q4 K2 Y$ Y2 b$ A7 @& a
  45. - I4 V! C6 x. @* N- h$ c
  46.     }+ g3 W# j6 [8 n. D
  47. 5 F' H2 K/ e/ }0 A+ M, Z
  48.     QSPI_AutoPollingMemReady(&QSPIHandle);    ' q& @3 d1 n! ^6 M  I& P

  49. ) U' e- [+ g' y
  50.     return 1;
    * y) |6 ]7 v  k' z/ N, k& d$ `
  51. }
复制代码
6 k- r8 ^9 R: N0 R5 o7 I
78.4.8 函数HAL_QSPI_Receive% [, Z8 `. [  j+ g2 ^; ?/ s
函数原型:
6 S% h2 d6 E) q( R: W
, ]' h7 M4 s7 Y& Q0 L
  1. HAL_StatusTypeDef HAL_QSPI_Receive(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)  o% U5 x% R# ]& A8 _
  2. {8 ^; Z) K5 J6 o/ {, O5 h
  3.   HAL_StatusTypeDef status = HAL_OK;. ]. q9 s5 D  \( ^6 w' b5 u
  4.   uint32_t tickstart = HAL_GetTick();" w" d; g; d, e8 A0 h$ U0 q# w
  5.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);8 W3 t  K( d2 q( _
  6.   __IO uint32_t *data_reg = &hqspi->Instance->DR;
    ! }6 j7 m$ S* U) ^5 z0 \

  7. 1 q$ }3 S6 m  k! b0 M, n, I/ s) H
  8.   /* 上锁 */4 F1 x7 H; z8 n5 C
  9.   __HAL_LOCK(hqspi);# G3 Z" z6 t7 u8 m, S
  10. 6 v) I  j4 @, ]1 ~6 J. o
  11.   if(hqspi->State == HAL_QSPI_STATE_READY); K* ~3 V( g) g, w" N& b. R1 n
  12.   {2 N6 p" {7 a5 b1 r5 \  V. f
  13.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    : n8 m- R; s) W3 v/ @6 L

  14. * A5 Q. h6 r) n1 e
  15.     if(pData != NULL )
    , N% i2 C2 T( K7 i2 V
  16.     {( g& O- U8 R, \. b( b+ s0 e" u% G
  17.       /* 更新状态 */' h! x0 u" F- {0 K% _0 {
  18.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;6 X& G3 v! p( v+ N$ E
  19. 9 |5 z$ M4 K2 t8 F* I# H( K) ?
  20.       /* 配置接收 */
    8 W( K+ d) z) f% f# m* X! {
  21.       hqspi->RxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;
    + U- X2 V  _6 l& p& i7 L
  22.       hqspi->RxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;  a& X' h6 M) R; X( }
  23.       hqspi->pRxBuffPtr = pData;; [1 q8 s0 d5 v, e& i
  24. % s$ Q0 I, b/ F5 Q+ c
  25.       /* 配置QSPI,间接模式 */
    7 J$ B" F3 h+ d, R% f( S! e# F1 v
  26.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);
    ' C% D, A5 D: b8 k/ \

  27. 9 L5 K' i4 k$ C0 ^9 S
  28.       /* 启动传输 */+ U. L" [- D/ F0 ]# S
  29.       WRITE_REG(hqspi->Instance->AR, addr_reg);: t! w! H7 n* E( T* p1 p# S9 Y

  30. 3 ]' f" g* j: N# c$ t! ^3 L( T
  31.       while(hqspi->RxXferCount > 0U); J9 K6 `! H1 [- V) `1 ~
  32.       {1 `4 ?. F/ J7 P
  33.         /* 等FT和TC标志 */
    4 ^5 l; S! p1 x
  34.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, (QSPI_FLAG_FT | QSPI_FLAG_TC), SET, tickstart, Timeout);$ O( s+ s0 q% Q! z

  35. ; O. |9 X8 K" ~1 ~" G: f5 @7 d* E! _
  36.         if  (status != HAL_OK)
    6 O7 Y0 V- L7 W
  37.         {
    $ W1 m5 d4 O: p" ]3 b6 T& R
  38.           break;' ~  k3 `) u2 z0 h0 M% {
  39.         }
    $ v. X( U1 l0 _: {1 D) Z

  40. # w2 K4 I6 Q$ V2 ^0 m
  41.         *hqspi->pRxBuffPtr = *((__IO uint8_t *)data_reg);8 c  u& F8 _" V# Y7 {% _, y
  42.         hqspi->pRxBuffPtr++;
    $ Q2 }+ d8 H1 P/ E( C( v
  43.         hqspi->RxXferCount--;
    3 ]! o; }. d0 u/ e
  44.       }
    3 t9 ^" h! p# l

  45. , h& X+ v8 i: V- h9 \5 m
  46.       if (status == HAL_OK)) O, o; W* Z! k
  47.       {
    # F6 O$ Q& C1 S* i  R
  48.         /* 等待TC标志 */
    8 z" S9 A: ]: t2 W
  49.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);
    , l5 M* L  J' \2 z

  50. 4 G! G5 D' }# X! u
  51.         if  (status == HAL_OK)  ?. R2 M" _8 [+ e
  52.         {
    0 X- u: s4 c% ?5 ^! r
  53.           /* 清楚传输完成bit */
    0 |% r" D9 F% R5 g% J$ A
  54.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);
    3 _; j. D0 a  J4 ^
  55.   Z  I' W1 r# u; K' ?8 J6 r# P
  56.         }4 l8 a) m, t9 `9 \6 B! r# N
  57.       }3 ~  c2 j8 p* e+ g% V2 c

  58. 7 `# [4 j. P0 l, M0 x
  59.       /* 更新QSPI状态 */8 S# z% P0 Q6 v0 u, t) ?% U5 \
  60.       hqspi->State = HAL_QSPI_STATE_READY;
    $ }+ o/ o& z+ F7 J: Z
  61.     }
    5 c3 ^; _* b4 A  I( w- K* e
  62.     else" e. a4 r4 }% D% d" r& {, e2 u
  63.     {6 O/ l" \3 K. W3 {0 f$ t
  64.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;0 `7 L: \1 l; V7 \! x' g/ s, @5 d
  65.       status = HAL_ERROR;
    4 R5 f: E8 `  c8 F# v& d( g
  66.     }
    5 \( [! r' f$ e" {6 N
  67.   }# ]+ F. a6 m( f; |* G
  68.   else- b( w& k& Y, U: y
  69.   {
    4 p4 r7 j8 r4 H8 d3 C, N! B
  70.     status = HAL_BUSY;
    . w  `: U4 O$ |
  71.   }
    : P) S% K, q# a( }
  72. % p3 C( k: |% C, {0 g9 ~$ X
  73.   /* 解锁 */+ Q) c. {5 f! _' D1 h+ i1 }
  74.   __HAL_UNLOCK(hqspi);
    / P  T3 `! Z+ z( F

  75. & Q9 W  j1 k7 j3 {" n5 P7 P
  76.   return status;2 @9 }1 Y  L! j, r) a# Z; S& G) a
  77. }
复制代码
+ O  W( k: q0 e5 K
函数描述:
4 d+ F) l- w0 n. u1 `# N& s0 j+ U0 _6 [
此函数用于QSPI接口数据接收,函数采用查询方式。/ p6 }% @7 l9 P
! x/ C+ Z0 W. n2 b1 @
函数参数:
& h# J* v1 Z/ F( D$ d
- G1 ~. l3 l) Y; A4 i- h) V  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。9 {8 }. K# `" e7 ^+ n
  第2个参数是要接收的数据地址。' X6 ^5 o4 O! T' C% b. t' f" `
  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。
. n; V& t0 x, C6 l; r/ e- ?- c9 N  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。* F1 w( N. T: ^6 C5 _$ w
使用举例:, U, A7 z1 u) |4 t+ k0 o

( z2 m( M, s% V$ r
  1. /*
    0 u2 b0 p, q) o- d9 \) X) W9 n6 t
  2. *********************************************************************************************************
    8 K& E/ p9 m/ R, @  u
  3. *    函 数 名: QSPI_ReadBuffer
      o2 E+ h/ J- Y; o' V4 j+ {
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。' u" s: P, O0 ^: A/ T& `; H
  5. *    形    参: _pBuf : 数据源缓冲区。
    $ J6 Y7 r- ]) z+ G
  6. *              _uiReadAddr :起始地址。( d  Z, r) |, h& `5 C. P4 m4 ?
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
    % u% d8 D& i$ c% S
  8. *    返 回 值: 无
    ( L# f; ~+ _  C, x% g# B9 ?
  9. *********************************************************************************************************
    6 `# n( z7 S$ P4 R# |  x$ C7 u+ f
  10. */
    $ F+ v& o: C) i/ K: ?
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
    2 T* O' P: h+ t
  12. {0 c! P  d2 I- O) U  N" ?

  13. # W# Z! j- H) y0 J( a7 s: X5 t
  14.     QSPI_CommandTypeDef sCommand = {0};6 `6 ?/ ~0 t/ ?  O; G
  15. + r3 d6 E8 I2 b0 a9 s9 u" r% }

  16. 8 _4 y% b5 d# O0 g7 ]& Y: W
  17.     /* 基本配置 */
    ' W. Y/ _- d9 u
  18.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */- _# V1 c: m; n3 x
  19.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */6 q4 M* U, I8 F0 s9 G' N
  20.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 */
    * W, ~: Q, O4 o) |
  21.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */
    & d. M  h" D- N( {  ]
  22.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */
    2 W' B* s, G0 ]8 o2 y" i
  23.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */   
    ! D7 G% _) O' X

  24. 4 R/ N/ q9 r6 [7 K
  25.     /* 读取数据 */2 s2 o# w3 I) D7 D  R0 v+ f
  26.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */+ @% |3 q0 c; [0 I# ]' c& w
  27.     sCommand.DummyCycles = 6;                    /* 空周期 */  e5 h' O! v, G1 Y) H; }9 ~2 n/ c
  28.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */9 ^  Y, l" e: A" F% s4 k+ L
  29.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */ " K6 o$ y' Z  k
  30.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */
    , J5 v  T/ G8 y7 z7 T
  31.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */ 3 Y  \3 H. n( J; x: {

  32. ' y7 j% b- f4 B1 ^* T' U
  33.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK): I" @- L0 U6 e3 R/ T
  34.     {
    ( M$ {: L1 e+ V( j, _+ s- e
  35.         Error_Handler(__FILE__, __LINE__);$ A: I/ f& ~& R+ _$ Z+ K2 [
  36.     }3 B; E7 [3 R+ }" A2 v4 H, ~
  37. 9 _- M" v9 I  |' ?7 O
  38.     /* 读取 */
    ) Z) y) R/ L, I3 ], Q. _/ e
  39.     if (HAL_QSPI_Receive(&QSPIHandle, _pBuf, 10000) != HAL_OK)
    3 L1 o9 b! Y, \& O, {
  40.     {
    - [0 W+ r* U; V' m  y
  41.         Error_Handler(__FILE__, __LINE__);
    ) T! b/ h- r) ^% {
  42.     }   
    1 h% j0 w5 L4 X" ?! p6 p7 [
  43. }
复制代码
- i, _/ T* B$ _; b
78.4.9 函数HAL_QSPI_Transmit_DMA
' Q& d, S" P4 _% @; c函数原型:( }/ ]7 P/ [+ {6 H; A( ^4 m
/ |: k' S% m: i* L- B" P
  1. HAL_StatusTypeDef HAL_QSPI_Transmit_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData)
    ( Y$ U: W! m9 K5 s
  2. {+ U  m, L- @8 i
  3.   HAL_StatusTypeDef status = HAL_OK;  B( A" N, `$ n- ]# j: }3 u5 P
  4.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);
    ; @1 L9 m( c6 c) a
  5. ! |9 v/ _, T# i3 n
  6.   /* 上锁 */- n. L, f$ m3 l. [5 q0 ?
  7.   __HAL_LOCK(hqspi);1 ?1 ]$ m8 N% ?. b5 t- @

  8. 9 Q, f6 K3 Q  E5 E# \* |$ g
  9.   if(hqspi->State == HAL_QSPI_STATE_READY)
    " o% U8 R1 F# l
  10.   {
    ( y3 ^; [% i. T5 j0 M
  11.     /* 无错误 */
    # s" N4 C" V* f0 \3 r, D
  12.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    & g9 [  U- m+ L" \0 t& l! @% }2 w* f
  13. ; |' @* N3 S  n3 @- w6 `
  14.     if(pData != NULL )5 U( _$ w7 @3 d0 _4 H! E$ l
  15.     {! {/ L. C: `: N5 \
  16.       /* 配置发送字节数 */& P  x7 H+ [! p& D
  17.       hqspi->TxXferCount = data_size;
    5 |, I' H/ X! D" j* X

  18. " A; O7 A2 R2 s" z  R
  19.         /* 设置QSPI状态 */
    7 N3 |9 i- a$ U+ Q
  20.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;
    6 i' l' D; I7 i' M
  21. 9 i7 L  A( j. f; F
  22.         /* 清除中断标志 */8 U5 Y, F# R) |0 l( U  p3 B
  23.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));% O% W9 M4 p# M( ~

  24. ; q2 b( z/ J# A6 ]4 f' l9 M& |
  25.         /* 配置发送 */& w' \! _0 Q- ^3 U1 x( L
  26.         hqspi->TxXferSize = hqspi->TxXferCount;
    9 [$ ^  @6 E9 X1 [1 N2 s/ F; @0 A
  27.         hqspi->pTxBuffPtr = pData;& e1 j# m, n$ Q; X

  28. 5 j# F! V! Y1 ~! w
  29.         /* 配置间接写模式 */% w) P6 @! s- Y' g* y5 f
  30.         MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    # E! v* s1 m5 I& L

  31. 4 X$ t* q! Q3 Z6 A
  32.         /* 设置MDMA发送完回调 */9 X. |% `, |& R5 z- h, |3 Q
  33.         hqspi->hmdma->XferCpltCallback = QSPI_DMATxCplt;( e+ e- D  U. g0 e$ w7 u

  34. ' U) O; ?0 U" E) x* u. q4 B
  35.         /* 设置MDMA错误回调 */% _7 ^+ X4 N  q! l5 o
  36.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;5 |* n# q& ?" k3 a
  37. % L& T, L5 _2 f% ?) v4 e
  38.         /* 设置MDMA终止传输回调为NULL */% B3 w/ `! o& c8 ]5 @
  39.         hqspi->hmdma->XferAbortCallback = NULL;) L7 H+ ~& O( Z/ J7 o* ~- N
  40. : p7 o9 s7 e! o- `4 x
  41.         /* MDMA的目的地址是QSPI DR寄存器,设置禁止递增 */
    3 Q( K: R/ }( k; g
  42.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) ,MDMA_DEST_INC_DISABLE);) v% z6 d. C5 I- p

  43.   K' ~" q7 X) k! b" n4 |
  44.         /* 更新MDMA源地址配置 */; c! F$ c" u( F$ ^
  45.         if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_BYTE)
    7 S% z' w* z1 `7 P8 v1 w4 Z* }5 Q
  46.         {- e) Q" E- @5 G4 Q; F, j
  47.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_BYTE);0 W% [+ f  Q8 R9 }5 j% N+ b$ }; N
  48.         }
    + V$ j5 j- p" s& v- l, @
  49.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_HALFWORD)
    1 w1 k5 c$ o8 V  G
  50.         {4 X3 ^( b/ B% Y+ ~6 ~
  51.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) ,
    & R+ i9 i  G) r6 s- P) G% C
  52. MDMA_SRC_INC_HALFWORD);4 @! J* Q, C8 L9 F9 h
  53.         }
    ' D: ]/ t1 s, `- E! `/ B
  54.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_WORD)
    ! q- p/ u$ W+ j4 ?/ m$ n$ M- Z
  55.         {6 I6 O- @4 q. l+ C9 {4 N5 L& z
  56.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_WORD);
    4 A: z3 j- @: k. q" _7 r  W# c. _/ w
  57.         }
    9 h: ^# g. T1 l/ `
  58.         else" M) E, m5 P2 K
  59.         {
    % ~+ Z3 p. w" m) ?" f- W
  60.           /* 配置错误 */5 k& Q' a, u6 E: D
  61.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
    6 e5 d- E$ j* C1 b
  62.           status = HAL_ERROR;
    - t2 U4 E7 J7 R/ V
  63.         }3 W1 r( ~5 y6 N2 o6 q7 S
  64. ) G' }3 t& @0 n
  65.         /* 使能QSPI MDMA发送 */1 [! f0 V( Z( D( m
  66.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)pData, (uint32_t)&hqspi->Instance->DR,; J& N( r/ ]0 h# W3 l
  67. hqspi->TxXferSize, 1) == HAL_OK)
    8 o- l; [0 Z5 t! c7 y: i  d% Q
  68.         {/ \& d6 W+ t6 y/ M8 x" |
  69.           /* 解锁 */
    % I& |( k) h4 k8 Z& [) w$ g, S
  70.           __HAL_UNLOCK(hqspi);
    3 z! q& ?/ ]! G" l% o
  71. 8 f& j; d* Y$ Q# I
  72.           /* 使能QSPI传输错误中断 */
    : z8 j: S( s0 m9 J0 a
  73.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);# |7 ?6 M# w1 P. u! B/ J$ t  Y
  74. ( a/ U4 t6 W/ H. ^
  75.           /* 使能MDMA传输 */# ^: L. i/ Q, M
  76.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);1 J5 W* A' N  R( ]* g' s& t& j
  77.         }; G$ e* P4 I/ ]! L/ i
  78.         else
    : O8 y4 R3 Z4 {8 j9 }9 S
  79.         {
    ! I5 n3 z7 [7 k" O; a3 d: }/ L
  80.           status = HAL_ERROR;
    7 A5 S) A: O6 J- p1 q3 K; o# |8 _
  81.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;& C* D* Q' n; O; L
  82.           hqspi->State = HAL_QSPI_STATE_READY;% H7 q4 B/ w$ R' L# P

  83. & T2 r7 v) p, D5 l- o
  84.           /* 解锁 */
    # C; {/ u5 M- `
  85.           __HAL_UNLOCK(hqspi);+ f1 M3 X- F( r( c( F' ^3 q' I
  86.         }
    : ^# D, V2 F3 @
  87.     }
    ' m7 H$ {$ l/ s
  88.     else
    & E, U1 f) M/ n) O7 W: _+ I
  89.     {4 N; s9 R1 b. D) H; B: V$ I) ?
  90.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
      P9 \0 {* y- I* X) C  ~
  91.       status = HAL_ERROR;
      @  ]# _* O- w: o, L3 M
  92. / J+ Y) o+ j' b8 V0 \
  93.       /* 解锁 */
    - |' v6 @% Y3 }2 b3 Y, S- q
  94.       __HAL_UNLOCK(hqspi);
    ' ?/ R9 D/ i- @8 ?/ {4 D
  95.     }9 |6 k; c! @9 n6 T5 W" S) M
  96.   }9 l5 c' q, Q! Z1 G. O0 }
  97.   else
    # C* N6 S+ I9 D; k: S
  98.   {
    $ j% p8 X: U* o
  99.     status = HAL_BUSY;
      P& h' e7 M" o6 C# `4 a/ C. i

  100. $ b4 y( h* Z* A8 K6 Q
  101.     /* 解锁 */
      k$ t4 I: {0 @) O7 F
  102.     __HAL_UNLOCK(hqspi);
    + z* t) E, l. P$ ?7 l# r0 S8 g9 Y8 m
  103.   }
    ( {. T% [: ~- \& Q8 ]: G0 b; Y
  104. 3 ?6 j$ y0 L3 J! _2 M) R  z6 j( `
  105.   return status;
    4 t* F0 ]9 M" K- d0 {( `5 C
  106. }
复制代码
( c5 C3 Q1 I7 Q- t: ]% _% s- m9 @
函数描述:  [8 Y0 T; F6 Z1 G; J
( E1 P. T" N: Y) K+ d/ \" [; H
此函数用于QSPI接口数据发送,函数采用DMA方式。1 S' v; t! Y' c1 L+ K

5 i; _6 x! u& p函数参数:0 i6 g! L: ~7 E& L5 _
% l9 A4 A( x: u2 X
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。. B& I8 V$ A6 |/ n% s2 v
  第2个参数是要接收的数据地址。  x) O3 [( ?8 t0 K$ j% U
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
1 j6 z8 C, C* [+ i; b, y使用举例:
# K5 q# z- ?) ?- I4 ]/ f! m/ t: P0 w6 \& R- m& ^
  1. /*3 A9 B8 ?  B  I. Z. P( Z+ Y" A; H
  2. *********************************************************************************************************4 k7 w* E; B5 R3 H5 i6 N# c& Z
  3. *    函 数 名: QSPI_WriteBuffer
    " s0 Q( L) g6 a6 E1 p1 P9 [& N
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入, r6 c+ k6 w. W' O) t) S6 a3 R' O
  5. *    形    参: _pBuf : 数据源缓冲区;& s" U: s, G4 O0 n2 |3 n) l
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。% u. J3 c4 x7 s; A
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。1 |2 F( c! Y3 c6 {
  8. *    返 回 值: 1:成功, 0:失败
    3 A9 W4 `8 o% d+ @( }3 p- @3 `
  9. *********************************************************************************************************
    3 _' _" g6 `# ~% g0 J. a1 f9 a3 }( h4 i
  10. */
    3 L$ z; S% Z2 x9 @0 n3 P; R
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)  U" A- |, E7 u
  12. {# ]4 i- B" U" A* U( @) ^1 R8 [4 F
  13.     QSPI_CommandTypeDef sCommand={0};
    8 ]! y2 u6 y& l, l6 k' ~
  14. 1 i( `6 a: U0 r) g$ ^, j
  15.     /* 写使能 */
    - l+ O( i$ A6 |
  16.     QSPI_WriteEnable(&QSPIHandle);    0 K3 D( }$ c) q4 j% Y! c
  17. 0 k* a* x( o& v8 m  ?) Z+ P
  18.     /* 基本配置 */
    0 Z9 Q( r# Q- x! i* e2 ?3 V
  19.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    ) o0 z  Q+ {9 n. }. }1 z- L% ~
  20.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */; Z( U) I! |5 G2 v, D
  21.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    ' i3 E/ |( |& J- r6 k6 B/ T
  22.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */2 I6 |9 Y8 U% O2 s
  23.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */( Y$ t$ x9 t6 B+ D! o9 ]
  24.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */   
    - n! g5 ^1 I, O9 c0 h; H
  25. " j5 N+ ^  u9 Y3 ~
  26.     /* 写序列配置 */6 \2 V7 O! i4 Z
  27.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */* O6 w: d' P$ E
  28.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */
    . E* g% }8 x: E
  29.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */
    / I" x8 i1 v- k8 a
  30.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
    ! T; y6 j" c) r
  31.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   
    ) ^' d& c# }8 Y
  32.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 */- U) Q  J7 i0 j# @  u9 M/ [( ]
  33. - B( T. G9 H2 z! ^
  34.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
    1 D" g3 @9 }& r) S1 S" e
  35.     {: L) y$ F, C8 f
  36.         //return 0;  b0 S: c4 t- C2 @2 P
  37.         Error_Handler(__FILE__, __LINE__);
    7 f% Q' Y- W7 S& F: Q5 N9 G
  38.     }
    . }; o: Z9 Z1 A. ?# A4 @

  39.   e" e1 W  m) G& _
  40.     /* 启动传输 */
    % j* z6 n, Z1 @
  41.     if (HAL_QSPI_Transmit_DMA(&QSPIHandle, _pBuf) != HAL_OK). M* `7 ~3 [1 o8 s9 R5 n% I8 X
  42.     {% _7 M5 S. d: e4 f8 l
  43.         //return 0;
    ) w) I  v  Z2 v8 A) ~, ?# y- N
  44.         Error_Handler(__FILE__, __LINE__);6 r, ^, B$ w4 l9 d* H
  45.     }
    " `& E- n' b% M0 i

  46. 6 i; H9 q" e$ C# t- T" G8 ]0 a# s$ j
  47.     QSPI_AutoPollingMemReady(&QSPIHandle);   
    7 }& ~  c7 j0 r
  48. 5 z& L3 F; b) T: m
  49.     return 1;9 D+ P- u4 R7 E& ~# h6 h" F6 z: }# O1 w
  50. }
复制代码

8 j- ?0 k3 j, \78.4.10   函数HAL_QSPI_Receive_DMA
6 F; n8 D' e( [) r  o函数原型:' S1 K: Y3 y0 U% q, x( T

2 T+ b6 j0 A; e9 C" A
  1. HAL_StatusTypeDef HAL_QSPI_Receive_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData)1 G+ R( {+ [0 Q
  2. {# ~4 _' N& J3 x' R
  3.   HAL_StatusTypeDef status = HAL_OK;
    ; X* F( u. k/ C+ ]2 q' b
  4.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);7 j# p4 }, ^  S8 o
  5.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);- i" O5 V1 G1 O. ^; z3 X
  6. & H% f6 \8 y( {% a5 E
  7.   /* 上锁 */3 o. D5 A" x# ]8 }
  8.   __HAL_LOCK(hqspi);/ L( O: P* m# t' v

  9. ( S. B. O! I+ a6 e8 L% B) i6 W
  10.   if(hqspi->State == HAL_QSPI_STATE_READY): W( b" V' S$ Z# y. B. O2 I8 y# A
  11.   {
    0 Q* [# T3 n4 O. o( {7 J2 ~
  12.     /* 无错误 */
    ( }7 |$ l% A+ L
  13.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;0 o+ w) B( F* q8 t' z$ ]

  14. , e5 c# Q6 g; \2 i2 H3 h: b
  15.     if(pData != NULL )
    ( r- X3 v- a* H  I2 J! Q% C
  16.     {
    2 y& T" c9 X- }
  17.       /* 配置接收 */9 Y5 i- A4 i. w4 ?0 b5 N
  18.       hqspi->RxXferCount = data_size;3 z$ I3 q, o8 C5 p6 s7 y
  19.         /* 更新状态 */
    : l+ y4 o6 D9 s  F: i$ I& ~2 ~0 E
  20.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;0 F8 r, a1 G5 `* ?& I

  21. , q& E6 d3 k& w- S$ \3 v
  22.         /* 清除中断标志 */
    . L2 |9 X! W7 H% ^& y7 H9 d
  23.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));
    * D$ ]2 n: C6 n% @6 ~

  24. 3 p9 w9 O' d7 Z4 F# Q
  25.         /* 配置接收 Configure */7 p- x9 q3 k  L( W2 M, M
  26.         hqspi->RxXferSize = hqspi->RxXferCount;
    # `' t- Z) h$ A6 w$ ]
  27.         hqspi->pRxBuffPtr = pData;
    ! m4 L* |! j' d* i$ e' {9 @

  28. ; L  Z1 K5 c' z  [
  29.         /* 设置接收完成中断 */1 {+ S, P3 Y0 ^1 B) H  G  k
  30.         hqspi->hmdma->XferCpltCallback = QSPI_DMARxCplt;: P5 c- x1 v% P

  31. ' D  F. F/ o6 k3 P* b
  32.         /* 设置MDMA错误回调 */' B0 S$ j; a3 I, b' J  v
  33.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;; w+ Q. ~3 s9 H& _
  34. 4 }- `5 S) c! E; y! U
  35.         /* 置空MDMA终止回调 */) I. Z! k. ]# @: [& m7 _$ M
  36.         hqspi->hmdma->XferAbortCallback = NULL;- x3 j) X8 @/ {# Q6 y

  37. 9 E* l0 W3 J9 J$ c$ A
  38.       /* 接收模式下,MDMA的源地址是QSPI DR,要禁止地址自增 */0 s' X" r& c* T1 g
  39.       MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_DISABLE);
    # b# {5 Y7 P- G5 r- U0 J7 ?' H$ ?
  40. % K! w3 O4 |2 Z1 [. O1 }
  41.       /* 更新目的地址配置 */2 f' ^9 r3 U6 G; \" v
  42.       if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_BYTE)6 S! a" w+ Z  P% T% o9 Z) b; V' T) r
  43.       {& @: y' e3 \0 e5 l- i
  44.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_BYTE);
    . K2 ]) ^# R" g; x  ^
  45.       }
    ( `: e1 w+ E. Y) k) W4 M. J8 X1 D7 E
  46.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_HALFWORD)/ h; t+ f$ R* h8 M4 n0 f0 T
  47.       {
    ( S$ N! _$ z0 F6 J- @& r$ }. ^+ s
  48.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) ,
    2 F" m; R* q1 y
  49. MDMA_DEST_INC_HALFWORD);. s  ^% f- O: `7 k
  50.       }
    + ~0 t3 R3 ~3 [) |8 D3 ]4 @
  51.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_WORD)
    / S3 T7 M% L5 S& p5 V. d' N8 P
  52.       {
    $ F! s- z  _/ _' h, V! X
  53.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_WORD);
    1 E* _0 {3 u2 u% L# E
  54.       }
    * z) O, J* W8 W1 A8 Y
  55.       else( D  k& i( P9 Q7 W# i1 Z5 Z8 M
  56.       {
    $ Z% f( X% M. s9 F0 j% P
  57.        /* 配置错误 */6 S$ ]: j* I- [/ E. Z& F
  58.         hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
    1 ?+ H4 ]1 ?4 P- m, a
  59.         status = HAL_ERROR;+ D" o2 {* ?  B3 Z* U
  60.       }! k0 x9 q: R# R0 B1 e' e
  61.           /* 配置CCR寄存器,间接读 */" a: b/ h5 Q, Q% ^! D6 _
  62.           MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);
    2 Q9 l  j7 n+ a8 ^
  63. ; Y' ?1 Y8 z4 L- w* y8 T
  64.           /* 启动传输 */
    , S( [2 H3 g# t& H4 f4 Z
  65.           WRITE_REG(hqspi->Instance->AR, addr_reg);
    ! c! x( D; O, v% I# Z1 m) C
  66. ' k" }7 D2 `9 g4 ?- I3 w; {
  67.         /* 使能MDMA */
    6 h- v; w. Q9 ^2 ]
  68.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)&hqspi->Instance->DR, (uint32_t)pData,
    / \! H/ n4 P( Z$ O2 W
  69. hqspi->RxXferSize, 1) == HAL_OK)# Y! y% t3 ^& q0 U* |* y- E" T2 [  c% J
  70.         {! f5 E) L9 j2 s: ^, }# v$ B% {6 X
  71.           /* 解锁 */9 v) T6 h9 S% a- ~7 N! D7 e
  72.           __HAL_UNLOCK(hqspi);
    $ [) M8 m3 B- K" w! h, _1 k, N
  73. " c- G; ~8 G! n+ E6 V" \) u
  74.           /* 使能传输错误中断 */
    ( X/ v# {3 K8 ?3 q1 |
  75.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);7 D4 {3 C2 n+ u0 N8 Z

  76. ) L" d8 |4 W! w9 u! F4 v8 q
  77.           /* 使能MDMA传输 */2 x% d+ }+ E  x0 P
  78.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);
    2 @  j: y) l2 o: G) y' s
  79.         }
    - M# m0 ]2 y9 ?$ S! C
  80.         else. ~6 M* X. s2 |/ ^* t3 M9 O  |$ {5 S
  81.         {
    $ e; {) p+ `0 `$ o- p, F) H$ E" ]
  82.           status = HAL_ERROR;. F/ m" F+ v+ q
  83.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;+ j) a/ H; r( M! G
  84.           hqspi->State = HAL_QSPI_STATE_READY;
    7 s0 A; ]; n- v+ K. m

  85. 8 N! o& A" [& f. A; S
  86.           /* 解锁 */. B7 _/ ^* L) h) |
  87.           __HAL_UNLOCK(hqspi);
    * y9 d0 ~) |3 r8 R8 U; z5 C
  88.         }
    ) w  R  _* J9 a- `  l
  89.     }
    # `8 s- f+ T! j0 \& U- K3 m+ X2 G
  90.     else
    ) x/ H/ F2 N* x/ a; T+ B
  91.     {
    % e1 d; O9 X% C5 C! [# a
  92.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;* Z% V  K! T/ |3 V% h+ J
  93.       status = HAL_ERROR;* L5 w- O0 f1 |; T0 i4 n1 m1 a
  94. * y& c0 P' c8 R
  95.       /* 解锁 */
    5 k1 L4 U4 R2 }
  96.       __HAL_UNLOCK(hqspi);
    & @8 u+ s0 ~2 U2 d9 Z7 y8 N/ J& R
  97.     }/ T% U* Y, \$ n* R5 I
  98.   }
    + V  p! I$ [5 v# x
  99.   else
    * O& n( ]2 l7 I0 g4 t' [/ v
  100.   {* @6 w) ~& _" Z, ^  S5 n
  101.     status = HAL_BUSY;
    7 c& N$ T' ?* }* ]- u
  102. ' d3 E2 d( K6 S  E
  103.     /* 解锁 */
    0 [) }5 a( m4 ^2 a. f% \& N3 ^
  104.     __HAL_UNLOCK(hqspi);
    ( m( ^4 h7 I% V. V" I
  105.   }- t3 n. A+ |/ J/ u

  106. $ i. Q  _# Y/ E8 D8 W& O
  107.   return status;
    $ ^) }; J9 o+ b6 p  H
  108. }
复制代码
/ ?: y2 x8 y2 @9 h# b
函数描述:
) m, M$ h% U: _; G# X& X) N) l; t+ V7 U$ X8 K
此函数用于QSPI接口数据接收,函数采用DMA方式。. N. Q" J8 t- M/ O( }

) E/ c  v+ n2 @, i, F4 Y: r函数参数:5 u$ A% |7 J1 C- ?4 Y! @  M
8 M5 {4 E% D$ Y7 }! X
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。- T1 p( t. Q% \
  第2个参数是要接收的数据地址。) A3 R1 ^, e% _2 I, n/ W$ g
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
2 r& q: {+ z! D1 z) X0 M5 d使用举例:6 i9 j5 S- `9 T
( w2 y  `) v5 a6 D" M0 q
  1. /*
    % m% h/ l0 U, A1 E: J5 q
  2. *********************************************************************************************************
    7 P  Z0 U$ M1 K: H4 T( h( V
  3. *    函 数 名: QSPI_ReadBuffer
    # ^# i+ c% m% q5 U
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。
    ( G7 W+ H  P; y: J8 C' }
  5. *    形    参: _pBuf : 数据源缓冲区。
    ! G) T' l) {+ x2 ?8 l3 n' f
  6. *              _uiReadAddr :起始地址。9 H. e. e5 i5 i
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
    ( k' l' V+ @/ R7 s
  8. *    返 回 值: 无# c9 ^3 t/ c& a
  9. *********************************************************************************************************
    # A3 L' J2 ~" N
  10. */% |/ g/ N, a8 x& c" s& D6 H; r
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
    . b' c  h, ~6 }; A4 s' F+ d  a
  12. {/ e; N+ a6 ]* K; f" i1 e1 ^

  13. & L$ u- r4 ^+ W
  14.     QSPI_CommandTypeDef sCommand = {0};
    1 m5 A: e, E  R' O& g% t4 R1 v- p- r
  15. % Z0 }, X# ~2 J% I3 r: b
  16. $ }! N. s% L! s! V! P2 E! a
  17.     /* 基本配置 */& _8 `) R7 x7 \/ s' S
  18.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */6 c9 G& s# v+ V$ s
  19.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */
    $ G" k! ~* r0 V& ]( B. E7 d
  20.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 */1 L' F+ v( O$ E- a, x
  21.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */
    : {4 a$ j4 c3 h$ z8 L
  22.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */- u6 \6 c% {2 J
  23.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */   
    3 w! I, g4 j8 c3 L# S1 o' q: Y! e
  24. ( k- y; _+ v6 x/ l
  25.     /* 读取数据 */& A; h% l9 |1 }! ?6 c2 T
  26.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */  n/ j1 h" N5 h+ s/ @
  27.     sCommand.DummyCycles = 6;                    /* 空周期 */: @9 s' |" q+ S; D7 v, Y
  28.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */7 k5 @5 i$ n4 _% c: z5 T. p
  29.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */ 9 i  W& `% Z, `# B6 o) v8 R. L' m
  30.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */ $ x  N+ Q  N5 u
  31.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */ * {, F, x. R4 U$ F, ^+ ?0 H$ `4 F

  32. . r- u2 @. @" w1 Y5 V
  33.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK): f" V. b6 B- z0 W! f0 Z6 \
  34.     {* b, [2 f. l* X
  35.         Error_Handler(__FILE__, __LINE__);
    # h! J4 u& M( L' q
  36.     }" }3 \+ W$ d! ~# C8 F4 H# F
  37. % n. v% ^0 e- n9 I/ g. `3 k
  38.     /* 读取 */6 C% I$ \3 A' \, \$ m' w
  39.     if (HAL_QSPI_Receive_DMA(&QSPIHandle, _pBuf) != HAL_OK)
    : K3 y/ J/ C6 i. J6 J* ?
  40.     {7 Q: k) ]% a5 x+ ^7 _5 ~- z
  41.         Error_Handler(__FILE__, __LINE__);
    , m: A$ s* d& P1 t2 K6 ?
  42.     }    ! x7 ~7 Z( e. ?* t  V6 l9 ]$ s. d. V
  43. }
复制代码
) W0 D- }( e0 Q
78.4.11   函数HAL_QSPI_MemoryMapped- t+ F+ u0 i4 O4 ~" E- E. X
函数原型:* @( Z! {  X& b( a4 m
1 s) N# ~% y7 b5 z  Q3 ~
  1. HAL_StatusTypeDef HAL_QSPI_MemoryMapped(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_MemoryMappedTypeDef *cfg)( \( b5 K% D. M- Q7 N3 p& d' f" A
  2. {
    0 w- c  O& @# N2 M
  3.   HAL_StatusTypeDef status;9 q, S5 z/ k0 b' Y; f6 I
  4.   uint32_t tickstart = HAL_GetTick();/ ~% b" n2 r" t( W# l

  5. ! q) E( b' M( j7 F
  6.   /* 检查参数 */3 _& P) z! y0 \0 }: S4 E- L
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));8 j- V8 ]4 H3 w/ {( q" v
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)7 g; E! D* f7 B- c+ p# U
  9.   {9 ~% k: O* n4 Q9 R3 T; Z: ]
  10.   assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    5 }, i& ^! b6 k. a$ p
  11.   }8 M6 P3 y9 u0 Z% j' B" o
  12.   b; C) J! o2 X. p0 e5 G8 A
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
    1 S. K! w  J: g# [0 B" @
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
    / U1 `) c) t. v: k
  15.   {
    - o* M: Y# n2 I7 k: i3 m- D
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));* h) w8 b+ `/ R7 o+ f2 v1 P. T
  17.   }; n3 `8 P8 d, g! g- W+ U' r
  18. " Z- I% \# z$ h$ G# b. h) p
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    ; r$ [+ L# j6 _1 {3 u# U7 l
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    & ?8 Q/ D2 S0 l
  21.   {
    : Q; s6 }9 ^* V; S+ T# B2 k4 y
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));4 I- p! u; k; Z! Y5 ]
  23.   }4 u* T/ K: A3 N. E, E( r5 m

  24. 8 a4 B# p& @! b9 X
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    ) Z/ T6 V  P% g* d' H" Y
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
      Z% ^' p; |9 h0 ~7 {' F0 w
  27. 3 h5 @$ _0 E0 b* p  N! |" ?8 e
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    ( T% \7 x: ]5 C4 X9 B+ Q
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
    - j3 W% s+ S) E* f& F& B" q0 p# P
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));2 B! ]$ T0 I% L2 P: l* D) F7 S1 z, D

  31. . v) Z9 s: y. O5 g6 R9 f
  32.   assert_param(IS_QSPI_TIMEOUT_ACTIVATION(cfg->TimeOutActivation));
    - a* @& j' S% N2 D% J9 d4 E" s& _
  33. / n8 `5 e1 t$ z) g4 h% Z( R3 J
  34.   /* 上锁 */% |$ @9 `) t5 ~; ]
  35.   __HAL_LOCK(hqspi);: e+ Y9 Q/ n. l2 U. E
  36. % D- v' c0 P" y* P9 n
  37.   if(hqspi->State == HAL_QSPI_STATE_READY)
    7 N& X/ q) T7 i8 ?# _+ J
  38.   {' l: W5 W- A6 {( P
  39.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    ! Q7 ^, |( ?6 f. q2 Q* Y

  40. ( A4 I) ?: F6 \* |
  41.     /* 更新状态 */
    " K2 ?5 |4 h2 P
  42.     hqspi->State = HAL_QSPI_STATE_BUSY_MEM_MAPPED;
    $ C* ~  \* x7 Y0 ~5 O$ T! E# R0 _

  43. % t6 {9 y" |  W. T9 O$ O
  44.     /* 等待BUSY标志复位 */, x5 n/ E6 P' K3 T
  45.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);: B" U7 X/ k  j2 Q

  46.   ^. B1 H# D! J8 M, E
  47.     if (status == HAL_OK), T9 ]; Z4 a% |  S5 v
  48.     {
    * F; l: ~1 u( a! C9 ?4 O
  49.       /* 配置QSPI CR寄存器溢出时间计数 */
    9 E! v6 b( J/ q
  50.     MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_TCEN, cfg->TimeOutActivation);
    , B% p, R  ^$ o4 ^. m( l" o2 e
  51. 2 J7 _4 A' t  }) ]- y
  52.     if (cfg->TimeOutActivation == QSPI_TIMEOUT_COUNTER_ENABLE)  j! I9 E' I; c; j# D, a1 [
  53.       {7 ]" t3 F) X$ C2 Q$ w
  54.         assert_param(IS_QSPI_TIMEOUT_PERIOD(cfg->TimeOutPeriod));
    0 P( p7 p& k% {# L. C

  55. $ X/ b7 p; ^, e" k, q$ x
  56.         /* 配置溢出时间 */
    ( E0 w/ ?% `2 g8 \7 I- F9 k
  57.         WRITE_REG(hqspi->Instance->LPTR, cfg->TimeOutPeriod);) n+ C9 [8 o, F8 a  ^9 d
  58. 2 g8 h0 |+ k! x2 |1 O
  59.         /* 清楚中断标志 */
    5 ~2 {' f1 K- b8 {9 C; }9 j
  60.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TO);
    : b2 _' p+ f  k  A
  61.   G& i0 Y% X. }. z8 e9 ]
  62.         /* 使能QSPI溢出中断 */& J0 d% z7 j" e* W  Z/ u
  63.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TO);
    # G5 E: z( c* P) e
  64.       }$ d* Y8 f8 V* r+ L$ \, p

  65. 8 B9 ~# U* Z7 M1 U; Q1 W; T7 k- J
  66.       /* 调用配置函数 */) D" X- B/ c5 A' y; q! w& X8 U
  67.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_MEMORY_MAPPED);# i3 e# v8 O: h$ k7 H& M$ c& v# F
  68.     }
    # ?' H9 F4 z* I: {3 F. x2 R+ g
  69.   }2 M& K% E0 o8 W% T# J
  70.   else5 f6 [8 f: M  w' u9 p2 O6 {9 @3 L4 L
  71.   {9 `* H3 I8 a, |
  72.     status = HAL_BUSY;
    " o. c- R' K" w2 `$ h7 X( t
  73.   }( k& ~0 d( `# C5 m

  74. % A( X, |3 Y' O4 M5 X( a
  75.   /* 解锁 */: \) [3 W5 ^( b6 P# q
  76.   __HAL_UNLOCK(hqspi);
    3 A6 B# [) r! o9 L0 C" c

  77. " \& A- u" T8 v9 a
  78.   /* 返回状态 */6 x% s( H3 V) p+ `4 N: z/ G
  79.   return status;
    0 R7 B4 A% F  I
  80. }
复制代码
- p7 q: \. t7 E  I& ~' ~0 O0 k
函数描述:
6 m7 F9 W) J' E5 e4 n) G
: D. [8 T) R7 |+ c$ T6 o5 N用于QSPI内存映射设置。  {: k0 R4 r1 I4 R- F2 ^( u

, d4 P* X, U/ B! Z$ r$ H' a7 G函数参数:
; \; z0 G) P; s* l* X! A) N
8 H# \3 F8 S" d  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。: f) g' T: i( m1 D5 I. M' i
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
0 U  s7 @0 d8 t/ D/ a4 ^  第3个参数是QSPI_MemoryMappedTypeDef类型结构体变量,详见本章3.6小节。: J# j+ U8 Y% o, N+ c4 ]$ H6 ^
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
6 P# d4 v3 T8 e3 A7 y' g0 H使用举例:
8 W8 ~9 b; W6 @- Z: W  h
1 S3 ^& {  s$ s' y, {! {& m
  1. /*
    + O5 O& G& `7 z: M
  2. *********************************************************************************************************( Z' Y/ v' h* t
  3. *    函 数 名: QSPI_MemoryMapped
    0 K! G, Y$ h2 s  w7 h+ P3 F+ l
  4. *    功能说明: QSPI内存映射,地址 0x90000000+ d) |$ p3 d/ K8 U' ~. ]
  5. *    形    参: 无( g3 k: _# c' P4 R/ r
  6. *    返 回 值: 无+ u; r" d9 W& Z4 n+ a' g
  7. ********************************************************************************************************** P! f8 q' n% s- U4 _2 f5 j9 ]1 `& [6 {
  8. */+ \6 ?! e' l% A- I
  9. void QSPI_MemoryMapped(void), x7 l0 @7 h; n$ P2 q
  10. {* {4 D' U/ L' z& E
  11.     QSPI_CommandTypeDef s_command = {0};
    " z& M1 u4 }1 j4 }
  12.     QSPI_MemoryMappedTypeDef s_mem_mapped_cfg = {0};
    5 \. U7 X! z# w+ X* J

  13. , W. k# i! l' v3 U
  14.     /* 基本配置 */# n) M+ Q& \- p( v0 |: L
  15.     s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;      /* 1线方式发送指令 */ " @1 j9 O9 |. |0 c, J
  16.     s_command.AddressSize = QSPI_ADDRESS_32_BITS;             /* 32位地址 */- z5 g1 t( [4 E2 y$ i# I
  17.     s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */  S2 H. \; H9 @) U  d/ x* p; W1 ^
  18.     s_command.DdrMode = QSPI_DDR_MODE_DISABLE;                /* W25Q256JV不支持DDR */2 X+ O( ~/ O1 S* {+ {  D, h& F3 n
  19.     s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;   /* DDR模式,数据输出延迟 */
    ! j- K' v: B% E, k4 f4 l
  20.     s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次传输都发指令 */
    2 M6 M3 H  J( w+ r9 ?6 n
  21. , P5 r7 E& G6 C3 j
  22.     /* 全部采用4线 */
    $ h8 S- E  q& E8 [( C. V8 M; y
  23.     s_command.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 快速读取命令 */% W* R1 L3 H/ z# q* p* x
  24.     s_command.AddressMode = QSPI_ADDRESS_4_LINES;                 /* 4个地址线 */
    6 L0 {0 k- b" i- c# @* b! ~
  25.     s_command.DataMode = QSPI_DATA_4_LINES;                       /* 4个数据线 */
    6 |1 T1 c' g! r( A5 A: ?
  26.     s_command.DummyCycles = 6;                                    /* 空周期 */
    5 s3 [$ a: ]) p3 b4 A% C. g

  27. # V$ }: c$ n3 ^" D3 K# H
  28.     /* 关闭溢出计数 */# m: I- j9 }" g( W* s1 o6 g! H5 g- \
  29.     s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;+ e+ B8 y8 L8 z" R: q. d
  30.     s_mem_mapped_cfg.TimeOutPeriod = 0;
    4 |2 O4 p* x4 q

  31. , h+ X& ?9 K1 ?6 p& e+ [
  32.     if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)7 p- ^/ E7 S' b; d6 r7 B& P4 b
  33.     {
    4 e2 F* n7 e; z0 b
  34.        Error_Handler(__FILE__, __LINE__);
    & a  T4 }& C% Q, c+ U9 E% P) c. _
  35.     }- k& ?7 c) w6 W& P
  36. }
复制代码

1 Z5 `! H" j) M, ?. q. z78.5 总结2 J# S2 c2 q3 ]
本章节就为大家讲解这么多,要熟练掌握QSPI总线的查询,中断和DMA方式的API用法。- b2 w6 B; z) M6 z9 D  a- c% y" N

5 |! |, E3 E  `% ~' o: H' V$ \) x, z$ F
74f88e781c0aa6369a48d73fb7dbe7d9.png
赞 收藏 评论0 发布时间:2021-11-4 18:44

举报

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