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

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

[复制链接]
STMCU小助手 发布时间:2021-11-4 18:44
78.1 初学者重要提示
! n% B' d8 G+ v  QSPI接口,可以做1线,2线或者4线使用。
, h. Z+ s5 v, [5 g  J0 X$ g" H  注意,QSPI接口不分主从,QSPI仅用于主控。! \: K- H, T, {$ E
  可以单独使用BANK1外接一个Flash,也可以单独使用BANK2外接一个Flash,不可以BANK1和BANK2同时独立使用。但可以两个BANK合起来做双BANK(也称双Flash,即dual flash)使用,即8线模式。
% n5 v/ K# `) X6 B5 M% D4 R9 F7 o& X  STM32H7可用的单线,双线,四线和八线SPI QSPI OctaFlash等涵盖各大厂商+ c* f7 D) Y# i% q& c) @% ~4 |1 k4 B
78.2 QSPI总线基础知识
) {7 A" {! f6 r9 I1 V- x- V% b4 o78.2.1 QSPI总线的硬件框图' D; z$ n9 \0 @% _" Z
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解QSPI的基本功能,然后再看手册了解细节。
& t4 b* i: _! _4 R) E3 B8 L" ]& S$ \% s6 I; K9 w
BANK1外接Flash/ X6 E' v1 g$ u( V, {
& v( ?2 h& _; f7 h/ t3 D  \; N
f04c8d70b5dfdaf87e9a1a4f54b38e55.png
: a4 j! ?  c2 b1 K, q9 _* ^  N

# g! L9 v' a$ ABANK1和BANK2都外接Flash:5 e9 F/ b# v9 w& h: R
) u2 m: ~- ^& P7 ]5 ^! K7 I- D/ T" l
60f4042c5098f3ba9a7e40219c023175.png
. I( p7 s9 X- I! O/ Z% Q  A( d+ w- f8 ?

" ^! p8 D$ [1 u2 G通过这个框图,我们可以得到如下信息:
, \$ v* W: y7 H( d1 x- [8 F: n$ z& ]: l4 R. k
  quadspi_ker_ck时钟输入
  v) X7 K' g5 R6 U4 L内核时钟。# `! }' Q) i/ a/ o2 E

8 g" I# r) J9 F6 Q8 S, W; G  quadspi_hclk时钟输入
! Z1 {# k) R7 j: R, v为寄存器提供时钟。/ z3 J4 k$ b+ d
# e$ \; w7 Z' c4 t9 f
  quadspi_it输出信号& H* X: r; {7 N. p% e4 i, R2 ~
QSPI全局中断。
1 R- J& t# N, N1 R' F. }  |/ J* W; }; E# Q% k1 D  n
  quadspi_ft_trg输出信号
+ N- q/ l, n; y2 [MDMA的QSPI FIFO阀值触发信号2 ^# Q3 N4 K! ?* e4 s& q$ E
  }/ N1 J' Z- b. y* O
  quadspi_tc_trg输出信号
$ H0 T2 k! w" }: Y! w$ [MDMA的QSPI传输完成触发信号9 }/ e; Z- I) u) [% T
& N$ I' Q  F& u, ?! o, {
  CLK( k: A* A3 I  V8 f5 m: _; m! l
为外接Flash提供的时钟。为外接的两块Flash同时提供时钟。
) {6 f, E/ n2 y6 x9 C
( B# [3 P9 Z, ~( Z) z  \5 a+ |" {  BK1_IO0/SO
' d( F/ `* P# k+ T. `在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash1使用。  w1 X0 G) y2 H4 [& E7 L* a- c
8 I* K& K" `9 T9 o
  BK1_IO1/SI: ^- ~+ Z! m- F$ t( b0 E
在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash1使用。
5 ?1 ?9 l7 K( f. o$ z$ `; `) `$ T6 m# U4 L9 m
  BK1_IO2
: o  Q, `+ K" U在4线模式中作为双向IO,供Flash1使用。
3 I: w5 o3 n0 g% I. }  X3 Y7 E1 A' v/ a* e0 W. b+ I+ v
  BK1_IO3; W/ [& c8 F0 d. J
在4线模式中作为双向IO,供Flash1使用。+ o# ~$ C* q/ N

6 Y( K; X+ O9 i" j7 [1 s  O  BK12_IO0/SO. B" z+ I  P4 M9 q% s
在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash2使用。
+ @4 S$ W, O' b5 @) u/ `( h- ]- V( a8 j/ a0 J: P1 a* X$ B
  BK2_IO1/SI: W$ R' b. M1 @  U
在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash2使用。4 ]& z: W. A* \" _, _! f9 P
% V6 w5 e- p- I3 |" ?
  BK2_IO22 h5 p, r4 W4 s6 W. e7 q6 t' I5 v
在4线模式中作为双向IO,供Flash2使用。
$ ^# L* c- P2 o! |; l" v% d# P1 f/ R$ n$ @* \
  BK2_IO3
) C2 q+ X' P# ?* I在4线模式中作为双向IO,供Flash2使用。
; D; ~/ l% Z$ p. @5 N
; C, k  n. p" \$ z7 l- s  BK1_nCS1 ]) y# K1 d* u/ m; ~% @% y
片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash2。
( N! @! R7 g$ F* S& k% _
9 D. J+ X6 [; \% U! d  BK2_nCS
; X3 j  ?4 \1 Q2 j5 {# O$ [片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash1。
8 Z4 M# x/ n+ x
/ |, D2 {' E9 d78.2.2 QSPI的时钟源+ F( K$ m7 D& C) J+ a$ a; e
这个知识点在初学的时候容易忽视,所以我们这里整理下。
" ^2 _* z/ w) l& N9 K4 Q: j& _3 u+ R8 Z  m( g3 }  ?
STM32H7主频在400MHz下,QSPI的最高时钟是200MHz,可以选择的时钟源如下:/ V- S  _2 {. z( C" Q
9 ]$ @1 O: J- d5 C8 ?2 y7 f
60a21420cdf6bbfc171b77ef44ebcf28.png
% ~* S6 q8 i: Q' G' c- k

& J. M% r9 n- l! k4 ~% T2 U
12523b301f01c6108162699ca2ad5685.png
4 j2 X$ s- ~# @. d1 y( X' o/ y

' `1 w: `' D- K0 _
5 K- `- d5 O6 d% k  }我们的程序中默认是采用的HCLK3作为QSPI时钟。# y3 a) G5 W: J# O3 l* m
/ D" C7 e6 s/ n* m8 ^
78.2.3 QSPI 命令序列+ }9 F) g8 z) M/ H
QSPI的命令序列主要包括以下几个阶段:指令阶段、地址阶段、交替字节阶段、空指令阶段和数据这五个阶段,任一阶段均可跳过,但至少要包含指令、地址、交替字节或数据阶段之一。" V1 D/ E& S, E; y5 _
1 R6 e. L% `5 R; ^+ ?2 }7 P/ j6 b# I
2cb087bbc794898408c6160acfd426e4.png
. |- r8 V4 G) N9 w$ W
' F# W+ Q2 P$ R( V) Z, _' @0 b
  指令阶段
5 g/ P2 d# _  P+ _2 r* \" {1 u在此阶段,将命令(8位指令)发送到Flash,允许发送任何值。用户可以简单地将所需的命令写在指令字段中。根据软件和硬件配置,可以1线,2线或者4线方式发送。在某些只发送地址的案例中,指令阶段可以跳过。2 m+ o5 P2 G- k( S% C. r
+ G* h3 u" C" z. v1 Q
地址阶段
. o* r' Z7 ^  O' |6 W" [在此阶段,将地址发送到Flash,从指定的地址读取或写入数据。 地址阶段是完全可配置的,允许发送1、2、3或4个字节的地址。在间接模式和自动轮询模式下,用户可以简单地将所需的地址写入QUADSPI_AR寄存器。据软件和硬件配置,可以1线,2线或者4线方式方式发送。 在一些不需要地址的情况下,可以跳过地址阶段。3 s; n2 l! w+ Q' a5 U; M/ y! `

" C1 b" D) ?3 G' W1 |  交替字节阶段0 M: P* ^* b  r+ X
QSPI接口支持的一个额外阶段,具有更大的灵活性。它是通常用于控制操作模式。交替字节阶段是完全可配置的,并允许发送一,二,三或四字节。- ~' c$ S* R1 @3 r! @' F7 }
; K3 d& W/ [$ E
  空周期阶段; g( f# r$ |2 j4 O1 o  @" q9 e
在高速时钟下运行时,此阶段可以确保有足够的“周转”时间从输出模式切换到输入模式。
7 b' b. c; |  i' }. T) {
; N9 h1 {) B) |" j: }  数据阶段
# j2 F( S# J4 B) O) n6 l, s9 n1 y这个阶段实现数据的收发。9 l$ U0 x- r% |0 b% Y) f
+ o' M$ s# D: D3 S3 Y
78.2.4 QSPI的1线,2线,4线,SDR和DDR模式
, M4 m3 y+ e3 c$ i5 W这里所说的线是指通信阶段使用的数据线个数。
, g  Z+ y) |, v' D7 c0 i
5 R3 Z! G3 P7 k' P* Q& O+ q4 T
213a38369fe04824fa8640f515beb2fc.png
7 n% i! O1 N( q

# V; c: n/ r% G7 N5 ~; t  |1线(SingleSPI,虽然是一发一收,但属于1线方式)
6 k5 V& ^: i* R, Z4 u, h发送用的数据线BK1_IO0/SO(BK2_IO0/SO),接收用的数据线BK1_IO1/SI(BK2_IO1/SI)4 B5 A# T+ l+ R
4 p* t. Q5 J, K
1线模式下,所有线处于的状态:
2 @" P8 ?& ~$ M% X; t% N0 k$ D1 V0 P7 R" q
(1)  BK1_IO0 / SO(BK2_IO0 / SO)处于输出模式。9 @% @# m) R  D0 T) ~

6 z; K8 T0 x6 S3 s  ?8 T* Y (2) BK1_IO1 / SI(BK2_IO1 / SI)处于输入模式(高阻抗)。
9 z% d" D3 E5 t  \, h4 K* l9 [
8 I. a- m* {3 s8 l (3) BK1_IO2(BK2_IO2)处于输出模式并强制置0。' J/ O2 f$ J5 W! M" G2 O
4 G7 I& h/ \9 R; X
(4)  BK1_IO3(BK2_IO3)处于输出模式并强制置1。
% c$ M5 m3 b7 v2 |4 J
6 D7 Q$ |& g* x) q( g- ]
7c6105bc6d18539b680aeeed7ec93aed.png

) g' e8 o: ?& P, K# \/ f0 f5 B* j/ r, L9 R+ s/ w
  2线(Dual-SPI)7 R3 @' Q3 K1 Q8 V/ t8 Y$ v( q3 y( {
同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1)做输入输出。4 L( G8 R' R- c6 B7 q1 J/ ^; d/ l, l

# E) _! |& r: A2线模式下,所有线处于的状态:
: w" o8 ~( T7 ^- ?5 j/ x! X
4 w4 M) N- J7 } (1) BK1_IO0 (BK2_IO0 )和BK1_IO1(BK2_IO1)读取时处于输入(高阻)。其它情况下为输出。
7 U9 \0 U% P$ q# ?5 d5 {" @9 i' Q! d! o( n. x
(2) BK1_IO2(BK2_IO2)处于输出模式并强制置0。
" S2 h8 B* W8 Q% T- Z3 e
% t) U3 c/ P" K3 s (3) BK1_IO3(BK2_IO3)处于输出模式并强制置1- v) ?" u9 d8 J$ M4 _% \6 I" b' F
5 f9 m) G* n, a0 K. Y

+ ^, d# f: D& ^  `
) X( C0 }3 W0 P, f2 T4线(Quad-SPI)0 D- O! }! r7 B; t+ p
同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)做输入输出。
& l0 s& O: k' B9 j0 H$ {4 T0 Q7 r5 l2 M# @8 j
4线模式下,当读取数据时,所有线处于输入(高阻),其它情况作为输出。& s& j* N' R1 z# Q% }5 Q, V

( W, l0 U+ ]$ E1 Y
9d022cbcfd5fb3f3950421c3312e505f.png

9 r2 R  N8 d" ^. d0 e! N( Y. |) K/ g8 O1 w# M4 u
  SDR
5 b/ i. H+ ~9 U6 W  C在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号仅在 CLK的下降沿发生转变。
" f( T9 n0 p% G0 R% a6 ?* y$ V% w0 }4 b# D
  DDR
, q0 H4 \4 l6 \' {  |在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号在CLK的上升沿和下降沿发生转变。. J+ N- Q5 P# ], o0 k
) r9 N  J2 j9 \0 |) {, y
  双BANK(双Flash)
0 k  e7 b& s& f  J+ p双闪存就是将QSPI的两个BANK分别接一个QSPI Flash,然后时钟公用,片选公用(也可以不公用),从而实现8线模式。
( A3 F/ f" z0 X2 Z! e4 L; I
9 T" y# d: h! y! G: x" U( J
d28d743492529e4d88e9b64567fe52b4.png
" i& U* O. T" N) I( T7 w8 i
; f5 N8 m9 M9 c2 k
78.2.5 QSPI间接模式,查询模式和内存映射
1 C( F, {2 T5 I! J7 F9 P* K! fQSPI支持在以下三种模式下工作:1 p+ b/ |; l$ q* h% t+ x
' I% D0 V/ _, S
1、  间接模式:! _8 j5 X% \2 u3 _0 V2 a
$ F7 Z" ?3 ^" }, E
这里所谓的间接模式是指寄存器方式访问外设,就跟我们操作串口外设一样。间接模式主要用于以下场合:+ M, O& B* K- |
% ?0 S2 ^1 w. [; K2 }, v
  用于读取,写入,擦除和配置QSPI Flash。
' z1 H  h0 {/ w. Q! x: L  如果不需要AHB总线访问 QSPI Flash(在内存映射模式用)。/ Q( Z$ @) w' f- L( v/ q" w6 J
  CPU或者DMA通过QSPI数据寄存器执行所有操作。' e. Z9 ?! o( @! s/ b; U

. \$ e- ?5 m# E. R7 J8 i% V; A5 O# g" r4 [/ i% T9 ?: u4 j
在间接模式下,所有操作均通过QSPI寄存器执行,含读取和写入操作都由软件管理。 QSPI接口类似于经典的SPI接口。传输的数据通过数据寄存器与FIFO。在在此模式下,可以从大容量的外部Flash读取数据或向外部Flash写入数据,可以支持到4GB容量。7 {4 g( p6 Z8 H# G1 r

* E$ D  W2 M% \" p3 N如果进行擦除或编程操作,则必须使用间接模式,并且所有操作必须由软件处理。在这种情况下,建议使用状态轮询模式,然后轮询闪存内部的状态寄存器以了解何时编程或擦除操作完成。+ R8 l2 ^" a2 M3 J9 m, f. ?

/ f0 e# U& L7 r' \+ S: K1 U9 C/ ]/ a  R* m, V1 f0 z
) P- m) v3 V7 b1 j
2、  状态轮询模式8 N' S$ l1 _2 w' |$ H3 o4 I
$ U9 s7 C% r0 {- g) L3 m8 B7 f% |
在以下情况下使用状态轮询模式:9 J  m3 y* s4 I4 j
. H7 K. W: X4 V' F3 n0 f
  读取QSPI Flash状态寄存器。1 C3 l( S1 J" a+ a2 q
  在操作结束时自动轮询状态寄存器。
1 p$ G' `- R& w+ }( W: X可以自动轮询内存中的指定寄存器并减轻CPU负担,例如检查擦除操作何时完成。QSPI也支持定期查询QSPI Flash,并且可以屏蔽返回的数据位,将所选位与所需值进行比较,结果比较可以通过下面两种方式处理:
3 L1 l8 I& L1 K, Y
% G6 s8 t+ H! ^  AND与操作模式:如果所有选定位都匹配,则产生中断。( M6 a$ _7 Z+ _8 ?
OR或操作模式:如果所选位之一匹配,则产生中断& Y. m! f3 }8 G  t* s

3 P* \. f, Z% s4 J% Y- ]1 [$ y0 Y$ z% v' |6 D
发生匹配时,QSPI可以自动停止。
3 f- |6 S2 I) f4 E! J& E6 P
! N  D6 k+ L% Q3 o4 f1 K
8 c: ^/ s  |% q$ i$ |  o/ M
2 r3 \2 }1 U% o: g3、  内存映射模式
/ \% T/ [6 n7 o/ q3 A; [
/ }9 k! b, o. h- s. l2 |! P  p; y在以下情况下使用内存映射模式:
; w% r0 ~( p8 J+ M4 i- i! ]8 }2 W8 w' y# V
  用于阅读操作。
7 {  K9 J2 H3 _3 J4 i1 g9 h  [  像使用内部Flash一样使用外部QSPI Flash, 任何AHB总线主控都可以自主读取数据。
) b; s5 l- Z7 Z6 q# f. o  用于从外部QSPI Flash执行代码。( m; I* h+ Q4 F9 S; u
# M1 V+ u+ y4 @
& U" s1 m2 r! y/ u+ ^
QSPI接口能够管理多达256 MB的内存,在内存映射模式下地址范围是0x9000 0000到0x9FFF FFFF。& H4 A( W- g9 S. E  P* s

6 M4 v6 e0 g* @* m( e& A78.3 QSPI总线的HAL库用法- q3 N( b6 r  b$ q7 W5 H; [
78.3.1 QSPI总线结构体QUADSPI_TypeDef
/ ^2 }4 I0 z( m% WQSPI总线相关的寄存器是通过HAL库中的结构体QUADSPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
$ D+ d3 M% ^1 z+ d
, \. ?; z4 d$ B
  1. typedef struct
    9 D5 E1 F2 |& P9 t4 r
  2. {
    7 j1 ]" |0 M( P6 @. ]* {
  3.   __IO uint32_t CR;       /*!< QUADSPI Control register,                           Address offset: 0x00 */( N/ g4 C5 L0 N* c1 q, w. `( Q2 x
  4.   __IO uint32_t DCR;      /*!< QUADSPI Device Configuration register,              Address offset: 0x04 */
    7 q6 ?3 J2 {; a; ]* C( y, N
  5.   __IO uint32_t SR;       /*!< QUADSPI Status register,                            Address offset: 0x08 */
    7 R& R7 q' P$ I( R' c; ^$ l  o
  6.   __IO uint32_t FCR;      /*!< QUADSPI Flag Clear register,                        Address offset: 0x0C */* p. I7 B3 j8 z$ L, o9 v
  7.   __IO uint32_t DLR;      /*!< QUADSPI Data Length register,                       Address offset: 0x10 */
    4 j( v. }# p& ^+ I
  8.   __IO uint32_t CCR;      /*!< QUADSPI Communication Configuration register,       Address offset: 0x14 */( S4 W% P. b( g. K& H( q3 f' B3 v3 e) q
  9.   __IO uint32_t AR;       /*!< QUADSPI Address register,                           Address offset: 0x18 */
    & y- F5 s5 T) x8 {' v
  10.   __IO uint32_t ABR;      /*!< QUADSPI Alternate Bytes register,                   Address offset: 0x1C */
    # U7 K* }. R" n; U+ G  V2 T
  11.   __IO uint32_t DR;       /*!< QUADSPI Data register,                              Address offset: 0x20 */
    " A; t6 j8 O& e& I
  12.   __IO uint32_t PSMKR;    /*!< QUADSPI Polling Status Mask register,               Address offset: 0x24 */8 f. C- V/ C1 x) k1 y
  13.   __IO uint32_t PSMAR;    /*!< QUADSPI Polling Status Match register,              Address offset: 0x28 */
    ) c" y; [/ Q; V9 B
  14.   __IO uint32_t PIR;      /*!< QUADSPI Polling Interval register,                  Address offset: 0x2C */
    & t- ^" _+ j3 Q* Y5 q* g
  15.   __IO uint32_t LPTR;     /*!< QUADSPI Low Power Timeout register,                 Address offset: 0x30 */
    ( Q8 h5 h  ]; `* J* a8 B
  16. } QUADSPI_TypeDef;
复制代码
; E# V* O9 ~  I& |
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。/ n1 b' @  H. _/ P
" c: [+ M& h6 `% ?+ ^6 v( `
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
& k% g$ O4 w  c. y# ]2 U1 ?2 ^
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */( B3 I) p. Z+ o7 b
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

& R. [9 f% x; O" f- w下面我们看下QSPI的定义,在stm32h743xx.h文件。
* G0 h) c% Y5 L, V* _/ y' w2 b& \8 B
  1. #define QSPI_BASE ((uint32_t)0x90000000) /*!< Base address of : QSPI memories  accessible over AXI */
    9 f' p6 r: R0 N  i$ K9 @
  2. . l* D  S: Z- ], O) }$ H% w
  3. #define PERIPH_BASE           (0x40000000UL) 7 q3 [; L  V) S+ y- N5 _& \: W# C
  4. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)
    - |! V5 n+ _0 z

  5. ( z: q7 f- D2 y7 w8 g
  6. #define QSPI_R_BASE           (D1_AHB1PERIPH_BASE + 0x5000)6 d# s" n- |7 [0 h  v( y
  7. #define DLYB_QSPI_BASE        (D1_AHB1PERIPH_BASE + 0x6000)" H# U8 q5 {* I  r* S0 J- S3 X6 M) o
  8. + T% O9 p! b. X4 [' K$ _0 E
  9. #define QUADSPI               ((QUADSPI_TypeDef *) QSPI_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52005000
    ! y! k; @5 p0 ]9 _# E9 B1 t& M
  10. #define DLYB_QUADSPI          ((DLYB_TypeDef *) DLYB_QSPI_BASE)
复制代码
! m1 a' p6 r7 M
我们访问QSPI的CR寄存器可以采用这种形式:QUADSPI->CR= 0。
& Q0 t+ ^* U& o& h& g; t& f9 x- J
78.3.2 QSPI总线初始化结构体QSPI_InitTypeDef
! g6 O( ?. Z( `, r" v下面是QSPI总线的初始化结构体:
) n, a9 G) b. ]$ [9 u5 k" Q1 |$ I7 B  ^9 J0 w/ ?& U) V+ A( u
  1. typedef struct3 B5 v2 {2 \. S( X: `9 b
  2. {
    4 X. \- h, L6 q9 f; [' m/ H
  3.   uint32_t ClockPrescaler;     
    9 z( n( n4 E2 o; z
  4.   uint32_t FifoThreshold;      : K# @$ B- N- [: H) ^
  5.   uint32_t SampleShifting;   
    " ?& l% K  W3 P4 d: R
  6.   uint32_t FlashSize;          % V, N% f" p2 n  G* p* m3 {1 l
  7.   uint32_t ChipSelectHighTime;
    - \8 @/ j8 t9 {" t! d5 [" E3 |) I
  8.   uint32_t ClockMode;         
    ; g- @& w8 H( ?
  9.   uint32_t FlashID;           ; |# s, X) j% [. |$ }# }  R5 c" i
  10.   uint32_t DualFlash;                                           ; X" s0 f. P6 e) m; ?
  11. }QSPI_InitTypeDef;
复制代码

, ?/ N- j, t8 D下面将结构体成员逐一做个说明:
; }- ?& A* @$ m' @. ?7 b8 A$ Q- K* n' T& \0 I% W
  ClockPrescaler7 N# q, N% j! @; L
设置时钟分频,参数范围0到255。特别注意,这里是针对HCLK3作为QSPI时钟来说的。+ y  v# {' ^! ^2 A
7 q* x+ `# l1 _3 E% x6 |
  FifoThreshold# b5 @8 b6 i; h% D! R8 h
用于设置FIFO阀值,仅用于间接模式,参数范围1到32,单位字节。6 n' d/ Y4 n% D8 x- M6 R$ R

; x2 f# K- h4 W( t  c1 t  SampleShifting
' u+ j. N% E# `- ?0 Y5 h/ [QUADSPI在FLASH驱动信号后可以选择再过半个CLK周期后才对FLASH数据采样,这有利于推迟数据采样。支持的参数如下:
/ L) C" a! r" }/ c; X5 x- Z4 o/ R. |
* T2 \* k. J6 F8 u$ Z& n#define QSPI_SAMPLE_SHIFTING_NONE      ((uint32_t)0x00000000U)         B. }! R+ g2 {: `2 Y  o" L
#define QSPI_SAMPLE_SHIFTING_HALFCYCLE ((uint32_t)QUADSPI_CR_SSHIFT)$ \- d( V# u6 \) o3 w7 ^
  FlashSize
6 {6 p$ H+ Y6 W5 _1 S1 A- E( jFlash大小是2^(FlashSize + 1),单位字节。
8 M) H$ h- o/ d8 L- `$ I* o2 Y, L
% b; `3 E4 Y% h0 I7 i, _间接模式下,最大支持的Flash大小是4GB,内存映射模式,最大支持256MB。  n& D  K6 N) m0 H

; k" r! n0 i+ Z$ Q5 F0 j
  1. #define SPI_POLARITY_LOW       (0x00000000UL)
    & P1 ]6 Q7 J. {  {: ]- @; h
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码
4 a; j- M, H* ?2 a
  ChipSelectHighTime, C) }. E# h7 H
命令之间的CS片选至少保持的高电平时钟周期ChipSelectHighTime+1。支持的参数如下:, |) V' Z' L' g. [/ i6 s! f2 e- G
) \* ?0 {% O/ ?, y. F# w: _- F- E
  1. #define QSPI_CS_HIGH_TIME_1_CYCLE      ((uint32_t)0x00000000U)                             0 x/ Q5 _% H& H6 y9 o
  2. #define QSPI_CS_HIGH_TIME_2_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0)                     % [( l2 N: R+ _" O- j$ E" C; y5 v
  3. #define QSPI_CS_HIGH_TIME_3_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_1)                     
    " ?, Q* Z  r' y( G& T% |/ p' S
  4. #define QSPI_CS_HIGH_TIME_4_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0 | QUADSPI_DCR_CSHT_1) 2 e$ A. B! L9 N  a
  5. #define QSPI_CS_HIGH_TIME_5_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2)                     
    3 _8 z" u' Y/ m/ n6 m, ^# \
  6. #define QSPI_CS_HIGH_TIME_6_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_0)2 h9 B6 f) n7 I; s  U
  7. #define QSPI_CS_HIGH_TIME_7_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_1) 3 R& t5 y  D1 ]& y( q/ ^
  8. #define QSPI_CS_HIGH_TIME_8_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT)   
复制代码
               
) Z! E4 w. t# h7 c  FlashID- T2 g4 {) Y# M' Z
用于选择要操作的BANK,即用BANK1还是BANK2操作Flash。0 h* d4 P9 X6 n* \/ [
. R& V. S% X% N. K5 P
  1. #define QSPI_FLASH_ID_1                ((uint32_t)0x00000000)      
    ; R# D% Z: F- f6 n
  2. #define QSPI_FLASH_ID_2                ((uint32_t)QUADSPI_CR_FSEL)
复制代码
. U3 M0 I* ?  w
  DualFlash& F& w; q' ]' A$ j
用于选择是否使用双BANK。
& w( I8 i% |) S) o8 L) J3 t6 ^/ J' Z) s) E
  1. #define QSPI_DUALFLASH_ENABLE          ((uint32_t)QUADSPI_CR_DFM) /*!<Dual-flash mode enabled*// ^$ A5 ]5 g  Y5 ^0 R! F
  2. #define QSPI_DUALFLASH_DISABLE         ((uint32_t)0x00000000)     /*!<Dual-flash mode disabled*/
复制代码

0 H: l. d& A  Y/ Y7 R78.3.3 QSPI总线句柄结构体QSPI_HandleTypeDef
7 f! E7 f* M8 X下面是QSPI总线的初始化结构体:7 Y- |; I0 L' o$ r. k  q# |, N% U. d* P

% u  u* S2 s  W2 d4 h+ \5 a2 i
  1. typedef struct9 T' z5 [  g0 H1 A$ B
  2. {8 y) i6 _, [# Y2 [/ ~' `) ]" V) u9 N
  3.   QUADSPI_TypeDef            *Instance;        /* QSPI registers base address        */2 Q* r# L3 n" h8 \
  4.   QSPI_InitTypeDef           Init;             /* QSPI communication parameters      */
    : O3 m2 o' u5 l  e; j# Z
  5.   uint8_t                    *pTxBuffPtr;      /* Pointer to QSPI Tx transfer Buffer */
    7 E# m& d; E" @' ^8 {
  6.   __IO uint32_t              TxXferSize;       /* QSPI Tx Transfer size              */4 o5 ?5 |% g) x* i* w
  7.   __IO uint32_t              TxXferCount;      /* QSPI Tx Transfer Counter           */& B( I9 P+ v  q+ w4 w9 H6 x) _
  8.   uint8_t                    *pRxBuffPtr;      /* Pointer to QSPI Rx transfer Buffer */# \1 }$ S+ R3 M
  9.   __IO uint32_t              RxXferSize;       /* QSPI Rx Transfer size              */* p" ?) x; s( j1 k' e) A
  10.   __IO uint32_t              RxXferCount;      /* QSPI Rx Transfer Counter           */' W7 w, g; \+ N) ?# O4 y; C0 \
  11.   MDMA_HandleTypeDef         *hmdma;           /* QSPI Rx/Tx MDMA Handle parameters  */: I" {; i/ b7 ?6 i+ `! d# [
  12.   __IO HAL_LockTypeDef       Lock;             /* Locking object                     */
    . U+ S- ?8 u7 D
  13.   __IO HAL_QSPI_StateTypeDef State;            /* QSPI communication state           */7 d* n5 `% S& ~+ Y8 o
  14.   __IO uint32_t              ErrorCode;        /* QSPI Error code                    */
    5 A! L. o) j8 m& a/ F
  15.   uint32_t                   Timeout;          /* Timeout for the QSPI memory access */ % x  Y7 C! L; [
  16. }QSPI_HandleTypeDef;
复制代码
" W. C4 W4 a0 f3 Z
下面将结构体成员做个说明:
- o: J+ ]* C5 M( m3 D
) A# J& Y1 t1 d% X- J  QUADSPI_TypeDef   *Instance( o  o7 {/ }9 l1 V8 ^: O% q
这个参数是寄存器的例化,方便操作寄存器,比如使能QUADSPI。
7 ?& N4 u, f4 J" A3 j
1 x' ?1 p9 |4 w6 fSET_BIT(QUADSPI ->CR,  QUADSPI_CR_EN)。7 v! A- R# L- M! y
) i& K" L2 J5 v) s& x
  QSPI_InitTypeDef  Init0 m* }' `. }9 m5 C7 h
这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。
2 B) O+ m$ |/ l3 ^+ I; p
2 [$ w- o# i# J  MDMA_HandleTypeDef          *hmdma
1 L/ [: [2 X3 M' _" K" q& c用于QSPI句柄关联MDMA句柄,方便操作调用。% p) |: H0 U& l# i6 y% W8 V3 o

" n$ s$ @6 r3 p  z" J4 P  其它参数
0 S. f( [+ t. ]其它参数基本都是在函数内部调用,用户基本不用管。1 t- Y( M# d( c! {2 B; l8 ~
- \  b) D" N# |# H$ U4 b; ]
78.3.4 QSPI命令结构体QSPI_CommandTypeDef
7 w, E, o9 Q; F6 B; ?2 v) t下面是QSPI总线的命名结构体:. A8 e9 X0 _+ a: O+ S

1 J6 `  p% X( J
  1. typedef struct
    ) }3 D* S5 p! ^, `
  2. {
    3 ~3 g$ ]1 r2 M# B6 V% U
  3.   uint32_t Instruction;        # v# ^) A$ Y. |3 z; h
  4.   uint32_t Address;             @8 q9 q7 k2 ~
  5.   uint32_t AlternateBytes;     3 a0 M0 y+ ^0 \1 A( N: s' \
  6.   uint32_t AddressSize;      
    2 ?/ Y' y2 R4 I) X3 A, x5 D
  7.   uint32_t AlternateBytesSize;
    ) W  k0 I5 D4 ^" ]1 X  t
  8.   uint32_t DummyCycles;      
    2 Q! I& O# A, W1 C$ t
  9.   uint32_t InstructionMode;  & E1 H; J* @0 P! A' P- G% ]
  10.   uint32_t AddressMode;      
    * c3 a* O2 t: Z/ f4 j
  11.   uint32_t AlternateByteMode;
    1 f% B4 s% ^$ h; d; y0 A
  12.   uint32_t DataMode;         
    " G% p; V4 y8 T' ?
  13.   uint32_t NbData;         
    - N$ Q* ~! G4 r
  14.   uint32_t DdrMode;           
    : T8 K: @4 V. k' W! F  B
  15.   uint32_t DdrHoldHalfCycle;  
    + H( Q4 a* L  m% B
  16.   uint32_t SIOOMode;         
    # ~5 ], l. E& P9 d+ h1 D
  17. }QSPI_CommandTypeDef;
复制代码
; R/ X" X6 r3 y& C1 J3 y4 {
下面将结构体成员逐一做个说明:, o8 t% B: G, l5 d0 T

/ X" k  a- U/ k  Instruction# n# r4 |% B  m' v% G2 p# x3 a- q
设置要发送的指令,参数范围0x00到0xFF。2 |/ F$ d% r+ K  T
9 Y1 T- c2 [9 }  q: d: g9 |# f
  Address* y2 S/ c4 K7 _% E( n/ e6 a8 i
设置要发送的地址,地址由是1个字节到4个字节来表示,参数范围0x0 到 0xFFFFFFFF。5 |. o8 X% M3 ]( r9 M! `: [7 z
' n, y. ^- M- Z) H
  AddressSize
, B# R. W$ G/ {+ I0 f/ d5 U地址大小,即表示此地址需要的字节数,支持的参数如下:
* Z6 b7 z9 F7 f& _) r+ X
5 Y% r' E( g( M
  1. #define QSPI_ADDRESS_8_BITS            ((uint32_t)0x00000000)           /*!<8-bit address*/5 Y$ c# K4 [+ ]7 [
  2. #define QSPI_ADDRESS_16_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_0) /*!<16-bit address*/* L5 k6 n+ |7 P- b2 p) |9 B. b" K
  3. #define QSPI_ADDRESS_24_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_1) /*!<24-bit address*/% ^9 `4 t$ p6 j& @
  4. #define QSPI_ADDRESS_32_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE)   /*!<32-bit address*/
复制代码

4 ~) O  ^# L3 N' W  AlternateBytesSize+ ?1 f1 ^) y8 s7 A* |
交替字节大小,支持的参数如下:
& n5 c+ e9 W, K  l. t- O8 c8 Z  y  {& ?, e5 M; Z2 l1 f# Y% T% M8 q
  1. #define QSPI_ALTERNATE_BYTES_8_BITS    ((uint32_t)0x00000000)           /*!<8-bit alternate bytes*/
    / f$ y2 T* x& b8 @% \% _
  2. #define QSPI_ALTERNATE_BYTES_16_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_0) /*!<16-bit alternate bytes*/
    8 O% N* @9 y% Z1 S% z6 w# W
  3. #define QSPI_ALTERNATE_BYTES_24_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_1) /*!<24-bit alternate bytes*/, J# Z# M2 f, z) s0 l; T2 }6 S5 K
  4. #define QSPI_ALTERNATE_BYTES_32_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE)   /*!<32-bit alternate bytes*/
复制代码

; E7 N7 a# F. o* J  DummyCycles
% Z5 E' d! u, O! ^2 D执行空周期个数,参数范围0到31:
' G, \8 a. K! R+ l$ k; C; C# W
/ r2 @9 k3 L# _$ R' B( |  InstructionMode
7 `5 {% E- I# V5 b2 r指令阶段需要几线模式:
5 q! ^  _- ^! m$ T* V$ k8 D
& \4 v5 E. M. |5 Z& Q- M" V& m5 C
  1. #define QSPI_INSTRUCTION_NONE          ((uint32_t)0x00000000)          /*!<No instruction*/7 p* F9 b" u8 N
  2. #define QSPI_INSTRUCTION_1_LINE        ((uint32_t)QUADSPI_CCR_IMODE_0) /*!<Instruction on a single line*/
    + o3 I0 a  v% T$ k% I0 x' `
  3. #define QSPI_INSTRUCTION_2_LINES       ((uint32_t)QUADSPI_CCR_IMODE_1) /*!<Instruction on two lines*/! F( h. R  a8 i$ r7 d
  4. #define QSPI_INSTRUCTION_4_LINES       ((uint32_t)QUADSPI_CCR_IMODE)   /*!<Instruction on four lines*/
复制代码

( `, a; W1 W, d4 t4 O# q- ]6 {1 F  AddressMode
5 f1 ?; T. X3 ?地址阶段需要几线模式:
4 t  P% z& o0 T7 U
0 b) I4 `3 x# b( C) g! {* o
  1. #define QSPI_ADDRESS_NONE              ((uint32_t)0x00000000)           /*!<No address*/
    ; B- n# j  f4 w4 F0 n5 U4 H
  2. #define QSPI_ADDRESS_1_LINE            ((uint32_t)QUADSPI_CCR_ADMODE_0) /*!<Address on a single line*/
    ' A& [1 s+ M3 {/ B. K# @6 V& e
  3. #define QSPI_ADDRESS_2_LINES           ((uint32_t)QUADSPI_CCR_ADMODE_1) /*!<Address on two lines*/; G  I3 M, [: H# J* j' _( A+ X$ Y
  4. #define QSPI_ADDRESS_4_LINES           ((uint32_t)QUADSPI_CCR_ADMODE)   /*!<Address on four lines*/
复制代码
; ]/ x" B# o# L7 f/ {( t8 o
  AlternateByteMode
. @) A) u7 A: N" C! _! W7 @交替字节阶段需要几线模式:
  L* y  Q7 A1 a  Q) g. G# P0 L; {, o  _& R+ t, n+ W
  1. #define QSPI_ALTERNATE_BYTES_NONE      ((uint32_t)0x00000000)           /*!<No alternate bytes*/8 o  X8 F8 f* ]. V9 m8 k- F
  2. #define QSPI_ALTERNATE_BYTES_1_LINE    ((uint32_t)QUADSPI_CCR_ABMODE_0) /*!<Alternate bytes on a single line*/
    # A  P6 h5 _* E
  3. #define QSPI_ALTERNATE_BYTES_2_LINES   ((uint32_t)QUADSPI_CCR_ABMODE_1) /*!<Alternate bytes on two lines*/* s- H) |+ D3 |0 Q
  4. #define QSPI_ALTERNATE_BYTES_4_LINES   ((uint32_t)QUADSPI_CCR_ABMODE)   /*!<Alternate bytes on four lines*/
复制代码

% n. H: p0 U! u- n& X) L  DataMode! F+ l/ {/ ]1 z: k3 X
数据阶段需要几线模式:
$ ^; P! U; G# |& C5 n* k4 W1 L( D' E" s$ }/ s! j
  1. #define QSPI_DATA_NONE                 ((uint32_t)0X00000000)           /*!<No data*/
    3 k8 {, f& O2 P+ V% ]! @. g
  2. #define QSPI_DATA_1_LINE               ((uint32_t)QUADSPI_CCR_DMODE_0) /*!<Data on a single line*/0 L; d1 b# X$ W; v4 M
  3. #define QSPI_DATA_2_LINES              ((uint32_t)QUADSPI_CCR_DMODE_1) /*!<Data on two lines*/0 B7 O5 k8 I- ~8 P
  4. #define QSPI_DATA_4_LINES              ((uint32_t)QUADSPI_CCR_DMODE)   /*!<Data on four lines*/
复制代码

8 P" d7 _! T# a) ]5 p7 r% Q  NbData
* k6 I; ?7 q. j- e7 c/ o要传输的数据大小,参数范围0 到 0xFFFFFFFF,如果设置为0表示不定长,直到存储器末尾。! K. o9 z) T/ b7 I% F$ W: e

! p1 h+ Q7 E3 V% [( T  DdrMode
5 z; ]" q7 R4 L9 D6 ]7 [用于设置是否使能DDR模式。数据阶段,交替字节阶段和数据传输阶段可以使用DDR模式。支持的参数如下:8 ~0 k8 X& O# i  J  [) w3 k* K) [3 Z

/ Y: V% I- K& a. m
  1. #define QSPI_DDR_MODE_DISABLE          ((uint32_t)0x00000000)       /*!<Double data rate mode disabled*/
    3 V7 N1 d! n; ^9 M9 E* C, |
  2. #define QSPI_DDR_MODE_ENABLE           ((uint32_t)QUADSPI_CCR_DDRM) /*!<Double data rate mode enabled*/
复制代码

& _; P0 b( Z- ]  DdrHoldHalfCycle
" R6 e- T9 G& ~( f( u2 t+ i5 L2 D* [' KDDR模式下,用于设置延迟半个时钟周期再做数据输出。
! T; a' o1 T" j3 K% A' C7 q
7 s9 \2 Q) J& R1 ^5 M& L8 U
  1. #define QSPI_DDR_HHC_ANALOG_DELAY      ((uint32_t)0x00000000)      
    ; U, c& A& Q; [
  2. #define QSPI_DDR_HHC_HALF_CLK_DELAY    ((uint32_t)QUADSPI_CCR_DHHC)
复制代码
0 F9 ?% B  k4 A- A) V0 E5 E* ~
  SIOOMode) f8 @4 j( @& m4 l3 i/ @
设置仅发送一次指令还是每次操作都发送指令,支持的参数如下:
3 r$ j  i5 F* Q  ~' ], n1 f; S8 b2 [7 A4 r) U
  1. #define QSPI_SIOO_INST_EVERY_CMD       ((uint32_t)0x00000000)     6 |* A4 N8 _* q
  2. #define QSPI_SIOO_INST_ONLY_FIRST_CMD  ((uint32_t)QUADSPI_CCR_SIOO)
复制代码

! |/ G8 G1 u5 v  ]. c! v8 T3 J' O78.3.5 QSPI自动查询结构体QSPI_AutoPollingTypeDef" R9 i3 d4 P+ B. N2 H' J. \
下面是QSPI总线自动查询结构体:$ O( I; z, p+ M* D' A# S9 d" g
4 |8 K5 |8 E5 J7 g2 w
  1. typedef struct
    7 u' o  ?! h9 C- |6 o3 m: Y
  2. {- M% x% _  c1 j3 M
  3.   uint32_t Match;            
    ! g$ |0 c3 d# h6 t  C% X0 R
  4.   uint32_t Mask;            
    " a9 O& I3 a2 f5 G
  5.   uint32_t Interval;         
    , B" T- p, \+ J& M* a& [! e4 q
  6.   uint32_t StatusBytesSize;    9 T' h" g% Y; s2 X' \( g
  7.   uint32_t MatchMode;      
    1 ?- V4 t0 R0 l+ f( _
  8.   uint32_t AutomaticStop;     % {  ^- X$ D" n' C- N6 `  F5 K/ o
  9. }QSPI_AutoPollingTypeDef;
复制代码
8 W, S# f" X1 d0 r" q: y9 X  a
下面将结构体成员逐一做个说明:4 e7 t# D# H/ R0 [# V
5 s+ p2 A/ R2 Y6 S3 O4 m
  Match2 i  {5 @6 G2 E4 s1 u- S% L" R2 F
参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器的值与此参数成员值做匹配。参数范围0x0 到 0xFFFFFFFF。  F- U. s# B" t4 N" Y8 U

( c0 B) p, R; j. u1 |$ E: k8 Y+ }, E  Mask
9 C% x9 u4 t& v' k9 q. G: f用于设置屏蔽位,比如Mask = 0x01,表示仅保留bit0的数值,其它bit忽略。参数范围0x0 到 0xFFFFFFFF。
9 M6 w& l) k) l: C- `: `6 G/ C& y+ a' q' L
  Interval+ {) L9 W% L- E& b3 }" b! ^
指定自动轮询阶段两次读取之间的时钟周期数。参数范围0 到 0xFFFF。
, y! e7 `5 q" a7 e' H5 o& I# M2 p# X, h! ^5 [4 p7 U
  StatusBytesSize
1 A% E6 N# ^6 F用于设置状态寄存器大小,参数范围1到4个字节。
& ~, [1 M7 X% u( c. M* R( a* i7 X7 C. _
  MatchMode
" d& @/ k( h! u* ?. `$ Y# j参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器完全与参数成员Match一样(与操作的含义)或者任意一个bit的值与参数成员Match中一个bit的值一样(或操作的含义),比如Mask = 0x01,Match=0x00,MatchMode=与操作,表示不断查询状态寄存器bit0,等待其为0。
" D' ?; [; o+ P$ S2 s2 G5 V5 a0 e; H. o9 v9 x
MatchMode支持的参数成员如下:4 b0 d4 L; G7 b; ?
1 D" w8 V' Z" T# w* Y: ^
  1. #define QSPI_MATCH_MODE_AND            ((uint32_t)0x00000000)     /*!<AND match mode between unmasked bits*/& v, }! \( Q) s( X( U4 p; R4 J, b6 r8 D
  2. #define QSPI_MATCH_MODE_OR             ((uint32_t)QUADSPI_CR_PMM) /*!<OR match mode between unmasked bits*/
复制代码

1 s4 _, \% t. e8 L" ?# y" C+ O  AutomaticStop8 f/ q& K7 a0 W6 ]9 u
当与参数成员Match匹配时,自动停止检测。% v, F" U3 T: Y5 ~' N0 B& X! q& D
- H/ N" Z$ K4 R4 N
78.3.6 QSPI内存映射结构体QSPI_MemoryMappedTypeDef
. J1 J9 j6 }3 `( [6 `& f下面是QSPI总线的内存映射结构体:
. H, X$ g" q0 O
( L1 u; j" e7 N9 E8 Q- C
  1. typedef struct. O! }$ B2 h6 J  _* [* n0 n) \
  2. {
    2 s, m- s  L4 r1 O/ ?
  3.   uint32_t TimeOutPeriod;    - {9 d* [8 g4 G( i
  4.   uint32_t TimeOutActivation;  9 g7 D- e& D& P. T3 ^3 r
  5. }QSPI_MemoryMappedTypeDef;  
复制代码

$ i& I3 B( l& [$ i" U3 o6 f3 u下面将结构体成员逐一做个说明:
4 h' r- p+ m0 Y* r# m/ ~8 j3 A+ n
* f6 ^. w+ Z" `. V) y/ C& j  l  TimeOutPeriod
0 R2 E% [! y+ R1 ?/ YFIFO满时,释放芯片选择之前要等待的时钟周期数。参数范围0到0xFFFF。, e7 V& w" L4 S9 ]( `" h
8 E  s. |1 P& c6 S7 G* m' w
  TimeOutActivation0 U) ^9 \7 ~$ \! K
指定是否启用超时计数器以释放芯片选择,支持的参数成员如下:; ~! p7 P. K2 `3 O
& V$ I4 n+ i/ K2 a5 u
  1. #define QSPI_TIMEOUT_COUNTER_DISABLE   ((uint32_t)0x00000000)     7 g; _8 t6 F  F4 ?/ _
  2. #define QSPI_TIMEOUT_COUNTER_ENABLE    ((uint32_t)QUADSPI_CR_TCEN)
复制代码
6 A* h' }% X" U" t+ _
78.4 QSPI总线源文件stm32h7xx_hal_qspi.c
# z7 N9 f+ P5 t4 ~此文件涉及到的函数较多,这里把几个常用的函数做个说明:
7 z( P. k6 a. T, e$ D- y
' l& J4 g* m) g3 h  A4 T( g* ^  HAL_QSPI_Init
( h, f. o/ y* Y3 F  HAL_QSPI_DeInit
4 O9 }/ ^  b2 n- B5 u: S  HAL_QSPI_Command
6 Q: a# x- R6 [+ {  HAL_QSPI_Command_IT, K, ~* f* Q3 u; l  U
  HAL_QSPI_AutoPolling
- {3 F  o: d  M) z% o* [  HAL_QSPI_AutoPolling_IT
+ J6 c* k' O+ X7 s  HAL_QSPI_Transmit
6 E2 f  Y- c2 M  HAL_QSPI_Receive
- u+ c$ X* Y5 f/ \3 ^  HAL_QSPI_Transmit_DMA% q# x5 X0 a( h/ T& ?" Z. P
  HAL_QSPI_Receive_DMA/ N: C8 O0 j4 K$ j* m- {8 r3 C( @6 Z  m
  HAL_QSPI_MemoryMapped- J* B0 X6 p( e2 V; i: E" R1 T
78.4.1 函数HAL_QSPI_Init. _7 Y3 h, h. `) O8 p- C
函数原型:& S& Z$ ~# p8 R
8 [0 J5 k: O+ M4 w
  1. HAL_StatusTypeDef HAL_QSPI_Init(QSPI_HandleTypeDef *hqspi)% d7 g( J/ z) M% @
  2. {
    ' W7 L/ U* Y7 L$ d1 U. ?
  3.   HAL_StatusTypeDef status;  V, q; h3 D, V/ [2 l9 {
  4.   uint32_t tickstart = HAL_GetTick();
    - r! J+ o4 b  l1 x( M. q) O
  5. / E) I# y# {: }- g- W. v
  6.   /* 检测句柄是否有效 */
    & V9 V- N4 `4 d9 j: ?' _9 k
  7.   if(hqspi == NULL)( p- `$ A7 ]. _% D1 t! G1 C
  8.   {
    0 d0 z7 ~0 s5 R7 e; e/ q4 a
  9.     return HAL_ERROR;
    # u& Y0 s8 d* D. g  H1 j2 B4 Z
  10.   }! H/ S0 G( y7 S2 N

  11.   P8 I! ]5 F# j( v0 W
  12.   /* 检查参数是否有效 */
    $ a( M" k5 d! B, K; Y
  13.   assert_param(IS_QSPI_ALL_INSTANCE(hqspi->Instance));$ |4 w  c3 z7 @/ n# F" Z. B+ W# s
  14.   assert_param(IS_QSPI_CLOCK_PRESCALER(hqspi->Init.ClockPrescaler));$ b$ y: Z  X- B( U
  15.   assert_param(IS_QSPI_FIFO_THRESHOLD(hqspi->Init.FifoThreshold));
    * S7 U6 S& B' b; G! [
  16.   assert_param(IS_QSPI_SSHIFT(hqspi->Init.SampleShifting));
    , c2 _- s7 `: [+ O% O
  17.   assert_param(IS_QSPI_FLASH_SIZE(hqspi->Init.FlashSize));
    5 R/ ]8 q0 ]+ y  V$ E* w- R# _
  18.   assert_param(IS_QSPI_CS_HIGH_TIME(hqspi->Init.ChipSelectHighTime));6 I' N5 C1 p4 W1 {; y  k
  19.   assert_param(IS_QSPI_CLOCK_MODE(hqspi->Init.ClockMode));+ n& I9 i: V) H# Z. U8 S6 ?# w, f
  20.   assert_param(IS_QSPI_DUAL_FLASH_MODE(hqspi->Init.DualFlash));
    ) f( ~# G  F9 W

  21. 6 a. F  j  M& L7 p# O5 v
  22.   if (hqspi->Init.DualFlash != QSPI_DUALFLASH_ENABLE )
    ( v  m5 P# h+ T$ r" `. B3 W' ^
  23.   {" L8 M  Y3 r: l9 L
  24.     assert_param(IS_QSPI_FLASH_ID(hqspi->Init.FlashID));
    % j; ^; o: u+ F( P) {: {+ p% F
  25.   }
    . |+ w1 P& V5 Q" f$ L. @

  26. 6 s1 a: ?4 j) c. ]+ q
  27.   if(hqspi->State == HAL_QSPI_STATE_RESET)
    % ]  {9 j+ R! [4 I, O+ ]4 V
  28.   {  p! \- P/ M7 E/ ?" k$ N' O

  29. . R# N& Z/ g7 Y
  30. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1), v) B3 S. X. K. S+ W0 r
  31.     /* 复位状态,设置默认的回调 */+ S, K* k1 R, \
  32.     hqspi->ErrorCallback         = HAL_QSPI_ErrorCallback;( u& j2 f( b3 t2 b4 Q: Z/ e. S& S
  33.     hqspi->AbortCpltCallback     = HAL_QSPI_AbortCpltCallback;1 G- ^* K4 j& V9 M8 U
  34.     hqspi->FifoThresholdCallback = HAL_QSPI_FifoThresholdCallback;
    8 N8 a+ a" T& s: o0 M7 j
  35.     hqspi->CmdCpltCallback       = HAL_QSPI_CmdCpltCallback;
    % u. ]7 R/ {2 F0 _
  36.     hqspi->RxCpltCallback        = HAL_QSPI_RxCpltCallback;
    & |- i, k! Z9 f" N5 Z2 X
  37.     hqspi->TxCpltCallback        = HAL_QSPI_TxCpltCallback;' X+ {, Z: r9 N( u' k
  38.     hqspi->StatusMatchCallback   = HAL_QSPI_StatusMatchCallback;9 H2 _& J5 b' T3 {# @
  39.     hqspi->TimeOutCallback       = HAL_QSPI_TimeOutCallback;
    - g' a( E7 o$ V
  40. + O; Q8 u3 N9 n0 p8 p
  41.     if(hqspi->MspInitCallback == NULL)8 H0 m1 {" A7 Z, ~8 D7 j
  42.     {/ [. W$ ~; O. B
  43.       hqspi->MspInitCallback = HAL_QSPI_MspInit;* C+ o- E5 w, C! Q' J
  44.     }
    $ a: z) u  f1 m/ M3 _8 @) ]
  45. 1 X- Z) Z% l/ n& \3 a. d
  46.     /* 初始化底层硬件 */8 T$ z  [+ K* P/ t
  47.     hqspi->MspInitCallback(hqspi);
    " {' I5 ^! J7 E7 W, a9 Y; g* ^( J
  48. #else
    3 J3 O4 C2 a$ F5 `# y
  49.     /* 初始化: GPIO, CLOCK */, E# g% [9 d: A
  50.     HAL_QSPI_MspInit(hqspi);9 [+ m+ p* ?! L
  51. #endif( B1 s: q# X% {" }* R: r

  52. ! O/ {# S2 t+ q9 `' t! ?
  53.     /* 配置QSPI内存访问默认的溢出时间 */
    % a( V4 `0 g3 E+ ^" r* N0 a
  54.     HAL_QSPI_SetTimeout(hqspi, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);0 ~; h- d# r) ]/ K# G' M( s+ ^
  55.   }& b& {* V5 ?. p- T( D
  56. 7 V8 _) X) A3 ^& N6 |5 F( a) ?
  57.   /* 配置QSPI FIFO阀值 */. |2 g$ B6 j$ G2 [5 J5 s
  58.   MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_FTHRES,, m8 J: E' z* ^6 H0 Q0 @% S* G- t8 ^
  59.              ((hqspi->Init.FifoThreshold - 1U) << QUADSPI_CR_FTHRES_Pos));
    ' i9 m( o6 \" o4 I. k0 L

  60. - c, b4 E0 L$ ^, `4 n4 I) f
  61.   /* 等BUSY标志复位 */
    ; w/ m/ R/ k' ~  R& ?
  62.   status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);! J9 D& J  d# S4 q; k* |- [
  63. ' a0 G- {2 a3 i1 [9 J* j* m1 h
  64.   if(status == HAL_OK). K* T# M. b9 o. X. G! l
  65.   {* I; H; }8 `' L+ Q, M9 A) F% f7 K
  66.     /* 配置QSPI时钟分频和采样延迟 */
    # C, Z( ?5 ]/ L- e& d5 x3 ]  p
  67. MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PRESCALER | QUADSPI_CR_SSHIFT | QUADSPI_CR_FSEL |$ ?& q+ ?9 N, b+ Z
  68. QUADSPI_CR_DFM),
    , r( O2 w) C( E, g2 F2 `' S
  69.                ((hqspi->Init.ClockPrescaler << QUADSPI_CR_PRESCALER_Pos) |
    1 {# }: J' G' O6 V
  70.                 hqspi->Init.SampleShifting  | hqspi->Init.FlashID | hqspi->Init.DualFlash));
    / }3 I1 K/ t; l3 x% m& C4 N. M

  71. * t2 I! {; }- E% U( r8 P
  72.     /* 配置QSPI Flash大小,CS片选高电平时间和时钟模式 */$ l7 H- v9 k& [2 m
  73.     MODIFY_REG(hqspi->Instance->DCR, (QUADSPI_DCR_FSIZE | QUADSPI_DCR_CSHT | QUADSPI_DCR_CKMODE),
    # [6 |6 S" J" [
  74.                ((hqspi->Init.FlashSize << QUADSPI_DCR_FSIZE_Pos) |+ `* Z+ W# J/ a) _, f2 {* f" U. B
  75.                 hqspi->Init.ChipSelectHighTime | hqspi->Init.ClockMode));2 q4 B) C8 X- m- Z( [# ?4 }

  76. ; |" n: q) e: q  l, J  s
  77.     /* 时钟QSPI外设 */
    # i8 N) Z( y# W8 b5 m; |4 p" w
  78.     __HAL_QSPI_ENABLE(hqspi);
    6 K3 |: t4 Y& B: N/ Z2 s
  79. * Y9 n: C& c6 a# E7 q/ k
  80.     /* 设置QSPI无错误代码 */
    8 p  o( n- J5 a1 W) h2 |
  81.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;3 |/ W3 H4 J: m# [/ G

  82. : i& Y9 p+ D. w% ~$ l3 q3 a
  83.     /* 初始化QSPI状态就绪 */
    + V& Z7 `8 q8 n, G
  84.     hqspi->State = HAL_QSPI_STATE_READY;
    1 B, {  [8 K; L& R  T! v  Z
  85.   }! f! O" O) u3 K' C9 z% _) d9 N
  86. ) C# Z$ Q# @: s3 W/ w0 }# T
  87.   /* 返回状态信息 */
    % ~) t1 t9 c& \9 X1 ^( {5 V6 D3 J
  88.   return status;4 v$ f; J! e4 |$ |
  89. }
复制代码
0 x) M; X" s' m; n
函数描述:, o. Q  C$ W/ D

$ a% b- V* U4 c此函数用于初始化QSPI。
$ y3 U0 D9 X6 ~5 H* D
& r* ^% s; {/ |- i: j函数参数:
5 M) Y; P& g; t, I
7 @( _& Q1 O; k/ P. L. ?  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,详见本章3.3小节。0 O3 ]" J0 t% C" D  R5 |
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。: k& j( o  ^/ h
注意事项:
3 w# A( q( v# @7 z; c, o, T+ n
函数HAL_QSPI_MspInit用于初始化QSPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
% N& I6 K6 ~% M. c3 _9 }如果形参hqspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量QSPI_HandleTypeDef SpiHandle。
9 a5 d) k* N7 A' j' {2 h5 c对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_QSPI_STATE_RESET  = 0x00U。
/ J& d4 u: ]. i" k  S: Z6 b8 J6 y+ R. K" @3 p
解决办法有三
8 @6 x/ D( p. c4 s4 T$ A- h/ X- D( X9 L
方法1:用户自己初始化QSPI和涉及到的GPIO等。7 {% G) L/ b2 w' _- D
2 n; _% v! K; @/ H* x
方法2:定义QSPI_HandleTypeDef QspiHandle为全局变量。" m5 ~! w4 b% {# {5 b
& g; ?! |( c# F) q
方法3:下面的方法3 k2 Z1 Z2 R1 E
  r4 J( p  u8 [5 k3 O% F1 C3 z
  1. if(HAL_QSPI_DeInit(&QspiHandle) != HAL_OK)
    4 d" R$ d7 t2 g8 H" R1 t1 K
  2. {
    1 n7 ~- T0 Z/ V" O  M' k
  3.     Error_Handler();
    # c. p* _( i- y+ V
  4. }  
    " s/ U7 ?$ n9 @: g/ W% l
  5. if(HAL_QSPI_Init(&QspiHandle) != HAL_OK)5 \6 a# N) Y; ~3 ~) K  o3 k4 L; N
  6. {  z' p- j; c/ G
  7.     Error_Handler();
    # A0 s4 s$ W$ f0 x( Q$ G0 R" T
  8. }
复制代码

- H, o" W7 x) m, ?, z5 i使用举例:; U0 q1 y- m1 ^/ n& ?4 A/ [

. p9 X; F# h8 e  U
  1. /*
    , B7 f8 G  ~6 A6 {6 l8 g/ l+ B
  2. *********************************************************************************************************
    0 K% i- Q) f6 o8 ]% Z0 O
  3. *    函 数 名: bsp_InitQSPI_W25Q256
    ) R1 t. p" T4 r) a
  4. *    功能说明: QSPI Flash硬件初始化,配置基本参数9 x$ J. q8 [% S: j& T
  5. *    形    参: 无) J- r- L" h; E, e
  6. *    返 回 值: 无
    # d6 s: A. G- m4 ?+ U" n2 N
  7. *********************************************************************************************************- L& {; l& [  q4 O. f" v6 Q) F
  8. */
    ! O7 S0 O( ?, [0 U
  9. void bsp_InitQSPI_W25Q256(void)
    3 Y0 A  T0 U! L" z4 m: c$ y
  10. {
    1 A3 V# [9 X' ?4 G
  11.     /* 复位QSPI */
    3 f# m& z% m. Q; p. n
  12.     QSPIHandle.Instance = QUADSPI;
    8 m0 ^! ~1 ]+ s
  13.     if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)
    * ~0 {+ d5 E& R4 D; D5 G$ ^
  14.     {% S- s5 x# c6 P0 Y$ X4 B
  15.         Error_Handler(__FILE__, __LINE__);
    6 T; j! ~& }4 w$ E
  16.     }
    + I+ L/ ?; T" {7 |# n7 A

  17. . w5 P, Q' ?, _4 [1 ^- u% g$ A! ~: l
  18.     /* 设置时钟速度,QSPI clock = 200MHz / (ClockPrescaler+1) = 100MHz */
      l6 q3 N. T' t7 T2 P* E' O
  19.     QSPIHandle.Init.ClockPrescaler  = 1;  
    + z8 j7 V8 f. F1 a# e) p: o
  20. ! u4 ]3 n2 u: l8 p
  21.     /* 设置FIFO阀值,范围1 - 32 */
    5 ?$ l. }; k$ c4 J9 Y- X
  22.     QSPIHandle.Init.FifoThreshold   = 32;
    2 t& K3 ]$ ?6 x6 n
  23. - ]0 H2 D  Y* Y2 N* y- e
  24.     /*
    ( S! F* c0 Q/ k" U. ^5 ~6 A
  25.         QUADSPI在FLASH驱动信号后过半个CLK周期才对FLASH驱动的数据采样。
    . A$ D/ v- P  W( J/ n
  26.         在外部信号延迟时,这有利于推迟数据采样。- S1 J: `2 M9 W: m* _4 [0 J
  27.     */
    1 L4 |" T+ @3 L
  28.     QSPIHandle.Init.SampleShifting  = QSPI_SAMPLE_SHIFTING_HALFCYCLE; / \$ H1 ?& Y0 N) z5 \% D

  29. , j7 Y6 W. K5 O4 S
  30.     /*Flash大小是2^(FlashSize + 1) = 2^25 = 32MB */
    . Q/ t$ }3 `+ Z2 D
  31.     //QSPI_FLASH_SIZE - 1; 需要扩大一倍,否则内存映射方位最后1个地址时,会异常。
    : a# g" K* h; f: M) _6 H3 N
  32.     QSPIHandle.Init.FlashSize       = QSPI_FLASH_SIZE; 3 O6 s4 d' @- G( {+ p/ Q
  33. 0 w6 H; f! l" }2 f
  34.     /* 命令之间的CS片选至少保持2个时钟周期的高电平 */
    9 [( J$ b4 a3 K5 }0 f9 K' P
  35.     QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;" Z: O5 X" z( B5 U, `/ `# r2 u
  36. $ ?" m6 ~' F, Z4 W  \7 z! P+ e% C
  37.     /*3 x$ u% s/ `/ U6 L* `
  38.        MODE0: 表示片选信号空闲期间,CLK时钟信号是低电平3 n" t, v8 z, ^$ I7 A6 t! Y
  39.        MODE3: 表示片选信号空闲期间,CLK时钟信号是高电平' M# y* S& F0 Y6 c; T
  40.     */- |$ ?5 R. X! }( y0 [3 K
  41.     QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
    5 U  q" g+ m4 Z2 W5 m

  42. 0 f5 V' ^7 D- o' d) A/ g) `: ?
  43.     /* QSPI有两个BANK,这里使用的BANK1 */
    / N* U+ f, P7 |3 I- z
  44.     QSPIHandle.Init.FlashID   = QSPI_FLASH_ID_1;
    . e& K0 w, K( l7 Y, t
  45. 8 b/ C& q; _! Q$ J, U
  46.     /* V7开发板仅使用了BANK1,这里是禁止双BANK */
    ! r9 E8 T: f  F# D
  47.     QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE;/ @, t! B! O  P( T; B4 O; u3 [
  48.   P" ~* {$ v& m9 P, C. I, \
  49.     /* 初始化配置QSPI */; t" a' l8 q# ^
  50.     if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)$ o$ q- y3 W7 b" s8 D6 q% U- T
  51.     {
    " C0 K! k& U6 u' ~: E
  52.         Error_Handler(__FILE__, __LINE__);0 l) r! F  f1 H3 V9 Z
  53.     }    ( O& X1 U- H8 R- P+ u% L; s9 h5 E
  54. }
复制代码
$ `5 y  W, v( \
78.4.2 函数HAL_QSPI_DeInit" ^. H; x- ~0 D, P4 J) o
函数原型:1 v9 F- D, a( q! _, T! {
6 ~& }) S' V8 E) _
  1. HAL_StatusTypeDef HAL_QSPI_DeInit(QSPI_HandleTypeDef *hqspi)
    # K6 g$ `! K7 l5 i- ^, |! N9 ~7 J
  2. {
    : w) Z# U+ s; P7 N% U
  3.   /* 检测QSPI句柄 */
    * w0 J9 m8 h' ~$ B
  4.   if(hqspi == NULL)" M  g0 K1 {1 _, ~
  5.   {
    : `8 B5 B" _  o( F7 S% f+ ~$ G% @
  6.     return HAL_ERROR;0 o) J5 ^+ D$ u% B' K  |
  7.   }$ v" X0 f: t7 Y4 r* u! |
  8.   m7 A2 B2 q2 z! v' J  H. {# ?9 v/ C
  9.   /* 禁止QSPI外设时钟 */0 q9 _( u6 \% N
  10.   __HAL_QSPI_DISABLE(hqspi);% u: @! p2 c) L4 U

  11. " k, u+ d3 q$ T  p1 w4 ?
  12. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1): F" D3 q$ K+ b2 t
  13.   if(hqspi->MspDeInitCallback == NULL)9 @( Z4 e* h3 @& Q5 Y! c) K! J
  14.   {+ i! x' ~9 H3 B+ W
  15.     hqspi->MspDeInitCallback = HAL_QSPI_MspDeInit;
    0 S) b' ^1 m  v2 S
  16.   }# T( F, [; z$ ^8 [
  17. - J! A# L9 z$ o6 o2 s* ?4 E
  18.   /* 复位硬件底层 */
    , f, M  ]# J5 H( Y" S
  19.   hqspi->MspDeInitCallback(hqspi);
    ( Y; x- d! Q: l% \% t
  20. #else
    ; V7 {7 J4 X; u! {' k) ]1 P" G
  21.   /* 复位: GPIO, CLOCK, NVIC... */; i; L3 j! X* a; D
  22.   HAL_QSPI_MspDeInit(hqspi);
    ! C' \1 ~" R: J0 b
  23. #endif
    & o+ |# o' z8 J7 l

  24. 3 {$ X! Y: l& E; m: h/ ^
  25.   /* 设置无错误 Set QSPI error code to none */
    5 Q% h* X8 }# L0 C/ q
  26.   hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    ' E. |! P1 n! P# B4 X  L% m

  27. 7 y$ U% G* Q3 g* e" n5 x
  28.   /* 设置QSPI状态为复位 */
    ' J9 `( G& T) S. P
  29.   hqspi->State = HAL_QSPI_STATE_RESET;7 Q7 Y7 U& P$ r

  30. 3 f  {5 n8 _! o5 }* ]! O
  31.   return HAL_OK;& ^5 r4 ^. @' Q4 D1 t9 z1 P
  32. }
复制代码
1 P* M: t  U" ]7 S8 C# m
函数描述:
3 v3 ?7 B0 {9 h6 i& D" ^
4 T8 r" {/ h& V5 a用于复位QSPI总线初始化。" W& K+ T. h% Q& L0 p1 L! f

( h1 O  j/ _, Z* V# Z( J& R! l函数参数:# s# a7 j' w( L4 y0 X
- c  f% A0 ?  g& T8 N, V) A) l
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
3 p6 K7 j. K/ `0 G  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
* s8 T/ A. _/ x0 ^( ?5 ?' g: h. a78.4.3 函数HAL_QSPI_Command8 O: @( V& U5 j; A5 ]. |
函数原型:
3 e, i0 H) }, O) c3 D4 I" U# Z  N0 L. Y" r; S1 n3 z" C7 V
  1. HAL_StatusTypeDef HAL_QSPI_Command(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, uint32_t Timeout)
    / k9 U( h) O, R4 b1 {
  2. {4 F7 d' s' g" W9 ~: d  Q$ P
  3.   HAL_StatusTypeDef status;; F: ^& ^  W  d2 m+ ]9 E4 k' O
  4.   uint32_t tickstart = HAL_GetTick();
    1 r  e4 E8 j9 c  B
  5. . z* |* y) W- m0 V$ W
  6.   /* 检测参数 */7 T( k- E+ L; C
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));) O" v8 I" D2 ?; B: m- l
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)+ n8 f, b) j; K* c/ S, T3 D$ N
  9.   {
    3 \) f+ T9 p$ _7 Q! U3 T5 t* m
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));7 z) ^9 E& ]! |! O$ L1 c- e( k1 U
  11.   }
    * i. c$ Q! {, R
  12. " \3 `! ]; Z0 l0 p* ~4 L
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
    9 ]  Z: Y& D( }9 j, P8 J
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
    9 d5 ?7 _3 z7 e  \% Z* H4 H
  15.   {
    8 S  n1 t3 `! o8 |
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));3 w( ?4 U2 C  m$ M0 }: y: a
  17.   }5 U% F( }0 l% B4 o( C  ^7 p8 l7 M$ t4 x
  18. 0 g* v$ }, U- m2 q; y! ]5 P
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    6 E5 L# d4 p. {$ {
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)0 D* b9 o! O- m
  21.   {
    2 O/ i  C* g# g7 i* Y2 c
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));# ]. B. L: Z; N6 w0 Q
  23.   }+ L, I# N, V4 m; P4 H
  24. 9 n+ O! ~- |1 C/ X5 {0 E: c7 ^
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    . @! F5 Z' h% g  Y. |7 D
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));+ w3 c$ K$ J9 t7 m" }

  27. 4 I8 `9 n; B! p# k; _3 w: g8 l9 O) C
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));. d; d/ m9 n" c$ P( o9 T# m
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));) c9 |0 s& l& W, n' w; J! @7 x4 ?
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));, m5 C+ K# v" u( T* H/ C

  31.   a7 ?* K+ X4 [) b8 n1 \" E& g; m
  32.   /* 上锁 */( k: F! D- j, {+ y( e" w; t
  33.   __HAL_LOCK(hqspi);6 {- S$ D$ O* H1 f( H! {
  34. & \! H3 @2 Z6 Q; ?( U+ U4 C
  35.   if(hqspi->State == HAL_QSPI_STATE_READY)
    0 H3 X, Y' M' |# d
  36.   {; B. b' i8 o- O' f. b6 p9 [
  37.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    . f1 G: g( b* i. G; p* i- Y
  38. $ {- \0 ?, \( P( q$ r# d4 x
  39.     /* 更新QSPI状态 */- v& _3 H1 ?  p, n: e. h2 P9 ]' \
  40.     hqspi->State = HAL_QSPI_STATE_BUSY;
    $ K3 D, a' P! J" p& Q, L

  41. 7 h( ]4 ~/ `, q. i9 h
  42.     /* 等待BUSY标志复位 */
    ' w( |2 U9 A+ Q/ Z- X/ Q3 ^( h/ a" Y
  43.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);; f* C4 G/ E- a: R4 y% E% R
  44. - Z$ y, L( t) y, P& Y
  45.     if (status == HAL_OK)4 o  L' Z% ^% d9 t: U
  46.     {
    3 z, e; ?7 u8 `' K
  47.       /* 配置QSPI  */2 E* N+ x7 n2 v" n; [" ^
  48.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);# e+ [" B, B; C8 G  o8 a) o

  49. & J- a- u: w: P: v0 S: I
  50.       if (cmd->DataMode == QSPI_DATA_NONE)0 q/ h) U5 D$ y5 T6 b! K
  51.       {% ^) @7 o' b7 E& T1 P
  52.         /* 没有数据阶段时,配置完成后立即开始传输,所以请等到TC标志设置并返回到空闲状态 *// z4 L8 I) B/ \; ?" h; N& M" p, a
  53.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);
    " W7 B' v4 e* ?' a' x$ @

  54. & f9 r- Z( j: @$ y9 t# W5 H3 U  e
  55.         if (status == HAL_OK)
    3 r5 ?4 B2 M" u
  56.         {
    + z! I: w: x) ~5 H+ d0 B: v1 T
  57.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);0 L! W' d+ T, _- s. v
  58. " [9 P) E9 }9 f9 l. O1 d5 q
  59.           /* QSPI就绪 */: @0 v1 X! u# C0 k, C; [( U
  60.           hqspi->State = HAL_QSPI_STATE_READY;
    # H- ?+ P/ w5 {- P9 r' S
  61.         }
    * u# p* Z4 Z( t
  62.       }. M( n2 s) K8 u3 d9 |% Y
  63.       else
    2 \: Q& h% b" k' G/ W: g
  64.       {
    $ A9 W& n! ~  b" \% q
  65.         /* QSPI就绪 */
    ! f7 d2 Y5 s/ t% p5 y% n$ M. y
  66.         hqspi->State = HAL_QSPI_STATE_READY;
    $ C6 i% U8 f9 A; q/ J/ f/ T( O- f
  67.       }6 s  H) o5 A* y% F
  68.     }; Y6 u" m' Q; ~1 R
  69.   }
    & T2 r; w% ~) ^. j
  70.   else  p. c2 v: a8 X3 h( b0 X3 k
  71.   {/ ^/ a% C- F0 M2 B
  72.     status = HAL_BUSY;
    / z( J# c: l: B7 k8 ^4 z8 \! E- @& k4 H
  73.   }4 _3 y! V) e6 T  @. q

  74. ; h+ e! u0 o  n: J9 F
  75.   /* 解锁 */, x5 o# _- {" y6 X5 X3 O
  76.   __HAL_UNLOCK(hqspi);
    + Y) z. w4 P) b( V, t, V; q  t
  77. 3 w1 H9 n/ Z4 ]7 M' l
  78.   /* 返回函数状态 */2 Q6 j( K- @# v% P, \$ G
  79.   return status;
    , {8 \: H) e9 A  o! G; o7 r) A
  80. }
复制代码

  n4 O- ~5 I' i函数描述:
, y% T+ g6 T  i1 [3 t" i" U' Z8 e6 \
# ]0 q2 n# O; U6 w' [* C6 q2 N此函数主要用于为QSPI Flash发送操作命令,查询方式。
0 O1 P. F7 c5 B/ D6 h5 P) G
3 x5 T9 g  J, I; a; M: n: S函数参数:  @) A. O, e& [9 p) U, [

# G; d( v4 b$ r4 z  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
( N$ O$ w. h& _  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。* L: U4 n# W/ k
  第3个参数是溢出时间,单位HAL库时间基准,一般我们设置的是1ms。
+ j' p+ ?; g1 K! F7 U$ m4 n  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
* l. ], o5 k/ R+ V使用举例:0 k6 y* ~! y& S5 p0 ]" x$ P% @. ~
' k+ U% r: j! K0 `
  1. /*
    0 g9 N- ]3 z9 W2 i
  2. *********************************************************************************************************
    + r; t6 G9 v& S* R, o
  3. *    函 数 名: QSPI_WriteEnable0 @: o7 b6 Z0 d& ~+ v
  4. *    功能说明: 写使能
    3 b1 W% h6 r# i) T
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。
    6 Y; a" X3 ~1 j6 _0 f: o- `
  6. *    返 回 值: 无
    & z! O% D# u0 |9 D" q+ u, b
  7. *********************************************************************************************************
    / t; ~4 W/ t' |# S5 d$ Y1 B
  8. */
    - x6 j1 U4 p. L7 X7 k) \
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)( W, C8 @' D' p5 s, ^
  10. {- S; c  H& V. q/ ?+ A# A
  11.     QSPI_CommandTypeDef     sCommand = {0};' P6 M8 r1 ?! E# h/ }# X+ \

  12. 0 k" E0 _: r5 Z$ T
  13.     /* 基本配置 */6 y% c9 ]6 w+ x. N" z& `
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */! u. d- n/ ^9 J8 @* J; U1 a# v
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    * M( z) @) E& @: O/ H# }
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */- y" s" p) V* {; G
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */5 V9 d" F1 }, D* n- Z$ A
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */0 B. @  _4 ]4 }( }6 G- A
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */: @* s9 \+ M* w6 H6 K: ~
  20. 3 U% }, N. T0 V6 _
  21.     /* 写使能 */
    ) F; ?% a% g; p  b. m+ G0 H
  22.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */
      L7 N; o, ~, N
  23.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */' K: R" L7 K7 b
  24.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */: f0 j7 ~( U, T. F) a- m
  25.     sCommand.DummyCycles       = 0;                 /* 空周期  */* h! A7 ]8 K- g" E9 T' q8 K
  26. 3 m) w& R% P- z; m2 U
  27.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    # M2 i. P+ w6 m" U  r
  28.     {' E, c: f* r. c; {% h( C- J
  29.         Error_Handler(__FILE__, __LINE__);# ?  x* p- U" A) ?
  30.     }    : L. P5 L3 Z2 i+ G3 ]+ t+ r
  31. }
复制代码

, ]6 _. q$ ?( M& c78.4.4 函数HAL_QSPI_Command_IT
, B4 ~, H" @! R6 T( U+ }函数原型:2 M5 r7 r4 ^" m

- |7 N& d3 I2 P! O
  1. HAL_StatusTypeDef HAL_QSPI_Command_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd)6 m3 |/ M! q! H" A4 C2 K2 A5 p* N8 i
  2. {& z4 B% f5 b' H% v- ~' M
  3.   HAL_StatusTypeDef status;
    ' T' m) ^. L( B
  4.   uint32_t tickstart = HAL_GetTick();) |0 e& s' i9 Z- M

  5. ! D; X" U3 E( z3 c" J
  6.   /* 检测参数 */
    ( X- |0 H3 C4 m, W8 H
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));+ D/ R3 ?  P2 W4 b
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
    - ?  I0 J) X: R2 J1 R+ N: F2 w
  9.   {
    9 _7 w) Z; g- H+ L  t% M1 A3 o4 d
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    - B& R% C. N8 m' h% v9 q; I
  11.   }
    8 Q1 p* O% B7 Q5 V% j
  12. ' Z  f5 }$ f/ L' U+ c, Z7 }
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
      ^3 Y5 w7 o4 R* V
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE). G- ^6 u2 ]- i" k  N& k4 P: u, Y
  15.   {
    1 \  p5 C7 z1 I' k% r3 \& ?9 r9 J  ?
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));% W3 P9 R4 B6 l2 ^2 g6 v& `
  17.   }! b% ^: W: S' L7 p" ]
  18. / V2 `  I- T: f2 A: p- w
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    8 Y; d1 a  I' V1 D7 g: K' y* @
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)6 s3 K* c1 J5 n- F0 e
  21.   {
    ! N# i! z* @- [+ }, z4 W# L& A
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));& w" {! h' U$ ]2 [! G
  23.   }, `" t+ m2 [9 c4 C
  24. 7 l2 V; x: G( v
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));6 i. H4 U% b  {; @; B
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));' n+ X- j3 D# `+ c$ Q

  27. 9 g$ i; D5 z7 N" w
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));4 A0 W- Z; A) ?, D
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
    0 J/ d& I) B- C/ g
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));4 L1 O2 s7 v5 w2 u% ~# l
  31. $ G. v4 C; H4 x6 H3 K3 }( v" X6 I
  32.   /* 上锁 */
    5 C- T; ]$ A! o3 \: V2 c$ V
  33.   __HAL_LOCK(hqspi);( K7 F, ]7 z$ `: Y6 @+ h, A9 {9 F
  34. ) W- W* H: E' G5 t
  35.   if(hqspi->State == HAL_QSPI_STATE_READY)
    : y6 ]) s; L8 X$ o6 C
  36.   {
    % L: C3 g) v% N/ m2 ]/ _
  37.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;6 T4 f$ i9 v& f  }6 E

  38. 3 A" p; Z2 ?9 w( G
  39.     /* QSPI忙 */# {  w; Y' R! Q# U
  40.     hqspi->State = HAL_QSPI_STATE_BUSY;
      d* V* q  Z' C: P: u" P7 C
  41.   {/ i* c" t( H, r" A
  42.     /* 等待BUSY标志复位 */# M8 j" c% p- Q3 S$ v) s4 \
  43.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);& \5 w  y* f% v* O+ m( C' _0 ]- ^
  44. + n4 }% Y0 g1 `& W/ O
  45.     if (status == HAL_OK)1 }& _* l6 h; n- S; @9 ?$ i
  46.     {; E, Q* g: K$ n7 }
  47.       if (cmd->DataMode == QSPI_DATA_NONE)
    $ C- p( Q0 H# M2 X) ?9 Z
  48.       {
    4 B6 o- K6 H6 ~/ j% f# m# v% m
  49.         /* 清除中断 */
    ( F5 S' p+ a$ n' u/ R1 ^$ J/ q
  50.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_TC);
    ) Y! G9 J6 `; R3 L/ z# M
  51.       }3 O- W$ Q  v; Y* R

  52. 3 T7 {1 T  _6 l/ k  }
  53.       /* 调用所有配置函数 */
    : P& o! t* b! u: \- U0 x! g1 q
  54.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    , [. M  o! N$ }, |5 C! Q7 c% c7 M

  55.   s) P% K" Y: E/ h5 W. O
  56.       if (cmd->DataMode == QSPI_DATA_NONE)
    : c+ ~/ Y6 ~8 f
  57.       {$ j; S, T% Y# e2 ~, o/ b
  58.         /* 无数据阶段,配置完毕后,立即开始传输,所以机会TC和TE中断 */  O) M* S& X$ M$ ~6 T" U; E! x
  59.         /* 解锁 /5 E$ |: O5 y/ {3 r
  60.         __HAL_UNLOCK(hqspi);: t4 G! q' {$ b

  61. ' h# n/ ]& e2 W' R/ f) K
  62.         /* 使能TE(Transfer Error)和TC中断 */% z2 V6 y' h; t. g
  63.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE | QSPI_IT_TC);( |1 e/ f! j+ o+ n6 o& i
  64.       }
    8 o- O+ E2 c5 Z3 c0 p
  65.       else
    ( w9 D; d6 ^4 n* B
  66.       {" q& E' `) z& j0 ~) G0 [7 H
  67.         /* 更正QSPI状态 Update QSPI state */
    6 t7 f/ b: u- @: `) n: G  s
  68.         hqspi->State = HAL_QSPI_STATE_READY;
    8 ~6 T+ ]* P4 o0 w. I( f

  69. ) g6 d% x9 r9 F
  70.         /* 上锁 */
    6 m$ W/ j- ]0 |. x5 V: }' }
  71.         __HAL_UNLOCK(hqspi);
      b: h, C9 M9 ^
  72.       }: @/ A0 M0 D1 c  L
  73.     }
    ' I( y' i' D4 N. L0 g6 m
  74.     else$ V# ?) _+ a+ Z" L  m
  75.     {
    0 g5 \# W) v- K# R9 p/ O
  76.       /* 解锁 */
    3 Z4 U  R' d, w$ C5 n) K% u
  77.       __HAL_UNLOCK(hqspi);3 E  g& @  W+ w' E
  78.     }2 B3 O+ R# G* G* _9 E7 L
  79.   }
    4 S) I6 t/ v, I% f+ l/ h$ F. J0 B
  80.   else
    4 M+ r4 K+ i1 i8 k' \! ]5 f
  81.   {1 M0 i& ~. q" P+ D% k
  82.     status = HAL_BUSY;
    - I# d! H  m6 K1 |
  83. 8 L! \1 {: }& v4 y* N% _
  84.     /* 解锁 */
    $ E5 @/ D/ V0 K/ z9 M1 e" M8 J% l
  85.     __HAL_UNLOCK(hqspi);
    : b5 M- f4 D7 d, K9 ~
  86.   }' C) `3 ]5 M! l1 Q2 h
  87. % h4 \/ R4 E+ R4 C1 {- L
  88.   /* 返回状态 */
    ; N7 J9 L! y7 D! r
  89.   return status;
    ' A3 E4 _+ r. w3 g' u0 `
  90. }
复制代码
3 l2 c& ?( Y8 M4 Q4 H0 |
函数描述:
, W/ _% e1 r8 k( [  f; \3 Q
7 g. @: F* F, K  J此函数主要用于为QSPI Flash发送操作命令,中断方式。
: R1 Q$ [) O/ ~4 s/ L$ o
. l7 P* _( ~$ d% L5 p函数参数:
, f8 a5 o! J$ g% H0 Y& ]  B  l' R  O) ]) ~$ }
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。% m7 H8 l9 d, w0 m4 L$ W: u
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
$ {9 g2 t; [* k5 {% n7 _  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
: w' y% f/ @  l使用举例:
; M" g: ~6 i( [3 T$ ~" s3 h. U5 \6 c6 _% C1 i
  1. /*- f- L$ l! c3 Y. Q9 g
  2. *********************************************************************************************************; S# {  s+ G3 s
  3. *    函 数 名: QSPI_WriteEnable
    4 h5 [1 V6 `$ Q
  4. *    功能说明: 写使能5 M$ m0 d/ H9 f
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。0 A$ N2 Z* I3 a1 [
  6. *    返 回 值: 无$ E+ y& k+ ^# V$ |# |! T" K) m
  7. *********************************************************************************************************) X/ P. `3 ]! S
  8. */7 ], |; b& H- X/ H
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
    4 |0 Y7 C( A4 Z4 p, c* Z
  10. {
    ) h# g8 Z- v$ N' W3 Y+ o( ~
  11.     QSPI_CommandTypeDef     sCommand = {0};
    5 I  v! {$ d" C( V- s+ y

  12. 5 R2 Z4 O5 k! B* e: l# D
  13.     /* 基本配置 */4 g0 h9 ~7 J: b  i1 e/ W" L7 e
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    ; e$ T8 @1 ]- L- }1 @
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */, s) e& Q! A4 O1 ?0 H
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    8 j  A3 q( K6 R/ F  w( o
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    - v2 R/ _3 C/ s! l* U
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
    0 a, H8 p+ c. X& M8 s
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */) Y+ b# P, a9 z8 [& E* ~1 |; Q/ Z4 t7 u

  20. & z) }1 s2 Y5 }
  21.     /* 写使能 */4 |/ |' H3 o8 h3 h# ]7 l
  22.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */2 @% Y/ o6 P4 g6 o
  23.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */  X+ v3 b+ _% y+ `, @
  24.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */
    - ]8 |( V! R7 r0 Z$ C6 m9 m3 u
  25.     sCommand.DummyCycles       = 0;                 /* 空周期  */
    % {+ S( d. Q8 m4 i

  26. 9 m9 s+ o& w9 ]/ b- L4 ~& l/ M+ c; e
  27.     if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK)
    - U/ S6 Y6 `' j, c1 K' L+ D2 o
  28.     {" f: N3 C& I& ]2 b
  29.         Error_Handler(__FILE__, __LINE__);: Q) @- u* T9 x3 Q
  30.     }   
    0 K" g+ q" W9 _
  31. }
复制代码

! n1 M1 u/ e9 b78.4.5 函数HAL_QSPI_AutoPolling2 u' n1 p; W$ j4 N
函数原型:: Z8 c3 G4 O! \% n3 ~5 T0 g

  d! s0 J1 r+ r+ Y! ]+ J+ s
  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg, uint32_t Timeout)
    # h& J5 [7 n. V( q' `5 W# o
  2. {
    8 k, F# @& }" F7 L$ _" H$ _3 v
  3.   HAL_StatusTypeDef status;
    ' x( w7 ]& r) \% I7 V' _8 W/ [! K2 W
  4.   uint32_t tickstart = HAL_GetTick();) `1 Z+ I. E7 K2 K

  5. ; H3 o& t6 w. i/ J3 ~% X1 S& ^
  6.   /* 检查参数 */
    : G1 ^& ?5 @, l# p8 g' Y4 n* }. j
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));- H/ r, |! Q( g! Q8 n6 {
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
    ) f+ B+ G4 f7 n$ @8 f* F
  9.   {. L' Y. W1 \1 t5 |# k
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));8 \/ J+ \0 x. `
  11.   }( g! M/ D6 g+ B
  12.   _- Z- Y0 @+ V+ j
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));2 ]  H% \; o  ^$ Z
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
    # T$ B9 K, d9 t! n* t) {  n
  15.   {  l7 ]) d; t" O* M* h( f: E
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));6 g7 ^1 W* N7 x5 e& |) K7 S: S
  17.   }9 \: ~4 w; s7 @1 q  M3 A

  18. 6 g: W& Q/ H, z& Y' Q
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    5 q* w1 R* C& i+ N9 j% v
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    , {; [) a5 S4 \: H* f  F
  21.   {
    9 `8 ~9 a) `3 @  A. Z$ m" C
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));' k, C$ {6 Q; i7 l) s0 Z
  23.   }
    $ N  z  N9 }; w1 Y& R2 o* M
  24. 3 U+ g- x  T8 Q$ P0 J1 g
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    4 N: c) N* r" F) K  t, e) O4 e
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    ; c( i+ \: g  Z9 F9 r9 e

  27. $ S8 @7 u: G6 ], S4 R# e1 q0 B* C
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    ; P+ ]- x6 y- h, g
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
    $ |: G- E# x8 m. u
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));& Z: R6 @, D5 r* }. S3 F7 m& V* Z

  31. " V0 h+ N, N5 ~1 }$ ?% l
  32.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));
    ) E. d# t8 b) _
  33.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));
    % ~9 f; R/ ~+ d7 W) H) ^# t- Y
  34.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));9 l3 q8 k1 ]% h
  35. 7 {2 R5 ~9 \; m
  36.   /* 上锁 */( N$ ]6 }5 C7 I
  37.   __HAL_LOCK(hqspi);8 M4 m' w3 d0 _( P

  38. $ V8 D3 }3 A& e! s# @
  39.   if(hqspi->State == HAL_QSPI_STATE_READY)
    * w/ P* Y( {' h7 u/ u
  40.   {9 j2 g6 |4 K, O1 a
  41.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    7 h+ T& I% W. E7 p
  42. 9 k, T9 j- d! Q3 m% R
  43.     /* 更新状态 */. ?6 m) a' J$ c' e( p4 f
  44.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;2 c$ \3 \9 L! P% ~) U' d
  45. - L1 P. g2 G3 v7 g
  46.     /* 等待BUSY复位标志 */
    ( D/ T7 z  o  m" o) ^, K5 U: n
  47.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);
    . g( T- }$ a! S2 J7 R
  48. ; Z3 U0 o% f1 `. w
  49.     if (status == HAL_OK)( q; F& E" f) K: ?
  50.     {: v$ e/ O3 c$ `8 s5 x
  51.       /* 配置QSPI匹配位 */
    ! U" h% m: t% Q9 R$ f  M% I
  52.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);
    , A/ `# w! K0 e
  53. $ u5 Y( `  c# I9 ~8 Z) t
  54.       /* 配置QSPI屏蔽位 */( @9 B+ t1 }$ |5 M9 J' O1 K0 [* ~
  55.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);
    ; ?6 r& H% v  Q) [3 v& t! j& z( ~
  56. $ ]4 D- W  i% r0 \  ?
  57.       /* 配置查询时间间隔 */
    3 t- m/ t6 K% o
  58.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);  v1 y. V* F8 R% j8 N
  59. , `! b" j, x3 V
  60.       /* 配置匹配模式,使能自动停(否则阻塞方式无限等待) */
    + ?+ A" o- V1 ~: S9 V9 g
  61.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),: I' \5 H; o4 {% e
  62.                (cfg->MatchMode | QSPI_AUTOMATIC_STOP_ENABLE));, t* ?% W( Y. D7 `, x+ n2 E
  63. ) W0 T1 P+ W% q/ T5 V7 s% S
  64.       /* 调用配置函数 */
    6 [' X1 L5 Z! M( Z" f
  65.       cmd->NbData = cfg->StatusBytesSize;$ j; ?  `+ |! P! M$ R
  66.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);' p) Q& Z+ {( {! Y; v4 J

  67. ( F, D( p. v1 h& _
  68.       /* 等待SM标志 */' B  ^# e! x* v/ |% q% \# W
  69.       status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_SM, SET, tickstart, Timeout);
    % ^* I* I3 ~; s* }: f. |

  70. 0 a3 D5 j  O. w; p6 s' q- E6 R
  71.       if (status == HAL_OK)
    - n9 F8 t9 W0 }1 E$ R4 P
  72.       {
    9 N5 @6 H; S1 c1 q
  73.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_SM);! A2 u/ y9 m* R5 H; l8 v
  74. , d7 l% {) [1 f
  75.         /* 更新状态 */& Y% `: o; ~& p' u3 N
  76.         hqspi->State = HAL_QSPI_STATE_READY;
    & c$ ~, v$ G- T& ^  _. z
  77.       }: V# ?7 p" t  R* a7 {
  78.     }
    . |& o+ g4 n% V
  79.   }. M! b9 I1 h5 `2 [6 o/ Y5 i1 k6 x
  80.   else. b& ~; R/ O9 U4 C' X+ H
  81.   {" g5 z4 J- t) A% H
  82.     status = HAL_BUSY;9 B! @; Z' c# q/ ~0 ?
  83.   }8 F0 x" ~4 h4 p* B9 f/ o0 t

  84.   }5 F4 J! V" [8 t% E" s1 a& G  f
  85.   /* 解锁 */7 m7 B% q; K$ ?5 n" P2 v# N/ a
  86.   __HAL_UNLOCK(hqspi);
    $ R* I9 O8 w/ x0 y& I* r: x3 ^7 D
  87. " _3 C8 b. k2 H( P
  88.   /* 返回状态 */' f, J- }- y6 o5 a5 r) |/ k, J
  89.   return status;( N' k+ m/ o5 F* _! l% y  n1 Q* b
  90. }
复制代码

; c# _7 D4 u7 A2 y7 j  Z$ @: _6 j函数描述:
! K1 B' r2 _1 V- _( i" i( e9 R$ m3 l
用于状态标志查询,函数采用的查询方式。2 M5 w. _7 {0 _
) F3 Q! z- w! r! V7 Z+ r/ T
函数参数:
7 u% v- n4 r- T& U, s2 Y
4 R. l& f, p3 H9 e: Q3 |8 t; u/ a  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
$ ?7 j! z! M6 D) S- p4 V' ~  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
: X6 z" h( N* _$ w  d( ?; P9 K" d; e8 m  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。, i6 d7 M! h" u' j6 ~5 {% s$ A
  第4个参数是溢出时间,单位HAL库时间基准,单位1ms。! g4 ]* g6 U+ Q+ {1 c
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。! o- ?  @, m; D( D8 `& S0 A
使用举例:
/ J0 o& b/ U; `8 [1 d7 V* y
/ }' v" h2 I' o( C' ]( O
  1. /*0 J8 |$ W! T* ?2 Z$ U
  2. *********************************************************************************************************4 \2 Y, m- z2 Q0 p
  3. *    函 数 名: QSPI_AutoPollingMemReady; ]- U3 |9 Z6 `6 S, h3 {: R
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用
    ; F- @% W2 H( Y6 R* |
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄# j" w3 @; [% G2 F& o0 B
  6. *    返 回 值: 无
    . m+ [% e8 s% g) O  I+ H: R
  7. *********************************************************************************************************
    : n+ M/ b5 E5 @/ i9 N2 Z; U% N9 ?" ^
  8. */
    * ]* l# D' a* k
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)
    ( g& L3 a5 K2 o* [3 d
  10. {
    7 Z3 b$ _4 M; P/ i" b
  11.     QSPI_CommandTypeDef     sCommand = {0};
    & j6 V6 O" W  {
  12.     QSPI_AutoPollingTypeDef sConfig = {0};
    : M0 D- t: Q8 M8 j# Q2 j8 J
  13. 8 a' U5 m! d7 P
  14. 5 k- g$ N- X, P9 ?1 n
  15.     /* 基本配置 */; q; A; T+ V! t' L# n" R# K  [5 r* J
  16.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    ; a% I. I; G6 r+ N% |. {& Q
  17.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    5 V) w5 z3 O7 L  Z  T9 |0 `$ Q
  18.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */2 \0 G* a4 a  _
  19.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    2 u# P' z  f- G% H/ D
  20.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
    * }# r8 U# B+ ~+ B. Y& h! v# c
  21.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */
    6 @6 T1 D7 e- [

  22. : H4 N; T0 S$ d7 L  z- M
  23.     /* 读取状态*/* x& a% g! m+ a
  24.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */
    2 x) ~7 X: w  `; |8 k# W
  25.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */) S7 j- c8 N: \9 P0 _
  26.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */& q  g* l5 ~0 v9 p1 t. s+ y' V
  27.     sCommand.DummyCycles       = 0;                   /* 无需空周期 */
    8 a) r6 B  |3 b; g
  28. + D! j& x/ Y$ o* g; Y+ H( m+ a
  29.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
    % @+ E9 O. d2 K$ Q; Q0 v; N4 I# `7 k
  30.     sConfig.Mask            = 0x01;
    $ ?% F& D/ b/ }' @% l) j% {
  31.     sConfig.Match           = 0x00;
    + ]7 _5 d, |7 k& }8 @9 N, R  l
  32.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
    : l$ G/ I! c5 R  y* O; B
  33.     sConfig.StatusBytesSize = 1;' g$ x* r! O5 |% ]: ?  g
  34.     sConfig.Interval        = 0x10;" U1 p/ t8 w' u0 w% E) \& G
  35.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;$ p3 q# Q/ E5 y- o) L
  36. 4 b: W/ {3 j3 [) y# i
  37.     if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, 10000) != HAL_OK)
    8 x# f  a0 ?, ?' p/ |% B
  38.     {
    # f; k9 z4 V$ L! c4 J! O
  39.         Error_Handler(__FILE__, __LINE__);
    " |5 f3 m6 h  l7 n
  40.     }
    7 @$ F. F" A0 E" h) S0 O; G
  41. }
复制代码

6 m  N2 r% ~( w9 p+ r1 ^78.4.6 函数HAL_QSPI_AutoPolling_IT5 k* ^, V' J( L( z
函数原型:
' A& c) e3 j3 L0 I; v4 o
1 M. B. s/ q: u' s+ ^9 g
  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg)8 ]% t/ S' G5 K
  2. {% v$ p3 u, W4 I
  3.   HAL_StatusTypeDef status;& ?# k3 I+ ^' b  O' j# c
  4.   uint32_t tickstart = HAL_GetTick();
    % L9 h) v7 f" O# p6 @( M+ _- h# `# {
  5. / D1 y$ w; L6 S) t) G0 X- r
  6.   /* 检查参数 */
    % ?. ]7 x; {: e! _1 ?6 N
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    3 u1 Z) S, y6 C" x# j# o
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE); J5 v. O7 ]  Q: r
  9.   {
    3 K+ f6 U& J( x& B9 Z) T2 b
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));. \8 U# p1 v) G. Q
  11.   }
    9 _6 N# Y1 |$ |# O, {8 {9 q, [2 w) l, [
  12. 1 J: ?! X5 \; v/ v  }8 b7 `
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));" A0 I$ K1 u8 s6 U4 G+ W
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)5 W. T& M0 A' S& T  z- @
  15.   {/ n0 Q6 x: ?6 V, {3 \
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
    % q; H1 R# l5 h7 [4 M
  17.   }  V' L8 Y: t, g

  18. : E% K& K' Q3 k; w: ~* J
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    6 [- a" L) {/ Q) q. T9 `2 L# W: d2 f4 d
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    " c" O$ g6 R8 a
  21.   {
    # j% G& Q: D" J6 [0 b
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
    # H+ z  b* V: s1 d
  23.   }
    . Y9 c, {! I2 D0 N! l: Q$ n/ Q
  24. & V2 C& F# Q+ q2 v# }
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));0 H6 r, Q2 F" v) m5 [
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    2 D" l5 [' [2 v7 {$ \, w) d# `
  27. % z4 m. ^% F# k5 k
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    7 S3 K' L, P+ Y9 [: n
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
    " g2 T! ?( \# k9 K  P
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));
      c5 L# v% x  J* _1 F. |

  31. ) I  R* O6 F) n8 n3 R* q: R9 Y, p- Z
  32.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));5 b2 V/ U* [5 c" l% i: {
  33.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));
    & X7 \/ x( c5 X8 {, K: E
  34.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));; ^4 q& C: P; ?9 R# i; G
  35.   assert_param(IS_QSPI_AUTOMATIC_STOP(cfg->AutomaticStop));
    * h/ F# A: Z4 C) J# T  o
  36. - t  ~; I% {% v8 y7 u, h3 D
  37.   /* 上锁 */) {- F; l* T. P
  38.   __HAL_LOCK(hqspi);  }) k( k8 |7 I, g- l

  39. 4 [6 r7 s3 \  j
  40.   if(hqspi->State == HAL_QSPI_STATE_READY)1 t9 D: ?/ U: Y) {9 e
  41.   {
    ) [8 d* s: f" g6 p9 A
  42.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
      X+ q; i3 r# C6 [. e2 S
  43. 9 d0 a# v# w7 B! M, W
  44.     /* 更新状态 */" `+ L6 @6 @$ _
  45.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;
    . ]# c! E( f2 {$ C& P, B
  46. 6 Y( g: Y0 \% g" p( m( q* E, Q
  47.     /* 等BUSY标志复位 *// e" x; n" F, W' C
  48.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);
    2 P- p, X9 c4 ^5 f: U0 r2 E2 @3 t
  49. 9 u# \2 D5 z( t3 t; W
  50.     if (status == HAL_OK)+ h/ `, G* o. `- U  V* b. Z% q
  51.     {
    & Q2 K& V7 l0 f  Q' h3 D' F3 C
  52.       /* 配置匹配值 */
    * d6 Y" d, Y1 U9 w8 d; ~5 b
  53.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);
    ! V( o2 M) F6 ]# \" B) X
  54. 3 c/ F7 s0 Y# ^  N( `' F& C" J3 t% m
  55.       /* 配置屏蔽值 */) [8 }3 D; Z7 r% j" W. p/ O
  56.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);3 e1 h' Y5 E4 P: r( T. J2 r$ k! w

  57. & Z( g' U" w$ o
  58.       /* 配置查询间隔 */
    1 t" m( R3 y5 k
  59.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);1 z" w/ S( P/ T  w) s0 T
  60. 4 `6 U1 v" u* d! C
  61.       /* 配置匹配模式和自动停止位 */
    6 m$ F9 n8 ^8 W% W0 |/ r0 e
  62.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),
    0 P0 X0 |0 k- g2 T; G7 V/ ^' L- o
  63.                (cfg->MatchMode | cfg->AutomaticStop));! z# B4 T7 ?5 B. k, F7 w
  64. ; B. \9 B" Y; ?' B) _2 t2 `/ d
  65.       /* 清标志 */
    ) d7 Q1 ]( Z0 F
  66.       __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_SM);
    9 `- C' W, b; Y+ h1 @

  67. 3 o, `$ o" J3 Q2 G
  68.       /* 调用配置函数 */
    5 g- Z- D  y9 z# |2 ?; q8 r8 S1 ^
  69.       cmd->NbData = cfg->StatusBytesSize;
    , h0 G' k" Y1 r
  70.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);
    # T, b# m. v& A
  71.   u4 r! E9 D$ }% {( _/ @% u
  72.       /* 解锁 */
    * j  g8 F- u# U) c; o7 E
  73.       __HAL_UNLOCK(hqspi);3 d: \8 U1 N% `$ V. i

  74. ; o0 D. a% s- P, A5 T5 @$ N! v6 w
  75.       /* 使能SM(status match)和TE(Transfer Error)标志 */
    ' t6 a% b" A& [% q* t
  76.       __HAL_QSPI_ENABLE_IT(hqspi, (QSPI_IT_SM | QSPI_IT_TE));
    2 y6 J5 [! f& C, T
  77. + m  {' E- P" Y- ?
  78.     }9 s) a( e% R- T5 B9 q2 ]: i
  79.     else/ |8 C7 }/ O2 k% z; W, F) R. E
  80.     {  }3 _% M# F; `3 U. w6 |& J
  81.       /* 解锁 */
    7 ]+ `& f, E% c( {9 W& ?' d1 {
  82.       __HAL_UNLOCK(hqspi);
    & Q& Y$ L5 Y1 {3 l, h. {
  83.     }4 r. X, ]: V" @  H* [
  84.   }7 `* @8 }, P& N
  85.   else& H5 G% y% {2 l) q
  86.   {; ^: B! g+ I& |% g9 Z3 ^2 Z3 j
  87.     status = HAL_BUSY;
    ; R! n: T5 K0 ?: M  ]' C
  88. " G  D) w7 j) X) u- r+ Z1 o
  89.     /* 解锁 */2 k; l+ G' J" N  u  T5 ~3 Q9 ~
  90.     __HAL_UNLOCK(hqspi);
    7 \6 P8 b9 V, j5 I' l" X
  91.   }" |3 Q2 e6 o2 @* K! U9 }

  92. . U# s. V- c* T! ?9 }6 q& t, n& q
  93.   /* 返回函数状态 */
    8 P" Q9 L  P5 N( Y
  94.   return status;# w$ w- A9 L  G5 ~; w: ^+ N3 k- o! W
  95. }
复制代码

( n1 k' j4 ~1 `4 e3 R函数描述:
% _9 i( J1 q3 g- f& ^
) `7 a' V! Q- y* m* y* I5 L用于状态标志查询,函数采用的中断方式。
+ C. ]) B! i" z2 c/ r4 U! j. B/ U% v
函数参数:' l$ E8 @/ \2 g6 Q
) d  V4 O: h: a/ @$ c
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。; h9 l( t$ z- u; ~* L! q
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
5 P# p' o+ K. I& ?  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。
: P2 C: P5 h: ]: B$ v% ]  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
+ v  H5 j* f+ W+ M1 O使用举例:& [$ N1 x: z+ i) [
. b; w* E! K# c7 \  w1 }
  1. /*2 h3 h8 O9 h/ g4 p5 A9 T! ~9 ]
  2. *********************************************************************************************************+ n0 H; f0 a% G+ h; M
  3. *    函 数 名: QSPI_AutoPollingMemReady& y* l( m: q& q# A" F" |
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用9 {+ F1 t! X/ e. S
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄
    ; d8 o5 J% O, q3 K6 N2 b& k/ e- V* ^
  6. *    返 回 值: 无
    " `2 g; X* t; H1 K% k. n
  7. ********************************************************************************************************** _9 M' M1 x3 @% b2 v) C7 _0 h, H
  8. */8 r  h& {( j6 _4 ]- b+ q
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)" M! X) d; z! e/ c. s/ M5 G3 Q7 ~# w: j
  10. {5 T2 x* M+ l0 @
  11.     QSPI_CommandTypeDef     sCommand = {0};/ J) s+ x! D4 W8 B  [1 t
  12.     QSPI_AutoPollingTypeDef sConfig = {0};3 f. z7 `9 _- K* g
  13. 0 k! i$ ^# b( G# U6 y1 F

  14. & Z# C( z4 N) P" [) M" i
  15.     /* 基本配置 */7 P& d; I: Z6 |" r/ E, \" v/ D" P  t
  16.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */: [9 g, n0 A0 J! H$ ^1 A& G9 `8 K+ m
  17.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    / q; y. S4 S2 G9 G
  18.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */7 q; ~7 U# D6 M" F1 u, R
  19.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    2 U% A) }/ q3 ^1 W) v2 e8 {
  20.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */& `$ p/ c: C+ _0 d" L
  21.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */
    $ X* r# w- k( k. m7 f" R, f

  22. - N" P9 w! W$ d+ ]' ?
  23.     /* 读取状态*/
    4 B& k( }+ X$ w. l# ~, v) |' b& ]0 W
  24.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */$ B* y4 f# y2 F: i" c
  25.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */
    : v0 b7 i7 q2 _6 J; l/ G0 b
  26.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */) I0 q" U/ i/ ?1 b
  27.     sCommand.DummyCycles       = 0;                   /* 无需空周期 */8 r. z/ h" A. K/ T: i
  28. 1 g6 o, q* ], L! Z- j5 j5 K6 B
  29.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
    " F% G; A2 v: i, U
  30.     sConfig.Mask            = 0x01;
    7 Z+ V) J: c9 G6 g
  31.     sConfig.Match           = 0x00;) ^! l) s2 \8 I) y; i7 Y& l
  32.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
    # w( M/ U8 ?) H' X% b4 z- J
  33.     sConfig.StatusBytesSize = 1;6 A4 _; F* d( t+ u3 d
  34.     sConfig.Interval        = 0x10;7 @$ ~; F+ _' V
  35.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;
    ' \1 ~; A4 s; `
  36. ! ~# Q1 K. m5 ~- B% f! x& S
  37.     if (HAL_QSPI_AutoPolling_IT(&QSPIHandle, &sCommand, &sConfig) != HAL_OK)  K% E- x; c, \) E  `  I3 r; |
  38.     {$ i# v7 Y  T8 z" k3 A
  39.         Error_Handler(__FILE__, __LINE__);2 a+ J: P# E( u/ ~- M- U
  40.     }$ k* K/ \0 F9 b7 c
  41. }
复制代码

/ w8 i/ W0 r& q- B- u$ N78.4.7 函数HAL_QSPI_Transmit
: M4 f1 u# T' d函数原型:" L8 C+ f, D' D8 _- k

1 Q% Y9 H; n  ]! W& L! Y
  1. HAL_StatusTypeDef HAL_QSPI_Transmit(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)
    ! W. n, {* h" x, }8 W3 y' x6 h
  2. {
    " e7 f0 V7 V- e. ~. v$ F
  3.   HAL_StatusTypeDef status = HAL_OK;
    0 u$ P. C: C% g2 }3 v& l" ?8 _
  4.   uint32_t tickstart = HAL_GetTick();
    6 W% D1 e9 g5 G1 h; [
  5.   __IO uint32_t *data_reg = &hqspi->Instance->DR;
    ; X, `1 Y' m& P) C; p1 |
  6. , T5 u+ _: _3 d) o( r6 d) p# n
  7.   /* 上锁 */
    & b7 z' Z$ X, m
  8.   __HAL_LOCK(hqspi);1 i4 J# q6 m& R6 b6 N0 C7 f

  9. - v3 H+ h% v* b. u9 x1 Y7 {% e
  10.   if(hqspi->State == HAL_QSPI_STATE_READY)
    1 D1 v% f+ v/ T. v. V6 N
  11.   {  K, W1 h* ?' }7 x' Z5 y' T9 q. L
  12.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;) a2 A' ]7 `( x% q7 Y4 C
  13. ) `5 C6 \6 l8 E5 G
  14.     if(pData != NULL ): P( B* f' A- H( K, J9 e. z
  15.     {$ [  V$ o6 q# m+ l- t6 y' h# ~( I
  16.       /* 更新状态 */( }! |) Y0 q1 l+ t8 L5 y
  17.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;0 R9 D6 v, ^8 Y
  18. 8 c- s2 D% I' a) E. Y1 I
  19.       /* 配置发送 */. C6 T$ }+ N3 C$ I# ?
  20.       hqspi->TxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;5 @5 U* s( ^8 K* `
  21.       hqspi->TxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;
    $ u4 ]0 ]  h" W: I2 o7 h. K
  22.       hqspi->pTxBuffPtr = pData;+ S+ x7 S) i4 q) T! J4 D

  23. % N% f1 C! [* `. b
  24.       /* 配置QSPI,间接模式 */
    ' }0 m$ W- w5 q
  25.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);/ ~8 \) q' ^5 ?, g% v
  26. # {" {1 U5 ~( z7 ]
  27.       while(hqspi->TxXferCount > 0U)
    % p9 K! p% P1 S3 v! i
  28.       {: \" C5 g4 n$ A. e/ W1 @
  29.         /* 等待FT标志 */  x+ _! h! Z& z9 Y8 R7 E6 N8 i+ @
  30.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_FT, SET, tickstart, Timeout);; C1 `; A- s& s4 l4 j' I
  31. 5 H( d, u9 G- \. f7 S- V
  32.         if (status != HAL_OK)
      n, v6 G$ a7 K3 ?( ~- P0 C+ ~
  33.         {
    , O* P4 Z" }4 D5 C! r# q
  34.           break;0 Q/ G9 b% P! G5 d% t9 ]
  35.         }
    & {" S* t+ G) i5 G/ B; ^; R
  36. : B) U9 G/ R2 I: x+ ?" z! ~2 I8 c) j
  37.         *((__IO uint8_t *)data_reg) = *hqspi->pTxBuffPtr;. @/ {. C/ ^$ C4 ?2 c9 x' n: ?
  38.         hqspi->pTxBuffPtr++;
    " ~$ o( C# Q) n9 ?
  39.         hqspi->TxXferCount--;! H7 p; N" [) R' ?
  40.       }1 ?5 G+ `+ Z1 ~9 ?/ u$ u

  41. 9 I7 S. L7 \3 L" }1 W  ^( \
  42.       if (status == HAL_OK)
    , s* e% R9 E' T+ f" S  ~  q3 Q
  43.       {! g% T, |. B+ ?, u
  44.         /* 等待TC标志 */
    4 S. `' H* f, I, f) g
  45.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);
    - e: c( E6 C$ u: w( T) L
  46. / X/ k; r! h2 E: k
  47.         if (status == HAL_OK)
    # F  K% F8 ^3 u* q4 c- v2 w
  48.         {5 C9 ?6 d. V! a; K
  49.           /* 清楚传输完成 */
    - x$ {7 _6 Y% a: G
  50.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);' e, {; u0 x0 y0 D* y! n

  51. * t0 u, x7 ~6 A8 Q6 Z
  52.         }& J9 s9 q  t  ^6 f  l3 u$ j
  53.       }
    3 m9 \0 Q, J$ Q: B3 K5 c- \- h& Z

  54. / y' U" U4 H. w  P7 O
  55.       /* 更新 */0 l" K% j4 o, P' Y
  56.       hqspi->State = HAL_QSPI_STATE_READY;8 g5 g; P' a7 Z, z' o, T" z5 l
  57.     }2 Z( K6 I: B$ a
  58.     else9 {/ o) B( M2 C5 F; W6 |# E
  59.     {/ z, m8 ^, p; d6 j
  60.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
    7 F6 q- D% `1 d5 h# t. E
  61.       status = HAL_ERROR;6 l/ w0 }( U7 n6 E4 |
  62.     }% f+ F; H; X$ D2 K) L
  63.   }
    9 h+ I2 m% l0 Z# h: D* Z
  64.   else
    - d7 D/ |" G0 B% q1 ~* J
  65.   {  D& i! Q, v; w9 [% r) v, i. b' G* s
  66.     status = HAL_BUSY;
    ! U% _2 I- `/ a/ P, B8 L
  67.   }
    2 s$ V/ G. B9 k# ?; V2 ?3 w
  68. " S) \: I( D& q4 G) E* L8 a# L" L
  69.   /* 解锁 */( }  w/ b4 g8 x
  70.   __HAL_UNLOCK(hqspi);
    ( l0 e% D& }% p7 z/ d6 Y2 T

  71. 0 e# Q+ S% W5 W
  72.   return status;
    4 A; s1 U9 c! a5 v/ t% b
  73. }
复制代码
, D% T( R% A* X3 \. O
函数描述:  }5 ~# K& w" P% e

7 x1 {2 @6 o: ]! h" Y( ^3 f此函数用于QSPI接口数据发送,函数采用查询方式。
9 h* ^5 Y: x& v" V/ O7 f: v4 W/ N8 n4 s, g4 d
函数参数:% k( d' ]$ M4 c4 R+ j
% V. E8 v% D5 s6 ^+ z: e& Z0 w) ]
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。: i" r6 A5 f4 x& x
  第2个参数是要发送的数据地址。
- N. m# i* Z+ f/ C' _5 ^1 C: \2 W  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。
5 E: h3 Y" U  [4 D5 p  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
1 k6 Z0 s6 k. h+ S4 v使用举例:- d# {- A4 f! t) r& Y. }* B' l& n

& J. w' s2 z* Q* T
  1. /*
    * A" V, q& Q3 j5 o$ {6 ~% u
  2. *********************************************************************************************************
    8 }" p) }5 e0 O2 g. o+ J$ y
  3. *    函 数 名: QSPI_WriteBuffer% w/ Q% @& x. o3 a8 a) s/ z$ |
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入0 \) L3 v, h* P1 x
  5. *    形    参: _pBuf : 数据源缓冲区;
    9 ~1 U* T" h+ O9 z7 C
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。7 }8 |+ v: C: x( ^* ]9 @
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。$ Q( K$ a$ _# R/ q! Q/ R
  8. *    返 回 值: 1:成功, 0:失败' T. H' k% s( B5 A) Z7 f8 B" l2 f
  9. *********************************************************************************************************
    ( o2 ^# _7 A, _( `9 R9 h* M
  10. */
    ! F- \! f' W" t# z7 v2 C; o& g
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
    % y: N) D- m+ R9 ~  Q( v
  12. {
    7 x: B+ F  }- C2 W
  13.     QSPI_CommandTypeDef sCommand={0};0 G/ R+ v) K  G9 {, ~. [2 X6 w

  14. 2 d. d. c! f- s' S
  15.     /* 写使能 */' w$ H! K! u" F( d) }0 v
  16.     QSPI_WriteEnable(&QSPIHandle);   
    2 r1 e. g/ D; L
  17. . _; b1 p5 ]; m
  18.     /* 基本配置 */
    + f4 U% Z/ C. Y, U
  19.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */- @2 x# w( b! K$ ]% J' f& y: s( o
  20.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 *// z' y; O3 m3 Q' G# {: U3 I8 n3 \
  21.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */7 C; w1 [- ]. D$ Z
  22.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    " j" `0 N) n" [, n6 K+ I7 _
  23.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
    . A4 h5 p0 M1 W, @' X
  24.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */    8 Z# b- B9 P  b+ d
  25. 6 T: r4 D/ a5 Z6 X# G/ \
  26.     /* 写序列配置 */1 e/ P( k2 e& r) @) e
  27.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */
    . y: w: u/ l, F/ ]; Z, m
  28.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */, \, a9 n2 s, [' N
  29.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */+ t) b6 n  g8 j) L& T2 o/ S9 A
  30.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
    . ~* r" l/ }4 y, A  V& ~
  31.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   / d0 H0 J  f) M9 Z' @
  32.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 */
    - K& J8 u  S0 k4 f2 o2 c" ^8 Z7 o
  33. ) t, {1 K8 t; V; ]$ n# |
  34.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)2 @3 E2 K5 C0 N3 L) ~! F1 E, S
  35.     {. v5 t; P8 s4 e7 W; Y
  36.         //return 0;
    7 u2 [, D" d  e' M* e( M5 n
  37.         Error_Handler(__FILE__, __LINE__);
    / @) ?# M0 ?3 A1 b8 \* M" i
  38.     }
    9 l' k- ~. S8 D, \9 }( w
  39. ' @- c3 _6 j7 d; z- h0 q: q% k
  40.     /* 启动传输 */
    ( P7 ]& Z- T" o( v
  41.     if (HAL_QSPI_Transmit(&QSPIHandle, _pBuf, 10000) != HAL_OK)
    # q0 z: |% C% c. Q* T6 S
  42.     {
    - F+ Y1 j9 l! ?6 _
  43.         //return 0;9 X' f$ P& O  r$ n1 ^# P
  44.         Error_Handler(__FILE__, __LINE__);. R9 L( D5 ~- d2 G, V4 ~$ s

  45. ' a4 T9 T3 \+ q1 O4 d5 _! v1 P
  46.     }
    ' k# F/ x9 [, x% I

  47. 1 \/ L# c+ [! i
  48.     QSPI_AutoPollingMemReady(&QSPIHandle);    ! F& e. D0 w5 o) X4 z/ _

  49. 6 P8 s( O* k5 y6 Q# x+ L8 d
  50.     return 1;
    0 s# {) E8 F+ d. b( o
  51. }
复制代码
5 `2 h/ j: I9 g' B6 \2 W8 M8 B
78.4.8 函数HAL_QSPI_Receive' H" k1 K" w9 F: b7 {2 P% m, p
函数原型:
' F3 ^8 U+ a2 m. j8 I  L, m
/ q. ^: i* h6 i. p/ i4 x/ y$ B4 R
  1. HAL_StatusTypeDef HAL_QSPI_Receive(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)
    1 A9 G& g9 y' O" S
  2. {
    # c# g& A) C6 T( b9 i( Z& l+ e* y
  3.   HAL_StatusTypeDef status = HAL_OK;
    # V, E6 G& c. r5 J$ U. R6 ^; W
  4.   uint32_t tickstart = HAL_GetTick();
    1 B# ]2 O: W5 c8 G% H# f7 V
  5.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);% L/ ]4 a2 y2 Z* R
  6.   __IO uint32_t *data_reg = &hqspi->Instance->DR;* W; k4 N. e: R" g
  7. ! T+ d6 V( x& A: M% w* m& s7 j
  8.   /* 上锁 */: m  x1 w- ^0 F' S. k0 e
  9.   __HAL_LOCK(hqspi);
    ' G  I# |9 B) c* h7 ]0 c

  10. 6 P8 B3 @* x8 m
  11.   if(hqspi->State == HAL_QSPI_STATE_READY)
    1 v/ O) m4 N" D9 I
  12.   {, d, @/ f% A) D( D" A: ]* l6 D
  13.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;2 t" @6 m6 w# V& V! ?
  14. 5 K/ ~. I* R# ^& ?9 b' k7 g/ [2 m
  15.     if(pData != NULL )! F9 @5 |* S1 m% f+ F
  16.     {
    0 U' l6 \! p- j. |- q6 e0 o3 F6 h& T' D
  17.       /* 更新状态 */
    3 O2 _& A- L- @- c( @5 \
  18.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;+ i# c% E* {- t: b
  19. 1 H# b. s8 H  i& |; `: y; h
  20.       /* 配置接收 */
    1 \) ~2 q3 S; g0 u2 d
  21.       hqspi->RxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;
    + `: e2 F9 R/ [6 H2 K
  22.       hqspi->RxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;
    7 e( x- M8 K' o: I5 {3 Z3 k
  23.       hqspi->pRxBuffPtr = pData;
    ! L( P: {5 a1 x- m9 R
  24. , ~1 ?1 D' q% G- F/ G
  25.       /* 配置QSPI,间接模式 */
    1 c1 E2 s; r' T
  26.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);/ H  a' H! G8 X

  27. 4 E/ e( i+ u/ l% n
  28.       /* 启动传输 */2 |1 g" _( S+ w
  29.       WRITE_REG(hqspi->Instance->AR, addr_reg);- F. \+ r2 z2 A; [' b# w6 C
  30. # R+ v# ^6 x1 Y/ E
  31.       while(hqspi->RxXferCount > 0U)4 ]) |$ o4 i4 k+ {! E
  32.       {. n% _! h9 I/ p) X4 B7 {
  33.         /* 等FT和TC标志 */2 W# P6 t; Z: G
  34.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, (QSPI_FLAG_FT | QSPI_FLAG_TC), SET, tickstart, Timeout);. R. W- J8 c6 H7 h/ d! J
  35. 4 l2 k7 ]8 e$ ?- H' n2 ~9 I. r1 ~+ u
  36.         if  (status != HAL_OK)5 k3 D9 [! ~/ R& B, ?
  37.         {
    # n- Z: r' _; M! b+ P9 |
  38.           break;
    * E, b3 n7 y. H6 C: w  g( `: N
  39.         }* {) J" h1 I3 O- J% Q6 v  M2 N$ Q
  40. / k+ c- P7 L! u* A3 l( a
  41.         *hqspi->pRxBuffPtr = *((__IO uint8_t *)data_reg);! F  ]% W+ j) c
  42.         hqspi->pRxBuffPtr++;
    / D' ~/ I' @8 j3 v7 [/ {: X1 f
  43.         hqspi->RxXferCount--;
    9 L  m6 ?. M! f7 w+ H/ K$ K  ]
  44.       }. m+ O0 t( d8 o& Y- E

  45. & b7 c3 j% j$ u. l
  46.       if (status == HAL_OK)) Z( B8 }) C4 r* }( n; _* E1 h. |
  47.       {1 C; U( ?+ a7 C/ l7 _) l7 V
  48.         /* 等待TC标志 */# Q9 z# a4 Y9 H$ _5 r& C& f' a# r, L! B% W
  49.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);" [" L6 s( S; j0 \

  50. . R" B3 t# x8 f7 W2 F" r4 x
  51.         if  (status == HAL_OK)5 v% a, l7 L; {: t( [2 M
  52.         {' o6 F  |% G$ M1 E7 ], T5 [5 x' r
  53.           /* 清楚传输完成bit */: q. M7 \, o# i( m5 N
  54.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);+ L& K, o0 D: o8 A: F4 T
  55. ( |7 ~- P5 H0 N5 h
  56.         }
    8 F5 y8 p' M1 X8 N4 Z5 [1 B
  57.       }
    % @8 b; s( d0 q1 E  e" T; w7 T
  58. * F" v' v' K1 I9 a; _
  59.       /* 更新QSPI状态 */2 N3 ]5 [1 n; a! Y/ E
  60.       hqspi->State = HAL_QSPI_STATE_READY;
    - }1 J- T# h$ T+ w5 P" o! c
  61.     }+ e9 n3 H4 h. `6 V7 J/ y4 Z
  62.     else1 \7 I' v& }# I% f: L
  63.     {
      N, t( w/ W5 J& G. f
  64.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;  H+ T; l+ t) X8 }1 R4 w
  65.       status = HAL_ERROR;
    ; e8 N( u' T9 Z, Y( m$ j
  66.     }, n5 W! L: O! [  ^$ m
  67.   }" K0 U+ S0 h4 ^# c' }6 b
  68.   else
    / a. F2 Y0 l2 e! [5 i( c' L# A
  69.   {
    5 ~$ s; ]- m$ t5 q
  70.     status = HAL_BUSY;  @4 K: H& ?- p7 [
  71.   }
    # x! Y2 y" T/ U- Y2 y. t; d3 Y
  72.   J8 ?* z2 s+ n( ^; m
  73.   /* 解锁 */
    # g: R& S$ Q' ~! [/ U  ?
  74.   __HAL_UNLOCK(hqspi);
    4 O9 y7 o/ m/ Y

  75. ! i# f) G2 ]5 M8 S
  76.   return status;
    $ M3 Q' i0 a, R6 o6 ~% |2 w- e
  77. }
复制代码

' ]" @) h: X/ v8 w- c* D函数描述:% t6 w, J. X4 y' J4 @3 ?- D) P( v. V: L
! e7 {# F. v) G2 W- z) }
此函数用于QSPI接口数据接收,函数采用查询方式。
0 j% `. S; V) H% d# u
, v+ P9 m. w9 Z6 b" h$ |函数参数:3 w$ o* i3 h6 G& y6 R( l: O: U. v
! T! E+ i. V# z) Z) r
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
( K: ^7 j; C, `3 `  第2个参数是要接收的数据地址。3 L7 C- ?. ^) Q( z3 o
  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。
! J0 r8 Q$ d8 Z7 |! e) B  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。- d8 S1 y1 h4 d6 \% h+ T4 J) b
使用举例:' U: z* o: a# ^
- ~- J8 |3 \  U( C
  1. /*
    1 m$ c7 U6 F5 l+ o" U3 `
  2. *********************************************************************************************************
    ! h# e# U, y) P4 s) g, Z
  3. *    函 数 名: QSPI_ReadBuffer
    * S6 N% Y, n  o% _+ u
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。
    ; V& L1 E0 G9 n
  5. *    形    参: _pBuf : 数据源缓冲区。
    ; \% \# e0 c+ L, s
  6. *              _uiReadAddr :起始地址。
    0 F9 p* {' d2 l0 z, |8 H& H
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。" |2 u, Q8 X2 ^1 e7 G
  8. *    返 回 值: 无
    9 Y7 K4 |" ^. J: @
  9. *********************************************************************************************************
    ) F( t8 O6 K; U" x) i
  10. */1 B1 [! i4 S% m# g) x4 c
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)/ B% I7 }' P/ f* V5 x) ?  P  H
  12. {0 a' i$ {4 X6 O7 P& ?2 p

  13. 5 `/ j7 z& R; q& Q; {2 e' @+ Z) W
  14.     QSPI_CommandTypeDef sCommand = {0};5 k/ J6 d6 T0 n

  15. , f* i6 }: B4 G) ^6 v+ N1 D# v" V
  16. 8 R) R0 R1 R/ i! J7 n& r; Y
  17.     /* 基本配置 */# u  i  [. k9 E- h& \
  18.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */
      z, c! H$ T  M2 v4 W! |! L
  19.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */2 ^' [1 v7 [. N5 s3 |: s
  20.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 */
    ! E% L/ _1 I& F0 B4 q' j' X- N1 {
  21.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */, `' z0 C3 d9 I$ f
  22.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */5 r: d: |* P1 I
  23.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */    3 b, u' q: T9 p5 O# v! \6 M6 f

  24. 1 |0 W' U3 l8 J; @# G4 H
  25.     /* 读取数据 */
    # d5 P( s. ~- b+ ~/ r* G) h
  26.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */
    1 l) Y3 t: {+ G% C0 Y
  27.     sCommand.DummyCycles = 6;                    /* 空周期 */
    $ }- O% P* \$ k, z+ q
  28.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */
    $ a* L3 t) }, R. @2 S
  29.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */ , r) K5 Q" U7 o' H9 Y1 s  [  ]
  30.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */ , j# @0 L8 }: j1 }5 i, ]; H3 a, J  `
  31.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */ 3 Z8 V  c7 |% Y- {6 X5 t" N

  32. 8 I6 L2 q9 c) Z1 i! _
  33.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
    " E1 \9 b+ u2 o9 o. {+ Z
  34.     {2 d- Q: K0 P0 @9 c2 j
  35.         Error_Handler(__FILE__, __LINE__);
    + q; r+ H* G% ?. S
  36.     }
    4 d; E. {$ }, v% ?

  37. " A0 \( U' s0 z, r7 d1 H7 Y
  38.     /* 读取 */# c  p+ S- m" ^, C' I
  39.     if (HAL_QSPI_Receive(&QSPIHandle, _pBuf, 10000) != HAL_OK)! X" y& _6 I. e: z
  40.     {8 G4 K3 }. F3 N* c; d; _
  41.         Error_Handler(__FILE__, __LINE__);
    ; I$ V/ p  W, d! B% m
  42.     }    ( ]/ _' B2 B3 d/ i) c: t
  43. }
复制代码
- P& @( c. U7 _6 c) R; ]0 U& f
78.4.9 函数HAL_QSPI_Transmit_DMA
( ]5 I5 ]& e+ a$ T9 Z2 f8 I& ~函数原型:
# }3 W. r7 e4 L. L/ a' g5 w9 H; Z  C0 }) Q; @
  1. HAL_StatusTypeDef HAL_QSPI_Transmit_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData), {' }3 H1 T* q
  2. {0 W" S9 i# k5 B: {
  3.   HAL_StatusTypeDef status = HAL_OK;
    4 i+ w. K; Z) R+ X  ~
  4.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);( f% s$ l5 o, e
  5. " Q) G% g9 v+ M! {! r, i
  6.   /* 上锁 */
    5 H! ]3 ]8 O% p% g# Y, r6 g
  7.   __HAL_LOCK(hqspi);6 j6 d+ T) E+ V

  8. 6 s% P7 Z7 @8 w; L" w
  9.   if(hqspi->State == HAL_QSPI_STATE_READY)
    % ^) L. |5 k1 w+ v3 `! ^
  10.   {
    0 W8 u6 i4 i" N1 V0 H5 _
  11.     /* 无错误 *// e1 u" W5 g) Z# p' L4 `
  12.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    / _4 E: }- Z$ e5 z6 g  V

  13. 3 E9 H8 \# K* N2 S$ m$ c8 _! B
  14.     if(pData != NULL )
    " K8 k  O, F1 O7 z- d5 @
  15.     {
    7 Q2 `1 S5 d. x) f* O' F4 \# |
  16.       /* 配置发送字节数 */
    5 q+ U8 t1 e) r: g' W$ k
  17.       hqspi->TxXferCount = data_size;
    . \7 N2 A, z% `

  18. & {* ?7 j! N5 {8 D& d# h8 h: _
  19.         /* 设置QSPI状态 */
    ! A! b9 A+ E# h) c8 ]
  20.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;' E4 q* [! A1 z0 d, l6 ^

  21. - Z# v- n7 ^( \. o% {
  22.         /* 清除中断标志 */
    " s/ N, ~  b' x( m& n
  23.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));
      P3 N, _/ e( x5 D& a1 Q( h

  24. & s3 N& T, m) ~5 Z1 T$ t$ D$ d
  25.         /* 配置发送 */
    9 C" Z3 b. Z; ~1 Y6 h4 C  c, X
  26.         hqspi->TxXferSize = hqspi->TxXferCount;
    - ~7 J2 {' I" V. o; D7 V+ {3 x* |
  27.         hqspi->pTxBuffPtr = pData;9 F( ]: C* K8 c

  28. 9 q$ z: e; ]8 U- e, r
  29.         /* 配置间接写模式 */, r8 P. R9 y) q  Y# ~/ \8 G* R& U
  30.         MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    , m; V" v! l& {! _  @& F& Z# |& _

  31.   i# W2 n2 b  b& ?; ?4 x, v
  32.         /* 设置MDMA发送完回调 *// E: x7 v" v! c$ J1 b3 t- ^6 l. s/ }
  33.         hqspi->hmdma->XferCpltCallback = QSPI_DMATxCplt;
    8 _. R+ I+ y! N0 Z' x3 Z1 c2 c# C
  34. , J5 c, p+ A" ?4 @( }
  35.         /* 设置MDMA错误回调 */, Z0 o' K' N$ |+ d  ?0 T2 b9 m
  36.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;
    ( @/ |4 P9 i" h! n4 U0 W- C* V
  37. ) z: C; v) W7 _+ b' p2 m
  38.         /* 设置MDMA终止传输回调为NULL */
    3 o6 t( e6 s, ]
  39.         hqspi->hmdma->XferAbortCallback = NULL;
    6 S! F# n3 S: S- M' u
  40. % E8 e  s; r& {' k' Z2 c
  41.         /* MDMA的目的地址是QSPI DR寄存器,设置禁止递增 */
    % p3 a* K! k7 ^1 S7 b/ ?
  42.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) ,MDMA_DEST_INC_DISABLE);* ?) b* [1 I1 G0 J1 ^8 E5 B
  43. . K5 q  Q8 X' f
  44.         /* 更新MDMA源地址配置 */
    - z% R! T4 E2 Y3 g( D. X/ u
  45.         if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_BYTE)
    ' r" F7 s3 z  j
  46.         {
    5 o- T" |# X0 \  i1 j& O) K) U
  47.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_BYTE);  L2 x, X: u# {" g# T! s
  48.         }2 W; Y3 J) G8 _& W# l# e3 A
  49.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_HALFWORD)3 X- I8 M" L( @, o+ l
  50.         {
    8 ^5 T5 W" }( U' y; v: @
  51.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) ,
    6 S" Z+ S& i' Q
  52. MDMA_SRC_INC_HALFWORD);
    . M& T3 p9 F6 H+ P; P' a
  53.         }3 g9 ^% A- @$ ]! U) p$ ^4 |
  54.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_WORD)
    1 P( H4 m% g3 G3 t5 s% _
  55.         {
    # q" m: j9 R# T+ ]+ Q* T. h* N' f
  56.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_WORD);
    8 }2 e- P) N' ~8 T1 N  |
  57.         }; R% R8 y% i  _
  58.         else7 I, @! }; B3 F$ n7 x7 P+ ^1 [) q
  59.         {( `1 ~; |6 t: b8 B: \" z
  60.           /* 配置错误 */7 q7 L; I% e# K; l/ _# K& {+ @
  61.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
    1 i. K+ P/ K' [1 W8 w: X. Y4 W
  62.           status = HAL_ERROR;
    0 n9 v# g6 g, n( c3 P
  63.         }
    % R$ ?' E* V- Z5 J8 a+ q0 F" j$ G1 _
  64. , F! c- i# \8 l; z* x8 g
  65.         /* 使能QSPI MDMA发送 */4 W/ @/ d, h2 F1 o4 ~7 Y
  66.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)pData, (uint32_t)&hqspi->Instance->DR,; o; S, w3 b* o5 g+ @, C
  67. hqspi->TxXferSize, 1) == HAL_OK)
    / E5 \- U8 m+ S) n' S5 O* O
  68.         {3 A+ D( F& w/ \& V0 y7 J, @# ]4 f
  69.           /* 解锁 */( C, p( a5 b  k* P
  70.           __HAL_UNLOCK(hqspi);
    8 L# @6 B3 {6 N* K+ `6 {) I

  71. ; ]4 k2 M! L: i' Q& D
  72.           /* 使能QSPI传输错误中断 */
    2 h- R* K# B$ v4 q" c9 g, u9 }8 k
  73.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);
    9 m. Y# ]) l7 w9 Q& ?0 q
  74. ; `/ k/ L8 P5 y( L5 Q
  75.           /* 使能MDMA传输 */! }3 W/ b7 s$ V; z7 T! F- I: }
  76.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);
    3 @( {$ q' \. V
  77.         }1 ^! P1 L/ d% f0 \9 C# a
  78.         else9 I6 V5 m: O1 O; R( W5 x& @; L
  79.         {
    # t) z5 I/ v2 S! v& C) V
  80.           status = HAL_ERROR;
    " @) D2 X+ P. o1 {' B4 x
  81.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
    8 m$ E$ y0 ^3 ]& ]; y' v. x! z1 Z/ ^
  82.           hqspi->State = HAL_QSPI_STATE_READY;, @/ I  v& S5 E3 F

  83. 9 s  B& B! Y& y3 F6 U
  84.           /* 解锁 */
    9 o6 D( E9 h6 o5 t
  85.           __HAL_UNLOCK(hqspi);) t6 j1 |6 X/ p8 p
  86.         }
    2 p9 ^- C: @+ r# v
  87.     }
    9 D1 `/ j5 J7 x% ^2 O2 D
  88.     else
    ! E7 R) t2 K( }% J2 {8 T# r
  89.     {, H/ T% s* a$ z' D3 ?$ r
  90.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;' N+ o  y! ~6 X( P, t/ A
  91.       status = HAL_ERROR;! }  ?. k8 j' A! P

  92. 5 s; G- X6 Q8 ?9 X1 b. v8 L+ x
  93.       /* 解锁 */
    ! y7 F' |1 Z9 r0 X+ B
  94.       __HAL_UNLOCK(hqspi);7 l: W1 L+ k9 J6 h) s+ A, D4 `+ B
  95.     }
      _9 |" V1 N+ d9 S
  96.   }3 J. u' A$ h" m
  97.   else
    7 \: g1 |9 f' Y& I, M
  98.   {/ I  q! X; N' x6 h0 Y( K
  99.     status = HAL_BUSY;- n# _9 g& i9 V7 c# d2 \3 f
  100. ) n- U. Y) B& V# Z/ I+ _
  101.     /* 解锁 */
    # y2 I4 M- J4 s! T! q# R. w/ M. B
  102.     __HAL_UNLOCK(hqspi);
    5 X; _5 h& H& M+ l* y2 B/ d3 \1 Y1 Q
  103.   }
      `. T! I" V+ \

  104. : M' W) |3 b0 ?2 o
  105.   return status;1 z5 K- y6 Y! K/ y8 y! t3 E
  106. }
复制代码

2 q5 _/ v* P7 m' ^函数描述:
. |: r- L2 L) w4 }/ i, t/ D$ i
; R- ?& R* t+ j此函数用于QSPI接口数据发送,函数采用DMA方式。, }( m; S' y2 Z9 V) z) ?- }
  @8 Z7 {6 \# U' i$ j& @9 u
函数参数:! r5 S  `4 w( _8 L
1 U  g. m& {% Q0 B( s
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。6 H6 y% [7 J! [& W- o
  第2个参数是要接收的数据地址。+ S$ b4 E4 `  v, [& I% L
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。$ L9 U4 f+ `2 P8 p2 a+ U1 u' G
使用举例:+ J7 k- E0 f& `5 C+ Z+ s, Z

9 e- L) C7 J7 z, i2 P. L' S2 w
  1. /*. H0 ~1 r# V, v
  2. ********************************************************************************************************** r6 d4 Q# n" U+ F( s$ W
  3. *    函 数 名: QSPI_WriteBuffer
    5 `. O- h7 H; g# H) N0 W
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入0 X; ^5 N' R2 t) t
  5. *    形    参: _pBuf : 数据源缓冲区;3 T$ z' _4 q# U
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。! H% B, F( z6 M# u+ s: p
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。  g. a0 k3 c3 S) r0 L! A$ i
  8. *    返 回 值: 1:成功, 0:失败
    - L/ B! T' ~( _
  9. *********************************************************************************************************
    ! c$ C3 I: ], v& e/ m/ p
  10. */
    ; H! y8 i( k. ^. u8 c- E$ R
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)0 x: Z. x; p9 F- J* a; h
  12. {: O$ U1 k( ~! Y/ d% o5 @) U' J  }
  13.     QSPI_CommandTypeDef sCommand={0};
    ' U2 }9 \/ d9 P4 F6 K

  14. 1 z, u$ s. l" `1 B% h" y# W' ]
  15.     /* 写使能 *// y" e1 l7 I1 o" s% O+ R, [
  16.     QSPI_WriteEnable(&QSPIHandle);    % [8 P7 H) P: I" a5 J* p/ C, T
  17. / R+ O; r- k5 X/ `0 a9 G
  18.     /* 基本配置 */  o+ [) d3 W9 V5 }- }" q; M7 _
  19.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */* `8 q  Y. Q3 k% Q, c, [
  20.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    ) E* O, s" J, g7 ~6 O4 M0 N
  21.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */+ L6 e$ H4 O8 S. [" k- J
  22.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    5 P8 l1 _' Z& `. S& u' l
  23.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
    $ v2 L& a* L" T. N8 s
  24.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */    % v, R! b' f# u. h9 M
  25. % z- ^- `0 N5 M
  26.     /* 写序列配置 */
    ; O) {. S2 q8 N& c" Y
  27.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */
    4 L( ~( s: L% Z6 j7 X. q
  28.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */
    ; ]$ ~( c! K* H, e1 @+ ^! G  _/ i. I
  29.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */
    6 s3 `. D, h' w, p) ^4 _8 F
  30.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
    # R; M  v- z: c4 Q0 F
  31.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   - C' C7 |% x* F; O" ^
  32.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 *// w- U1 @, Y" n% d3 ]4 T7 V

  33. 2 d# B& e4 @9 e( Y; j2 ]" T' a- V
  34.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)& N2 f: |9 F2 o) ^
  35.     {
    5 u9 d& G0 }4 Q# d/ M5 S- G( c
  36.         //return 0;8 X7 g# ^/ s7 J. W- C! U9 Y& S
  37.         Error_Handler(__FILE__, __LINE__);
    . m- O/ d3 k7 _3 S' j4 F9 J
  38.     }
    * Z9 B4 e: l3 Y6 L

  39. ! e& b. E8 R7 z6 d: r' r5 A% s
  40.     /* 启动传输 */
    5 O0 w& `+ n; G' V
  41.     if (HAL_QSPI_Transmit_DMA(&QSPIHandle, _pBuf) != HAL_OK)
    8 y8 v0 y: j3 S) x+ D+ T0 C
  42.     {4 c; R4 e! _; `0 s* M
  43.         //return 0;" J4 @, R8 `# D: N) k! U
  44.         Error_Handler(__FILE__, __LINE__);! }  R  I1 M) l" W1 q; A
  45.     }, t! s% I: _$ X0 o# o! X( Q

  46. . a) x8 c  H( ]: d; k7 x4 x8 Z
  47.     QSPI_AutoPollingMemReady(&QSPIHandle);   
    ' z: Y. [/ }# R5 j2 N
  48. 3 m1 m6 S6 S* h  X
  49.     return 1;
    - o2 W! A8 b8 R- n) e3 j
  50. }
复制代码

( L+ {5 t' X% Y1 Y" N( f1 w, U, [0 A78.4.10   函数HAL_QSPI_Receive_DMA
8 W0 \7 H  x. {$ p3 t' i函数原型:, a. S" B: v0 ?8 k; ~; @

) N# }  b. E) Q9 E6 T2 K
  1. HAL_StatusTypeDef HAL_QSPI_Receive_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData)2 r3 E8 `. X8 X* V0 K, B
  2. {, t1 ^0 w6 c" `4 m
  3.   HAL_StatusTypeDef status = HAL_OK;
    / L( c( {& x$ G" E
  4.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);
    3 o' [, c/ l4 N8 u" v6 x
  5.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);
    : K3 [5 }% h; ?. ?1 u2 R
  6. - g4 X) j- Y' f1 \8 j  [
  7.   /* 上锁 */6 m1 z0 [7 _* e, f
  8.   __HAL_LOCK(hqspi);% a- P! c" |/ n# ?
  9. / J6 a# N, g  X, @
  10.   if(hqspi->State == HAL_QSPI_STATE_READY)1 O0 m; z( B8 O$ [! u
  11.   {
    8 a+ A1 `  O! o0 T; M
  12.     /* 无错误 */2 j4 t) @9 L! i; x! e/ g
  13.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;8 f3 s- \$ L5 R! q
  14. . m7 _  l6 g1 b4 |5 N5 G
  15.     if(pData != NULL )& h# n/ F% }/ O& O+ {
  16.     {
    : ?. T. }4 `& ~( O- S- j
  17.       /* 配置接收 */' ]/ o9 N9 A$ Q( L
  18.       hqspi->RxXferCount = data_size;
    1 ?+ u* p7 S1 h7 T2 ~* c
  19.         /* 更新状态 */
    2 S; k/ k2 d* T, ^2 J7 ?/ s
  20.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;
    ! U. u8 c9 B2 l7 s& `9 ~9 v4 L
  21. ( F" f( ~7 d6 E; e: K
  22.         /* 清除中断标志 */0 S( d5 v; g; U, t5 d4 y: d: X. U
  23.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));3 X, @1 |- E) B. K: x+ `
  24. 6 d$ m# A& b6 o
  25.         /* 配置接收 Configure */
    * i! h& N# y7 }+ \& N& t) A4 O
  26.         hqspi->RxXferSize = hqspi->RxXferCount;
    + A0 U5 g% T3 E( ?
  27.         hqspi->pRxBuffPtr = pData;0 p- n* B( g+ r3 V/ h- E

  28. 8 V! I/ C# z8 O. {! Q
  29.         /* 设置接收完成中断 */% K/ U' c# |0 [: ?7 Z, f
  30.         hqspi->hmdma->XferCpltCallback = QSPI_DMARxCplt;4 L, v9 h* R0 X$ V. h# s7 J( D

  31. ; N3 M" i7 Q& p3 K8 F3 X6 |
  32.         /* 设置MDMA错误回调 */) ]. |. {# {* B* B8 U; o- x
  33.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;
    5 {) l6 ]. J: h/ p1 M; ^
  34. ' L, e9 G, o' a0 S& c
  35.         /* 置空MDMA终止回调 */
    ' p: A- r2 G; D+ _; b
  36.         hqspi->hmdma->XferAbortCallback = NULL;
    ) e/ m7 I7 ~0 ?3 W$ Z" ^, |( Q
  37. 2 y9 D6 `$ N0 ?0 l7 b
  38.       /* 接收模式下,MDMA的源地址是QSPI DR,要禁止地址自增 */# V& ]/ p- Y3 x3 @  }1 l
  39.       MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_DISABLE);* U6 [) d& o8 \9 p( m! ]* ?

  40. $ H% P  ~3 w& i" `0 B5 ?' T& [0 K0 k; a
  41.       /* 更新目的地址配置 */
    5 v9 n+ b4 S. }) z
  42.       if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_BYTE)
    # w: R! q4 c1 Q, x, f
  43.       {' S2 J; z3 X0 K% Q& _
  44.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_BYTE);
    " l4 t5 }  t) u$ e% r- g
  45.       }
    8 o' G; R1 L" v' d2 f, e& W
  46.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_HALFWORD)3 D5 D6 W: N8 M" }6 \) G
  47.       {; O2 h; r0 D( t
  48.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , ( ?: m: N. T- n1 g6 d/ s- W3 U
  49. MDMA_DEST_INC_HALFWORD);
    - V/ `+ e6 C  ~7 q9 L
  50.       }- {4 Q1 N/ b/ o. ~# C- ]5 W
  51.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_WORD)1 w, G9 K7 t* s* F* ]4 I
  52.       {
    8 J9 \# s7 T- m
  53.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_WORD);
    , w0 H$ s4 o: _2 T$ }. N2 V
  54.       }
      v2 s' c! k) E5 h$ b- o! P
  55.       else
    3 [* x0 S1 K7 ^
  56.       {% h' T. @, C. K+ ?. T
  57.        /* 配置错误 */
    ' {9 x5 ?" a) ~9 A2 T
  58.         hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
      @) Q- j; f2 _: Q% m! b; j* ^
  59.         status = HAL_ERROR;
      T2 h/ D: H( F' K9 v2 d$ ?
  60.       }
    ) W1 g5 N7 T6 [) F
  61.           /* 配置CCR寄存器,间接读 *// c8 A+ i1 z$ M' T+ Z
  62.           MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);8 k7 f0 E) B+ ?. E3 ~

  63. 2 o1 x4 G& q0 ^5 J* u  y4 g
  64.           /* 启动传输 */
    + W4 b. |1 }7 I' n  Z9 T
  65.           WRITE_REG(hqspi->Instance->AR, addr_reg);
    * R: S9 x8 p4 c  w- ^: X6 o3 n

  66.   s+ b. z+ Q) Z# y8 S3 R
  67.         /* 使能MDMA */- J% l% O4 P1 Y' A, e1 l
  68.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)&hqspi->Instance->DR, (uint32_t)pData,
    4 J# H- \& j/ ?! n
  69. hqspi->RxXferSize, 1) == HAL_OK)6 l$ \1 R  m8 g/ `  e
  70.         {+ I2 y6 ^$ U' t/ ]
  71.           /* 解锁 */
    " u' l4 _- {  K- [' M9 c# J
  72.           __HAL_UNLOCK(hqspi);
    : S' r9 J# \0 ~
  73. * n! P7 d; s0 ~8 o% u7 d1 s
  74.           /* 使能传输错误中断 */
    ! U& a. k; w2 ~% t
  75.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);
      w2 i7 w# K- k
  76. 0 j( {! z3 k# n5 D( Y9 l
  77.           /* 使能MDMA传输 */
    ) H, x1 N! t- ]! e
  78.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);% r1 V; \8 J( J7 [
  79.         }
    # @% [$ l2 [* @4 ~
  80.         else+ d" q3 J* e6 l7 }
  81.         {  S) I( [8 N% Z- n
  82.           status = HAL_ERROR;
    ( E- [  q  l( G6 }" Y- V  r" b
  83.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;# E$ b5 K8 E' I" j( ^1 K
  84.           hqspi->State = HAL_QSPI_STATE_READY;
    , M; d$ _* ~  q2 D
  85. . e7 c8 x+ \! L) s9 |
  86.           /* 解锁 */5 i  x% n7 z$ ~7 [( ~+ ^2 K$ w
  87.           __HAL_UNLOCK(hqspi);
    ' {  t. ?3 `0 w# y$ ?
  88.         }
    7 ?  z5 n2 [# q9 n3 s
  89.     }
    & d+ L. I. e3 a
  90.     else, n3 m/ C- K. R( F: C! V
  91.     {
    0 B6 `+ i' V/ {
  92.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;- s! O: S& f, J2 k' r& v
  93.       status = HAL_ERROR;; Z+ n* w$ b/ S" Z" c$ H4 c- Q# ~! z$ q

  94. " V& {. M( R* U, |6 v# d. B
  95.       /* 解锁 */9 _# w8 B$ L4 M2 v/ Q
  96.       __HAL_UNLOCK(hqspi);. v3 ~1 H- g4 y
  97.     }
    - r4 s; Q, e8 q6 o
  98.   }! V: ^7 e0 ~% ^+ [8 G1 a: g
  99.   else) b6 i- P8 u1 c: S3 h% @
  100.   {$ [5 F. A" k9 x/ b# Q
  101.     status = HAL_BUSY;1 ~: I3 y% C8 q- M
  102. 1 Z! G# b+ D8 v+ `
  103.     /* 解锁 */) `! n; b* v* X% J% t; m7 o2 C
  104.     __HAL_UNLOCK(hqspi);$ V4 M+ [$ B! E2 y: H- E: b
  105.   }
    4 Z* X# |8 o0 U' H% F8 X( w

  106. : k1 Z! d- v$ X1 r! e# L
  107.   return status;
    3 S* x  q9 M) A" M8 D% b
  108. }
复制代码

7 [- D* F- M  L( {( s2 [函数描述:+ O1 G& h! W5 b$ f8 ~5 x) g! R

/ F+ I5 P5 b& S4 z. Q" m此函数用于QSPI接口数据接收,函数采用DMA方式。2 J  `9 m9 x$ J

. F& f( \1 A/ s* [1 t6 f函数参数:
' r' o: S6 ~' U2 K. Q( Y
1 t1 b- v7 b0 r; I# _  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
) z# C9 I. A) ^4 n; N5 Q  第2个参数是要接收的数据地址。
! ^& M$ B/ ~9 A% x+ P  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
2 M; F" Y# U" N  z+ @, ]使用举例:
5 e# f; a, @) j1 L/ T' k6 @3 a8 |7 l9 B+ X& r5 N
  1. /*
    0 E, G9 L$ t# b0 A. O5 B
  2. *********************************************************************************************************) S- L9 c. b# s/ J, T9 n9 Q
  3. *    函 数 名: QSPI_ReadBuffer
    % t& p, t! l+ K& t, F
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。
    - L$ l9 k* z$ R: o% a! M6 Q
  5. *    形    参: _pBuf : 数据源缓冲区。
    ; x: Q) T9 Z/ g  k: B8 ]
  6. *              _uiReadAddr :起始地址。/ g2 o$ t" H2 g$ r! ~% [3 D+ q
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
    ; B( u3 v' L9 Z+ L" Y! q, F1 K
  8. *    返 回 值: 无6 p3 w1 G' I/ z6 s" _4 y
  9. *********************************************************************************************************
    , I' v7 x9 |& \% Q
  10. */
    / R. Z7 _! m2 h( n
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
    4 d6 k* f. Z! i& W( n0 b/ Z
  12. {
    + L7 f4 Q1 l9 Q) h
  13. 4 G+ o) m/ I; P% W, S
  14.     QSPI_CommandTypeDef sCommand = {0};
    1 Q: e) ]9 u$ m' q# Z: O3 R

  15. 5 k) f' A# p, f& |: f! ^
  16. + w2 ~: K/ @8 h" K2 t' |
  17.     /* 基本配置 */: Q) U" N$ H. m  l
  18.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */1 D- y6 F; z( I0 K  m0 x
  19.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */
    9 [4 @# e3 c; \: \' U+ u
  20.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 */+ n5 c  S! d0 }; ]
  21.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */
    2 G) [  c: R) L) i. t. B
  22.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */9 e# M+ ]9 B) D* i) I
  23.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */    ( L' B' H9 f' j; f2 {6 {4 Q/ j

  24. ' r5 x. J: ?' u& G6 O) R
  25.     /* 读取数据 */8 l' w4 N2 ?* ]/ U7 H8 L$ v
  26.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */
    6 B7 v: y1 a3 [4 ]
  27.     sCommand.DummyCycles = 6;                    /* 空周期 */) |% n+ k! U: C" l% d/ T7 A: }
  28.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */
    / v7 j, t+ \5 m$ Q' d6 J8 z
  29.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */ & ^! T- v, o6 X# n/ c- W
  30.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */ - b% p# Q+ @9 {! {* m2 O) v& H
  31.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */ + E- X: @8 F- _7 |) t( W9 B" n

  32. $ T, _3 N+ `" c- o
  33.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)! m6 }% `3 J4 d- h9 S& J; S' [8 x
  34.     {
    7 A0 x' J% O! I( M% y$ b
  35.         Error_Handler(__FILE__, __LINE__);
    ( B" h+ Z& e( Q; |
  36.     }) Q% I, G# |( K) V

  37. * c/ k, q+ P. t6 u3 ~7 C5 m: l. l# X
  38.     /* 读取 */
    / d9 m1 }* ~: k! q& d
  39.     if (HAL_QSPI_Receive_DMA(&QSPIHandle, _pBuf) != HAL_OK)! R) J. M9 m4 A2 y: m% K& I
  40.     {
    0 z. X% H+ b' w7 N0 E
  41.         Error_Handler(__FILE__, __LINE__);0 Y1 z2 y5 J) G* Q
  42.     }    # P% b  x, b4 H" ]0 g' s- v" B
  43. }
复制代码
3 D6 K8 U3 b. u2 w# |) D8 c. v1 S
78.4.11   函数HAL_QSPI_MemoryMapped; H; w& k( G% N
函数原型:" ^: Z0 E1 O7 x
6 t, C5 J( h+ U; P
  1. HAL_StatusTypeDef HAL_QSPI_MemoryMapped(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_MemoryMappedTypeDef *cfg)$ Z; t3 U9 n- _" X" P+ U
  2. {
    ( F3 W+ W8 C* ^- z  v" w5 ~
  3.   HAL_StatusTypeDef status;; ]+ l8 t0 [3 I0 c( O
  4.   uint32_t tickstart = HAL_GetTick();
    7 q: y( @9 ~2 j& F; h8 j
  5. * h0 n" \* W" J' P
  6.   /* 检查参数 */) l" x$ G! {+ V
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));# b* G: P$ l' q/ e" A
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)- o, y# D9 r, _, f1 V0 f0 f
  9.   {( X! ?0 _$ ~$ U3 p  E5 t0 l, T5 g2 ]
  10.   assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    # y" h6 }9 R% r, }/ O* i) N- l' M
  11.   }4 @2 H8 h0 x% }3 D4 A  v( f5 u9 t
  12. . V) Q5 j2 d) }+ C2 V1 j! [3 w! L
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));- _3 x0 J7 y- s0 b2 p1 N# |
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
    5 U9 B7 j% I" m% B; ?; M" t
  15.   {( Y: G3 ]( N. _* \0 |0 a* o% b
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));8 C. _1 t/ a6 i
  17.   }$ c6 m/ [3 ~6 i
  18. " D4 ~  J/ r( _7 ^+ Y
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));" l3 z0 X4 ~% G2 U: F
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    5 F" G# v2 I% B$ [1 Q3 o
  21.   {6 F6 z5 C0 \/ I7 g2 I
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));( v+ a- F& b  K& W1 O# N
  23.   }1 y" o5 t! Y' v7 s( f
  24. 1 p( b5 B' G- V( K, a- F( U5 z2 R
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));# m4 G# q5 e6 ]9 n
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    6 r( I6 X# b" @7 }* r- ?; w

  27. 7 b9 g& k6 L5 y% B
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));- C1 `( @1 j7 |: G3 d
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));8 v4 {0 k7 I* j8 K5 Y2 J) g0 R5 `
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));: I) t  V9 }# k( V
  31. 8 R: `8 L/ i$ W) a9 v$ A
  32.   assert_param(IS_QSPI_TIMEOUT_ACTIVATION(cfg->TimeOutActivation));
    / E5 Z) ]# p2 ]  i4 y" D

  33. 6 ^) x- Q6 G3 }6 a0 ]
  34.   /* 上锁 */5 q- p; W' q* y; o" Z* h
  35.   __HAL_LOCK(hqspi);1 T$ S5 u/ ~( D* w; h0 d/ b; R! ^

  36. ! Q7 e3 K& k) l9 V+ R, P' ^
  37.   if(hqspi->State == HAL_QSPI_STATE_READY)
    * u) c8 C  K6 ~2 u  d; n0 e( T+ n
  38.   {
    + @! L, G+ W) F3 N  q! i- |9 P( Q( _
  39.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;& e4 D% ]) c$ L" x* w
  40. % C& N  e" d" b6 G
  41.     /* 更新状态 */: }* e0 W3 L8 G1 g$ S
  42.     hqspi->State = HAL_QSPI_STATE_BUSY_MEM_MAPPED;
    1 g8 O  B: j4 d! ?; w* U2 V
  43. 7 D- W  Y( A: p& H6 ^1 C
  44.     /* 等待BUSY标志复位 */2 N4 @0 [) {6 Q
  45.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);1 A7 ?( D6 t7 f9 M

  46. . M6 b8 r7 r) H! t0 |( r, i) ]
  47.     if (status == HAL_OK)! {* Z  ^$ j( m# X7 _& y# j
  48.     {
    6 }5 g5 n# y' O" T
  49.       /* 配置QSPI CR寄存器溢出时间计数 */
    * \  j( w0 F/ e* _( a8 r, G% H; ?
  50.     MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_TCEN, cfg->TimeOutActivation);' U3 y$ j+ S9 j9 u6 N: X

  51. . S' l( G: I; P/ r' A2 ~# E
  52.     if (cfg->TimeOutActivation == QSPI_TIMEOUT_COUNTER_ENABLE)5 H0 _  a6 h7 N# c# i' [7 E
  53.       {
    $ Y( B, D( c2 L
  54.         assert_param(IS_QSPI_TIMEOUT_PERIOD(cfg->TimeOutPeriod));) b. Y/ K1 M+ Z# K& `

  55. ' s3 Z- z6 i. `
  56.         /* 配置溢出时间 */2 {! A  S0 c: a; ?. H7 H, `
  57.         WRITE_REG(hqspi->Instance->LPTR, cfg->TimeOutPeriod);
    4 z0 h/ |5 I& \
  58. $ @' q# A1 M' ?9 o
  59.         /* 清楚中断标志 */  i0 g$ _8 R. a5 l- A8 X
  60.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TO);  T, ~  p2 V) p4 X7 b: j# v' u

  61. - V( l5 O9 |  J% m" j% f
  62.         /* 使能QSPI溢出中断 */
    # v- T* M7 s7 S2 _
  63.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TO);
    ! ?9 H5 o/ g6 J: z: k7 A/ |
  64.       }
    * h' V; s7 O7 \; O/ n! w
  65. " h* B# W4 L9 K* S4 e. p; `
  66.       /* 调用配置函数 */" B/ S% @* t6 O% k* @
  67.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_MEMORY_MAPPED);5 c: v$ }, c# N1 [
  68.     }+ N9 w( A& w  B9 l% `
  69.   }% U# H8 a' G6 Y$ n0 Y
  70.   else
    ! F3 L7 I+ ^  |9 M4 }, v9 X  Y
  71.   {
    + ~9 X: |/ y# I
  72.     status = HAL_BUSY;
    $ r! ?& c8 c$ [. D
  73.   }  B6 n: ^; |% m: u# G6 b
  74. 8 x2 c# [* J. s4 _( v3 G
  75.   /* 解锁 */
    3 _- k1 P0 m8 Y* J  H
  76.   __HAL_UNLOCK(hqspi);  ?  E, z  v6 C5 D* r( C# J

  77. # _' W; F. L/ j: H" z
  78.   /* 返回状态 */
    " L; J  m% L* G
  79.   return status;: h0 x) E' l% b9 o* [8 O$ H) K( E
  80. }
复制代码
% S$ j( {' a* x  ?0 W. B  @3 G
函数描述:7 L8 G: |4 H+ n7 o0 b8 r
, [" J0 h% Q/ R( V6 a2 ~
用于QSPI内存映射设置。( b# ~) H3 U6 {8 ^4 Q  ?1 G9 Z
, L& f" |) X3 V
函数参数:
+ P) k& v$ z+ M' m! ?/ X9 y! }: l; w- S) c# ~. c
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。: q+ O3 ^- e$ t: B  D9 |2 @
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。9 Q2 u; ?# {" `" ^! N: _/ ?  m
  第3个参数是QSPI_MemoryMappedTypeDef类型结构体变量,详见本章3.6小节。5 Z2 \* U( j6 o: t) F8 A
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
# r" t  `$ z! p/ h! A- A1 O使用举例:7 q$ D" a& |6 T" M( a# N0 L( v

8 i9 `+ Z$ p8 Z" H+ i& o
  1. /*( k8 Q, v) U2 s8 V
  2. *********************************************************************************************************) [: o8 W" e# G8 H; W9 N
  3. *    函 数 名: QSPI_MemoryMapped0 F! `8 a  G8 V* E( n' e1 q
  4. *    功能说明: QSPI内存映射,地址 0x90000000
    & F+ _. S! e+ y1 y" ~; s
  5. *    形    参: 无, G) E$ h0 b3 a/ W$ y' K, e
  6. *    返 回 值: 无
    , r: O0 D* G! I  q: @5 A
  7. *********************************************************************************************************( I7 `' k& y- n3 A
  8. */, K! _' X: y7 c+ G9 u' f7 w
  9. void QSPI_MemoryMapped(void)8 B' A. {+ S! {; ^& ^
  10. {- J, r: Q2 Z6 X  R; R( A
  11.     QSPI_CommandTypeDef s_command = {0};0 J0 a, E2 `) N; Q
  12.     QSPI_MemoryMappedTypeDef s_mem_mapped_cfg = {0};% u& A; X! m' }/ D" p! S6 Q: P
  13. , U4 \3 s: ?; p  f. V- K; G% w9 N) w
  14.     /* 基本配置 */$ M1 \; v0 C& e7 f. s6 x
  15.     s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;      /* 1线方式发送指令 */ 0 i/ G" S0 z  j6 z
  16.     s_command.AddressSize = QSPI_ADDRESS_32_BITS;             /* 32位地址 */. ^, J% t( Q$ P2 f% v# }
  17.     s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */# f9 a" ^1 s% Y, s
  18.     s_command.DdrMode = QSPI_DDR_MODE_DISABLE;                /* W25Q256JV不支持DDR */+ ?2 T) F5 g* A9 l5 o" c% |
  19.     s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;   /* DDR模式,数据输出延迟 */* r- g( z8 Y+ H
  20.     s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次传输都发指令 */
    3 w( X0 m5 I: I. _
  21. 4 D7 \5 |4 y0 D1 z  K/ \( q; P
  22.     /* 全部采用4线 */9 W' I% c2 B4 p
  23.     s_command.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 快速读取命令 */* r  m2 |. Q5 f7 Y& ~, t
  24.     s_command.AddressMode = QSPI_ADDRESS_4_LINES;                 /* 4个地址线 */
    2 M5 u2 o- |% P1 x' F
  25.     s_command.DataMode = QSPI_DATA_4_LINES;                       /* 4个数据线 */9 ?$ X: ^3 O* O. ?4 A
  26.     s_command.DummyCycles = 6;                                    /* 空周期 */' e- b# o! K% ]" x4 z' \2 h  g
  27. 1 `+ |( X" Q5 P; c
  28.     /* 关闭溢出计数 */
    , ^2 s( V9 y5 E% \
  29.     s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;( M8 S% _' p% V8 C$ x
  30.     s_mem_mapped_cfg.TimeOutPeriod = 0;1 m, `) g1 q' _" |0 t( }
  31. % Y7 A3 |& r, u7 q' q
  32.     if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)
    7 b. f" _0 g) d3 y: r$ }2 L
  33.     {
    4 H  r; c6 _; S: n! `
  34.        Error_Handler(__FILE__, __LINE__);
    * a8 i, B' o7 n3 A6 b1 E
  35.     }8 L. ~+ o! S- T) }  W* Y" O
  36. }
复制代码
1 ]; l. q$ l2 p5 W! f* Z2 E
78.5 总结
+ `/ g0 _, D" H5 u" u, b本章节就为大家讲解这么多,要熟练掌握QSPI总线的查询,中断和DMA方式的API用法。
" g/ y' S9 @% r- [. }: R
6 m6 i2 `2 c. l: d! W" ]
& g- h# |, N7 ^9 ~$ M4 j. n
74f88e781c0aa6369a48d73fb7dbe7d9.png
收藏 评论0 发布时间:2021-11-4 18:44

举报

0个回答

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版