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

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

[复制链接]
STMCU小助手 发布时间:2021-11-4 18:44
78.1 初学者重要提示
" z/ E% ]+ x; |& b  QSPI接口,可以做1线,2线或者4线使用。$ \9 ~) Y8 ~' U7 P7 q8 t
  注意,QSPI接口不分主从,QSPI仅用于主控。! E: c) U7 L+ V$ h5 ^& L
  可以单独使用BANK1外接一个Flash,也可以单独使用BANK2外接一个Flash,不可以BANK1和BANK2同时独立使用。但可以两个BANK合起来做双BANK(也称双Flash,即dual flash)使用,即8线模式。
; ^& W! v. W2 w6 z6 b* }) ~9 t  STM32H7可用的单线,双线,四线和八线SPI QSPI OctaFlash等涵盖各大厂商, Y" g, c0 h' a' Y" N/ v
78.2 QSPI总线基础知识
# l# h+ ^' e0 Y& V( D* _' }78.2.1 QSPI总线的硬件框图8 V# s" u  S1 O+ ~
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解QSPI的基本功能,然后再看手册了解细节。
, }! M& }9 a# o* k5 v/ N. _) m5 v% r3 @% l0 M4 V/ B
BANK1外接Flash
( O1 W: L, o. o3 \0 e) A+ M4 T  t# ~# X# @# c
f04c8d70b5dfdaf87e9a1a4f54b38e55.png

# D. }' J- m( f
# |3 @) S# B9 _' }8 `- z# GBANK1和BANK2都外接Flash:
( A' V" T! b9 a2 d, u8 i- ^4 I6 G& ~; S1 `
60f4042c5098f3ba9a7e40219c023175.png
/ O4 D0 Z% ^5 ^6 H  f7 U
- A& G- M! _" x' c+ N
通过这个框图,我们可以得到如下信息:
; l3 m3 R; F$ j0 l
; S: `6 Q: s1 U; }8 O  quadspi_ker_ck时钟输入
8 e8 K8 x  k+ g  L9 t9 {内核时钟。
: F3 w! H/ j  u. Y; {- i, `# [$ ?/ G+ v3 Y& b* }
  quadspi_hclk时钟输入
& z) u* w0 f1 P6 z为寄存器提供时钟。
! I) V. |$ x6 q7 ~1 n6 w% Z) f6 s
  quadspi_it输出信号6 o* p/ k. x- m
QSPI全局中断。3 o) b0 t2 B; H0 O

- `2 x* @, Z! W8 o  quadspi_ft_trg输出信号
6 Q. l0 Z1 E/ v1 t5 f; b6 dMDMA的QSPI FIFO阀值触发信号
: A# Y( `1 X. o2 U* L
4 p! @# B7 [8 q" ^$ ]' [  quadspi_tc_trg输出信号, Q* c5 C* i# a2 T  R1 v' K% E
MDMA的QSPI传输完成触发信号, w8 x7 U9 ]1 y/ c' c9 R+ Q

% T, U0 r) Y- }; I  CLK
% F0 N' f4 e+ T为外接Flash提供的时钟。为外接的两块Flash同时提供时钟。
0 H8 I, [- M% t2 t( {6 S
1 c; D2 S: U# X' W! F$ }; ]  BK1_IO0/SO; a' p, C2 S2 z. U3 l4 S
在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash1使用。# w7 U' v9 W( Z3 E8 m5 v/ F0 l$ o9 G
# M5 E$ \! M8 [8 Z6 a$ n
  BK1_IO1/SI
) E. |2 s2 S% R- o在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash1使用。$ T6 G/ U3 @- H8 U

3 x, c1 W! s0 ]  BK1_IO2
$ f! }# u" M' S$ L在4线模式中作为双向IO,供Flash1使用。
! \* g6 O' W$ o5 H0 l$ z8 h! c
0 j. `, d( H" @. z: z* u; _4 E) I  BK1_IO3) F9 ~( L' ?! n, W3 n
在4线模式中作为双向IO,供Flash1使用。2 u( O0 B& g' Y. E5 @( L1 i

, S1 _9 S2 Z& q( W+ D# U3 @  BK12_IO0/SO
3 ]  y  `/ R0 Z2 w) k8 a在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash2使用。% U1 z" A- d& y: ]- y

+ U! }6 Q0 R, Z( `9 |. [0 m  BK2_IO1/SI
5 u* t* o% ^7 E5 j& \在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash2使用。: j; s" G" J; L0 t# N5 R
: b% q' d3 U9 `; D, f$ ?
  BK2_IO2
$ L: T& c2 l+ B  ]% D5 \, \在4线模式中作为双向IO,供Flash2使用。
1 Y% j: ~( _8 A2 _$ D2 `6 a9 d0 Q: n
- f  {2 @) }4 K3 o/ ^* o5 |) g  BK2_IO3
9 I( ]6 f# W; h8 z9 c4 l! U( t# }在4线模式中作为双向IO,供Flash2使用。+ ]) E2 J! B. Q! n
5 }) L6 V$ J) p! j6 e* h
  BK1_nCS/ g8 W  t9 w( U: y
片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash2。
# u1 ], R( O: u1 x1 L3 h# s1 D$ i
: ]0 b, Y4 H7 H  BK2_nCS+ f+ a4 r- o8 ?2 s. \4 X0 Z: q
片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash1。
4 M- N0 _' S3 s# }: ]2 ]4 C/ V8 {6 X, `! h4 ]: v! t
78.2.2 QSPI的时钟源$ I; |, w+ r7 V8 A, B- J# k8 k
这个知识点在初学的时候容易忽视,所以我们这里整理下。
3 c+ d5 ?) c$ b! I
, g5 {" `. ]# \; r9 ]: ESTM32H7主频在400MHz下,QSPI的最高时钟是200MHz,可以选择的时钟源如下:& }0 D6 Y; U0 o4 ?

: i/ K% U0 J7 i. n! m( Z
60a21420cdf6bbfc171b77ef44ebcf28.png

% }0 X5 i3 E" s; S$ [  m$ @  }! O
' m7 R. V! b( R) A5 h
12523b301f01c6108162699ca2ad5685.png

  h' c' p7 m) i) ^
1 n/ E+ Y5 c& E; b' L) S) |
* X1 g3 l; |' \+ P8 n+ m我们的程序中默认是采用的HCLK3作为QSPI时钟。
3 f2 {, t" \& s* v
! X2 e, M8 K8 n$ a78.2.3 QSPI 命令序列  }! l1 g8 w& \0 F: N
QSPI的命令序列主要包括以下几个阶段:指令阶段、地址阶段、交替字节阶段、空指令阶段和数据这五个阶段,任一阶段均可跳过,但至少要包含指令、地址、交替字节或数据阶段之一。
: b) N9 x7 f! v+ U/ ]. v/ K2 s0 C( g8 k. |. z6 @" P4 e
2cb087bbc794898408c6160acfd426e4.png
0 d3 A& `/ \0 t6 |$ T. P

  U9 O6 `2 K2 x* a! J9 |  指令阶段
$ ~3 q, B" [. G" j在此阶段,将命令(8位指令)发送到Flash,允许发送任何值。用户可以简单地将所需的命令写在指令字段中。根据软件和硬件配置,可以1线,2线或者4线方式发送。在某些只发送地址的案例中,指令阶段可以跳过。
5 M, G* J+ o3 g' J" n- }# A, ^1 d; M! `  b" |" `, R0 Z
地址阶段
# {2 d) c+ a  f' R2 B7 J在此阶段,将地址发送到Flash,从指定的地址读取或写入数据。 地址阶段是完全可配置的,允许发送1、2、3或4个字节的地址。在间接模式和自动轮询模式下,用户可以简单地将所需的地址写入QUADSPI_AR寄存器。据软件和硬件配置,可以1线,2线或者4线方式方式发送。 在一些不需要地址的情况下,可以跳过地址阶段。
/ m( |  n; h4 [2 `
5 S& c/ x/ J3 s/ h# k* v3 f  交替字节阶段  [& @* V5 t5 b% K; g3 E* T" u, X: O
QSPI接口支持的一个额外阶段,具有更大的灵活性。它是通常用于控制操作模式。交替字节阶段是完全可配置的,并允许发送一,二,三或四字节。
. B- @7 c  N$ u5 `& V  T1 J  D% j
  空周期阶段
0 I2 K7 F* A$ t& e3 ?+ v6 k# u在高速时钟下运行时,此阶段可以确保有足够的“周转”时间从输出模式切换到输入模式。- a7 ^: D' y! y
; s/ v; {* ?7 {+ ^- Y
  数据阶段
! ~. x6 j# K. W/ f7 A这个阶段实现数据的收发。! W1 R3 w" m& @; x2 i* Y
+ S) j! z2 H% z! C& ?  i
78.2.4 QSPI的1线,2线,4线,SDR和DDR模式
7 M% L* v( K( c# O. @这里所说的线是指通信阶段使用的数据线个数。2 \3 S8 G8 T. V# e
6 L+ v& @) t$ ^' B- s
213a38369fe04824fa8640f515beb2fc.png
& F: r% x4 E/ O5 |
" H7 N1 n( V  s  Y& l: {9 O4 l
1线(SingleSPI,虽然是一发一收,但属于1线方式)
: l" |0 v+ f9 U+ M发送用的数据线BK1_IO0/SO(BK2_IO0/SO),接收用的数据线BK1_IO1/SI(BK2_IO1/SI)6 e. R2 Z7 k8 r8 u9 g1 k  g

3 W7 C& D, a  \( E  ]1线模式下,所有线处于的状态:
5 B; |9 r5 {7 S7 W( L; v$ Q5 K9 x# S1 P  v
(1)  BK1_IO0 / SO(BK2_IO0 / SO)处于输出模式。8 Y6 W6 w& b' P; k6 H

" ~0 e1 |  F5 V  F, p. _ (2) BK1_IO1 / SI(BK2_IO1 / SI)处于输入模式(高阻抗)。
9 r# M( I- R" M6 U; ]: x6 s
7 Z7 \( q0 `( m) w (3) BK1_IO2(BK2_IO2)处于输出模式并强制置0。
& n& a+ y" p1 l3 h/ J; W, K0 D5 Q) j" p$ V3 I7 G
(4)  BK1_IO3(BK2_IO3)处于输出模式并强制置1。
- z/ A1 J5 |  D0 H/ f) {, v5 n: g; j& _
7c6105bc6d18539b680aeeed7ec93aed.png
2 C& A- Y  R: F! E* R
, n6 e" g- c2 @6 {, W9 @
  2线(Dual-SPI)
, e. w4 Q& H" L& r同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1)做输入输出。/ }, P  V5 i! f# f8 m+ V0 J, L

+ x6 Y6 i: x  Q' |! o2线模式下,所有线处于的状态:
2 R5 y# i) r! M2 j9 b$ R6 J) e7 D( W$ L6 g  g  i/ ^* K
(1) BK1_IO0 (BK2_IO0 )和BK1_IO1(BK2_IO1)读取时处于输入(高阻)。其它情况下为输出。) l9 f  ~$ A! t# V  M0 M; P
% F$ O  P! k( ]$ g, F2 {/ V5 n
(2) BK1_IO2(BK2_IO2)处于输出模式并强制置0。, ^5 A& j: h+ f* G
9 S' @# Q2 H- \, e
(3) BK1_IO3(BK2_IO3)处于输出模式并强制置1. Q3 s' b  _0 B5 h. p" V

9 S' T( N+ |- f0 J5 [$ Q- n, t1 Q
& t3 D+ H; e# A5 y6 N- N+ f
1 i$ x. P$ i% ]: X+ z6 Y8 K7 N
4线(Quad-SPI)
+ }1 Y! w$ K: c6 H同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)做输入输出。% U/ b! g* x6 G# _/ T: H
; B6 ]- t7 _9 a% _
4线模式下,当读取数据时,所有线处于输入(高阻),其它情况作为输出。
/ B3 Q9 H8 x5 @7 x0 u4 f5 k2 [7 \
9d022cbcfd5fb3f3950421c3312e505f.png

, R2 R  M' a/ C' H, B/ v) W$ c6 S6 ]/ Q- g) T3 `
  SDR
! f+ j) W2 u" @8 r1 p. m在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号仅在 CLK的下降沿发生转变。
9 f/ n* j% z, ~/ G7 P2 E8 S5 M1 q. Y; O! x" I
  DDR1 p6 @! R; {  g8 _8 R
在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号在CLK的上升沿和下降沿发生转变。8 m7 h% j$ T6 d3 q4 |
, l: x0 ^' r5 w) Z& r* w
  双BANK(双Flash): e4 H: z) ]$ x
双闪存就是将QSPI的两个BANK分别接一个QSPI Flash,然后时钟公用,片选公用(也可以不公用),从而实现8线模式。7 ?" |* Y2 d7 V
8 y, B4 Q& H6 c! g2 q2 h- @/ |
d28d743492529e4d88e9b64567fe52b4.png
8 _* M, l1 f8 _3 B
% y; v/ }- K4 _* c" C
78.2.5 QSPI间接模式,查询模式和内存映射+ c9 q1 s' N: O9 [' W
QSPI支持在以下三种模式下工作:
/ X. e2 Y! g  G! M8 a$ |
$ s$ O/ Q, _% W' p1 C0 ^1、  间接模式:* j# |* I( V, N5 ]8 y! c

4 i* n/ K: J: m0 D- g% a这里所谓的间接模式是指寄存器方式访问外设,就跟我们操作串口外设一样。间接模式主要用于以下场合:- T, V! L( i4 ]* M$ T- K

3 C( C0 K3 f% ~4 T6 O  用于读取,写入,擦除和配置QSPI Flash。
  `$ q8 X. U3 ]) H2 O  如果不需要AHB总线访问 QSPI Flash(在内存映射模式用)。% t0 U: F5 J+ o
  CPU或者DMA通过QSPI数据寄存器执行所有操作。
/ k6 A; E) N; k' e8 ~8 Z' j8 G7 D9 k- E. o9 U. u

: U0 o* W9 J+ A8 M0 K4 d在间接模式下,所有操作均通过QSPI寄存器执行,含读取和写入操作都由软件管理。 QSPI接口类似于经典的SPI接口。传输的数据通过数据寄存器与FIFO。在在此模式下,可以从大容量的外部Flash读取数据或向外部Flash写入数据,可以支持到4GB容量。7 A2 @) O# q, e% _" a9 i) C% z

) I7 P8 c/ @0 y7 w7 E  {6 X% _如果进行擦除或编程操作,则必须使用间接模式,并且所有操作必须由软件处理。在这种情况下,建议使用状态轮询模式,然后轮询闪存内部的状态寄存器以了解何时编程或擦除操作完成。9 g" y7 }3 C7 k. `
' b  U" Y3 e0 {, m& h* M& |

7 D+ h7 A4 k; B/ t2 Q
, L8 p2 F7 j+ B( J% H" W, W2、  状态轮询模式
9 }9 o& `! ^: ~
9 O) K+ \6 n  p1 l1 A, x在以下情况下使用状态轮询模式:( z% a3 C# |( u3 b8 N% j6 ]7 X$ ^" s
; ]3 g* J7 [+ a
  读取QSPI Flash状态寄存器。- u; b) d) w2 ], s2 A
  在操作结束时自动轮询状态寄存器。( v; @/ n9 M0 j% t; V
可以自动轮询内存中的指定寄存器并减轻CPU负担,例如检查擦除操作何时完成。QSPI也支持定期查询QSPI Flash,并且可以屏蔽返回的数据位,将所选位与所需值进行比较,结果比较可以通过下面两种方式处理:) `, |! b9 d/ `% ?. R0 S
* E9 s  k! i9 Q$ P
  AND与操作模式:如果所有选定位都匹配,则产生中断。2 G% j7 G4 _, X
OR或操作模式:如果所选位之一匹配,则产生中断5 ?9 n; y3 X% p# b0 v" R
- q1 A: L0 y0 [$ T/ x& U4 w

$ B9 l# d1 r+ N9 a8 I$ ]发生匹配时,QSPI可以自动停止。8 H7 {) Z4 a) a$ _! Z8 D4 w; t. x
% q4 m7 A( @" n$ i: S4 M
/ l* ]- [0 R  Q) P
( b: W" F( T3 ~: O. H6 n0 E
3、  内存映射模式3 g' G4 L3 N# }! z, E
+ @) g( s- k, v" H
在以下情况下使用内存映射模式:
" o4 V/ x9 F: }; I# |! G+ N* U# l% w, N; s' P0 u! ^
  用于阅读操作。
9 O9 R$ Y5 k, W2 U& r4 V  像使用内部Flash一样使用外部QSPI Flash, 任何AHB总线主控都可以自主读取数据。
& B: [2 Z+ |2 N& I8 X  g( f1 k& z  用于从外部QSPI Flash执行代码。4 G, ^0 q( i. X4 a; K

' n( r" R. {) o& M9 }  T( q, Y* k
/ k1 X2 \/ C, v  }% {QSPI接口能够管理多达256 MB的内存,在内存映射模式下地址范围是0x9000 0000到0x9FFF FFFF。' {6 L. @, o* N9 c, Z

) l' Z% H( @* ~8 P78.3 QSPI总线的HAL库用法
  w. ^1 c5 \  [+ c% O78.3.1 QSPI总线结构体QUADSPI_TypeDef% ^/ f3 D2 b5 U. j7 j7 `. P8 Z
QSPI总线相关的寄存器是通过HAL库中的结构体QUADSPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
* e6 Y' i' t7 a* Y! E
7 f+ `" n* |) a/ a# ~' l- F& \. [: E5 m
  1. typedef struct
    6 T  `6 `0 y2 }
  2. {
    + E; c( b" B( `3 ]+ Q
  3.   __IO uint32_t CR;       /*!< QUADSPI Control register,                           Address offset: 0x00 */
    $ \% @# d& h4 I
  4.   __IO uint32_t DCR;      /*!< QUADSPI Device Configuration register,              Address offset: 0x04 */
    4 Y+ s5 ]) y2 C5 f* `3 z9 a
  5.   __IO uint32_t SR;       /*!< QUADSPI Status register,                            Address offset: 0x08 *// L& R9 {9 H  b  k  c  G  x
  6.   __IO uint32_t FCR;      /*!< QUADSPI Flag Clear register,                        Address offset: 0x0C */
    8 w+ z0 A: ]9 b2 g; }$ B
  7.   __IO uint32_t DLR;      /*!< QUADSPI Data Length register,                       Address offset: 0x10 */* X& e' E9 J5 x  R2 t
  8.   __IO uint32_t CCR;      /*!< QUADSPI Communication Configuration register,       Address offset: 0x14 */1 C$ j: S9 N5 [; `3 l
  9.   __IO uint32_t AR;       /*!< QUADSPI Address register,                           Address offset: 0x18 */: H& _: g2 n+ u
  10.   __IO uint32_t ABR;      /*!< QUADSPI Alternate Bytes register,                   Address offset: 0x1C */7 w! G+ d. s4 p* E0 l
  11.   __IO uint32_t DR;       /*!< QUADSPI Data register,                              Address offset: 0x20 */
    5 r2 q2 ~: D% v5 J2 z+ ^% }
  12.   __IO uint32_t PSMKR;    /*!< QUADSPI Polling Status Mask register,               Address offset: 0x24 */
    ' n; ~' D! v) U8 [/ p$ X4 b# ]& I
  13.   __IO uint32_t PSMAR;    /*!< QUADSPI Polling Status Match register,              Address offset: 0x28 */
    . G9 h: |2 W8 Q9 i3 v
  14.   __IO uint32_t PIR;      /*!< QUADSPI Polling Interval register,                  Address offset: 0x2C */+ l. F1 L" m- b2 M* L0 q0 T
  15.   __IO uint32_t LPTR;     /*!< QUADSPI Low Power Timeout register,                 Address offset: 0x30 */
    + }2 u6 d# z: M" W5 E7 f
  16. } QUADSPI_TypeDef;
复制代码

5 l7 F* r' {7 r0 M3 |% f这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
# S, A8 K3 x; v7 ~" A7 L- b. ^0 o! I
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
3 l) o8 [" g$ R
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    % p+ ?- g3 |2 K! ]) l- c' p# `
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
+ G" K( [) e3 Z" N: l  s+ \% _' F. N
下面我们看下QSPI的定义,在stm32h743xx.h文件。
* O* x" M# L6 @' j. I6 `1 ~" D
# I+ r1 [/ N) f5 A
  1. #define QSPI_BASE ((uint32_t)0x90000000) /*!< Base address of : QSPI memories  accessible over AXI */1 `' P4 d' X4 h6 Q& [) Z5 @5 S. E
  2. ! w& I% [: c# s4 t
  3. #define PERIPH_BASE           (0x40000000UL)
    + R) C9 ]" M9 }( F
  4. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)% c+ V. I! g9 c

  5. ; i9 p2 d+ N5 x) d+ }0 U
  6. #define QSPI_R_BASE           (D1_AHB1PERIPH_BASE + 0x5000)0 p) \, a7 j( Q" M1 a: V. q6 a7 w% x& W
  7. #define DLYB_QSPI_BASE        (D1_AHB1PERIPH_BASE + 0x6000)
    % K( X1 i, f, t) P8 l) l6 m
  8. $ O" r* v; K1 y& g. i& z$ i
  9. #define QUADSPI               ((QUADSPI_TypeDef *) QSPI_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52005000& K4 M+ s; Q# c: x) @* }0 q
  10. #define DLYB_QUADSPI          ((DLYB_TypeDef *) DLYB_QSPI_BASE)
复制代码

0 y6 ~& G* k/ \0 ~* A我们访问QSPI的CR寄存器可以采用这种形式:QUADSPI->CR= 0。
8 R! B1 c/ o3 e# z/ M8 ~( w( C
6 p1 c8 K. Z; ]1 W1 X8 N8 [% W# P# [78.3.2 QSPI总线初始化结构体QSPI_InitTypeDef
( m& r7 E1 D. G0 N下面是QSPI总线的初始化结构体:0 f6 t2 k2 G. D6 F
' z  t9 e! F; f) {# t' w$ I
  1. typedef struct9 t7 j" \+ U' A
  2. {3 P3 c; L9 p( g, F
  3.   uint32_t ClockPrescaler;     
    ; |, C3 Q% v% ^6 U: Y' \, B* y* a
  4.   uint32_t FifoThreshold;      9 |& e" b6 c2 O! V  @% y
  5.   uint32_t SampleShifting;    5 m+ j. N4 x) @
  6.   uint32_t FlashSize;         
    & P2 j# A4 {* E
  7.   uint32_t ChipSelectHighTime; ) A2 L- R6 f1 d+ A5 U/ l
  8.   uint32_t ClockMode;          * L2 Y! A& N6 H# T8 G
  9.   uint32_t FlashID;           6 F; @, o' d  Q/ f  I
  10.   uint32_t DualFlash;                                           0 A2 l! Y% P8 T/ I% f7 q
  11. }QSPI_InitTypeDef;
复制代码
. X/ u2 `) W. [( c- _( q+ S0 Q
下面将结构体成员逐一做个说明:8 W9 ?  v, z9 R4 `$ Z2 U1 f; p, a
3 q7 O: E! d7 m" @+ ^
  ClockPrescaler
4 c; X) n& [* }1 T) R/ D设置时钟分频,参数范围0到255。特别注意,这里是针对HCLK3作为QSPI时钟来说的。
9 J% F" p" @$ Y( w- L6 W4 x! f1 c' K& h. y/ E6 J% q# W! o6 s
  FifoThreshold
( \* u" A; A$ e2 e  S3 n  S* d用于设置FIFO阀值,仅用于间接模式,参数范围1到32,单位字节。0 x3 O* f$ T, y  j9 N
7 A! I9 H" V, y# y) |# X
  SampleShifting
5 C  g  r. a% s! eQUADSPI在FLASH驱动信号后可以选择再过半个CLK周期后才对FLASH数据采样,这有利于推迟数据采样。支持的参数如下:; o/ }4 A; N/ I8 P2 o9 m7 e; ^

0 G2 b0 e' g( r: u2 V' y8 i#define QSPI_SAMPLE_SHIFTING_NONE      ((uint32_t)0x00000000U)       * x: @# t, U( C  T
#define QSPI_SAMPLE_SHIFTING_HALFCYCLE ((uint32_t)QUADSPI_CR_SSHIFT)
1 ^1 h$ f( D4 ^: K; w  x* L) K  FlashSize7 e0 _# ~+ F7 G
Flash大小是2^(FlashSize + 1),单位字节。
9 ]; S: U. v- C, U- M* O- Q* D9 W& q) s0 {& ?# m1 t
间接模式下,最大支持的Flash大小是4GB,内存映射模式,最大支持256MB。
7 Q, ~% f2 B2 w6 a- ?) X5 _
+ x0 L8 B  H" Z8 t: i
  1. #define SPI_POLARITY_LOW       (0x00000000UL)7 J% e" L+ y4 A  G/ q1 S9 U
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码

3 b2 z8 @$ d# ^, B  ChipSelectHighTime
" L5 I+ Q2 F& M0 e4 {9 U; v! Y+ {命令之间的CS片选至少保持的高电平时钟周期ChipSelectHighTime+1。支持的参数如下:( r3 ]+ l4 g  A7 {5 L

( E4 O+ ~; z4 e* I
  1. #define QSPI_CS_HIGH_TIME_1_CYCLE      ((uint32_t)0x00000000U)                             , B. E5 b8 E; f  d, m1 _6 C7 t8 m
  2. #define QSPI_CS_HIGH_TIME_2_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0)                     " S6 h3 p' K! q# ~- e, q' p' g) u
  3. #define QSPI_CS_HIGH_TIME_3_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_1)                        `! s+ e! E5 J. j$ Y$ V
  4. #define QSPI_CS_HIGH_TIME_4_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0 | QUADSPI_DCR_CSHT_1)
    2 R" K' A; ]( H3 A. o7 B/ z
  5. #define QSPI_CS_HIGH_TIME_5_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2)                     4 a! N/ C  U+ m  c4 D8 E5 N
  6. #define QSPI_CS_HIGH_TIME_6_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_0)
    / J/ I. R/ j& }& \# q4 i8 f
  7. #define QSPI_CS_HIGH_TIME_7_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_1) 5 @/ t( a" x0 S/ S$ e7 w
  8. #define QSPI_CS_HIGH_TIME_8_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT)   
复制代码
               
- B# _7 T! g7 _0 m  FlashID
- A( G( Y" a$ F2 ^0 `用于选择要操作的BANK,即用BANK1还是BANK2操作Flash。
; Q. ]6 w$ ?3 Y+ \3 W: ?8 [) E
2 x2 `7 y# S% a3 Y% F1 J4 r
  1. #define QSPI_FLASH_ID_1                ((uint32_t)0x00000000)      , b/ R: ~+ |; O! j- y6 W
  2. #define QSPI_FLASH_ID_2                ((uint32_t)QUADSPI_CR_FSEL)
复制代码

( x+ d) K0 F- q/ b  DualFlash
1 Y& d5 i; L( P" \& V  [3 y用于选择是否使用双BANK。
) h* t2 E  A/ s+ A6 G
1 o0 a' K# |5 J8 \
  1. #define QSPI_DUALFLASH_ENABLE          ((uint32_t)QUADSPI_CR_DFM) /*!<Dual-flash mode enabled*/
    $ a8 F: Y! K" Z. a2 g
  2. #define QSPI_DUALFLASH_DISABLE         ((uint32_t)0x00000000)     /*!<Dual-flash mode disabled*/
复制代码
! \5 t% u3 v8 ]" [: F* I
78.3.3 QSPI总线句柄结构体QSPI_HandleTypeDef/ ?) U& X; I8 I! p6 {
下面是QSPI总线的初始化结构体:& ?. F  \8 d( i" z( q
7 Q" r1 @, Z, O( r: N
  1. typedef struct
    3 E8 p. B' `! R9 {
  2. {
      W9 I% P5 A3 Q9 _* S
  3.   QUADSPI_TypeDef            *Instance;        /* QSPI registers base address        */5 B2 r! X- }! ^' z- G$ Z2 l
  4.   QSPI_InitTypeDef           Init;             /* QSPI communication parameters      */
    3 K* ^" |, x3 ?" [
  5.   uint8_t                    *pTxBuffPtr;      /* Pointer to QSPI Tx transfer Buffer */2 X& ?- m9 s$ Q" o8 N& F$ c3 j
  6.   __IO uint32_t              TxXferSize;       /* QSPI Tx Transfer size              */7 D+ M' @/ a  c' w5 W) c
  7.   __IO uint32_t              TxXferCount;      /* QSPI Tx Transfer Counter           */
    1 C5 B7 u, N/ I; s! [
  8.   uint8_t                    *pRxBuffPtr;      /* Pointer to QSPI Rx transfer Buffer */% U" {  P; r) ]; c8 O  p
  9.   __IO uint32_t              RxXferSize;       /* QSPI Rx Transfer size              */& g0 n5 b- t  t5 m7 A/ g
  10.   __IO uint32_t              RxXferCount;      /* QSPI Rx Transfer Counter           *// @5 H' ^$ l9 U
  11.   MDMA_HandleTypeDef         *hmdma;           /* QSPI Rx/Tx MDMA Handle parameters  */
    8 o. R7 `& x% Z
  12.   __IO HAL_LockTypeDef       Lock;             /* Locking object                     */
    $ T7 |. x4 j/ ^& v6 W, x+ T
  13.   __IO HAL_QSPI_StateTypeDef State;            /* QSPI communication state           */
    % c. a7 a; |  ]5 j
  14.   __IO uint32_t              ErrorCode;        /* QSPI Error code                    */
    / I1 b) L0 S' u
  15.   uint32_t                   Timeout;          /* Timeout for the QSPI memory access */ 8 u4 ]1 |( G3 D$ {' u0 j, o% s
  16. }QSPI_HandleTypeDef;
复制代码
- ~: V1 E- b+ J. I
下面将结构体成员做个说明:4 k) g* o$ K) i/ I8 b& V
' D* e8 m- i  I9 g
  QUADSPI_TypeDef   *Instance
( \3 U5 q3 p+ }+ s6 Q/ [这个参数是寄存器的例化,方便操作寄存器,比如使能QUADSPI。) ?1 B6 }& X. s* l
! c9 d: O( w5 G4 q+ ]' A8 G  d$ V
SET_BIT(QUADSPI ->CR,  QUADSPI_CR_EN)。9 @6 ]1 W& s) q: D" {

/ Y9 r9 _% g+ ?/ c  QSPI_InitTypeDef  Init
9 w& b/ m3 D- Q% g" l这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。
6 {% i: k1 Q/ P' \) w. }  y  M3 U$ @) T
  MDMA_HandleTypeDef          *hmdma1 A1 s, L$ X4 ^7 W( q3 a) A
用于QSPI句柄关联MDMA句柄,方便操作调用。+ J5 r1 |" J8 Y& Y  O

; h9 z5 }/ h8 d4 s  其它参数
, X/ f5 R& K2 m) G: G% B% c# {其它参数基本都是在函数内部调用,用户基本不用管。0 N1 i6 |4 ^) Z

' z- ?6 Z7 S' {( U* }. e78.3.4 QSPI命令结构体QSPI_CommandTypeDef
8 J4 J" _5 l7 [! _6 c, C下面是QSPI总线的命名结构体:
1 }" i( {" C( h/ X
. O4 ^$ J4 ~! J' _
  1. typedef struct9 G5 `5 D& o9 c
  2. {
    $ y6 d! s5 _# |* B3 T, l
  3.   uint32_t Instruction;        
    + ?# ~: C  S# B" ^
  4.   uint32_t Address;           
    7 v1 I' C& Y/ P- x& H* R- e# N
  5.   uint32_t AlternateBytes;     
    ( p( D0 {$ E  ^: V& W
  6.   uint32_t AddressSize;      
    - j: s" [) K' t( J8 ]$ h) c2 U
  7.   uint32_t AlternateBytesSize;
    ) R) b& d& G& X8 J1 |7 u4 V; F! o! {
  8.   uint32_t DummyCycles;      % ^  ?6 F! t0 D0 G2 |
  9.   uint32_t InstructionMode;  
    ; u  ]" W4 n; h1 N
  10.   uint32_t AddressMode;      
    ! N: A* u; S; ~: K; w
  11.   uint32_t AlternateByteMode; ; ^" D; u8 E/ }% a. o- k3 p3 N
  12.   uint32_t DataMode;         ! X, s( Q5 u& j6 Y8 k' c, n6 m
  13.   uint32_t NbData;         
    " b) c6 t/ n8 h1 }; s
  14.   uint32_t DdrMode;           
    ' w% X8 E- q  A) b7 Q
  15.   uint32_t DdrHoldHalfCycle;  4 {8 y& ~# n' c& I* D
  16.   uint32_t SIOOMode;         7 I/ u2 _$ ^0 Y8 v' l  ?& j# C
  17. }QSPI_CommandTypeDef;
复制代码

8 Q$ }! D, O; D( o' n9 x* K  j下面将结构体成员逐一做个说明:/ o: E- M! S  H3 T% Y

9 B: ~( a. F9 r  Instruction
% g. t$ S  t: e7 y( j9 Y9 I+ D设置要发送的指令,参数范围0x00到0xFF。
8 q& G6 x: R/ C
7 O" P/ K% @* b/ c& M  Address
! l! i9 z3 D3 {5 p* s0 M设置要发送的地址,地址由是1个字节到4个字节来表示,参数范围0x0 到 0xFFFFFFFF。. A' Z& t1 |' E/ U* C3 }: V

8 A/ C3 G$ s9 g; l7 h- H  AddressSize' d0 x9 X- h( I! E1 [* N  [1 d
地址大小,即表示此地址需要的字节数,支持的参数如下:
6 a+ L0 A8 \/ T' Z
, W! [/ U; {6 n8 \& l) l+ _
  1. #define QSPI_ADDRESS_8_BITS            ((uint32_t)0x00000000)           /*!<8-bit address*/
    " L" l6 H$ X* n- o( R
  2. #define QSPI_ADDRESS_16_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_0) /*!<16-bit address*/; ]1 p7 x  V7 D( y, i3 i8 i5 b
  3. #define QSPI_ADDRESS_24_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_1) /*!<24-bit address*/
    & N! a3 j2 H9 V. R$ E! X
  4. #define QSPI_ADDRESS_32_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE)   /*!<32-bit address*/
复制代码
! c6 r/ F# e6 F" D. ?. G
  AlternateBytesSize' V  A* M$ L7 V; G0 J
交替字节大小,支持的参数如下:
7 ?* i: D$ ^4 {; ~! r4 |) i$ a. l8 l0 P; Y/ ]
  1. #define QSPI_ALTERNATE_BYTES_8_BITS    ((uint32_t)0x00000000)           /*!<8-bit alternate bytes*/! n; D, s1 |3 I" L" Q
  2. #define QSPI_ALTERNATE_BYTES_16_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_0) /*!<16-bit alternate bytes*/
    0 _6 P! t& ]( s: p/ J
  3. #define QSPI_ALTERNATE_BYTES_24_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_1) /*!<24-bit alternate bytes*/; ]0 `3 F6 X: i& [
  4. #define QSPI_ALTERNATE_BYTES_32_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE)   /*!<32-bit alternate bytes*/
复制代码

2 T" y, }  T* r' _) O  DummyCycles6 V- W9 H4 E$ w9 ~
执行空周期个数,参数范围0到31:% R# f( Q4 f! ?
" q- r5 T# q! t' \  t) C, \
  InstructionMode7 y6 l- Q/ }7 M7 c- U  m
指令阶段需要几线模式:
$ p+ B! I/ E8 U9 f0 \
! r- {; _& R0 z5 ~* k
  1. #define QSPI_INSTRUCTION_NONE          ((uint32_t)0x00000000)          /*!<No instruction*/6 ^) x$ P/ v& I* K1 q  n
  2. #define QSPI_INSTRUCTION_1_LINE        ((uint32_t)QUADSPI_CCR_IMODE_0) /*!<Instruction on a single line*/
    * c1 ~: I/ Y1 ^2 d
  3. #define QSPI_INSTRUCTION_2_LINES       ((uint32_t)QUADSPI_CCR_IMODE_1) /*!<Instruction on two lines*/
    # Z4 s% i& f) B; I/ b% i4 M. I0 i1 d5 @2 f
  4. #define QSPI_INSTRUCTION_4_LINES       ((uint32_t)QUADSPI_CCR_IMODE)   /*!<Instruction on four lines*/
复制代码
0 j, o" p5 w+ E# E/ l7 T( ]
  AddressMode0 s6 W$ n+ z. g, I! H6 m
地址阶段需要几线模式:
( M. K- Q& @+ m0 M9 S: E* M# s0 f3 y) B6 L
  1. #define QSPI_ADDRESS_NONE              ((uint32_t)0x00000000)           /*!<No address*/& G* v& N1 }. I) Y/ O# V. i
  2. #define QSPI_ADDRESS_1_LINE            ((uint32_t)QUADSPI_CCR_ADMODE_0) /*!<Address on a single line*/
      G, f( O9 z7 w: Z# d
  3. #define QSPI_ADDRESS_2_LINES           ((uint32_t)QUADSPI_CCR_ADMODE_1) /*!<Address on two lines*/; Q$ U4 _7 }5 }1 K
  4. #define QSPI_ADDRESS_4_LINES           ((uint32_t)QUADSPI_CCR_ADMODE)   /*!<Address on four lines*/
复制代码
2 s+ M4 Z2 a1 t# n* }
  AlternateByteMode
' v4 a7 v0 i3 J交替字节阶段需要几线模式:
9 E* |- q( T$ J  f0 R: l6 H  E. A- I1 K4 c7 `
  1. #define QSPI_ALTERNATE_BYTES_NONE      ((uint32_t)0x00000000)           /*!<No alternate bytes*/
    : b; S) Q. [% i- `3 X, n
  2. #define QSPI_ALTERNATE_BYTES_1_LINE    ((uint32_t)QUADSPI_CCR_ABMODE_0) /*!<Alternate bytes on a single line*/
    8 \: E  r' n& P1 Y8 h% T; X
  3. #define QSPI_ALTERNATE_BYTES_2_LINES   ((uint32_t)QUADSPI_CCR_ABMODE_1) /*!<Alternate bytes on two lines*/6 g8 H1 d! b" i3 Q/ I" g) A. B  E
  4. #define QSPI_ALTERNATE_BYTES_4_LINES   ((uint32_t)QUADSPI_CCR_ABMODE)   /*!<Alternate bytes on four lines*/
复制代码

, P% @& m! X" z# U9 t  DataMode8 O1 w& b' J( x1 g6 ]0 F: h; w
数据阶段需要几线模式:9 Z. {9 k8 |  q+ ]% l% [

' m2 O1 a( P+ V0 V2 I' I. `' i2 Q
  1. #define QSPI_DATA_NONE                 ((uint32_t)0X00000000)           /*!<No data*/' }3 q& C2 A% U9 V" J1 F
  2. #define QSPI_DATA_1_LINE               ((uint32_t)QUADSPI_CCR_DMODE_0) /*!<Data on a single line*/; |% b" o% T) c9 b! t
  3. #define QSPI_DATA_2_LINES              ((uint32_t)QUADSPI_CCR_DMODE_1) /*!<Data on two lines*/
    ) O3 B# ^) t/ k( P$ B
  4. #define QSPI_DATA_4_LINES              ((uint32_t)QUADSPI_CCR_DMODE)   /*!<Data on four lines*/
复制代码
/ h! e$ [  j$ P) F
  NbData5 |) k0 A5 i6 H# k3 P  F
要传输的数据大小,参数范围0 到 0xFFFFFFFF,如果设置为0表示不定长,直到存储器末尾。+ c, i  K0 Y6 j

) L: _% N" g1 a; D  DdrMode
' M1 V" b$ n! ~$ B* S4 C) ~; \用于设置是否使能DDR模式。数据阶段,交替字节阶段和数据传输阶段可以使用DDR模式。支持的参数如下:
& W+ L0 K: _0 {2 x& `5 T0 ?' b* U! A7 M
  1. #define QSPI_DDR_MODE_DISABLE          ((uint32_t)0x00000000)       /*!<Double data rate mode disabled*/
    - u1 H' \1 j$ H8 c; i& C2 c
  2. #define QSPI_DDR_MODE_ENABLE           ((uint32_t)QUADSPI_CCR_DDRM) /*!<Double data rate mode enabled*/
复制代码
4 m: c9 ^6 Q1 w, h6 c
  DdrHoldHalfCycle
5 }2 ~* u  b8 P6 c: o3 NDDR模式下,用于设置延迟半个时钟周期再做数据输出。
, Y9 t8 G' F5 A: h+ O! x% o8 A7 ?4 h) N. ~$ i' M! Z
  1. #define QSPI_DDR_HHC_ANALOG_DELAY      ((uint32_t)0x00000000)      , u2 r, T- k+ ~/ m
  2. #define QSPI_DDR_HHC_HALF_CLK_DELAY    ((uint32_t)QUADSPI_CCR_DHHC)
复制代码
: c1 g5 \5 p- ^* q2 m$ ?/ |, w8 I
  SIOOMode8 C1 r+ w( Y) g3 Q0 p$ Q5 Q
设置仅发送一次指令还是每次操作都发送指令,支持的参数如下:
1 P5 B" B$ Y  v$ v& T
- C% P+ ~. w  _! e, j3 ~3 K
  1. #define QSPI_SIOO_INST_EVERY_CMD       ((uint32_t)0x00000000)     , ?+ W- I/ X: }: I5 b( z1 ?
  2. #define QSPI_SIOO_INST_ONLY_FIRST_CMD  ((uint32_t)QUADSPI_CCR_SIOO)
复制代码
: }, ]: G4 ]/ N# ^7 G
78.3.5 QSPI自动查询结构体QSPI_AutoPollingTypeDef
6 x9 P* o3 `  y& V, o% G$ [! A下面是QSPI总线自动查询结构体:
  V) |6 z* L* l% A, |, k# s9 [# \& c! N8 R( c2 D1 k
  1. typedef struct0 S4 Z" k0 u- T3 N
  2. {
    ; J. R3 X/ p& s- @+ m) x+ ?
  3.   uint32_t Match;             2 W$ p, t6 ^) b1 |
  4.   uint32_t Mask;            
    5 i" c, j; B& H; v. e0 S1 D) D- i
  5.   uint32_t Interval;         - \! T: h7 C. w8 T; {- Q/ i
  6.   uint32_t StatusBytesSize;   
    4 I, r) ?, L) U1 E: N. o0 R: B
  7.   uint32_t MatchMode;       & E+ c% ]( x" G' t2 n& p* M$ d0 [
  8.   uint32_t AutomaticStop;     
    5 T/ Q7 S9 u. k, }8 ]- H2 A
  9. }QSPI_AutoPollingTypeDef;
复制代码
- k2 \8 j. q! l' u( ]6 F
下面将结构体成员逐一做个说明:
2 ^3 o$ j' u% G! P2 `* I% Q, ], J, ~( ]! d
  Match0 \. |" Q% d/ d- H% o# Z5 y6 G- Y
参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器的值与此参数成员值做匹配。参数范围0x0 到 0xFFFFFFFF。
$ J+ H- |6 G; T, G( W/ I- J6 s* j7 t9 B
  Mask+ ^0 h5 V2 Z1 n+ k+ t1 R* Z
用于设置屏蔽位,比如Mask = 0x01,表示仅保留bit0的数值,其它bit忽略。参数范围0x0 到 0xFFFFFFFF。4 X% D3 z" o% w; H/ D4 `' A4 s
4 n, q$ q! t4 }( f$ Y) Z% V
  Interval
3 Z2 G. d2 W- z& y指定自动轮询阶段两次读取之间的时钟周期数。参数范围0 到 0xFFFF。
6 }$ u7 O, [+ t! F" F* O
5 Z; ?1 T$ [% U3 @0 @  StatusBytesSize0 O+ n3 W) E% h4 v
用于设置状态寄存器大小,参数范围1到4个字节。; n! l3 z' ~0 a- Z) M$ n

) F* t' U, ~  N1 B9 f$ D  n  MatchMode. N$ R+ }6 a# e  I
参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器完全与参数成员Match一样(与操作的含义)或者任意一个bit的值与参数成员Match中一个bit的值一样(或操作的含义),比如Mask = 0x01,Match=0x00,MatchMode=与操作,表示不断查询状态寄存器bit0,等待其为0。. E: F) G- q) d7 x: C

/ g3 q' w, {( z$ ^! Y1 hMatchMode支持的参数成员如下:
4 r' \/ p" g, K! n6 G. x
( Y/ G* e% L0 F; X
  1. #define QSPI_MATCH_MODE_AND            ((uint32_t)0x00000000)     /*!<AND match mode between unmasked bits*/' n: R$ h- ]- S) y" E3 n
  2. #define QSPI_MATCH_MODE_OR             ((uint32_t)QUADSPI_CR_PMM) /*!<OR match mode between unmasked bits*/
复制代码
8 h9 T: u# q  Q: j) A' D* S& m& f8 r
  AutomaticStop6 i) _7 p6 q: u) \* J( Z
当与参数成员Match匹配时,自动停止检测。0 W! J' X% `- d9 t$ f' j# y
* B4 V7 V/ G; P
78.3.6 QSPI内存映射结构体QSPI_MemoryMappedTypeDef
5 T, o  b. w8 K下面是QSPI总线的内存映射结构体:
0 C# p+ Q0 z! x0 ~( ]# @$ }, ?$ _5 v0 Y& [4 N0 J/ J! t, I. i3 I
  1. typedef struct) a4 s, B1 h. K) G
  2. {9 B* ?( ~0 v/ o4 K3 [( t
  3.   uint32_t TimeOutPeriod;    # I5 W5 l1 c* l" v. H$ m! N# r
  4.   uint32_t TimeOutActivation;  5 @+ ?0 B6 Y4 f8 w7 H% C$ F
  5. }QSPI_MemoryMappedTypeDef;  
复制代码
9 o, x6 l/ R" I( S
下面将结构体成员逐一做个说明:" o0 m! V; S, {: k3 }" v
7 H+ N3 V- v, K) G7 _6 W$ \
  TimeOutPeriod
) ]5 Y0 L% }3 ^! T. o% g# j2 c/ L4 GFIFO满时,释放芯片选择之前要等待的时钟周期数。参数范围0到0xFFFF。6 E, R% j! }& @

( I& J% `& }% ~* L: ]8 t0 m( v  TimeOutActivation7 v( x) W+ e- `; }* L# Y4 ]
指定是否启用超时计数器以释放芯片选择,支持的参数成员如下:& t" q' `3 S% ~+ W0 e$ X0 @* g

+ G& G2 M) K1 P
  1. #define QSPI_TIMEOUT_COUNTER_DISABLE   ((uint32_t)0x00000000)     3 M5 N1 i3 j) Z2 ^- ~' h
  2. #define QSPI_TIMEOUT_COUNTER_ENABLE    ((uint32_t)QUADSPI_CR_TCEN)
复制代码
! y7 H* R$ e9 Q
78.4 QSPI总线源文件stm32h7xx_hal_qspi.c' z% k( M% ^- n2 I
此文件涉及到的函数较多,这里把几个常用的函数做个说明:
- y$ z2 V+ S9 A, w
! j, F6 h3 T- Z+ [  HAL_QSPI_Init! ]% J+ C$ T. K) Q+ U- F, ?4 p
  HAL_QSPI_DeInit% ]6 W& |! C/ d5 _
  HAL_QSPI_Command
0 G- p( t& p. x  HAL_QSPI_Command_IT
: j2 k+ K; n6 d! ^  HAL_QSPI_AutoPolling
+ q- l7 w; }$ ^% P8 \$ S% P) @  HAL_QSPI_AutoPolling_IT2 v/ H" |" N$ W* z8 ^5 b
  HAL_QSPI_Transmit
7 F8 E; L* V4 I6 e/ b  HAL_QSPI_Receive) t; d1 J4 i7 Q+ h- U$ {4 ^
  HAL_QSPI_Transmit_DMA
' d) j2 w7 e" j+ G  HAL_QSPI_Receive_DMA
1 M/ k! q# @9 L  HAL_QSPI_MemoryMapped
% b# n- |) ]$ z' w, y+ O78.4.1 函数HAL_QSPI_Init
1 E6 |% V: C, l) c0 O  w函数原型:
3 b0 x9 Y( c- ^& _9 m: B5 [5 k8 S! s
  1. HAL_StatusTypeDef HAL_QSPI_Init(QSPI_HandleTypeDef *hqspi)* s0 {8 \' C: w% i
  2. {- h2 X3 X" U/ W# B9 u1 l
  3.   HAL_StatusTypeDef status;2 }; B9 U$ t; n9 j8 `  |0 k* m
  4.   uint32_t tickstart = HAL_GetTick();
    ) ]! N' K) ]- S  I6 U

  5. ( C( @, P% g. x5 S# r- s5 Y
  6.   /* 检测句柄是否有效 */2 Z7 S7 e7 f. o2 D& `( p
  7.   if(hqspi == NULL)
    . `; n" j: C6 o. s8 x) G4 M
  8.   {$ N# A2 z9 ~7 j
  9.     return HAL_ERROR;% K: w' I: |' X
  10.   }
    ! z4 u" G: H* \1 w( r
  11. 2 [6 c5 G' Q( H
  12.   /* 检查参数是否有效 */( A; B, ^' i$ H6 i: r  G& r+ ~7 B
  13.   assert_param(IS_QSPI_ALL_INSTANCE(hqspi->Instance));
    3 g9 m' K% T1 C2 {$ `! p: j
  14.   assert_param(IS_QSPI_CLOCK_PRESCALER(hqspi->Init.ClockPrescaler));4 m/ e! ?* |  w" x2 l& x5 x
  15.   assert_param(IS_QSPI_FIFO_THRESHOLD(hqspi->Init.FifoThreshold));
    2 J! \7 m% t( c& c: Z# m# }
  16.   assert_param(IS_QSPI_SSHIFT(hqspi->Init.SampleShifting));; ?6 y8 t5 P: M" l' h
  17.   assert_param(IS_QSPI_FLASH_SIZE(hqspi->Init.FlashSize));
    / x  q9 R% _3 ^" d# C
  18.   assert_param(IS_QSPI_CS_HIGH_TIME(hqspi->Init.ChipSelectHighTime));
    1 z3 J3 @# F  r% G3 T- q
  19.   assert_param(IS_QSPI_CLOCK_MODE(hqspi->Init.ClockMode));( d% `0 o9 I" ]! q# X
  20.   assert_param(IS_QSPI_DUAL_FLASH_MODE(hqspi->Init.DualFlash));
    ! P, t5 t# ^" P9 Q" s' m& S
  21. % p4 K$ a+ j$ a. [% T
  22.   if (hqspi->Init.DualFlash != QSPI_DUALFLASH_ENABLE )
    ; K7 g9 s! h7 d% D
  23.   {
    8 f3 C* }& K9 u
  24.     assert_param(IS_QSPI_FLASH_ID(hqspi->Init.FlashID));
    5 W, P" N# ?1 f
  25.   }
    + `* U% y( d6 r' i
  26. 4 y, e1 x( u* `  O
  27.   if(hqspi->State == HAL_QSPI_STATE_RESET)
    ) v' B6 O1 T5 P
  28.   {
    $ I# \- B  t/ e
  29. ( S* l* z: ^* R1 I, m
  30. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1)
    . m) U) }5 J* |
  31.     /* 复位状态,设置默认的回调 */: Y: k, F$ B; V$ ]8 f3 r8 X6 n
  32.     hqspi->ErrorCallback         = HAL_QSPI_ErrorCallback;) T8 c" y: P) }; a* {1 `8 n5 j
  33.     hqspi->AbortCpltCallback     = HAL_QSPI_AbortCpltCallback;; A2 U+ H  h' f
  34.     hqspi->FifoThresholdCallback = HAL_QSPI_FifoThresholdCallback;
    + w+ `/ N& X/ D: ]! w
  35.     hqspi->CmdCpltCallback       = HAL_QSPI_CmdCpltCallback;" K* j+ g; v8 N. v" h$ V: d
  36.     hqspi->RxCpltCallback        = HAL_QSPI_RxCpltCallback;7 I1 a( {% Q3 M# \$ o  c
  37.     hqspi->TxCpltCallback        = HAL_QSPI_TxCpltCallback;. {1 r! X7 _# {; o
  38.     hqspi->StatusMatchCallback   = HAL_QSPI_StatusMatchCallback;' d% R! M- F" d2 i1 ?* G* w+ y8 p7 q
  39.     hqspi->TimeOutCallback       = HAL_QSPI_TimeOutCallback;3 n: q% Q' y* l5 b
  40. / U: L% O# B- p- X
  41.     if(hqspi->MspInitCallback == NULL)
    9 {, r+ M  w/ n6 m4 ]
  42.     {
    7 T. G$ L. y2 H: L
  43.       hqspi->MspInitCallback = HAL_QSPI_MspInit;4 [1 D) Y) k9 K1 o3 e9 K
  44.     }
    7 Q& r, b9 y6 o
  45. 6 G( r' l' C7 t( h6 Z% E
  46.     /* 初始化底层硬件 */
    $ D$ O) F$ R) |0 y  c
  47.     hqspi->MspInitCallback(hqspi);( Q+ |! j* q7 A& N3 l9 s
  48. #else
    3 I: E. L& w0 u" B+ Z+ v
  49.     /* 初始化: GPIO, CLOCK */4 Y; L. w. Y. r6 F; P5 q" _
  50.     HAL_QSPI_MspInit(hqspi);
    / v& I4 o$ v8 j& G' K; ?- k
  51. #endif! B2 H! i5 A7 J4 y+ X9 m9 x

  52. - Q/ v: L  u  x
  53.     /* 配置QSPI内存访问默认的溢出时间 */
    . G) w8 j9 m# B1 [' j
  54.     HAL_QSPI_SetTimeout(hqspi, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
    : }/ B- G4 f% v& q  |; p
  55.   }5 k5 {# y. E$ R2 t6 r9 N
  56. 7 ~! \% n; ]9 H* b# v$ x
  57.   /* 配置QSPI FIFO阀值 */
    9 L* T1 K1 {- @, P, T# `- S
  58.   MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_FTHRES,8 F( c. E) }2 f" X
  59.              ((hqspi->Init.FifoThreshold - 1U) << QUADSPI_CR_FTHRES_Pos));: Y+ ^* d- n; ~  f
  60. 4 n6 u, D% a- I; l1 t
  61.   /* 等BUSY标志复位 */. }/ n  _% e( i1 K
  62.   status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);
    2 f4 ]7 w1 L7 w

  63. * p0 C) H. A( z6 |) L0 G1 a& _
  64.   if(status == HAL_OK)4 k6 |  U- s; e1 V6 A) `
  65.   {( b+ W8 L& a4 {6 G4 b- e
  66.     /* 配置QSPI时钟分频和采样延迟 */
    ! w. K+ m0 {6 n' P2 A
  67. MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PRESCALER | QUADSPI_CR_SSHIFT | QUADSPI_CR_FSEL |
    4 t  x0 v5 [, Q! \
  68. QUADSPI_CR_DFM),2 W9 r7 W. c, |" c
  69.                ((hqspi->Init.ClockPrescaler << QUADSPI_CR_PRESCALER_Pos) |
    * O+ Y) g3 k) F- w$ p. u
  70.                 hqspi->Init.SampleShifting  | hqspi->Init.FlashID | hqspi->Init.DualFlash));( |# C7 q  v1 E; x: q
  71. ; o7 ^; `* {; v
  72.     /* 配置QSPI Flash大小,CS片选高电平时间和时钟模式 */9 W4 l" O, @: V0 R( ]
  73.     MODIFY_REG(hqspi->Instance->DCR, (QUADSPI_DCR_FSIZE | QUADSPI_DCR_CSHT | QUADSPI_DCR_CKMODE),* ?! f% n" j: f4 b2 l, n! f
  74.                ((hqspi->Init.FlashSize << QUADSPI_DCR_FSIZE_Pos) |: x' I4 C6 G- B0 T
  75.                 hqspi->Init.ChipSelectHighTime | hqspi->Init.ClockMode));& B$ g# C0 J9 `8 x
  76. . D+ v: P* S/ U7 P& O! ^: Y, M3 q2 y
  77.     /* 时钟QSPI外设 */
    5 U6 r# a7 f4 B9 k3 \
  78.     __HAL_QSPI_ENABLE(hqspi);
    2 v/ z( I8 t7 Y+ g# c
  79. 7 I! x# A! |% V' A  l& D
  80.     /* 设置QSPI无错误代码 */
    % m! p! Q# n( V9 e5 F1 v; t1 J3 ?
  81.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;+ z* k' ~! _, F0 K2 ^8 O

  82. 8 h1 j. x+ d& b
  83.     /* 初始化QSPI状态就绪 */
    # a" Z& H4 Y3 \* F
  84.     hqspi->State = HAL_QSPI_STATE_READY;9 K4 M, O0 `: P( X) ~9 h
  85.   }/ b+ \1 p3 x9 R, n6 d$ ?! g, e+ r7 `
  86. " b. j3 I( D9 s( I' f. ^, s0 [
  87.   /* 返回状态信息 */
    . f/ A3 F. a- v: @
  88.   return status;3 s: H; Y! ^" Z& \/ V4 {
  89. }
复制代码
( k0 Q! p3 |: R- L5 B8 v) v! R9 g
函数描述:$ U0 {$ \1 {5 E2 [% S8 i

  J5 ^. e" }# }9 ]9 r) Z此函数用于初始化QSPI。5 q6 V- Z8 H+ D! t- j' N( C4 g
& _) }8 {8 f1 B4 S% Y- Y6 p; v5 V
函数参数:
* C6 h" {5 z+ M& V3 R9 }3 h; V7 _- x2 k
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,详见本章3.3小节。4 M" Q4 k! t3 y; I8 G; N
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
% L9 p- H2 O- o. j+ @6 x注意事项:
( o( D% g% N1 v* v/ l( L: {/ _- e7 H' ^
函数HAL_QSPI_MspInit用于初始化QSPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。0 A9 p7 N6 S" P/ w* l( r3 b
如果形参hqspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量QSPI_HandleTypeDef SpiHandle。+ T) q7 ?# i4 ]. O, ]  `
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_QSPI_STATE_RESET  = 0x00U。; V$ @4 b4 J* R9 Y( g# x5 n5 @# V6 U

8 X% D: f  l6 G6 ^. R, D解决办法有三. h6 Q% d5 c" i3 v! `
/ I* j1 v: E) {- i5 Z* T8 D" p
方法1:用户自己初始化QSPI和涉及到的GPIO等。
' B% A! E8 C# A% j- z! J
/ p6 W* M/ e" w9 X0 p方法2:定义QSPI_HandleTypeDef QspiHandle为全局变量。6 b  R8 x# H, \5 Q

! n$ x- h2 E: u* ]9 |方法3:下面的方法( Y  U: f# C# i& V

# P: m& C) O/ E  R5 r5 i( T
  1. if(HAL_QSPI_DeInit(&QspiHandle) != HAL_OK)
    6 w) r, _2 A6 `! A; B+ ^
  2. {  g/ Y. B% e5 K
  3.     Error_Handler();
    - ~1 E3 ~, `8 I, Q) L
  4. }  0 y& W5 e* D; T6 a6 @; X' q
  5. if(HAL_QSPI_Init(&QspiHandle) != HAL_OK)7 m! F: J4 A3 r; w
  6. {$ B, X6 @, `6 w, N3 K7 E' s
  7.     Error_Handler();9 Y" T, X) Z" }1 M2 `
  8. }
复制代码

" c# u. e% n% L使用举例:
( b- {' e$ X2 u# l! C+ [& u& g: T6 c" h
  1. /*4 X+ V. c! J) q5 P& Y) g1 ?
  2. *********************************************************************************************************" g5 a% I- r9 c
  3. *    函 数 名: bsp_InitQSPI_W25Q256
    7 a. j+ j% a: d4 ^8 d+ X
  4. *    功能说明: QSPI Flash硬件初始化,配置基本参数( F7 U2 E0 s  h) F. x
  5. *    形    参: 无
    5 O2 Z' S7 w- J9 d, }
  6. *    返 回 值: 无& F. A/ j4 h3 C, s: M- H
  7. *********************************************************************************************************0 L% X8 x% E' G+ n# s
  8. */% ^6 d+ w9 W9 R2 t- M# n$ p) `
  9. void bsp_InitQSPI_W25Q256(void)( k7 R7 G: |7 H. O1 C
  10. {% @% z; W/ I; I7 Y6 @# I: _
  11.     /* 复位QSPI */7 w6 S3 W1 k9 m. s3 l: y* ^
  12.     QSPIHandle.Instance = QUADSPI;" ?0 q+ t8 Z$ N, L. U5 D; ~& d3 x
  13.     if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)# v! B! s- d: x2 G
  14.     {
    * K, ?/ x3 d9 D& z
  15.         Error_Handler(__FILE__, __LINE__);, W, k4 p5 _, `6 S
  16.     }0 E( Y2 I& I. z

  17. 5 O; }: ]% {; C& @' Y/ ^
  18.     /* 设置时钟速度,QSPI clock = 200MHz / (ClockPrescaler+1) = 100MHz */
    8 k, J5 P5 Z4 L
  19.     QSPIHandle.Init.ClockPrescaler  = 1;  7 p$ L; U  x+ j
  20. 5 f5 n9 V8 j' B
  21.     /* 设置FIFO阀值,范围1 - 32 */
    & E1 K* ^  p( T4 [* L4 N
  22.     QSPIHandle.Init.FifoThreshold   = 32;
    : @/ D4 X1 r) a
  23. % z$ j4 Z9 V0 b& J
  24.     /*
    * I" m" E* X$ V$ [/ x
  25.         QUADSPI在FLASH驱动信号后过半个CLK周期才对FLASH驱动的数据采样。
    % L- D7 H7 L/ e/ N3 H0 _) H
  26.         在外部信号延迟时,这有利于推迟数据采样。! B" B0 k  q! b+ W
  27.     */& r, P0 |% O- U; G  A; N
  28.     QSPIHandle.Init.SampleShifting  = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
    . b4 k; p  H9 p" j5 ^$ |# j- j
  29. ; f% |& x! R2 Q1 |+ X
  30.     /*Flash大小是2^(FlashSize + 1) = 2^25 = 32MB */4 |/ T8 s' Z' C9 M/ F
  31.     //QSPI_FLASH_SIZE - 1; 需要扩大一倍,否则内存映射方位最后1个地址时,会异常。
    / K' Z1 t$ N# U5 ^; f2 B( _
  32.     QSPIHandle.Init.FlashSize       = QSPI_FLASH_SIZE; - u/ s& ~+ n% Y0 O5 U3 [
  33. 1 r" {! a( F& w- U0 M$ E
  34.     /* 命令之间的CS片选至少保持2个时钟周期的高电平 */. O0 d8 v; }* f% L& g
  35.     QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;* G7 P+ t, ^; E& i2 |' h1 B5 {4 J( a

  36. / i! s$ C7 _4 r' Y" q
  37.     /*/ O9 c$ `& E0 R0 u, S
  38.        MODE0: 表示片选信号空闲期间,CLK时钟信号是低电平
    + B3 f, F" C% \' b5 Z$ n$ J+ E
  39.        MODE3: 表示片选信号空闲期间,CLK时钟信号是高电平- j7 o4 P3 x0 n1 J3 v5 V
  40.     */0 d3 X+ I$ x, q! v
  41.     QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
    4 Z& X# z* \7 G  ~0 O; Z

  42. 8 o4 |7 _6 r. n- z6 b
  43.     /* QSPI有两个BANK,这里使用的BANK1 */, }/ x7 t9 |9 ^; ^& J
  44.     QSPIHandle.Init.FlashID   = QSPI_FLASH_ID_1;
    4 g6 C( y" o+ W! L
  45. & L4 i% s. f" v# X# Y& \* z' E) ?) {$ [
  46.     /* V7开发板仅使用了BANK1,这里是禁止双BANK *// c" ^1 R2 Y3 c, U" k
  47.     QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
    , Y6 `9 e! K( s5 K' _2 ^7 d
  48. * ?4 O# ]9 [: b0 U& q/ @" E5 X* M
  49.     /* 初始化配置QSPI */+ O/ T* P/ ~* K8 @9 {
  50.     if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
    0 i. C* H# X/ \8 D3 F' J* C7 `
  51.     {% V; ]. m8 v3 R& H
  52.         Error_Handler(__FILE__, __LINE__);/ i/ m, i' U7 z# r7 h: F
  53.     }    $ F! v, |5 ?; f9 X
  54. }
复制代码
& A7 Y5 }6 s! m1 x1 C
78.4.2 函数HAL_QSPI_DeInit; Q# V( M/ }; E2 B* g1 j0 Y' M
函数原型:
7 M6 ~% q( E) w& d: Z( Q
5 j$ y6 t0 Q) ]5 F; u
  1. HAL_StatusTypeDef HAL_QSPI_DeInit(QSPI_HandleTypeDef *hqspi)  G! C2 C8 t: E* u% y
  2. {8 C1 ]/ f4 p# R. z
  3.   /* 检测QSPI句柄 */% Y; f# Z. e6 K
  4.   if(hqspi == NULL)" M+ j' u5 _9 ~% w
  5.   {
    ! }* C# L( I$ f6 C
  6.     return HAL_ERROR;
    1 X( G9 r5 I9 Q/ z2 i
  7.   }
    * a2 f# m1 b9 m# w+ ^$ t
  8. 2 U+ T! ]' l+ Q  |2 w  E9 G
  9.   /* 禁止QSPI外设时钟 */
    , z( R  b- u2 m" Y/ }
  10.   __HAL_QSPI_DISABLE(hqspi);
    6 N( F# U3 h0 c1 W( s

  11. # x6 s/ e) h/ ]/ ?* O6 i& k; }
  12. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1)
    $ J  Y* N1 j. e) C
  13.   if(hqspi->MspDeInitCallback == NULL)6 B) L; P. Q+ d/ `
  14.   {
    & a3 b6 [" H$ n* f
  15.     hqspi->MspDeInitCallback = HAL_QSPI_MspDeInit;7 S" x- h1 x3 W% G# f* |0 G5 c' q
  16.   }
    0 }4 X7 ?3 m* P# w- g0 y% w
  17. 0 r* l6 P/ E- `$ T  w8 f  L
  18.   /* 复位硬件底层 */
    / L. p/ [- ]- C( l
  19.   hqspi->MspDeInitCallback(hqspi);
    8 Z! m( c$ C, c# o! p' m
  20. #else
    ! }: u7 z9 ~  P% M+ U- A
  21.   /* 复位: GPIO, CLOCK, NVIC... */
      ~! E7 }" f# d" }, Z5 n1 @  H
  22.   HAL_QSPI_MspDeInit(hqspi);" z2 v; b7 ^- Q4 F& X
  23. #endif8 Z7 {  o$ n) [' y, |, O: H& a! ?) F

  24. , A. r; }+ k, y. N
  25.   /* 设置无错误 Set QSPI error code to none */1 o$ P% e# }" Z# i
  26.   hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;9 H( j' D, C3 u
  27. 2 F( j( P# p4 l  z: j9 r
  28.   /* 设置QSPI状态为复位 *// _3 ?4 V! a4 {% S6 r; X* w! e7 c6 ?8 m
  29.   hqspi->State = HAL_QSPI_STATE_RESET;% u0 p9 u% ?5 z- I+ x! T; \
  30. $ L* f' }6 l3 Z" r! {5 o. ?
  31.   return HAL_OK;% j7 {! X4 N6 {& h% k8 h
  32. }
复制代码

$ h3 v! |# m7 k& J! r; H; a: D5 M# [/ o函数描述:/ p3 m5 {" ^* N5 e
% m- s# r3 D6 t
用于复位QSPI总线初始化。
1 \# x/ P: c: M8 \
7 u: [. O: v4 E: V$ s函数参数:: r* b& q$ T; M* M
4 U1 E% @+ d& ]+ b7 e( r- K
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
. H$ @. A9 a0 i+ f1 r  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。) v$ r0 n/ C" U
78.4.3 函数HAL_QSPI_Command; a: g7 J' L( |  ^# n3 U
函数原型:
8 K' u' T0 P5 {5 K# C
" W% `! q6 O5 l1 m6 W; G
  1. HAL_StatusTypeDef HAL_QSPI_Command(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, uint32_t Timeout)9 z% @: ?% n1 H6 L
  2. {
    6 S5 r! u2 }+ `4 |. k) U
  3.   HAL_StatusTypeDef status;
    ( S3 [. z6 d: |- g1 J; k
  4.   uint32_t tickstart = HAL_GetTick();
    8 {6 n. ^" @2 k. d1 z
  5. 9 n# E4 b2 h) r1 W' q
  6.   /* 检测参数 */
    & r* c! {! x; p
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));/ G* {  z/ R* D$ f- \% g
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
    0 ]; ?8 r: H7 h1 o
  9.   {& N' P, ]5 A1 N8 s9 Q+ R, B6 r
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));, ]; j3 t- o" k( B2 M
  11.   }) `6 W' c  o  [3 i7 u1 m( W

  12. * |) ^% c' ?) Q; t
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));0 N( E. H8 I) n7 X# Y+ y3 b4 ^- Z9 g: g
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)9 z- e( Q3 t7 J5 q
  15.   {
    + ~; P  f6 r/ D) k" C/ O+ V5 _
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));  ?6 ^( w( F2 F# x8 `- i  ~
  17.   }  }) s/ A3 w* r: p9 l
  18. ; S6 o1 ]7 N5 R2 C
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    6 q0 o7 m, ?; L/ I8 d
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)4 [" ^) ^3 \) _" c3 Q8 i5 _5 D
  21.   {. b3 J+ Y3 |! b. \" v
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));% _% O# @# q% j$ q( ^" R
  23.   }/ P8 G2 O+ G4 s. c2 w0 ?

  24. : H1 h: Q) N, ?* q$ o5 |
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));( k' {) L. B$ ]0 I9 k( H8 Q( J0 b% f
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    5 z. a+ A, f# ~& ^, D7 X5 X
  27. : b  a: Z# o! l3 ?4 |
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));2 l% l, w" o' c" M3 o
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));6 F6 ~1 I8 v5 d0 ^+ E
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));
    4 V! c2 D5 H' A, [! |% n

  31. + b4 M1 a" j) g( R
  32.   /* 上锁 */
    ' p4 p, L1 l# m- {3 X
  33.   __HAL_LOCK(hqspi);
    : y% B9 W; d- A* Y: I
  34. % }$ i. ~* Q* ?; p5 Z- C6 g) b5 w& C
  35.   if(hqspi->State == HAL_QSPI_STATE_READY)* |" [1 C+ U2 }% |' w0 I9 K
  36.   {
    " H- }4 E9 l( {! b
  37.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    1 d& P) I+ |8 X2 `9 F  e( g

  38. ! N! ^  A! q7 r* O% ?4 ^6 v8 W' u
  39.     /* 更新QSPI状态 */
    / X7 e5 m) |' Q) U/ X6 j9 \
  40.     hqspi->State = HAL_QSPI_STATE_BUSY;. j4 x0 i; j9 T  h) }3 j

  41. ; `- [$ u, n' j
  42.     /* 等待BUSY标志复位 */3 c4 }# N% Y8 p7 G; B- S) q8 L3 @
  43.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);8 ^) r, x" U) b1 o2 `; z
  44. , q" P9 F: z% u4 Y# U% W# f) L5 B
  45.     if (status == HAL_OK)/ u5 X8 `$ W# K7 f7 f
  46.     {! [) w6 H5 r' Q& }3 j& o
  47.       /* 配置QSPI  */
    / u4 a0 C3 y' G" q" [
  48.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    $ h, s# w5 i8 f0 N2 C! x& e, l

  49. 9 c4 h# [& A% q) n  y3 C& e1 A8 I
  50.       if (cmd->DataMode == QSPI_DATA_NONE)' G& T7 W! H9 C" V+ Y
  51.       {, Y2 M2 }& F% L2 `
  52.         /* 没有数据阶段时,配置完成后立即开始传输,所以请等到TC标志设置并返回到空闲状态 */
    % p2 s# w  F$ x, q5 t" {
  53.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);
    & y! O) f. N4 i' \! e
  54. 5 ?, k2 I" ~9 n1 |
  55.         if (status == HAL_OK)5 S6 S2 |1 Z" W4 V/ n4 A  y6 n
  56.         {
    % I) k. y7 x7 ^& |& b
  57.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);3 n9 S4 p7 m  @
  58. : r* z; g* v$ ^* |
  59.           /* QSPI就绪 *// |7 B4 M6 D4 X* c) |4 V0 s7 a( i
  60.           hqspi->State = HAL_QSPI_STATE_READY;/ B; S2 c4 ?9 C4 w6 g) M7 d
  61.         }$ I7 u1 Z; s3 j( e  S( o8 S  O9 b, L
  62.       }' L4 c" |* h4 J# Y$ w* X2 `
  63.       else
      ~7 c/ x) ^0 K! T/ r4 Q' P7 c
  64.       {: r$ P, M6 s5 n; l
  65.         /* QSPI就绪 */& M) Q6 N2 R0 b2 S8 ~
  66.         hqspi->State = HAL_QSPI_STATE_READY;
    ( R, Q5 t; r! ?7 y, X8 }4 v* g( e
  67.       }9 U, [: r. v! L5 U, s
  68.     }
    & I: r- g- [5 L8 z1 b* O0 q
  69.   }
    - ~, B3 y7 Q( u9 f; p# `0 Z
  70.   else
    1 {; n: ], r# }: H! A
  71.   {
    : f; \; u; d% ]. c9 I9 x) |  H( f
  72.     status = HAL_BUSY;
    2 g0 R) |& S' q) W- ]* _1 \
  73.   }. t" d( j9 r$ G+ B

  74. 4 q8 F' i1 n) q4 ]) K
  75.   /* 解锁 */
    ' U0 i% p. T2 F) I! S! c
  76.   __HAL_UNLOCK(hqspi);6 Q2 n  ^# w( K
  77. # b& U3 p0 p: o2 q7 R  [1 p
  78.   /* 返回函数状态 */
    : Y9 g& s+ e) ~9 D
  79.   return status;5 V0 P$ M. e. k# a* [% \
  80. }
复制代码
, \' W- F, G2 G' `& L
函数描述:7 ~% V9 X" \3 [1 B. o1 V7 U  [

$ J2 a( P" w' W+ H! @- U9 h. O7 {此函数主要用于为QSPI Flash发送操作命令,查询方式。, f# {" R0 I0 K$ R0 S$ h7 W; P2 Z1 A
: A( }3 I7 n1 I5 j7 F# u. l) z" ^  o
函数参数:
/ b; \% U7 C; g8 e) k9 g7 A4 c/ l3 _$ \9 y5 o- [
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
2 y- D& i+ K6 ]5 U) C7 A; |  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。1 _) _9 h* S0 m" I* }
  第3个参数是溢出时间,单位HAL库时间基准,一般我们设置的是1ms。! R; V( U& A+ J% ~9 y9 k5 v  w
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。! @0 ]# ]/ b$ z8 _  _, X3 O
使用举例:
% n( p  I7 X2 G' T5 `7 j1 L. `
. V' M  u# k  Y7 v
  1. /*9 c$ j0 J  v! s- r. x
  2. *********************************************************************************************************- D* n" o1 d- p5 m9 q
  3. *    函 数 名: QSPI_WriteEnable, t# K6 ?* u$ ^6 w+ |0 f
  4. *    功能说明: 写使能
    ( |# \4 r/ L0 A
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。
    9 j3 F3 [8 `0 E# N0 n; Q
  6. *    返 回 值: 无
    3 [8 |# U4 }/ b% g2 Y5 E2 j1 F) t
  7. *********************************************************************************************************
    6 B( y, K! d) o" \
  8. */$ |3 G. T1 y$ n# n; T) E! h2 x1 C3 A
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)$ G8 ]3 r3 v! d5 V8 h! @
  10. {
    4 j7 z9 s4 E! C) o9 v
  11.     QSPI_CommandTypeDef     sCommand = {0};
    6 S3 j  M- T' o" m* {* G# W8 ~
  12. 1 g8 e! u% x* J3 B0 ^
  13.     /* 基本配置 */* F- V- |$ i4 ]2 l9 G; D
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    3 V" q8 H8 K- V6 a
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */5 _5 X* a* d2 ~& N. u, [, n, y; A
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    " H' a' w7 l+ ?3 d% E0 }, @
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */! ?, m! B, ]: B" W! E
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
    3 ?$ W( q! {# z$ g4 p. H
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */# r" C9 q. ^' V
  20. . q$ g9 W+ n. t1 Y
  21.     /* 写使能 */2 h8 f/ X+ i9 s; A' I, w
  22.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */
    ' q7 E+ K+ F( u' P3 N; z
  23.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */9 @) x8 `/ _. d
  24.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */2 P, ?$ Z$ e$ M4 F: g
  25.     sCommand.DummyCycles       = 0;                 /* 空周期  */' C/ x6 g7 ~& |0 J$ v; H5 ^1 J
  26. : |( E) d: J7 j& Y8 C1 T% `2 q
  27.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    6 \' a) u3 i4 i$ `3 }. A2 c/ f" X: u' X
  28.     {
    # L) ], w0 t  w$ G- ]2 L; ?6 l) H
  29.         Error_Handler(__FILE__, __LINE__);
    + R  Q  U4 S$ s( Q8 {
  30.     }    ' h5 e' S! I# b# F3 ~
  31. }
复制代码

& V! o# m& R; T: C6 h* u78.4.4 函数HAL_QSPI_Command_IT" g6 P, x+ ^6 }8 X
函数原型:
8 p) Q- v; _7 e; d9 ^* D+ D
/ j* S8 `, a* R1 n5 D$ w
  1. HAL_StatusTypeDef HAL_QSPI_Command_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd)
    ' \) \. [% g& A7 C
  2. {
    : g, c: B" y$ \8 r
  3.   HAL_StatusTypeDef status;+ Y8 V" A7 z- `, J+ o
  4.   uint32_t tickstart = HAL_GetTick();
    3 n: H" b5 e5 Q/ T0 ^: K0 F" |! `* y

  5. 7 v7 f; j* W% V1 Q7 e
  6.   /* 检测参数 */
    * D' l. ?- D( Z! }
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    $ o8 F. _  s1 R% l2 E9 X6 d! d
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
    - y# |6 S+ b6 p3 X- A
  9.   {
    6 S% X' {  ~5 Y
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    - o& l; q+ u7 M6 ^3 f7 N
  11.   }
    * X9 m' H4 u) {# L0 L5 p7 r' u7 }
  12. 2 b, k( Q* l& @7 G
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
      D6 A1 }# C* P" V
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)- U' Z0 p. A5 ~9 S- i
  15.   {4 w% ^, z; e2 A4 H: G# y; ~
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));/ f: B  n* L4 [1 c3 ?
  17.   }' X8 ?; @; k$ [6 ?

  18. / c6 S. @# l  z& [6 Y" P+ K
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    0 M% x  X# K. P8 P7 h  r
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    - E7 N4 Z; i# H/ y) w
  21.   {
    0 u3 x; l% Q) d. A
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));* k- ~- f6 [8 |+ D( h, r
  23.   }. g" K; k7 E& @4 i& x' b9 I

  24. * m, J. E$ n& V- f
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    ( u" n6 M* K7 k  }. C
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    5 m/ q, W. i5 F

  27. & }+ T! Z7 e; K; \9 Y
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    0 y, _/ ?. C6 [( X2 z9 v1 s
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
    7 w9 o: v/ F3 v  k$ O" [" d
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));/ F7 ~6 C0 Y! ?8 G

  31. ! U8 u* \  H$ M5 b- d
  32.   /* 上锁 */
    + }( R# k. R0 _+ b1 D# V
  33.   __HAL_LOCK(hqspi);
    " L. ^) Y9 t" f' }& b6 Z/ G

  34. $ e+ o% i# Z( b8 ]$ C
  35.   if(hqspi->State == HAL_QSPI_STATE_READY)
    ' q" F& t  x' `6 W: Z6 [
  36.   {
    2 S% i- c/ ?0 N
  37.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    - u2 _5 \( r+ m$ |5 w9 e

  38. 9 m* H# j. f1 T
  39.     /* QSPI忙 */
    ; [, _/ X/ ?' g" A+ h
  40.     hqspi->State = HAL_QSPI_STATE_BUSY;
    % _$ r+ x  f0 M& M7 z9 w  N

  41. # a: {7 D* q( H
  42.     /* 等待BUSY标志复位 */& G: g$ [, r8 i; Y, A
  43.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);2 q  K( _9 j( @9 T" c8 Q
  44.   [5 B. b! U% V7 d! r  [1 g" {
  45.     if (status == HAL_OK)
    $ F! g5 o! g8 k; }/ Y2 g
  46.     {" y8 z* L$ ^. I0 P( p* a; |1 b- [
  47.       if (cmd->DataMode == QSPI_DATA_NONE). S$ o) `& p# {8 |
  48.       {7 T- F' r& H5 t. j. [. P; h# S
  49.         /* 清除中断 */
    " J7 T) i! I& L( A6 a0 z: n3 h
  50.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_TC);
    5 G( N, @9 h+ ^+ h( m% c
  51.       }- d# g& }; h9 o0 d5 C% T8 V" ]! P4 ~

  52. 2 G* s: [8 X/ _# n( a0 s1 _
  53.       /* 调用所有配置函数 */
    $ K9 P1 j' Q7 m% g# S' _* T2 b
  54.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);. B$ D2 j; q/ Q- c  _7 T$ ?

  55. ! F' X2 ?2 I7 g5 b/ g4 R1 H
  56.       if (cmd->DataMode == QSPI_DATA_NONE)9 ~) r! O6 W% K! ^! f
  57.       {: b6 w3 w* V5 I4 g4 w7 ^, V
  58.         /* 无数据阶段,配置完毕后,立即开始传输,所以机会TC和TE中断 */% z( w$ A" w9 K  ?1 r5 d) @
  59.         /* 解锁 /3 e! n, }, x1 w$ U, ~
  60.         __HAL_UNLOCK(hqspi);1 `1 Q7 V% H/ a: |# |; I9 J2 `. f
  61. 1 y9 Q# _+ g7 t: \* n/ B& Q
  62.         /* 使能TE(Transfer Error)和TC中断 */" T' k) E( L4 s
  63.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE | QSPI_IT_TC);2 }, O/ r7 M! E
  64.       }0 U4 q1 |# U$ f
  65.       else
    5 e- @! q% h, U7 l6 g
  66.       {4 x* D: \( {7 @- [
  67.         /* 更正QSPI状态 Update QSPI state */+ O/ i, B% A+ `2 e; v
  68.         hqspi->State = HAL_QSPI_STATE_READY;
    - u) F, V1 q* u9 G3 {% [1 g- M
  69. & ]9 t- E  x& q2 c6 I1 f
  70.         /* 上锁 */
    3 e$ H7 p, X" j( h$ \
  71.         __HAL_UNLOCK(hqspi);  T# Y/ w9 s( T; P
  72.       }
    0 `$ s) F6 H3 v' S! f  m
  73.     }
    ! _5 g% I0 H7 z/ u
  74.     else
    / n. l- F9 E0 e: o5 w8 m
  75.     {
    ' D# {+ J0 x7 n
  76.       /* 解锁 */
    * V; n" P7 x& x' |9 a4 S( i, i
  77.       __HAL_UNLOCK(hqspi);
    " {7 [, ]& t% f+ r. u' |9 e! z
  78.     }
    , }$ @2 H4 Y% C' P0 P1 W1 f4 A
  79.   }. T( x" J! _- J# p  r3 U& ]
  80.   else
    ; D. h% D5 w2 ^$ q) i$ Y) S, E8 w
  81.   {% A3 z5 ]8 u5 i: P6 Z4 D) a
  82.     status = HAL_BUSY;
    ! N4 z5 B9 ^+ h; Z

  83. : t' O3 `; u0 i+ w
  84.     /* 解锁 */
    % @2 `1 o& ]" Z) u# p' t
  85.     __HAL_UNLOCK(hqspi);, P! S7 U! o* d8 F) P
  86.   }; Z0 k6 {8 G. Q2 d! F

  87. " I! y+ Z, i* Z$ B' R. {
  88.   /* 返回状态 */  s9 X* e$ a+ ?9 r# ^
  89.   return status;, o& ~) f+ k* P/ b, P& C
  90. }
复制代码

6 f0 V; e0 H' G函数描述:
: v: q, v7 ]" |6 I
2 i  ^& {" q! O此函数主要用于为QSPI Flash发送操作命令,中断方式。
# O% Q& k1 y4 u% q) t
" l8 j0 `" _- E7 A. f函数参数:
- n$ y! j% X  R# K& Y5 G' Y! S+ k2 I6 l1 W  P! c' Y
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
' z2 X+ Q4 ~4 h  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。) R. r2 P% Z& F% ]
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。! H( Y3 v; _7 h/ C/ B
使用举例:) d/ S% X' w/ ?, n& j% o

+ Z2 ~) w% s; X: j3 j
  1. /*; b1 b+ R& ~. c* z  O6 z
  2. *********************************************************************************************************# v  u* S, P  C& R
  3. *    函 数 名: QSPI_WriteEnable
    9 q! i1 }9 q; L9 D# m% z. I2 D
  4. *    功能说明: 写使能" ^) z% z4 `! B' X
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。
    2 i! U! O. \9 l- C
  6. *    返 回 值: 无3 F9 g$ k) o% S3 i
  7. *********************************************************************************************************
    # ~" w! y7 D9 Y' Y* V
  8. */+ k( F$ \2 H; U
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
    4 q7 c7 e* W1 x2 `! s9 E) r9 n
  10. {7 T/ O) e) |$ ^
  11.     QSPI_CommandTypeDef     sCommand = {0};$ }# H. Q2 B+ C3 L1 V1 H3 P; [

  12. 7 r# i: J& w6 J2 w8 Z5 N7 w/ C: y+ p! {
  13.     /* 基本配置 */8 }2 S% |+ Y5 U
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    " b/ w& E% T2 z5 e3 c" B. x+ x
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    ! [1 k  q( V' _: T7 p/ [- h
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */- W6 r' p- G" f3 F* ~0 U# T3 c1 ^
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */) @, M% n& Y" `3 S' X6 i& _
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */; @% s! ^, G0 f2 Z4 N* ?; }/ c
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */$ x' W8 v& j( Y. A

  20. 8 ?; I% B6 t3 N7 c$ C
  21.     /* 写使能 */5 }1 O8 s) U3 S$ Y; @
  22.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */' [2 W' j0 u( b
  23.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */: X9 ~! F+ f9 W7 J+ B
  24.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */
    , }3 V! |2 q6 I: N; z
  25.     sCommand.DummyCycles       = 0;                 /* 空周期  */
    * P( p8 E7 M; o& r; _

  26. # F" u0 g- w9 x; l
  27.     if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK)  X+ T% n7 C- D+ e, K/ e7 _( R
  28.     {
    # S% r$ ?  i4 N7 ^# `3 S' e0 G
  29.         Error_Handler(__FILE__, __LINE__);( _& `/ ?  Z* r  I
  30.     }    ! `8 }9 }+ \3 k7 ]- H
  31. }
复制代码

3 {1 w- W1 Y) {+ s" q% ^78.4.5 函数HAL_QSPI_AutoPolling" r+ s+ F9 G5 B. L8 p7 |1 _
函数原型:2 _4 r  h, F9 \) s

4 {' |. [- x7 u. H
  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg, uint32_t Timeout)
    - m) h: J) y4 R) K2 L
  2. {/ J, P+ H8 `4 A# R
  3.   HAL_StatusTypeDef status;/ S% P6 {& g% D! ^* P
  4.   uint32_t tickstart = HAL_GetTick();
    4 g; r* U* @3 u
  5.   f0 P- \, b9 N# N! [
  6.   /* 检查参数 */
    ) Q& }. F. x( D# c  J0 ^
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    ; r, z- i  z, ]5 R6 Q& p
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE): ^- Y  N- }5 l" C
  9.   {
      V  J; h/ `7 g* @6 k6 L7 g! x
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    : _  e8 @" \/ k
  11.   }
    " `, {# M/ O* X: Z$ c7 r

  12. % Z; u2 T* x2 K
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));! d/ r9 r9 I1 [* T4 t: v  J' z% ^
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
    + {7 [/ n8 a: X5 \2 _
  15.   {+ x3 Q8 `& ]1 m
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
    4 s+ L( h, B; c" _& \7 X5 O  T
  17.   }
    + q; d) T' h& t! {% y( O
  18. + s, I, y' |/ G6 L" @' z, S
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    1 c! e' G$ |2 ^3 W( k
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    * h( M4 _0 y$ Q& k
  21.   {
    , C& \5 Z" W0 g2 `
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
      m3 ?6 R7 k- i4 k7 r6 `3 f
  23.   }. Q* r. y8 f2 I( y- |/ N8 ?
  24. * I& `; i: K) S( }* E
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));  E- r! P4 B8 K' b% B& w+ b
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));1 F2 y  B1 a9 q1 C0 m
  27. + r% `! d0 @- F  K5 I9 E
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));( R/ A2 I: Y' w: c' `2 Y* o
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
    3 Q% l7 N* t5 Y5 u3 z/ ^
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));' h7 [2 q- i* g! L, B) c

  31. & A+ s* f7 D$ t+ h7 t0 [( b
  32.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));
    4 x0 l: u) ?* a
  33.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));
    ' L+ A( D7 h" z: \+ R
  34.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));9 B- c( S) `) Z
  35. 6 _! _+ X) H0 `( ^: M) d- I/ F
  36.   /* 上锁 */! M( \) y1 u9 O% G* d2 S" o
  37.   __HAL_LOCK(hqspi);0 I  Y3 u0 {6 I( h

  38. 5 T( P1 c7 r- @- }' E) ]1 v* T! b
  39.   if(hqspi->State == HAL_QSPI_STATE_READY)$ N; h4 T3 U$ C4 p. |5 r
  40.   {
    5 O/ u( }# s6 i' K: U* I' l
  41.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;3 G2 z$ S1 E8 A

  42. 7 O% x) _3 i- E
  43.     /* 更新状态 *// c7 m" b! G8 Z  V% y; S
  44.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;( Y8 G1 {+ H* S1 U0 m- [
  45. . ~. n* l: W, v3 P
  46.     /* 等待BUSY复位标志 */
    7 A3 G9 u  h: _$ h1 C9 [& H
  47.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);9 D+ }" t8 G2 l- |4 m+ K3 f
  48. / a" E6 h: k) C0 k* p; ^
  49.     if (status == HAL_OK)
    6 i& T7 @! M% D- x( @
  50.     {
    9 z" z! S  \( d" ]7 Z' a$ m* z) v) t
  51.       /* 配置QSPI匹配位 */: L. ^( p7 X; Z
  52.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);: D7 T; X" Y1 v  F

  53. ( F) b$ Q: t/ P- a3 Z3 F8 y
  54.       /* 配置QSPI屏蔽位 */$ b, }5 l% I7 E7 q0 ]
  55.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);& ?2 X, }; Z5 G

  56. $ f% J; ?, O( I, o% h
  57.       /* 配置查询时间间隔 */
    : T- c+ F/ h( m0 W
  58.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);  _& [# Q, V! }" c8 ^( G
  59. ) m* ^+ [! |: i# Z
  60.       /* 配置匹配模式,使能自动停(否则阻塞方式无限等待) */5 l( ]/ |; ]2 E3 C& H5 W
  61.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),
    9 m0 b8 c+ k  Z9 ^$ B- j* |
  62.                (cfg->MatchMode | QSPI_AUTOMATIC_STOP_ENABLE));
    8 `7 m3 |+ ^- C, J+ s

  63. $ z7 S, k0 Y2 ^2 y$ f9 e
  64.       /* 调用配置函数 */0 V8 j' x9 L9 G& r* h0 ]2 f
  65.       cmd->NbData = cfg->StatusBytesSize;3 d, b5 V3 W+ o( r) K
  66.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);
    $ a! M. y8 _8 L9 b
  67. / k2 U/ N+ m' h2 e! a. l
  68.       /* 等待SM标志 */1 D" |  `! A& H8 _  y
  69.       status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_SM, SET, tickstart, Timeout);' h1 [) q* H* f' l" V$ \

  70.   U( \( P0 \# r% f* I
  71.       if (status == HAL_OK)0 \% `" G* h( y0 k  [& }: ^
  72.       {) v6 a# o: S/ U6 h) V
  73.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_SM);
    % f2 ~5 F# q& U  @+ x
  74. # j6 I$ F5 i' l) {  t4 @9 R, t
  75.         /* 更新状态 */$ q. y. Y3 y( N4 N! u
  76.         hqspi->State = HAL_QSPI_STATE_READY;8 ~9 I6 p6 Q! G
  77.       }
    5 s1 n* W' ?* |' I6 T1 ~
  78.     }. ~8 d. \. l* W
  79.   }
    3 H: t( z, F# d& f8 y: ]
  80.   else% Q3 ?1 ^) R+ r  {
  81.   {
    3 |8 h: V7 _3 E. d5 ?! Z; e
  82.     status = HAL_BUSY;
    2 n) ^/ `1 a+ t4 C3 Q+ j, l& p0 I( u
  83.   }5 F; r1 ?1 X" b' w
  84. & K1 u( M/ G1 I' I- c* d( U
  85.   /* 解锁 */; H: w/ l, `. ]: T
  86.   __HAL_UNLOCK(hqspi);5 E0 [4 s# j8 G7 B* r
  87. " Q" |0 g$ [+ k, A5 C* m
  88.   /* 返回状态 */
    # [$ m1 Y6 i2 E' g$ F: @& F# u
  89.   return status;
    6 M; j: b  E+ S9 Y+ B  A
  90. }
复制代码

) ^" ]) D, g8 {- w8 }' q函数描述:
7 p1 G1 X2 C7 }0 @
! ~# o% R5 g% U, v% v, B3 Y用于状态标志查询,函数采用的查询方式。
  v$ e( X5 i3 W( a2 t+ R8 T6 y$ P# L- W: H
函数参数:
; @+ m! s" x7 K* D/ v8 A9 c- E' x5 ~! d- Q2 ?
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
8 i( H1 B( w& c3 N, R  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
$ I4 h: D4 S7 Z0 U. z$ A2 S  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。
( T4 K" O' K1 F5 \3 d  第4个参数是溢出时间,单位HAL库时间基准,单位1ms。0 y$ G' _5 O$ x$ q9 l4 U
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。' i( _" I' J; s+ @) B) X! T
使用举例:
8 L. f+ ]9 I/ v0 W. V$ N& h# C6 I6 x% J. n
  1. /*0 r1 y5 o& R& {% F
  2. *********************************************************************************************************0 P9 y2 j' M. B. }& J/ f
  3. *    函 数 名: QSPI_AutoPollingMemReady, _$ y3 v4 c. E# q+ x3 Z; B4 i
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用
    , r, g1 k# g+ a) x7 T( T5 V
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄
    / ?1 o$ ^% }! `) u2 g
  6. *    返 回 值: 无
    7 i4 b1 O2 u0 l9 r' l1 h4 a
  7. *********************************************************************************************************1 V5 @5 p. I& ]
  8. */
    % q: J/ |8 K8 N( _) o2 f. L+ y
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)
    ! m4 K* q  l2 x+ o# i
  10. {! o# t3 R5 F$ j( b5 z" y% H
  11.     QSPI_CommandTypeDef     sCommand = {0};
    1 E3 i7 s$ R  M4 u
  12.     QSPI_AutoPollingTypeDef sConfig = {0};
    2 b4 z+ ]% @! U, t0 K: T4 n+ j
  13. + A1 y: t# ^- W7 B/ I6 T
  14. " L9 @( e2 z2 i5 E9 o* D
  15.     /* 基本配置 */' I' t" b0 x( V" b  ~/ T* v( s
  16.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */3 q, Q7 I7 b7 n% `9 a" l0 E
  17.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */& q+ [, }# T* L# m, v9 @8 W3 G
  18.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */% Z" {5 Y3 d/ r4 S2 N7 p
  19.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    ' @; P: c5 [; n4 M% H2 {
  20.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */: u; t$ i  b' r) o* o  L
  21.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */
    # N% _" O4 n/ r8 |2 c) d

  22. ! y) m; Y8 @% S5 V+ e; z
  23.     /* 读取状态*/
    3 v% u: z4 W& R, d- n' F
  24.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */. |4 ~* P0 @4 Q) k
  25.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */
    9 l$ }" V, ]1 F- \
  26.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */9 L" [4 Q: r7 W& a6 z% f' Y' P7 a
  27.     sCommand.DummyCycles       = 0;                   /* 无需空周期 */
    ) h2 [) V0 y- M
  28. . ?) E5 E- U) h7 Q" `4 ?' I- M
  29.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */9 _  H. a# o. w% `# f+ l
  30.     sConfig.Mask            = 0x01;0 P9 V4 a6 c1 e" u# l" Q9 k- z
  31.     sConfig.Match           = 0x00;
    0 _5 I& w6 g: h
  32.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;+ `& ?! W7 r$ l. g8 E" f
  33.     sConfig.StatusBytesSize = 1;
    7 d) i- ]+ i0 B1 r0 `
  34.     sConfig.Interval        = 0x10;
    6 J; t# ~1 d4 l) Z+ ?/ ^+ m5 X
  35.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;' A3 h) L; N8 ]" s; {

  36. % g6 C4 u$ p1 j2 f$ u$ j* y& `
  37.     if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, 10000) != HAL_OK)
    9 q% n8 _+ Y4 w+ y5 g
  38.     {
    8 I" ^+ P. m. |* `
  39.         Error_Handler(__FILE__, __LINE__);
    8 b5 P. m6 v5 o) m: |  `! {
  40.     }# d0 U( Q  M( B
  41. }
复制代码
( u4 k, B* u* L0 d+ g1 ?% N, ?
78.4.6 函数HAL_QSPI_AutoPolling_IT
% p' M6 t  s' U函数原型:
( m1 p5 M9 r) z3 w2 H
9 a& }2 j8 L. {$ U$ j# x% s
  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg)4 z. {% }, z6 d$ I$ N
  2. {" L" N& t, c) {  z5 a
  3.   HAL_StatusTypeDef status;2 R9 t8 Q$ u. k
  4.   uint32_t tickstart = HAL_GetTick();
    5 @. ~* S! v$ ~. {3 @% l% {" f

  5. $ z: T7 C( ~! n+ J
  6.   /* 检查参数 */, z8 c% P* m- D) f
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    , Y1 t! \; D' Q3 Z: A& c7 a( [# d
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
    3 I" `/ L. P6 [0 q7 M% }
  9.   {" A' t/ i1 N1 v& g  V
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));( O, [' ?! Q( H4 l; {
  11.   }7 n% ?, a3 N8 [8 Y9 p

  12. 6 f  b4 y; J. |% `! B; }
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));( \8 d1 }/ W+ A6 Y6 T$ o8 j$ R5 [
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)) J% O2 |( E% {! [+ _/ a
  15.   {
    " X$ m5 l! L! Z1 i8 g
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
    2 [( K: l. @% `" x( P
  17.   }1 t3 K, M: M" s- b7 k7 Y9 C7 }

  18. 1 |7 Y& Q5 g; h7 M/ d- d
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    + q- }$ R1 j5 B' D) `3 S& W
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    # Z* Y* `; E( z6 F" {  V. l
  21.   {
    ) E1 W% _  P8 ]: A. o8 U$ a! K- I
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
    ) n( c& r- \2 |2 ?6 V1 r2 Y
  23.   }( L5 `6 ~" w1 ^. i9 Y+ }

  24. 6 y/ Z# |% p( u. h: v! J
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    8 o7 E9 R! f/ D  T
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    8 z& b# J1 ^& q. |7 J" C3 ^
  27.   C1 k  N- e2 Q5 o
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));8 {8 K4 {4 I, q% q
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));' ]$ Q+ @1 O* A" V+ C) [
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));; s% |& m$ \3 ]8 `/ _

  31. + J6 d& ]! R! ~: U2 U' {
  32.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));% _. j$ @. _# f% v. Q, D7 O: a# m
  33.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));- f" t3 b& j8 W# S6 \
  34.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));/ f) g$ A/ P# y- }" H) ?
  35.   assert_param(IS_QSPI_AUTOMATIC_STOP(cfg->AutomaticStop));
    $ l3 [5 {) E" P# k' A' r) @6 s' Y
  36. 1 ]0 p  C! E0 A. x0 O
  37.   /* 上锁 */5 I. c1 C9 `) t. Y; S9 [
  38.   __HAL_LOCK(hqspi);, c/ \: F0 e# K" F
  39. * P5 v6 v0 {+ s. P4 |8 q0 u3 X( |7 C
  40.   if(hqspi->State == HAL_QSPI_STATE_READY)
    ) u$ N7 I4 @$ \) x- A
  41.   {
    2 ?* x  r3 q: E) ~9 G; b
  42.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;" I# p& ~! ]/ _  c' m" f9 d
  43. ! h. T/ }' V3 p1 t' L
  44.     /* 更新状态 */
    . F* F5 O* G/ W
  45.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;9 {& X/ _, u9 F4 u# {2 l

  46. 5 d( N9 d3 o% ^: o; G! h
  47.     /* 等BUSY标志复位 */
    : |7 @: I" x9 ^& d- j4 U, S
  48.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);5 T" l! }) ]) }! D  E
  49. ' {: p, f3 L' U# |7 N
  50.     if (status == HAL_OK)
    / m- z* d9 J# w% v5 L  a
  51.     {9 W; w& d, L, W* o( @
  52.       /* 配置匹配值 */
    2 O3 f' ?) D; W1 F& {* q# C
  53.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);+ m& l, |3 ~" |5 b( _1 b

  54. 5 D7 i5 j  v  f& t
  55.       /* 配置屏蔽值 */5 s* Y/ p0 f( T6 k% s; ^% ^1 b7 Q
  56.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);7 C, f" H# s9 L7 N# j8 _
  57. ' A- T% R/ g" h0 ?' T
  58.       /* 配置查询间隔 */1 M% W% R8 m9 ?6 V$ ~! k! ?
  59.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);6 G6 i0 M# R# Z

  60. 9 J1 L' m$ `& ^9 _1 F  N1 ~' o2 R
  61.       /* 配置匹配模式和自动停止位 */) p7 R5 e* t/ z$ S
  62.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),
    , A1 z5 _& y% ?0 k' j* @8 C
  63.                (cfg->MatchMode | cfg->AutomaticStop));
      O3 @# e# h' W3 h: F# ^4 i

  64. " }7 O) q0 N9 R; ?1 X# r7 Q; `" w
  65.       /* 清标志 */, p/ k, ^# G3 L
  66.       __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_SM);
    ' e; Q8 ]2 R5 g5 I9 p  X. b; A

  67. 4 B0 X5 s+ \. s" u  e
  68.       /* 调用配置函数 */& ~- _& a- c# g% m
  69.       cmd->NbData = cfg->StatusBytesSize;" b% _% [/ B+ p: G8 K! O
  70.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);6 E- |7 ^: @) u; p8 ^. ]

  71. . f; z' f* k& o% k' ~6 n5 p
  72.       /* 解锁 */
    7 C! C  |0 m! S* m
  73.       __HAL_UNLOCK(hqspi);
    . a5 E) `2 }' Z3 O* ?& [/ P
  74.   a4 n/ m- L" h0 Q! ^& @2 \! f
  75.       /* 使能SM(status match)和TE(Transfer Error)标志 */
    5 N* X# h+ m& J/ ]" e
  76.       __HAL_QSPI_ENABLE_IT(hqspi, (QSPI_IT_SM | QSPI_IT_TE));( x- H2 K# {4 w# o, w' x
  77. & |8 q. R' o2 |
  78.     }
    / T4 c/ u2 X. M- ~% p' @. u! X
  79.     else
    , r3 ^; k6 s: ?- o) K
  80.     {" @0 R- p+ W; }" V: I
  81.       /* 解锁 */
    & V: [% r/ H/ v# x+ d" Q; s$ I
  82.       __HAL_UNLOCK(hqspi);% ?2 @0 ?1 Y7 W
  83.     }
    + |& q6 h5 [- v  W4 ?: D, D
  84.   }
    9 Z$ c2 D5 t; u# M8 n' P4 S
  85.   else1 o( \+ x4 X+ U( p6 r- G6 G
  86.   {! U* T  {5 n; z  Y1 K2 U# v- D
  87.     status = HAL_BUSY;+ _/ O  I6 t$ D5 a8 g% K
  88.   y9 o  v5 [  c- T5 x7 Q4 e" [
  89.     /* 解锁 */
    / _3 b& A" l1 y. {  A* @# r- ~
  90.     __HAL_UNLOCK(hqspi);+ e2 a  N: t3 B' E  j' c+ ?
  91.   }" h( N3 N! I  N" u9 @1 y

  92. - ^5 x% ^- Y! Z8 s% K: h. @
  93.   /* 返回函数状态 */
    - X2 Y7 c: i/ W- R$ U0 K4 k
  94.   return status;
    * a! v, X  M; ~; S% D8 ?. X
  95. }
复制代码
9 ?2 B0 R3 z! l" b# e
函数描述:+ s4 A  Q0 V2 i) Q+ T8 }
: t8 a$ u' P. A$ c9 E
用于状态标志查询,函数采用的中断方式。
" \# T- ?4 J. b( S
7 Z* p/ k6 k# F: s: w函数参数:. H& z) w4 W! S, A2 L4 r9 q

( J8 J# K% d# h* R  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。  E8 m/ s. r7 X! Y/ m# F
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。, V  J" |! t! b: t+ j3 o& T8 B
  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。# W& Z& g% X9 O
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。4 N. f1 [1 p: B, a6 s4 ^& [
使用举例:' Z5 w% l& ]0 R5 _1 x6 t+ d
8 R8 O! q  T; T# p: w8 K; ]
  1. /*" G! ]: B7 u  d( b* G
  2. *********************************************************************************************************5 E( V( N! y& O* N: _
  3. *    函 数 名: QSPI_AutoPollingMemReady5 \- O+ p2 ]4 L* C- C4 T4 j. u
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用9 e& x/ ^6 F$ e. R( G8 y
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄
    9 N0 S3 g0 u( {; O. P
  6. *    返 回 值: 无
    . T& Q& U, v- @# T0 f
  7. *********************************************************************************************************; G( e! s6 T& i, n; K
  8. */
    5 y3 s9 Q3 E) n; c7 q
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)
    : ]5 X3 d% v5 Q4 L: y
  10. {
    2 ~  s1 N2 B2 y8 v1 n$ X* U
  11.     QSPI_CommandTypeDef     sCommand = {0};
    4 T/ J: ^2 @/ q# V8 B3 q
  12.     QSPI_AutoPollingTypeDef sConfig = {0};
    & t0 P4 Y3 o8 |: \- ~* _
  13. 4 h& B' z) |$ F' ~" V
  14. 3 v$ U2 Y+ _- }# E4 y
  15.     /* 基本配置 */9 }) O5 U: P: F+ m; y- C+ n) ^
  16.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */" A) c( q' l0 n9 T3 r
  17.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    - o! [. |% |) f; F( M
  18.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    8 i/ h% U( B/ t: F" _. D! ~. q- G6 g
  19.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    7 l& n6 Z( E6 c7 A* I, X
  20.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */* F# s, F- v! ~' r
  21.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */5 b1 p; T0 ?  i  c9 d- Y  j/ Y

  22. 8 ]/ ]# n6 ^0 ?% F& g
  23.     /* 读取状态*/0 p5 [/ b8 t* \
  24.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */, ^* J8 |+ i0 j# V5 c
  25.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */, z; ~7 x* ~5 s
  26.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */% _% a; j& \6 A/ R
  27.     sCommand.DummyCycles       = 0;                   /* 无需空周期 */! `; H; f7 _* n" q8 s5 ~
  28. % K. r8 I! ~. V8 C( a
  29.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
    $ ?5 t) m* f4 K4 p
  30.     sConfig.Mask            = 0x01;
    " m! q# a. _& O, L2 x
  31.     sConfig.Match           = 0x00;: o$ p- A, H6 F
  32.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
    : j* O1 ?6 t& `  p: C3 [$ p& J
  33.     sConfig.StatusBytesSize = 1;
    ) e& G# @: U; y
  34.     sConfig.Interval        = 0x10;
    ! P0 N" ~: _. M
  35.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;1 d! F$ G" n: C0 |

  36. : {7 |( S1 I8 G6 s" w. x
  37.     if (HAL_QSPI_AutoPolling_IT(&QSPIHandle, &sCommand, &sConfig) != HAL_OK)+ f9 S0 T/ o4 X+ l% o( k3 m
  38.     {$ z+ \( x. K' l0 q" ^
  39.         Error_Handler(__FILE__, __LINE__);
    0 T/ |5 Q5 k. L0 }3 c
  40.     }2 {0 T0 r6 B" E! |
  41. }
复制代码
6 i; p+ o3 U  |- o
78.4.7 函数HAL_QSPI_Transmit
2 h$ C& V0 l4 E$ Q" v' X函数原型:
" w0 R' D  N- B
+ T+ ]% D7 x) ?4 x% v, ~/ U# i
  1. HAL_StatusTypeDef HAL_QSPI_Transmit(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)
      n- r+ D' w8 K* F9 l9 o; I0 ^  X
  2. {6 f4 b9 X8 h# o9 {" W
  3.   HAL_StatusTypeDef status = HAL_OK;
    : }' m% b8 T1 G' z
  4.   uint32_t tickstart = HAL_GetTick();: o4 `! O* Y: X  A' Q
  5.   __IO uint32_t *data_reg = &hqspi->Instance->DR;
    & j  w! v' \! f4 S
  6. 2 ?; |/ F$ p& Z9 \
  7.   /* 上锁 */
    9 F  \* J# e1 M4 w6 B9 E
  8.   __HAL_LOCK(hqspi);+ }2 e: b  l( n+ q7 j
  9. 9 Q6 J. R" _1 Y0 {" A. b9 H
  10.   if(hqspi->State == HAL_QSPI_STATE_READY)& k4 @2 S! g" K# C" x; h
  11.   {7 |- F$ p5 K& Q7 r. P% Z
  12.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    ' N! E$ U4 s( _

  13. ; |. P4 L0 m. I9 e' f& T% W
  14.     if(pData != NULL )
    8 z, Z$ C/ j3 u# G' [  H7 @
  15.     {( a4 R" s' b; [( Z$ n) C9 Y
  16.       /* 更新状态 */
    + h0 T  W3 Y& }3 Q: j( N: ~* x
  17.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;
    * J6 q/ B/ X6 [; T( g; K+ o$ g0 }
  18. 0 c. Q/ u' Y: W- J$ s' G8 m
  19.       /* 配置发送 *// M" E9 [) m4 M( v9 \6 x( k
  20.       hqspi->TxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;" C. \: w1 p2 X. D6 |
  21.       hqspi->TxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;
    0 K. r& S0 D7 c# E2 c
  22.       hqspi->pTxBuffPtr = pData;
    ( v# o$ G* C# [' T5 d* N  p! C

  23. 4 {# C. t2 L% g9 w6 ~9 E3 [6 ~
  24.       /* 配置QSPI,间接模式 */
    9 ]# N: F, n; L, w5 K0 y
  25.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    2 V7 m7 Y# \) d( b9 F+ B
  26. & a( B: {# |0 F. P3 _
  27.       while(hqspi->TxXferCount > 0U)
    % p. r9 I9 I4 M, n
  28.       {
    + W+ d- k  m* L6 H" ?
  29.         /* 等待FT标志 */
    6 C& e7 N  D5 c( [! K% I
  30.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_FT, SET, tickstart, Timeout);
    1 w: p! K: T  W) P/ ^
  31. 1 B4 s) H1 }! z5 `0 c2 o
  32.         if (status != HAL_OK)
    9 U% Z$ D( e1 ]& {8 s
  33.         {+ {; e% ^8 ]1 V6 E% @; u- ]
  34.           break;8 @8 }! ?/ M3 X/ b6 H" [
  35.         }
    & i2 K& G2 `( [: v
  36. $ T8 o$ ?0 t! o( b4 l$ x
  37.         *((__IO uint8_t *)data_reg) = *hqspi->pTxBuffPtr;
    ) z$ C) i/ I) m3 `; A3 T, J
  38.         hqspi->pTxBuffPtr++;
    3 u4 X& E6 o7 U4 W+ W; o
  39.         hqspi->TxXferCount--;
    3 b, X" h* }  Z! T1 G
  40.       }; O" ?" h! p) [
  41.   n* u- U- A/ f% O4 B+ r
  42.       if (status == HAL_OK)
    , ?7 p- @' c1 E: j, Q3 r3 n: G
  43.       {4 Y* T0 e) j( W9 r
  44.         /* 等待TC标志 */4 O5 S; `! _6 C! Q1 l  }
  45.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);$ k2 ~2 D5 S. @0 c/ M

  46. & a' F0 ^0 x. j# l: Q* C* Y( g
  47.         if (status == HAL_OK)' D5 Q! E  c$ Q; @
  48.         {
    / y, g* l2 \, e0 Z9 E; [
  49.           /* 清楚传输完成 */
    " c; O+ ]' I  R' P. {( t
  50.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);
    . Q* M$ O7 {1 _5 c8 m" {

  51. 3 i' U7 k  u: h5 i9 n- u
  52.         }
    7 d2 S+ ~" G$ O2 b. Y
  53.       }
    0 F: u2 w" B6 h

  54. . P% ^: k6 v' D% R* c% G% {
  55.       /* 更新 */% W2 }2 i  e. d0 M; V' v
  56.       hqspi->State = HAL_QSPI_STATE_READY;4 S4 f- l0 o$ g) |* H
  57.     }& B( s, s1 a* w9 G- Z2 |& Z
  58.     else& Q7 A* J5 P4 ~/ m- N9 t( I2 E
  59.     {# m5 Q; e. o* [2 f! j* P8 {- ]
  60.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
    6 f- A) b  V+ T- I7 a4 ^
  61.       status = HAL_ERROR;% }; ]$ b$ m6 {. S4 \
  62.     }; Z' D1 r( h: d$ E& D, K; Z! @( Z
  63.   }7 Y2 T, C) r* B8 S. x* F, V: @
  64.   else" K$ ]# H6 K% w2 l/ t
  65.   {
    & i7 O! t- e6 h) [+ |9 N
  66.     status = HAL_BUSY;
    ) ^6 @8 [, c' Z1 ?& `  C8 J
  67.   }
    ! _: S( M+ k1 p' u7 n9 I" q5 U

  68. 5 A% `9 l6 h3 s$ @  i& H
  69.   /* 解锁 */, K" B3 ~$ r4 D: n2 q) A
  70.   __HAL_UNLOCK(hqspi);
    " @4 G6 ?7 h  [( g& p9 v8 ^
  71. . {1 @. I( s' ~  c' h# g
  72.   return status;4 K: G; a2 c( g
  73. }
复制代码
6 `' Q& y' w; L% u- x
函数描述:
% k$ T! w) s2 p2 z1 c
* f) J! [+ Q( s( _5 w1 |此函数用于QSPI接口数据发送,函数采用查询方式。
: _9 Y/ R) }4 ?4 @9 [, P7 K& t- M+ s* N4 G, w
函数参数:* d4 X+ H6 e( ]" H4 A+ f4 E# e
# t- ]' S/ e) _3 s. K* m
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。) @( M- I" l; X+ E# Q& N/ ]
  第2个参数是要发送的数据地址。
* E' t3 g7 R: c  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。
$ ^9 Z, f7 Z1 }  q/ L& \. D  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
  a! V. G, q2 ]# ?8 u使用举例:( p* j6 p/ b* X9 `3 v* z

; @* h5 l  I! Y
  1. /*+ }; H1 W* y& {, p7 S1 P8 O
  2. *********************************************************************************************************. O+ H: j1 G' ~+ V! g) k
  3. *    函 数 名: QSPI_WriteBuffer. f$ R! {+ T5 Z; W  u. O, S+ Y
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入' _0 h  a' ^& k
  5. *    形    参: _pBuf : 数据源缓冲区;
    ; G+ I  @9 k' B: {- n- G
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。
    # `8 r" V/ N2 F6 N+ y9 e
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。
    % l" A; |. [9 n! Y% z0 N
  8. *    返 回 值: 1:成功, 0:失败- @& {- i/ P' [( O/ F5 w
  9. *********************************************************************************************************
    % c3 x" h, [: Q0 @/ ^! }% d
  10. */
    ! t' o- l; ?: t" @
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
    & E2 B9 c1 u6 m
  12. {( b: ~5 ]$ K4 K- ]
  13.     QSPI_CommandTypeDef sCommand={0};7 ?6 R; J, ?( I2 b% Q

  14.   W# L+ O) A7 h( F
  15.     /* 写使能 */
    2 x, B$ b/ U+ J2 l' P) H0 N3 h
  16.     QSPI_WriteEnable(&QSPIHandle);   
    % {; \( G; K% T/ b( ]/ V
  17. - \6 b0 K1 `1 p' c0 P& R
  18.     /* 基本配置 */
    # H7 L  ^: t  ]$ p
  19.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */2 @7 P7 q* F0 i6 P+ w* \
  20.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 *// @' Y# K  p2 X* @. j) J
  21.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    ) k. N# B& s$ n2 c' T* l8 Q0 n6 o! u
  22.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */  Q: H0 b; x4 M% t
  23.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */- P0 b4 p0 d) Y$ M) i+ g% E, p
  24.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */   
      W3 Z! A  u2 e5 G0 r& C
  25. ) B7 ^7 h1 }1 J. o
  26.     /* 写序列配置 */) I" c6 C; w( f
  27.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */3 h4 \) Z" C6 z# d
  28.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */. p$ d6 s$ Z: g2 O! W* Q7 o6 d
  29.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */. D6 F  `+ l7 T+ [! K, ]8 E- l
  30.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
    % p* j9 l" b& q8 g" \1 m0 R: D
  31.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   
    2 L0 i3 {+ ~$ ]: p/ {, g4 Q# w
  32.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 */6 l( d6 y* f" t- D0 C" o2 _
  33. " o; {; D5 e- @8 W2 e
  34.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)" ]# ]# r( R; X! O+ A$ p: g
  35.     {
    ( {3 s# J5 ~+ M. @- q
  36.         //return 0;
    + o5 |' W3 p8 u4 n3 ~: z' f
  37.         Error_Handler(__FILE__, __LINE__);
    $ w4 {" W! V' M) e5 e0 j7 C
  38.     }
    7 o. V. Q; C4 k% u6 B' Q. D

  39. 7 ?& t0 d( H, D6 j! j$ h
  40.     /* 启动传输 */
    * E; O( o0 B4 b
  41.     if (HAL_QSPI_Transmit(&QSPIHandle, _pBuf, 10000) != HAL_OK)
    0 ]0 s: ]. N! f6 f& x( O+ O5 i
  42.     {# N$ O: d. E$ b6 K7 _! H7 p: B
  43.         //return 0;8 n0 B) K% h2 N4 Z; u
  44.         Error_Handler(__FILE__, __LINE__);: o8 d0 c# S! }
  45. $ e9 P4 o$ r/ Q
  46.     }9 B' [+ t5 g, c6 r
  47. 5 F4 Z0 k6 }) A  I! h/ E! l
  48.     QSPI_AutoPollingMemReady(&QSPIHandle);   
    " a8 U" M" a8 ]
  49. * \4 g) m9 E( D+ Q# T: e
  50.     return 1;" `% g4 C: H1 F9 W7 K% Y6 s
  51. }
复制代码
7 Z0 A, H. I3 j4 v7 ?- F  N) ~
78.4.8 函数HAL_QSPI_Receive
4 D" l1 p. q8 a, O5 c函数原型:6 F  d2 x; W& H: i/ H4 a6 j

% B0 v4 Y) b8 `- W2 W; }9 G
  1. HAL_StatusTypeDef HAL_QSPI_Receive(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)) F) p) g8 Q( {
  2. {+ a, f. M: S; n- E) b6 c  u
  3.   HAL_StatusTypeDef status = HAL_OK;
    2 i) M* `) |! h/ s1 m$ q1 |7 a9 B
  4.   uint32_t tickstart = HAL_GetTick();' Y8 s" w) w! F( S0 p1 K/ ?! D
  5.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);
    6 y, e# s+ ]% l
  6.   __IO uint32_t *data_reg = &hqspi->Instance->DR;5 n& N9 g& H+ ^/ V) n4 E

  7. ) F. r8 x% ~. S
  8.   /* 上锁 */
    . d6 N& \9 `8 d2 \  I& Z0 K
  9.   __HAL_LOCK(hqspi);! Q' ^  H/ K. X, K4 d
  10. 3 F- v/ ]0 R( [8 I/ D7 R" I
  11.   if(hqspi->State == HAL_QSPI_STATE_READY)
    6 }4 E7 \5 c: @
  12.   {, z+ p( G9 `4 B
  13.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;. N( Z4 C) G9 ~& M$ P/ w; O5 n3 [9 c

  14. * B7 ^# J" ^: e* E  `& i6 e: W
  15.     if(pData != NULL )5 }9 C6 M) b3 H1 q- \. Y. B( @
  16.     {* p8 }& i8 t6 N6 L/ J
  17.       /* 更新状态 */" V5 O9 ]( v# v% H: Q" F( q
  18.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;
    : H3 G) k. _! @, m6 s

  19. 0 T6 q; d8 V* e
  20.       /* 配置接收 */5 L9 @) ?) W9 B
  21.       hqspi->RxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;
    . I3 j. h3 B/ {- ]  f
  22.       hqspi->RxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;
    7 g5 v  `; y- F7 e1 o
  23.       hqspi->pRxBuffPtr = pData;
    ' l- w+ d- @# @& P9 a1 O+ H2 n- R

  24. 4 J2 ^( i& G/ d* ]4 v- U2 |$ b0 v
  25.       /* 配置QSPI,间接模式 *// \6 E& F! x" M1 u; j, W+ M6 {
  26.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);2 |+ F- }6 ?" o; Y% _3 X) d6 t

  27. ; D4 I! z7 T% [) k3 ~9 f
  28.       /* 启动传输 */
    4 T( H9 w2 |& C3 n
  29.       WRITE_REG(hqspi->Instance->AR, addr_reg);
    5 e5 s3 F9 \0 F8 M+ A+ _$ j' Y
  30. ( P* u; M; ^* Z
  31.       while(hqspi->RxXferCount > 0U)) I* G2 s% W# k
  32.       {
    9 |" ~4 a$ h( q% q
  33.         /* 等FT和TC标志 */  {$ M: w+ ?+ Y
  34.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, (QSPI_FLAG_FT | QSPI_FLAG_TC), SET, tickstart, Timeout);$ q- w; ^1 i" J! Q

  35. ; t9 N* N3 t8 F: D6 u
  36.         if  (status != HAL_OK)! g% U& z* j! f4 n( y
  37.         {
    3 J" r( S8 i0 I
  38.           break;& I4 ?+ X/ u: W0 i
  39.         }
    ' ?3 h8 m6 b8 f" ]4 K$ A
  40.   f( j6 F3 _4 I4 ^5 o' j
  41.         *hqspi->pRxBuffPtr = *((__IO uint8_t *)data_reg);: A7 R9 @. {' ?6 v6 K
  42.         hqspi->pRxBuffPtr++;
    , P& h' [( ^/ n0 W
  43.         hqspi->RxXferCount--;
    # {& N! z) H" `% B& b% a% `
  44.       }3 {9 p0 u7 a( Z- `: G1 W& |3 J  ~# j

  45. 8 g9 q. G" F; J9 ^! Y/ [
  46.       if (status == HAL_OK)
    $ L  t' U& C& G3 [0 j4 a
  47.       {
    ' t$ W) {) N; Z9 X! |! t
  48.         /* 等待TC标志 */
    " Z8 V  @+ g8 a! l! n1 m' {, e- x* Q
  49.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);; q* }) H: r7 ?) x$ \

  50. / X/ u  N! ?/ D- J$ H0 C& W4 m
  51.         if  (status == HAL_OK)8 ~) n+ U1 f, U
  52.         {
    . ]- ]: q# [! c1 Z5 J) j- K' v
  53.           /* 清楚传输完成bit */
    ; R3 s, S( m( h* b7 O  q
  54.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);
    8 w! P7 P1 R# K- b

  55. & }* Z6 i' H2 V+ g
  56.         }
    & J2 q, {; ^4 d' e# R/ U1 r
  57.       }
    - y9 d- E& K- h# Z; T8 N

  58. # G( [  |/ C# |1 Q
  59.       /* 更新QSPI状态 */
    , _" m) r1 Z! _" d# u" t* K; k& X
  60.       hqspi->State = HAL_QSPI_STATE_READY;
    $ `9 q% c* b2 |9 E
  61.     }" y0 F3 J  I! C
  62.     else4 V1 S" C: d" p5 H4 k/ B$ a( g* M
  63.     {0 f- u/ w, `* v; v5 S1 P* Q; f
  64.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
    1 w/ m" u2 j8 k$ _4 f
  65.       status = HAL_ERROR;
    - m1 t) u1 o; y
  66.     }
    ' W9 Y1 t# V/ F$ a
  67.   }. Y, v6 u" |3 Q+ H0 O
  68.   else! L: _* U, P* a8 O: p
  69.   {
    " s( ~* c) b! L* }8 d5 y
  70.     status = HAL_BUSY;
    7 C! |% G: e% A  ~
  71.   }) ~" u. N: t% f

  72. ) l+ l( j( n5 O! y1 N6 h
  73.   /* 解锁 */
    3 u: \6 m5 @( N' N* q" j
  74.   __HAL_UNLOCK(hqspi);
    * n: ?" P5 Q* \$ C$ u

  75. ; m9 ]% F. m# l' X% @/ L
  76.   return status;( N4 k2 D- U* P
  77. }
复制代码

8 s" {1 G) \  u( Z5 n# ?- O函数描述:4 w2 `0 D* |% m8 D5 q7 E

& _0 I1 E  I# |9 R& A. ]9 D' [此函数用于QSPI接口数据接收,函数采用查询方式。
. c/ O8 g8 R* v3 {7 U0 s  {1 R
* D! w" J( |& i函数参数:
" }, N7 P9 y5 G4 i( \" j( E, G4 X5 ]' i4 ^
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。( `: X/ r1 Y& D
  第2个参数是要接收的数据地址。
4 a' q! h* ]: `  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。/ v5 z( V# J4 t+ r  y0 R
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
$ H8 i* R! p0 Y5 Z使用举例:9 N. e$ \( B) U+ n& r( l1 Z
) _9 y- e! S7 n( F' P
  1. /*
    0 ?$ n/ ]$ h( g/ @( x
  2. *********************************************************************************************************$ O4 Q) N2 p) N
  3. *    函 数 名: QSPI_ReadBuffer
    , ?9 {8 F5 a) S
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。* c7 Q' e* y) D# V
  5. *    形    参: _pBuf : 数据源缓冲区。$ w% k% {+ e: R7 v, @
  6. *              _uiReadAddr :起始地址。2 j- v. X8 {9 B3 O% a
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。$ C! U, W' ?% u! G
  8. *    返 回 值: 无
    / V5 b5 u+ w. o* R0 L
  9. *********************************************************************************************************0 @  \1 N8 z7 y3 c
  10. */
    " W3 C! I, I5 Q. i( q( H$ o: y9 }
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize): \/ K- L8 Y! }+ ^. `- w/ I
  12. {
    2 V; x2 c/ ^& N$ X4 _
  13.   A  m$ W" M/ b/ Y' O3 ]( P
  14.     QSPI_CommandTypeDef sCommand = {0};
    9 a' i4 |% m0 V0 F+ Z0 Y" Q
  15. ) h# Q0 G8 [, ]7 {1 w# }9 _9 a

  16. ! q  J+ ]' Z8 L: O. B* v/ q
  17.     /* 基本配置 */
    # {2 }4 H$ c* g: R) k
  18.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */3 W1 o) g+ B/ M; x- K. Q
  19.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */
    - j- l! [6 H- T& o: j4 b; s  r
  20.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 */; _, [# {( m. O, L6 o
  21.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */
    # s# f1 H! c7 ^
  22.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */3 c7 q% s4 A' B( Z. v
  23.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */   
    " ]& M( K0 W8 P5 ]$ H

  24. $ x" R* [$ Z8 k
  25.     /* 读取数据 */
    ; Q+ R+ C) A. x+ h+ p$ x$ Z
  26.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */
    ' q5 D8 d. J1 U! M, O6 K( C) t
  27.     sCommand.DummyCycles = 6;                    /* 空周期 */4 E+ z1 ?6 F4 |- D
  28.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */
    2 F9 d" h. {; |# `
  29.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */ # `6 S) a! l9 q3 O* D
  30.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */
    # Z. M; J& j( y5 _; c' s' Q2 R
  31.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */
    - D& H9 H) A9 l6 H8 |! ^! u- j
  32. 0 N' n) [# a- x$ }0 u, i* L
  33.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
    , P7 V3 H* K+ Q0 T
  34.     {
    ' V( Q/ N! f& c# O0 _
  35.         Error_Handler(__FILE__, __LINE__);
    6 l' ^& P6 Q) i- J9 @
  36.     }: |- H. b7 R2 N# b: u. j
  37. - W8 B& P: _, G3 {: f
  38.     /* 读取 */
    6 M3 r  M. `" Z, I8 o) u
  39.     if (HAL_QSPI_Receive(&QSPIHandle, _pBuf, 10000) != HAL_OK)& z/ u8 `  V  R6 D% U; a
  40.     {
    6 a& U- q1 g& @/ R8 a3 N+ B
  41.         Error_Handler(__FILE__, __LINE__);% i+ x$ D. F- a
  42.     }    ) q! g8 w  `* P
  43. }
复制代码
- l& r2 ~4 A" O4 P8 ]
78.4.9 函数HAL_QSPI_Transmit_DMA) R  v! h5 h8 F1 r% t
函数原型:
$ r- y' ~, E& D% a
, ~# J6 n; P4 U
  1. HAL_StatusTypeDef HAL_QSPI_Transmit_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData)" H: b+ X, \2 W8 k
  2. {
    9 N& v1 I9 }8 V4 I" t8 |9 I+ q
  3.   HAL_StatusTypeDef status = HAL_OK;
    / A3 Y8 N& Q; D& F* Q% c
  4.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);0 J7 H- G- R! K

  5. 0 I1 W% @, E/ {
  6.   /* 上锁 */
    " I% ?+ s- ?% U$ C$ G+ A
  7.   __HAL_LOCK(hqspi);
    # o& d8 f1 \' @5 K+ n& a; h

  8. 8 i% i4 U& S( w7 F
  9.   if(hqspi->State == HAL_QSPI_STATE_READY)! ]  c- w' v  }9 Z
  10.   {
    * J8 b+ @' P6 \; G  L
  11.     /* 无错误 */
    8 X3 }5 u8 n: T/ c9 {8 f1 j
  12.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;4 V1 w0 g" `# v
  13. ; t- `( a% L! A3 v$ o, d  ^/ `
  14.     if(pData != NULL )
    & U% p5 u* D/ k9 s1 Y. y9 L- m
  15.     {
    ! r/ R0 b; u8 R& _& T; I# D
  16.       /* 配置发送字节数 */
      @3 W. t/ @$ u
  17.       hqspi->TxXferCount = data_size;
    5 t% L# e7 s# n, w' g! b9 K

  18. ; S3 s* @1 f+ \5 T1 v  ]7 e/ I0 a
  19.         /* 设置QSPI状态 */  g9 s& H- C' ]3 w: q2 F
  20.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;
    $ x5 `$ |% l+ B: [8 E' V
  21. ' m( h: d: S; y  U; H5 q
  22.         /* 清除中断标志 *// q: H0 K5 t% T
  23.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));
    8 s. ~1 d) A( D1 A+ `

  24. * y5 W% [5 ]0 P  f; B1 t
  25.         /* 配置发送 */7 z0 d; J) O2 t
  26.         hqspi->TxXferSize = hqspi->TxXferCount;+ ~& E( z9 j1 Y( ?4 E1 M- u( H
  27.         hqspi->pTxBuffPtr = pData;& E( j6 Z4 p9 w! e9 j" L

  28. ) S! v9 ?5 E. |9 Y& E
  29.         /* 配置间接写模式 */# J; p! M- G' A, s2 E3 r2 O# N
  30.         MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    ' \/ S! N& y! O& L8 m7 |% b
  31. 0 y! y( P+ l3 e% M& Z: N0 ]$ U
  32.         /* 设置MDMA发送完回调 */# Y- H6 Q: c& U0 X+ I
  33.         hqspi->hmdma->XferCpltCallback = QSPI_DMATxCplt;9 O- e. }, R7 F( Y# G( g
  34. ( n. Z7 _+ u, w+ S
  35.         /* 设置MDMA错误回调 */
    % x0 D2 ~& w; w: e
  36.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;5 M# ?- h6 D$ Z# r

  37. ; e% l! z! y8 H# L& l; @( w
  38.         /* 设置MDMA终止传输回调为NULL */
    ' V+ L+ @  `+ l$ ]: x7 {
  39.         hqspi->hmdma->XferAbortCallback = NULL;
    + f; m8 j$ j' C1 M

  40. 2 n0 K+ S: T3 ^6 E
  41.         /* MDMA的目的地址是QSPI DR寄存器,设置禁止递增 */' [5 ^6 N+ K+ t! m. j
  42.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) ,MDMA_DEST_INC_DISABLE);
    7 H* D  |4 O% c- g
  43. & f2 w" \' r! ~* t0 g
  44.         /* 更新MDMA源地址配置 *// _$ Q* m% W: A" s7 B! k  v4 C" Z
  45.         if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_BYTE)
    2 s$ j% }% b3 {
  46.         {
    9 w$ @" r5 v$ S: B# t" M$ C
  47.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_BYTE);) _  p( u$ K) }) e+ O, m
  48.         }- S% C1 L( h; s' h8 z. l
  49.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_HALFWORD)3 X) Z8 R1 @: v' B4 N: a$ G
  50.         {
    * Y0 v. w$ ~* m' X; U- {
  51.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) ,% R# N5 R) H9 @+ p
  52. MDMA_SRC_INC_HALFWORD);3 q5 h. T0 z8 W, F' o. K) F8 ?
  53.         }$ ^$ B, I4 N* y( K9 L9 S; c
  54.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_WORD)" c; l5 j1 f# w- }# p
  55.         {- v4 A& ^7 \2 I! ^5 D
  56.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_WORD);2 i" q+ t$ h; S/ S3 F
  57.         }
    8 f0 ^: x1 b; i5 n! W
  58.         else
    % W9 b# f* `" h7 J! a
  59.         {6 ?6 @6 R6 Z9 {4 }$ s2 B
  60.           /* 配置错误 */
    4 S- ~$ D% U, h/ C) H9 ^
  61.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;7 Z3 {: ^/ `' p. |" ]
  62.           status = HAL_ERROR;0 A& h: }6 o3 Q! U! x
  63.         }
    + c9 H& j, P  F1 X6 ?
  64. & t4 |4 }6 f8 t
  65.         /* 使能QSPI MDMA发送 */2 U& _1 j6 y/ p- C6 l
  66.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)pData, (uint32_t)&hqspi->Instance->DR,
    * D+ a& Z; S7 w- \' n5 x
  67. hqspi->TxXferSize, 1) == HAL_OK)/ L# O% J, r/ }8 Y# A  N
  68.         {2 U; S  }$ G8 ]2 X6 g0 Z$ x
  69.           /* 解锁 */1 A: o. ?/ g6 b1 [
  70.           __HAL_UNLOCK(hqspi);
    : ~. H* A) K, Z
  71. 8 q- u2 V+ P: z% L9 y, m6 V
  72.           /* 使能QSPI传输错误中断 */9 v/ B; Q# K+ i% [  y- n' G
  73.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);0 H- }% \) T# r7 z; f

  74. 0 ?6 ~: G8 f% _4 j8 @9 X
  75.           /* 使能MDMA传输 */% u8 [' C$ q# t; J: ]1 s
  76.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);
    7 [8 `2 _. p' J
  77.         }0 s; r! E0 t, _( T
  78.         else
    * V! `9 F; V) Q# F
  79.         {
    ' V# {  Y& D% l& P3 d. j
  80.           status = HAL_ERROR;0 w3 V3 j( P) R
  81.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
    * p4 K2 G8 y7 H9 S$ E8 t9 {+ f/ w# T
  82.           hqspi->State = HAL_QSPI_STATE_READY;# o* ?  M4 ~& S7 k+ A6 x
  83. 8 ~; O- \! r7 ?0 [1 A
  84.           /* 解锁 */8 j' d% {5 |) m8 O8 U2 C# }7 w
  85.           __HAL_UNLOCK(hqspi);
    + c; N) Q! L) b% X/ K) N9 M
  86.         }
    ) |% h/ f/ v; |( w& a
  87.     }' r; q: W  n& B0 F7 C! S
  88.     else7 \6 ]3 O8 t: v( K: v; V
  89.     {
    5 @: [: Q! m. J9 t  {: m  x
  90.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
    - L  v3 q1 c/ o2 ?" Y
  91.       status = HAL_ERROR;
    ! L( |9 ~7 w, U5 J; l2 c

  92. ! B6 ^  M! {  q5 }  |
  93.       /* 解锁 */1 z+ N0 f) |. p; Y8 S) |
  94.       __HAL_UNLOCK(hqspi);
    ( g" a+ S2 _. y* K# h1 }4 [
  95.     }
    6 _# P6 w2 c+ }4 V+ k: U( J; h
  96.   }2 M& N. D5 T" u  c. J% R; |
  97.   else
    ' Z8 X; r# i: x) \. ^6 S  o
  98.   {
    # N% {& {  y6 `. v; a
  99.     status = HAL_BUSY;  }+ i! w  f& i# @5 A) u
  100. # Q" ~$ q9 d" b
  101.     /* 解锁 */5 C: Y+ _5 n* q: L% @, ]9 Y
  102.     __HAL_UNLOCK(hqspi);' ~& {+ n0 b+ l
  103.   }
    ' z) w2 W% N! W
  104. . E& |1 f# U# T* y1 y; A
  105.   return status;! @9 d( u# t; d# ^2 [! y5 p% z; U
  106. }
复制代码

0 x7 ?: y  G  ]' ^7 A, f函数描述:
: n9 K3 C+ ^$ G+ ?' W; x! ~" c+ q% r% x/ Z
此函数用于QSPI接口数据发送,函数采用DMA方式。0 ~" x! h# a% ?6 Z8 K# h7 |

- f5 `4 Y; x. _/ @+ B. u3 a6 n4 @函数参数:
0 _. T( D4 L1 c, I, Q+ P! h
9 m. }+ ]9 C) J: T. a  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
6 S* b7 k5 Q4 @, H' H, {" R  第2个参数是要接收的数据地址。5 M, \/ e4 N* h3 j9 M$ Y9 F
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。- j& Y' T. l" n+ A  l, H& B: K
使用举例:' ]1 W9 c  [. G7 R- P" W  s
; m; R5 |4 L* y5 O1 c9 r7 Z
  1. /*
    ( E2 V7 K2 o0 X- l( z
  2. *********************************************************************************************************
    . B) L% g7 h' N3 y0 \& W6 y
  3. *    函 数 名: QSPI_WriteBuffer
    3 A+ G/ A# }9 q- ~* S
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入
    1 ~/ |. _& j2 \6 }' `/ W
  5. *    形    参: _pBuf : 数据源缓冲区;
    & B/ s  _% L- A
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。
    ) e  Q3 Y4 X# W" r7 P0 i2 o' i
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。2 d/ M9 N5 x1 A7 i- k5 q
  8. *    返 回 值: 1:成功, 0:失败
      U: [/ F$ L% ]; B3 z! v
  9. *********************************************************************************************************
    ; V8 z- V  Z  X$ k, K& G- M; _
  10. */
    6 @- c4 T7 \) W
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)1 G4 l, E3 o5 R# F* z1 p
  12. {( ~0 Y  A* R2 @+ r. J( q/ u3 r
  13.     QSPI_CommandTypeDef sCommand={0};/ s( M! |% S4 E7 w- m8 E6 `" A; a* H1 n

  14. 4 A3 ~3 g/ Z3 p. q  F9 n* p
  15.     /* 写使能 */5 [! a0 q* R4 R8 n( F
  16.     QSPI_WriteEnable(&QSPIHandle);    / k5 @  L6 M$ ^. U

  17. * T' U+ n: [7 x( O5 }
  18.     /* 基本配置 */+ u+ f* c9 t1 t0 C! z8 q5 j
  19.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    5 _3 b  m. H5 I+ N
  20.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    " C' v0 A/ x/ I) v  W' h2 ?
  21.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    ( {0 a( o( L' f, `; L7 y8 w9 ^
  22.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    / T0 f) W' ^- t- n
  23.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
    6 d$ r+ _6 p1 K' u/ u+ I3 t4 O
  24.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */   
    + [3 \0 Z# j" T- j" H: Y
  25. 7 O3 T. h' G, [/ Z' d% F! h4 B
  26.     /* 写序列配置 */
    ' C7 q% @& n) ]
  27.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */4 D; Z; B, n- H4 W3 d" d
  28.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */
    : y! v! p2 j; k  I+ F. P. @7 g
  29.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */
    : V9 |$ i% a+ p4 F, v
  30.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
    2 D! D/ w; Z; L: X+ O4 u
  31.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   , e7 Z* M8 p0 s7 |7 {
  32.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 */; Z# \6 o  W7 f( q3 Q
  33. ! p) K# V9 ?6 I8 j" }
  34.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
    - ~1 q# m# v; H: N# `; s
  35.     {
    - M, L4 |) g, w' t! L5 n0 h
  36.         //return 0;
    . K$ ?/ R- n- ?2 T3 H
  37.         Error_Handler(__FILE__, __LINE__);! p3 b- O/ b: y% {- m0 R: G7 ~
  38.     }: k( A  p4 s" n8 B
  39. : d- k2 R" Q. b' d8 Z8 Y* w
  40.     /* 启动传输 */
    $ ~, q* D! T: L7 g
  41.     if (HAL_QSPI_Transmit_DMA(&QSPIHandle, _pBuf) != HAL_OK), C  C: g* Z5 y* A% q: {
  42.     {1 f, f" F! a+ w- ^6 c# R9 z" B; c
  43.         //return 0;+ V% b  B7 J2 m4 b6 B5 g6 {
  44.         Error_Handler(__FILE__, __LINE__);% a$ l  d' _) u1 l  Z4 e8 l6 p
  45.     }
    1 p2 x$ p' Q1 I6 k  ^
  46.   X* D# Z: V; i7 t9 e: u* P' Z
  47.     QSPI_AutoPollingMemReady(&QSPIHandle);   
      s& y* Y9 d: l

  48. ' W1 Y& K3 Q& @* I
  49.     return 1;
    % _/ C" ^+ m* u7 \, U& T
  50. }
复制代码
( o0 E: s5 C# G
78.4.10   函数HAL_QSPI_Receive_DMA
: ?6 [4 E, q  P0 e% d5 w9 ?# F" n函数原型:
0 q% _6 Y  f8 m% u0 N/ B/ }
1 f6 p" |, a2 u' C* B" j! I( m( w
  1. HAL_StatusTypeDef HAL_QSPI_Receive_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData)% E8 ~% ^, E! ]' o0 R. Z
  2. {
    " S& U, B9 @* M/ e
  3.   HAL_StatusTypeDef status = HAL_OK;4 F5 R: M0 ?+ b- N
  4.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);' e, V6 O7 |/ _2 \! L  [# S
  5.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);& Q. w4 o3 F# x% E

  6. - l- ]+ X' A4 e: H
  7.   /* 上锁 */
    * c7 q% l( H: `+ Q# A
  8.   __HAL_LOCK(hqspi);! B/ {* a5 s# b# m$ C! o8 ~

  9. * J" _) Q4 M; o3 h' Q4 t
  10.   if(hqspi->State == HAL_QSPI_STATE_READY)0 Q+ E3 T# _% i7 R( y
  11.   {
    ' `& G( }) O; d7 Y, @9 ?
  12.     /* 无错误 */. ]6 G3 r- }# @. r' x" R, P
  13.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;5 m8 j$ K$ N( N* m" |5 _! P  w! O

  14. $ @, q3 R1 D0 V% s
  15.     if(pData != NULL )
    $ N& e( t/ ^* W+ |+ D  M  M6 L# Z; v
  16.     {% I1 l% Q6 q2 E- U; q$ K: h
  17.       /* 配置接收 */
    + s& V8 }+ r6 F6 r* n( h
  18.       hqspi->RxXferCount = data_size;% v  o' Y/ d3 X  P0 Z- o2 P
  19.         /* 更新状态 */
    . ~- a1 o" I' N9 ]. U) n
  20.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;
    4 V; Z7 a: ]# }- S

  21. - J+ v1 F& f4 w
  22.         /* 清除中断标志 */4 E. A  D/ b) K- \
  23.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));
    # c( o3 h% m. @/ O2 u
  24. 4 _$ ]2 H$ r: W5 ]' E/ W; u0 n  U
  25.         /* 配置接收 Configure */- @$ T: d5 `- g1 N9 [4 a
  26.         hqspi->RxXferSize = hqspi->RxXferCount;& U, [% h5 w' a( c7 Y6 @
  27.         hqspi->pRxBuffPtr = pData;, @* y6 _- U5 Y+ |3 p0 o

  28. ( r9 b9 p6 o! f; F$ s5 ^" f
  29.         /* 设置接收完成中断 */
    9 }( ?$ ]2 F, L5 k' f4 f
  30.         hqspi->hmdma->XferCpltCallback = QSPI_DMARxCplt;. [- j% Z7 _9 S

  31. 5 \; h: q; o0 h
  32.         /* 设置MDMA错误回调 */  V0 r- A3 H: {0 Q; l
  33.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;
    / E- X' }* M# S& e1 b

  34. ' k- C: F& K7 E. c3 g& f/ Q
  35.         /* 置空MDMA终止回调 */
    0 c3 i& p" i6 E4 F2 {+ L* u: H
  36.         hqspi->hmdma->XferAbortCallback = NULL;7 ^& Z0 f1 g" s" T' M- i
  37. , @9 B* m5 o% B6 J/ i2 F4 N
  38.       /* 接收模式下,MDMA的源地址是QSPI DR,要禁止地址自增 */# ?  R( N/ i) o9 V5 W. e& C, h9 l
  39.       MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_DISABLE);
    $ k. {* @" x  E* w/ D
  40. ' p. _, Z: m/ F( I$ z
  41.       /* 更新目的地址配置 */6 `1 _' ?8 @3 {
  42.       if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_BYTE)
    & E* I! N+ c) t0 H( C0 i$ b( R
  43.       {
    & \1 P! N2 d) V% B) o
  44.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_BYTE);
    ) ~2 {9 s" ^+ Q" y8 s0 b( J1 m
  45.       }3 e; U% \% g2 O7 u
  46.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_HALFWORD)% P. u, J7 [' B! j2 z) Z* E
  47.       {( h- r) U* c2 M8 _
  48.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) ,
      d6 J, E6 O  j1 i+ g
  49. MDMA_DEST_INC_HALFWORD);
    : T2 w3 \. Y" b$ ]
  50.       }
    . H) |' T3 S8 U- k2 j
  51.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_WORD)& @( e  q: S) ~
  52.       {
    / V& Z! M. N: V
  53.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_WORD);& @: i. ^$ s7 j0 B, }( H
  54.       }; v5 D& Y6 W" |& P- @, V
  55.       else
    ' d$ m5 p/ s, K: Y- c$ T2 p, N$ N
  56.       {" {; S3 Y; l* W& C
  57.        /* 配置错误 */
    ( _$ j* ~' Q8 {6 A: a
  58.         hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
    ! q& j; W6 W9 H2 w5 m0 j& I! r
  59.         status = HAL_ERROR;( m5 l1 |1 g3 R  U- `' y+ m
  60.       }6 w$ [2 t8 a& C/ C9 p8 q, B
  61.           /* 配置CCR寄存器,间接读 */
    7 G% m1 [5 I7 ?" W8 G* y/ J
  62.           MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);( r  X5 ]# H- M7 W1 l9 ]0 N$ L

  63. 0 @* G# @# G' e8 b: D# ^
  64.           /* 启动传输 */
    5 t% u6 C6 b: ^
  65.           WRITE_REG(hqspi->Instance->AR, addr_reg);
    3 c- @4 U. U" `0 r
  66. - o1 K- O9 f# A* J& k/ k4 T
  67.         /* 使能MDMA */1 q$ H4 h* b# L9 C) J
  68.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)&hqspi->Instance->DR, (uint32_t)pData,
    2 l8 f4 `. ?, c& S0 T/ H6 u
  69. hqspi->RxXferSize, 1) == HAL_OK)
    % H4 _) ~8 x+ A; t7 n. `3 L% Z3 ]
  70.         {
    3 ]) ^/ ~" v6 z+ L% q8 ~
  71.           /* 解锁 */
    ; y: ]( M. v4 z9 j
  72.           __HAL_UNLOCK(hqspi);
    - U* S" ~- w/ x1 u: f

  73. 0 l, b8 Z! z3 A5 Q* h- i
  74.           /* 使能传输错误中断 */$ r7 _; b0 u' y/ N% z# l4 n, p
  75.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);' \+ E* x" f% E# n, w$ G! G

  76. & V" ~. L. G$ x& _* Y3 z4 h$ u
  77.           /* 使能MDMA传输 */" d, d4 S" S! I- R8 `. S6 V# _
  78.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);6 k/ H6 _, a* B: z1 N- V) j+ m& Q/ t# w2 s
  79.         }
    ' A6 t7 m$ f  n, t! v6 }# p7 ~
  80.         else
    + i4 F+ H% [9 Z- }% Y/ U5 {8 C
  81.         {
    + P  c3 C, h! b- p) M
  82.           status = HAL_ERROR;
    0 Z8 H7 L7 I: s2 Q- m' Z2 V
  83.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
    " I  w7 ^9 u# i! Z9 n! x
  84.           hqspi->State = HAL_QSPI_STATE_READY;
    : ^6 I+ ?0 V6 ~/ P

  85. + b; Y: J, t$ [4 b% ~* K( w
  86.           /* 解锁 */0 @! n+ W' I) e
  87.           __HAL_UNLOCK(hqspi);
    8 Y1 g$ `5 @/ x( t  o' v; V
  88.         }# x. z; R+ Q& i+ \1 H
  89.     }
    " h# \0 V6 i2 T* N3 O3 x6 t6 F" v
  90.     else; e% K' W( k8 ]& B( l
  91.     {
    , Y, k( ?7 R! s
  92.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
    2 g. `- ]$ G1 N+ f7 s, w
  93.       status = HAL_ERROR;
    3 D( `/ Z, g6 i5 G
  94. 1 ]+ k6 }1 }. z# V4 ?
  95.       /* 解锁 */
    / {4 {: C; m1 b0 }) r
  96.       __HAL_UNLOCK(hqspi);- ?0 t& I; ]' Q& H/ R1 m% X. B8 s3 e
  97.     }9 |" B: H( ?4 s! Q
  98.   }: d- M9 a( |) n  N5 ?5 X6 f
  99.   else
    : I  p- s5 V' {# O+ o0 j( p
  100.   {
    ( b; ^6 w; I, E% q! a
  101.     status = HAL_BUSY;
    7 A" y! \' [6 h+ B: J; k
  102. . H* I; N3 n! T5 c* }5 x6 C1 w8 P0 L
  103.     /* 解锁 */
    9 \# v0 S( s/ U" ^( j
  104.     __HAL_UNLOCK(hqspi);. G4 |, O% H, E5 a  ]& k$ ~  ?
  105.   }
    ; v9 z- I  f5 q7 W

  106. $ k1 X& q3 B" w  K) \+ b9 c
  107.   return status;$ f6 I- {* T  L& ^1 ~$ j% n
  108. }
复制代码
0 P3 u& o, H1 Z2 m4 Z
函数描述:
8 y6 t% l+ N/ Q* W& H- x0 G6 I6 a' L8 y  f; _2 C: Q8 ?
此函数用于QSPI接口数据接收,函数采用DMA方式。1 o% M$ |( d% I: O& s) X
+ ~- K" v8 U  N' J: C) \5 d$ P
函数参数:
; [; Q8 n3 d/ t# y% t) e" @- Y1 h2 j" t6 r8 f! }, r1 i
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
8 Y4 R8 J5 C0 d7 M5 K  第2个参数是要接收的数据地址。  L- k  [2 `5 U
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
$ |7 ]) P" \  q; d" ^# a使用举例:
( r9 p/ j  o5 U$ ^' }; z* Y  H, r* ^* m6 P1 ]" ?
  1. /*
    & t8 B. o9 t8 ?* J
  2. *********************************************************************************************************
    9 e# l. S) k% \, u  T
  3. *    函 数 名: QSPI_ReadBuffer+ ^1 a) B% k4 j7 K: @
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。
    8 ^( A9 k" C2 l9 G4 J9 M- {9 h
  5. *    形    参: _pBuf : 数据源缓冲区。0 k! z0 A9 N- X  y+ W* d. Q# U
  6. *              _uiReadAddr :起始地址。
    0 j: p" x! W% s( g
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
    - {, N: q4 S+ x" D. l6 X* r; H5 O
  8. *    返 回 值: 无
    ! t1 ^& g6 L' W3 ?: _
  9. *********************************************************************************************************
    # j( Z# s3 d- e3 ?9 |+ t: Q
  10. */8 @/ V7 v. f% N+ X/ W
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
    : T7 C" ]4 B8 r2 T$ D- h  l- _
  12. {1 v+ [. O4 J6 L7 U
  13. + Z2 S9 V: d- U
  14.     QSPI_CommandTypeDef sCommand = {0};
    . |! u$ L# e! x5 z

  15. 7 K5 J) L4 i% a5 g
  16. 9 u  C( M: K6 F0 \4 n
  17.     /* 基本配置 */. k4 B, ^. g7 O0 t. v0 _/ `0 P
  18.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */
    , [3 d( R. ~# S( E- o# W+ _( r4 I8 o
  19.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */! J5 G9 ~& R  v# E4 s: ^  u
  20.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 */
    : p1 }4 q) ~8 K6 {
  21.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */
    . Q9 j, E, N+ w% i& E
  22.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */
    9 Y! c5 n& J9 \! O/ y
  23.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */    : ~6 L# p1 _$ r/ ^; i" z
  24. 7 w7 g: D5 X+ x, d& I4 K7 w
  25.     /* 读取数据 */* _! n% E7 d7 h8 f) S( C* k
  26.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */
    0 z$ Z: t  L* N( W8 z8 q: n
  27.     sCommand.DummyCycles = 6;                    /* 空周期 */
    ' y' o3 n* }- h- M- o
  28.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */
    6 B! ~/ X: X8 q7 p( v! z2 S6 a: Y( H
  29.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */
      D0 I/ \, s# P# k$ w0 a! A4 z
  30.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */
    ' K2 h% C/ V" n% {- q# @% U
  31.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */ / U- q& X4 A7 @6 U6 k

  32. * ?4 a+ X- \/ x: `) y
  33.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)/ @: v: Q4 G6 u8 c
  34.     {
    9 U/ u2 e6 j( D: [( b) T
  35.         Error_Handler(__FILE__, __LINE__);) B/ P: a4 C/ |. a5 R& \* n
  36.     }
    : H0 }2 @- U9 {/ v: h9 ]- R
  37. 7 c9 j/ u. C! H2 z* {' g* F1 j$ o
  38.     /* 读取 */
    , M( A) {3 j7 e2 R3 H$ l' b
  39.     if (HAL_QSPI_Receive_DMA(&QSPIHandle, _pBuf) != HAL_OK)
    % p& J  P; P9 t7 V* n  _
  40.     {3 s5 Z/ ^# |+ n! N' h  z
  41.         Error_Handler(__FILE__, __LINE__);
    0 h, U# D- l/ q. k" s
  42.     }    ) j( _% J: h9 i* J
  43. }
复制代码

* u+ Z& f; [% a) s78.4.11   函数HAL_QSPI_MemoryMapped
* }+ L. o; Y/ V% N# O函数原型:
, s+ S$ B; i& @9 J  E  p( {/ T4 o0 @% _; Y: u: _& C% V4 V
  1. HAL_StatusTypeDef HAL_QSPI_MemoryMapped(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_MemoryMappedTypeDef *cfg)
    # e. ~' t8 I* }: q
  2. {
    & r* W+ D% V4 N6 j7 ]9 u; E) ?+ a
  3.   HAL_StatusTypeDef status;
    , H% t6 S5 q2 }4 O
  4.   uint32_t tickstart = HAL_GetTick();5 U! i* ?8 I& `( r6 X+ K+ o
  5. 9 [! m0 {) r8 G. S
  6.   /* 检查参数 */- L4 Y7 G& N( B% F
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));9 B: k  x  {8 u- }- s4 N
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)! e) W3 l4 Y! g$ u6 Q
  9.   {
    ( u) L; N  O9 b* j9 e
  10.   assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));6 B/ n+ @' b4 o+ `5 _
  11.   }; i; W4 k; [) c8 H8 w7 }9 @' A

  12. 0 n- q. h9 X. R
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));6 \6 R2 J2 a! C
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)4 b- P6 W! b* w7 p
  15.   {
    " e& N; ?# h! O  G2 q/ U
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));# k" @! L3 h. u
  17.   }8 P5 b% d) _6 [$ A: U! L' E
  18. . N$ g& D0 o7 Q. M
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));4 M2 z1 h" M! d- m: Q% H
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)0 T% j3 I9 G6 G. b! W+ S6 c1 o
  21.   {
    + X( R- L  O6 r- A* E& {/ X
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));1 c. m+ Z# Z7 x% m/ v1 G2 a3 V
  23.   }# @1 V- i+ I9 b$ ?  c" K% }

  24. : N* D; o; T4 b) C
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    8 _% i: \# x- V: L5 s6 e. U9 y
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));2 Z4 W( ?1 U/ e  b1 [

  27. 1 a0 b3 G9 ^/ y/ H/ X
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));. L  ]* R3 T! w; d# Y( i- C
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
    , [% |9 ?* x  @5 ^' M  q8 o7 u# j
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));% B! U, A; a" o, f. B& p. g( y
  31. . e" G2 N9 M7 l% D4 F
  32.   assert_param(IS_QSPI_TIMEOUT_ACTIVATION(cfg->TimeOutActivation));
    % ?. d0 E5 Z8 f8 J2 _2 q

  33. 3 y; o* ~9 ?: `' P7 l: F( L
  34.   /* 上锁 */$ N6 s* L/ ^: G! X  i/ X& z) u# Q
  35.   __HAL_LOCK(hqspi);2 l0 R; M4 T$ O/ ]

  36. 2 Q: Z! z8 T" l7 N. `
  37.   if(hqspi->State == HAL_QSPI_STATE_READY)6 A7 r; b# q7 c/ ]! P# X+ F
  38.   {
    $ u- F: L) s" e4 L" b# ^' N
  39.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    + d% q* q- J, @/ o+ R1 l

  40. 0 e! w  c1 h0 l$ y, A9 `7 i
  41.     /* 更新状态 */0 i. J- u' g+ t! |& k
  42.     hqspi->State = HAL_QSPI_STATE_BUSY_MEM_MAPPED;
    . f* ]) G8 o, c

  43. $ [- T' d* n! `- x/ d8 m
  44.     /* 等待BUSY标志复位 */
    3 w! h/ k2 s1 h' q7 R$ Q! K) _
  45.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);8 \' p& N; U" C9 Z' F/ l

  46. 4 V3 d9 w, b) o. v& ]) Q% z# A, m5 X
  47.     if (status == HAL_OK)  E  j1 F4 Y  |5 M$ j* f
  48.     {" T- U2 c+ k$ p& B4 Z, s! g
  49.       /* 配置QSPI CR寄存器溢出时间计数 */- ^* j7 S0 J* A. N2 t
  50.     MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_TCEN, cfg->TimeOutActivation);  [* @( X, |% e: i1 [. d  m

  51. ( G& M! A9 w) E' C: b4 Q+ c0 Y4 [
  52.     if (cfg->TimeOutActivation == QSPI_TIMEOUT_COUNTER_ENABLE)
    8 Q3 @# `% W, u* l( i$ i9 {4 K: u
  53.       {9 i: k) |# J' @* L& }% x6 |
  54.         assert_param(IS_QSPI_TIMEOUT_PERIOD(cfg->TimeOutPeriod));
    ! h5 V' ~5 @) ]( }1 w3 H
  55. 5 @8 ~9 L* v& z* d, F; u5 ^8 u$ I
  56.         /* 配置溢出时间 */
    7 e1 T5 W/ F3 q! f+ p2 ^
  57.         WRITE_REG(hqspi->Instance->LPTR, cfg->TimeOutPeriod);
    / q$ a8 G* o4 h7 I/ i8 x
  58. * I6 r" I7 Y; G$ h3 P- h
  59.         /* 清楚中断标志 */
    1 N% h  q  \4 \) p
  60.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TO);
      U0 U4 Z2 E5 P8 Z2 n5 ]

  61. # P3 C, O7 v5 a; j$ z- a7 o& K
  62.         /* 使能QSPI溢出中断 */8 @" f& B  X# x+ r/ H$ d& i% I  {
  63.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TO);
    ! G, Z; }, [0 t3 Z. ?4 y) i" w
  64.       }# D- G2 v, H& Q; s9 z  u

  65. : O! y3 ]$ q8 l& G- L0 |  V
  66.       /* 调用配置函数 */
    , M1 @+ w/ s' k3 L8 c$ L
  67.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_MEMORY_MAPPED);
    , g% h* a% h, |) c' W" B/ R0 U2 u" `
  68.     }% L# S, B6 l) q# V' }
  69.   }: f% g" e) k$ P  a
  70.   else  U  F3 J. W, P" H, ~3 q
  71.   {, [9 {% P6 W7 C8 h
  72.     status = HAL_BUSY;
    3 x) d, m3 B, w. }
  73.   }( R. W. p( o' c3 V9 X  j

  74. . u5 R1 m- h4 S  Z& b! Y
  75.   /* 解锁 */$ w. y# i) P5 A5 p) [
  76.   __HAL_UNLOCK(hqspi);
    / G* z/ w; [, L9 G

  77. 1 g; A/ P9 E; I  ^' _; e, a
  78.   /* 返回状态 */
    , K" W" F3 }# F
  79.   return status;
    8 V3 L& _5 M  b% F# ~
  80. }
复制代码
+ i" D" {% `* ]" H6 Q6 M( O
函数描述:
& p7 v3 f$ G) `" [5 T6 Y7 _7 q4 G6 r& a  o; b
用于QSPI内存映射设置。' X( \5 G" |, A6 y
% r- P( s  @1 b, N8 f) m- x& _( l7 v
函数参数:
$ q; K8 I) w) |6 q* D, w; n+ E7 }# e" l1 |' e( j2 \
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
1 c  A. E# j# X4 B2 c4 {  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
4 h, z" h! k) \2 D( t  第3个参数是QSPI_MemoryMappedTypeDef类型结构体变量,详见本章3.6小节。' ?. ]/ P- f  }! ^1 ]* P
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。2 k) S+ O0 y& t- `9 |. C: A
使用举例:
$ G2 ^+ V3 ~5 J6 S# d
; [# s* a/ U$ @5 A: n5 S
  1. /*; ~! f2 o  r7 l0 t3 {) O
  2. *********************************************************************************************************3 N8 U) S3 o/ W) K: q' q) Q
  3. *    函 数 名: QSPI_MemoryMapped, X1 M7 K7 e$ l5 h  q5 r
  4. *    功能说明: QSPI内存映射,地址 0x900000005 h5 \3 r8 {( {7 d0 p% I' \
  5. *    形    参: 无
    3 b' t' k: [9 _/ e
  6. *    返 回 值: 无
    % E  N# C: @, g0 y4 g
  7. *********************************************************************************************************
    # |; g& L$ k6 G- ]0 e
  8. */
    5 D4 d0 [- O* g  i: E  z, A
  9. void QSPI_MemoryMapped(void)9 ?) o- {1 [- E7 a2 r* A( k7 C; y
  10. {6 b. h5 c7 y, W2 S/ D# W5 y# G
  11.     QSPI_CommandTypeDef s_command = {0};
    : P- j+ F: {4 V
  12.     QSPI_MemoryMappedTypeDef s_mem_mapped_cfg = {0};
    $ G  W' d( b2 W, V3 C9 U6 w& D4 u
  13. * S2 V, ~$ O8 w- A- |! Z
  14.     /* 基本配置 */
    4 a' T1 [! `1 X
  15.     s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;      /* 1线方式发送指令 */
    9 T: b8 B# x3 P2 s- e8 T
  16.     s_command.AddressSize = QSPI_ADDRESS_32_BITS;             /* 32位地址 */
    9 u2 S! C8 q8 Z! S0 R, X
  17.     s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    0 ?9 q" Q# P$ l: k0 V: d
  18.     s_command.DdrMode = QSPI_DDR_MODE_DISABLE;                /* W25Q256JV不支持DDR */  {& q$ Q+ G8 g6 V
  19.     s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;   /* DDR模式,数据输出延迟 */
    ! Y0 ^* F- s* p/ J9 \$ k, Y$ h8 D
  20.     s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次传输都发指令 */9 C& f: L4 \$ Z' h: X
  21. 7 d7 E# o; G/ A
  22.     /* 全部采用4线 */& h- ^/ X: B% O6 r: V
  23.     s_command.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 快速读取命令 */
    % g7 l3 I: e1 `
  24.     s_command.AddressMode = QSPI_ADDRESS_4_LINES;                 /* 4个地址线 */
    / }0 \' ]+ m4 m+ L6 y- o: C9 S
  25.     s_command.DataMode = QSPI_DATA_4_LINES;                       /* 4个数据线 */1 o% ?1 S1 I) h; X6 O6 j
  26.     s_command.DummyCycles = 6;                                    /* 空周期 */
    . l+ U/ [1 F' K3 r+ r; o1 d
  27. + `4 z% K; c. V' t
  28.     /* 关闭溢出计数 */! v1 f2 j6 G; ]& n- ^
  29.     s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
    9 _) J6 v+ j+ C  T9 H
  30.     s_mem_mapped_cfg.TimeOutPeriod = 0;
    * Z, w0 J+ L/ u: v5 P2 r6 b1 @* ]" m

  31. ! r6 |  s: Z# @; T( ^6 D
  32.     if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK). M" V9 @* F' x. l' \" Y2 B
  33.     {
    3 _2 v7 ^. l1 [/ T5 f: j
  34.        Error_Handler(__FILE__, __LINE__);
    4 I9 D- J+ G, e1 O/ z7 H
  35.     }
    5 D8 ], B9 V" }
  36. }
复制代码

. E) Q7 ?6 ^, N0 W5 O8 a78.5 总结' H9 u$ O  r1 \
本章节就为大家讲解这么多,要熟练掌握QSPI总线的查询,中断和DMA方式的API用法。+ d9 c" y: o3 O2 U# _- Q  ^
9 \! o+ J0 Z3 `
: m. m5 d1 }9 Z; Q  ?, a% w( W
74f88e781c0aa6369a48d73fb7dbe7d9.png
收藏 评论0 发布时间:2021-11-4 18:44

举报

0个回答

所属标签

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