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

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

[复制链接]
STMCU小助手 发布时间:2021-12-20 19:00
72.1 初学者重要提示
) I3 T1 W% ?  K2 }, X4 g6 B  STM32H7的SPI支持4到32bit数据传输,而STM32F1和F4系列仅支持8bit或者16bit。
* e7 R. O% H" X& K5 m- i( t9 P  STM32H7的主频400MHz时,SPI1, 2, 3最高通信时钟是100MHz,而SPI4, 5, 6是50MHz。
5 X1 L+ U; N- I8 t& k) r; r2 Y  STM32H7的MISO和MOSI引脚功能可以互换,使用比较灵活。
2 S4 L+ \7 [/ S+ V  SPI总线的片选引脚SS在单一的主从器件配置下是可选的,一般情况下可以不使用。
8 V5 Y: O9 l3 u6 ~
: ?1 m: D* w# o& K( a72.2 SPI总线基础知识" I) X' ^( \5 d6 b. l
72.2.1 SPI总线的硬件框图
* ]+ D6 b0 {+ F6 c; {) U+ b! r
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SPI的基本功能,然后再看手册了解细节。5 V0 t- K' f: H% X' G

! G1 j; o/ T9 v" F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

. B) P+ L* f7 K/ }$ D
/ Q1 ], N7 l1 R7 l5 ?' C通过这个框图,我们可以得到如下信息:1 d2 j; T9 D( v9 m
  spi_wkup输出' \/ S, w0 M6 D# b8 ?
% Z5 c& G4 }4 `% {; q, Z0 D
低功耗唤醒信号。
8 `' t1 C3 t  q  spi_it输出$ H7 V" q: c( `2 V' I5 h1 R

; T# B; I4 ^4 W7 g" e4 d. h9 W* ^7 K4 N8 n4 ?
spi的中断请求信号。
6 v9 x: h4 u3 N/ n  spi_tx_dma
1 ?  V: b' O  H; M/ |; Y  spi_rx_dma! I/ H/ h  l* q. Q
( L! p" }  z+ g; m

" e! N$ J4 I5 n! N) ]$ n9 ?, i* ^spi的DMA发送和接收请求信号。. `1 i* \  \$ Y* E2 S
  spi_pclk: I  }2 b+ x/ t

8 X7 R6 l' p1 L- d
# v. G/ g  n. T6 w为寄存器提供时钟。. K+ X+ Q) v7 j" W1 h& Z; b; i
  spi_ker_ck
( q- A  P7 }* m/ m' m
$ K0 h3 ~' C) g# Z5 p3 n8 d. r; w
, n8 L8 Y, `5 x# I/ J6 k7 |为spi内核时钟。
- p4 O0 O5 W6 G2 S  SCK(CK),Serial Clock
6 b/ z! c$ l  i: E( u* l# m- n1 d( I+ |9 V8 N
+ u8 B0 R" U7 I7 g( z
此引脚在主机模式下用于时钟输出,从机模式下用于时钟输入。# z( f# K* \/ g1 e/ M. U+ M1 P
  MISO(SDI),Master In / Slave Out data4 U2 c& ^: Y1 |  U% P3 F
  Y. T% T* S- w6 |- }

/ M' p, W  J- z" I) ?" d4 w* C此引脚在从机模式下用于发送数据,主机模式下接收数据。( B, M) O1 x* Y; @5 U& ^
  MOSI(SDO), Master Out / Slave In data' s% i- A" g# w" s2 q! j

" [2 C1 L1 @8 ]: Y& a! \* Y' q: j, E2 C6 b+ J4 [
此引脚在从机模式下用于数据接收,主机模式下发送数据。
7 W% {. M2 ^: k9 H! s8 r0 m4 X; `  SS(WS), Slave select pin) Z5 Y* s) m3 }3 d5 g9 [
$ m8 ]+ [; ~6 ]' s0 m4 ?
; u/ i( {3 n' D( Z& w5 {# s
根据SPI和SS设置,此引脚可用于:
- A; S: H- F! ?  E- ha. 选择三个从器件进行通信。$ D2 C( g9 [' ]8 B/ D

4 d2 b. Z2 a& \2 j* y7 |b. 同步数据帧。
. s' p2 K; K/ l0 J0 y2 w+ B& p. T5 B
4 Z4 M8 E, {# e  i, z7 sc. 检测多个主器件之间是否存在冲突。- g6 Y3 }& e/ @' ~$ T1 E
' [3 k' d/ ]' }' J" i. x1 s
通过这个框图还要认识到一点,SPI有三个时钟域,分别是寄存器所在的ABP总线时钟域,内核时钟发生器时钟域以及内核时钟发生器分频后的串行时钟域。% O) O( {; |* X7 I- V3 ?% `
3 H, U8 Z( [& o. E4 O
72.2.2 SPI接口的区别和时钟源(SPI1到SPI6)
  Q! S! f% U9 P4 }; e
这个知识点在初学的时候容易忽视,所以我们这里整理下。# X# l( J: K( d
SPI1到SPI6的区别
. e9 Z& [3 f# `" s9 z" @  SPI1,SPI2和SPI3支持4到32bit数据传输,SPI4,SPI5和SPI6是4到16bit数据传输。
4 c9 ?$ _8 o0 Y" }* U, T  SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit。4 w: |4 g# [, a" b2 {2 j3 n) c. c
9 Z( Y$ @! l) Z# ^+ E
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
. U6 e* ?( _; b2 c5 G  F' s. }/ y
  T- H3 y0 i2 l' h2 [8 E+ W
  SPI1到SPI6的所在的总线(对应SPI框图的SPI_CLK时钟域)1 l" V5 ^, {) o( l) {2 l

- F) N" }8 `; ~: C* G" p1 N/ M
3 R' y' m$ S3 PSPI1,SPI4和SPI5在APB2总线,SPI2,SPI3在APB1总线,SPI6在APB4总线。注意,SPI的最高时钟不是由这些总线决定的。9 R( z% U- J/ B" P4 ?- [, p' k

+ b2 u; R1 s0 e, S" p! Y6 h, q% q  SPI1到SPI6的支持的最高时钟(对应SPI框图的SPI_KER_CK)
( l  f+ n3 q4 s9 C( Z! G' f
, d! C% {: j: u! B* a& e$ k
1 T# T& v4 w: \$ {0 ~; \STM32H7主频在400MHz下,SPI1,SPI2和SPI3的最高时钟是200MHz,而SPI4,5,6是100MHz, 以SPI1为了,可以选择的时钟源如下:
, Z9 K5 H( n0 X( [4 h* G0 l
9 J' l1 {8 K( Z$ Z" g
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

0 {; K, K! r* e/ j5 D, N" x- W' U3 l: c( Y$ f3 ^9 v
这里特别注意一点,SPI工作时最少选择二分频,也就是说SPI1,2,3实际通信时钟是100MHz,而SPI4,5,6是50MHz。
3 J( d% u  b' \& f
% V# _  M, [9 h* D6 E$ \- m$ n72.2.3 SPI总线全双工,单工和半双工通信
; \# H6 H; O! S  J8 X, e6 k: @; x9 l片选信号SS在单一的主从器件配置下是可选的,一般情况下可以不使用。但需要同步数据流,或者用于TI模式时需要此信号。
, a* r& |2 A5 M, p: G& @5 ?! D( T
9 |4 n4 Q, y) ?7 I0 F( s  全双工通信
: T( D5 N4 w: _# F. R2 S全双工就是主从器件之间同时互传数据,SPI总线的全双工模式接线方式如下:+ o. E# i! j4 x, u0 A# I+ ?7 B

( \9 |' M3 y4 h/ H* y/ u
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
  t- D4 Y  T# [+ b6 O

! W3 N$ [; c7 ~关于这个接线图要认识到以下几点:2 z3 n/ t6 R& }. h; `9 c
  注意接线方式,对于主器件来说MISO引脚就是输入端,从器件的MISO是输出端,即Master In / Slave Out data。MOSI也是同样道理。
3 s5 q/ y* }8 Y1 q+ Y5 v6 _+ t  每个时钟信号SCK的作用了,主器件的MISO引脚接收1个bit数据,MOSI引脚输出1个bit数据。7 G5 Z  M  T4 d! x2 j! s
  这种单一的主从接线模式下,SS引脚可以不使用。3 L2 A0 ]! e" [* A# `

/ J; n7 _  f' b半双工通信4 b( O! X' s  M% N# R( T. n  X
半双工就是同一个时刻只能为一个方向传输数据,SPI总线的半工模式接线方式如下:
1 z. E" |! W# b; t0 D: W! s, L& V. R
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

- X& ^5 G# h  n9 c' Q0 n: j: }( a% [( H& a6 b$ L& B" D
关于这个接线图要认识到以下几点:
2 n  s; A# t& U! C- h7 M# ^# }. V" c, q( A2 X, r
  更改通信方式时,要先禁止SPI。
1 W: m* X+ _% J' g# I  主器件的MISO和从器件的MISO不使用,可以继续用作标准GPIO。
2 S/ ?" ?+ G/ r7 c6 H" a  1KΩ的接线电阻很有必要,因为当主器件和从器件的通信方向不是同步变化时,容易出现其中一个输出低电平,另一个输出高电平,造成短路。7 Q0 O" ~  |" D  m
  这种单一的主从接线模式下,SS引脚可以不使用。
0 I5 _- f4 X2 q7 T% T# c6 N" G  4 a6 G$ N1 o6 c4 y# q% W
单工模式4 w' Q) O4 H$ I1 b/ |; M
单工就是只有一种通信方向,即发送或者接收,SPI总线的全双工模式接线方式如下:$ K# s7 k( m0 x8 r$ }/ H1 S/ Y
( ~8 ~1 {. R8 e- b( `0 Z
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

8 |( o6 Z: H( l! L) I; ?+ C$ M; J8 Y2 W* }" V. ?8 n) O
关于这个接线图要认识到以下几点:) E7 S: z  \8 g
- K0 o$ z9 x3 K1 W
  未用到的MOSI或者MISO可以用作标准GPIO。
' Z- `  i- q  }  {; E- K5 J  这种单一的主从接线模式下,SS引脚可以不使用。
6 H" H0 j! f; _" T
* Y) Q" t# F% z* T$ n- t72.2.4 SPI总线星型拓扑
# }+ n7 v) w: WSPI总线星型拓扑用到的地方比较多,V7开发板就是用的星型拓扑外接多种SPI器件:. ~$ q# [" F; J& Q; C5 Z# v

8 @/ u$ s, e: N3 f1 X& x7 X
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

' k5 y# V9 j' p7 p3 P
2 ~4 \3 M* ]% s4 w& l  E; @关于这个接线图,有以下几点需要大家了解:! w5 L  y' D- P* z
- l1 M$ o- m& A# M8 {! c& y' g
  主器件的SS引脚不使用,使用通用GPIO控制。为每个器件配一个SS引脚,方便单独片选控制。+ x" e7 ]7 E7 R8 s. n7 j: _
  从器件的MISO引脚要配置为复用开漏输出(很多外部芯片在未片选时,数据引脚是呈现高阻态)。# S2 r5 W: ?6 P9 ~0 v

# {+ V: N: H& B* D# a- B+ H$ ?% J) V7 u5 m' `: G% p' t
72.2.5 SPI总线通信格式
0 b1 d3 i: l# [+ y* BSPI总线主要有四种通信格式,由CPOL时钟极性和CPHA时钟相位控制:4 V" t( q# o+ l6 Q

3 l. b8 _3 K# X% q( D
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
# |  f7 M/ c9 U! ], q
3 \% f/ T$ g# v4 |( {* S( d
四种通信格式如下:
4 D4 b) `1 G) X% g  当CPOL = 1, CPHA = 1时: b  n% G. _) Z" q" U5 E

, A9 a2 E) k  Q# c& g
/ F0 b8 A7 R/ M1 j2 M, d. ^SCK引脚在空闲状态处于低电平,SCK引脚的第2个边沿捕获传输的第1个数据。  x$ }8 I/ z  G& F/ i; o
  当CPOL = 0, CPHA = 1时9 p2 x! _3 X9 A, B2 O" M

' V5 A0 X" A" j7 Q; A; U' B; \. D$ ^& _" S, K1 o& G
SCK引脚在空闲状态处于高电平,SCK引脚的第2个边沿捕获传输的第1个数据。
. f% _5 f6 t' f8 k, v: Z  当CPOL = 1, CPHA = 0时* |! f1 y$ X- E/ I) y  I3 `

- x/ V( A! z; N! c, U7 z4 X8 y5 D1 j0 C
SCK引脚在空闲状态处于低电平,SCK引脚的第1个边沿捕获传输的第1个数据。/ R, i8 u* V5 b# p9 H: X6 v' K7 h
  当CPOL = 1, CPHA = 0时2 f+ |8 [# g9 J1 x
  Z8 r; `3 V/ u3 i8 q5 M
. N* P; T% g6 ^  Y  {
SCK引脚在空闲状态处于高电平,SCK引脚的第1个边沿捕获传输的第1个数据。# \& O6 N( k& M; ~9 \9 c
; [+ V; s' _: `! ?* ]9 W4 I+ J8 b
72.3 SPI总线的HAL库用法
/ x1 M2 V2 _2 ]- k8 c; u
72.3.1 SPI总线结构体SPI_TypeDef
9 v( g- }- `6 P, ~# R$ h; @2 B; xSPI总线相关的寄存器是通过HAL库中的结构体SPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
7 J! X( {, q0 H
" C) o( z' W8 Q  J$ f* d' o# M
  1. typedef struct& F* P5 t* O. c/ G4 o4 |
  2. {
    $ g% S) V5 e7 F- n, K
  3.   __IO uint32_t CR1;           /*!< SPI/I2S Control register 1,                      Address offset: 0x00 */
    , S2 J  ?1 ~6 H: R
  4.   __IO uint32_t CR2;           /*!< SPI Control register 2,                          Address offset: 0x04 */
    . b6 b! B4 |# w" d% m+ \! s
  5.   __IO uint32_t CFG1;          /*!< SPI Configuration register 1,                    Address offset: 0x08 */
    % _; K# L0 O8 _4 i
  6.   __IO uint32_t CFG2;          /*!< SPI Configuration register 2,                    Address offset: 0x0C */
    " ?# {2 O- C$ }; j5 W. T) J
  7.   __IO uint32_t IER;           /*!< SPI/I2S Interrupt Enable register,               Address offset: 0x10 */
    * Y$ G! t9 @2 o. B: g, _5 J
  8.   __IO uint32_t SR;            /*!< SPI/I2S Status register,                         Address offset: 0x14 */
    $ a* ?4 Q- Y# |: _4 H+ c4 V, {  H
  9.   __IO uint32_t IFCR;          /*!< SPI/I2S Interrupt/Status flags clear register,   Address offset: 0x18 */7 U3 P' Q/ C! h8 N+ D! ~
  10.   uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                        */$ ^! j! ~! x* ?
  11.   __IO uint32_t TXDR;          /*!< SPI/I2S Transmit data register,                  Address offset: 0x20 */
    5 n- }# J) O, H+ Q+ x- Q
  12.   uint32_t      RESERVED1[3];  /*!< Reserved, 0x24-0x2C                                                   */, [# o" F# m9 C$ W2 e
  13.   __IO uint32_t RXDR;          /*!< SPI/I2S Receive data register,                   Address offset: 0x30 */
    ( W0 X% ]& s1 c  }6 s7 x7 H: c
  14.   uint32_t      RESERVED2[3];  /*!< Reserved, 0x34-0x3C                                                   */9 p, y  }0 n+ x% ?
  15.   __IO uint32_t CRCPOLY;       /*!< SPI CRC Polynomial register,                     Address offset: 0x40 */
    / e# u& q5 B9 V/ t) ]$ M; L' e
  16.   __IO uint32_t TXCRC;         /*!< SPI Transmitter CRC register,                    Address offset: 0x44 */$ a) b. H9 c! j* p1 o. I
  17.   __IO uint32_t RXCRC;         /*!< SPI Receiver CRC register,                       Address offset: 0x48 */
    * V; g8 n% w" e
  18.   __IO uint32_t UDRDR;         /*!< SPI Underrun data register,                      Address offset: 0x4C */1 K( l4 a, K4 G& N' ^" A
  19.   __IO uint32_t I2SCFGR;       /*!< I2S Configuration register,                      Address offset: 0x50 */1 F5 k' O% I5 {) D' \

  20. + n1 `3 k& N1 s1 `
  21. } SPI_TypeDef;
复制代码
' B0 Z: i2 W$ e3 z1 ]$ \
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
( J$ o& [6 W/ R2 ]3 D$ X  Z; h5 Q3 [' P5 V0 T* c1 Q; {
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
: y  n! i% W  J& \7 y3 {! Z2 A: `4 q' V& Y% r
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */: D9 E7 k" Q& O  _! n; [
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

' \# r- G; c: j" c+ |% o# F8 r8 u下面我们看下SPI的定义,在stm32h743xx.h文件。
" A3 m7 _% |3 ~3 u3 k) n! ]& w* Q. ~
  1. #define PERIPH_BASE           (0x40000000UL)
    - n; {) X& v  d) A3 z/ J
  2. #define D2_APB1PERIPH_BASE     PERIPH_BASE
    % N, V/ r8 K! P8 I% U) V4 c# F
  3. #define D2_APB2PERIPH_BASE    (PERIPH_BASE + 0x00010000UL)) g, N( x7 l) a, S1 g
  4. #define D3_APB1PERIPH_BASE    (PERIPH_BASE + 0x18000000UL)
    . _6 G( M1 L7 {- y
  5. 1 [: ?% l' q- l; M- H
  6. #define SPI2_BASE             (D2_APB1PERIPH_BASE + 0x3800UL)1 E4 ]% h! \: r# E: ?4 e2 C) ~
  7. #define SPI3_BASE             (D2_APB1PERIPH_BASE + 0x3C00UL)
    " y8 y. X# W) L7 q
  8. #define SPI1_BASE             (D2_APB2PERIPH_BASE + 0x3000UL)
    & j# W  b" ]1 W3 c+ }! I- J
  9. #define SPI4_BASE             (D2_APB2PERIPH_BASE + 0x3400UL)
    0 Z; v: ~- g% J* o  s/ `' W
  10. #define SPI5_BASE             (D2_APB2PERIPH_BASE + 0x5000UL)
    , F+ |& f, }; G  f( D
  11. #define SPI6_BASE             (D3_APB1PERIPH_BASE + 0x1400UL)3 z8 u! I" ?7 Y2 [/ P
  12. & m6 m% D; f) i
  13. #define SPI1                ((SPI_TypeDef *) SPI1_BASE). K/ K1 O* z" W
  14. #define SPI2                ((SPI_TypeDef *) SPI2_BASE)/ Y) d# g5 u1 a2 O5 `% Z
  15. #define SPI3                ((SPI_TypeDef *) SPI3_BASE)
    # j% N: C. U$ \  s9 }8 b) ?/ B
  16. #define SPI4                ((SPI_TypeDef *) SPI4_BASE)4 h. T1 J6 X# w5 A! C
  17. #define SPI5                ((SPI_TypeDef *) SPI5_BASE). e9 f" L1 c! j& u4 s& d3 Z6 a
  18. #define SPI6                ((SPI_TypeDef *) SPI6_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x58001400
复制代码
+ r6 S8 }9 B3 p3 n1 v$ j* X
我们访问SPI的CR1寄存器可以采用这种形式:SPI->CR1 = 0。2 Y) T4 y1 j6 f; j

& R/ q, ^% q9 o+ p- k0 Q: \72.3.2 SPI总线初始化结构体SPI_InitTypeDef
: B/ {0 A: m9 T6 H, c. F' b# o
下面是SPI总线的初始化结构体,用到的地方比较多:
4 c1 {7 N" K5 }" i  G3 s8 u: |. p
  1. typedef struct
    + S# j* |5 Z1 O$ q3 N( ]
  2. {
    ) a) Q3 m1 Z& T' u) Q7 |3 t& v
  3.   uint32_t Mode;                           
    / K! P7 A$ b2 Z1 U5 z4 A
  4.   uint32_t Direction;                     
      G( R4 V1 U8 K) z  T  {) t& r
  5.   uint32_t DataSize;                          ! l, H+ d/ o2 V& q8 n. E
  6.   uint32_t CLKPolarity;                       6 T5 [" ]  M  n8 T' _0 Y
  7.   uint32_t CLKPhase;                         # z" m4 t# d% B4 g; b
  8.   uint32_t NSS;                             
    4 e2 c2 q8 r9 g5 P
  9.   uint32_t BaudRatePrescaler;               
    & Y5 N1 A  O$ H
  10.   uint32_t FirstBit;                        
    6 e  {; k- S0 \
  11.   uint32_t TIMode;                          
    & K; Q8 A# `8 G4 K7 ]+ }
  12.   uint32_t CRCCalculation;                  
    ) K9 P: Q. k& Q+ u, u+ g
  13.   uint32_t CRCPolynomial;                     + R5 @! o9 s2 U' X3 h
  14.   uint32_t CRCLength;                        ' U; z. N/ L8 G4 z" v2 ^
  15.   uint32_t NSSPMode;                         ! G( h7 t! s; a, o9 [0 i9 ~
  16.   uint32_t NSSPolarity;                    
    5 j. g: |8 \0 n4 }8 N
  17.   uint32_t TxCRCInitializationPattern;       ) {7 B# d. V3 T' h. x
  18.   uint32_t RxCRCInitializationPattern;       % R" I# t; g/ @
  19.   uint32_t MasterSSIdleness;                 
    7 h0 i: k1 E' \/ c% S
  20.   uint32_t MasterInterDataIdleness;             [8 e- A9 `5 N% a) |1 A
  21.   uint32_t MasterReceiverAutoSusp;         
    , X% l; \' {0 M3 N2 c5 ~$ X9 g6 s
  22.   uint32_t MasterKeepIOState;               
    ( J' l8 J0 v9 h
  23.   uint32_t IOSwap;                          
    0 U/ r% r9 u& ~7 I& T
  24. } SPI_InitTypeDef;
复制代码

+ m7 I! Q$ n; W" H下面将结构体成员逐一做个说明:
% r1 Y4 K% R( N  Mode
. H; V( |8 S8 d+ D0 S2 W# d: z- }( x/ M- H
用于设置工作在主机模式还是从机模式。
2 C) {; W0 W4 `" K. p
  1. #define SPI_MODE_SLAVE              (0x00000000UL)
    ' G2 e# i, q5 f7 M
  2. #define SPI_MODE_MASTER             SPI_CFG2_MASTER
复制代码
" q1 u" z; Y: B6 ^" k
  Direction
! a0 u9 _7 z# K4 A  c用于设置SPI工作在全双工,单工,还是半双工模式。& W7 X% M" E/ Z. n$ H. W
. ^/ j3 a3 E. {! t3 I& a
  1. #define SPI_DIRECTION_2LINES           (0x00000000UL)     /* 全双工 */+ b  h" P! T; e8 v
  2. #define SPI_DIRECTION_2LINES_TXONLY     SPI_CFG2_COMM_0   /* 单工,仅发送 */7 D9 H5 e+ @& T4 s- R
  3. #define SPI_DIRECTION_2LINES_RXONLY     SPI_CFG2_COMM_1   /* 单工,仅接收 */5 y8 P9 e# j: E& o
  4. #define SPI_DIRECTION_1LINE             SPI_CFG2_COMM     /* 半双工 */
复制代码
# E9 N% t- T. D' h  `
  DataSize
2 k8 Y/ c2 ~) Z' P8 c用于设置SPI总线数据收发的位宽,支持4-32bit。- F: ?# L7 [$ c7 d* h0 J

9 P9 E- u/ P$ p5 G3 u, ]) _
  1. #define SPI_DATASIZE_4BIT                             (0x00000003UL)3 g% b* {8 a' |! {, |+ r8 t
  2. #define SPI_DATASIZE_5BIT                             (0x00000004UL)
    : j3 p  m/ o4 q& ?7 _; z) o% \
  3. #define SPI_DATASIZE_6BIT                             (0x00000005UL)6 s! K% k* e1 a( R$ A
  4. #define SPI_DATASIZE_7BIT                             (0x00000006UL)
    % v. }8 q1 `+ U) x* f5 g8 D0 Y
  5. #define SPI_DATASIZE_8BIT                             (0x00000007UL)
    ( u6 }/ N( |# V" _3 F6 I
  6. #define SPI_DATASIZE_9BIT                             (0x00000008UL)
    # Q9 f; a" r; U6 d- d: r
  7. #define SPI_DATASIZE_10BIT                            (0x00000009UL)
    9 t7 z/ b, L( h' c3 w1 A
  8. #define SPI_DATASIZE_11BIT                            (0x0000000AUL)4 s! \2 \, F) Y/ X: R# X
  9. #define SPI_DATASIZE_12BIT                            (0x0000000BUL)( y& }" u3 X: f( _/ b
  10. #define SPI_DATASIZE_13BIT                            (0x0000000CUL)2 z# r: v$ w4 W+ b  m
  11. #define SPI_DATASIZE_14BIT                            (0x0000000DUL)! r. J7 Y7 }6 c' _9 k1 `% E3 o
  12. #define SPI_DATASIZE_15BIT                            (0x0000000EUL), V  F% o' x, U
  13. #define SPI_DATASIZE_16BIT                            (0x0000000FUL)
    & ?! o! j, R, {5 x4 ~8 M% j. u
  14. #define SPI_DATASIZE_17BIT                            (0x00000010UL)
    & \7 c2 [" ?. x4 j* w
  15. #define SPI_DATASIZE_18BIT                            (0x00000011UL)
    ; p5 Y' ?) `" X8 J
  16. #define SPI_DATASIZE_19BIT                            (0x00000012UL)9 k% G% \& m$ F2 D) X7 d
  17. #define SPI_DATASIZE_20BIT                            (0x00000013UL)
    . P6 ]( Y  }# n3 y& v6 |: M
  18. #define SPI_DATASIZE_21BIT                            (0x00000014UL)
    & x/ i, P4 h2 @; B  c$ \# K7 Q' G
  19. #define SPI_DATASIZE_22BIT                            (0x00000015UL)
    9 U5 k& N; A( _% v2 ~
  20. #define SPI_DATASIZE_23BIT                            (0x00000016UL)
    ! l& g' ^6 A9 D) r% O& g& p
  21. #define SPI_DATASIZE_24BIT                            (0x00000017UL)6 W# V5 d6 G% n6 x
  22. #define SPI_DATASIZE_25BIT                            (0x00000018UL)
    ) L' l% D, D* l' x( r5 ~% D% Z
  23. #define SPI_DATASIZE_26BIT                            (0x00000019UL)
    " L2 M) |; ~, _) `# q3 ?
  24. #define SPI_DATASIZE_27BIT                            (0x0000001AUL)- f+ P# Z6 T& e% |' G2 \
  25. #define SPI_DATASIZE_28BIT                            (0x0000001BUL)
    : }# u8 C) I3 J
  26. #define SPI_DATASIZE_29BIT                            (0x0000001CUL)
    ! Q9 P% R* E' S1 U! _: a0 K; X
  27. #define SPI_DATASIZE_30BIT                            (0x0000001DUL)
    , a5 u) k9 L. [5 i/ N% _
  28. #define SPI_DATASIZE_31BIT                            (0x0000001EUL)+ t0 \4 A% ?- u& D: b  D; x; z
  29. #define SPI_DATASIZE_32BIT                            (0x0000001FUL)
    ( x: e# x4 R6 W* P- x
复制代码

& M' l5 E+ n1 I1 y3 {, R4 T! B* u7 B: p% I7 t
  CLKPolarity5 e: f1 h: {7 V/ C3 S
用于设置空闲状态时,CLK是高电平还是低电平。. J# s' }5 g. k' t
  1. #define SPI_POLARITY_LOW       (0x00000000UL)
    2 `6 J* f- T4 S
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码

( A" @; M; U6 n# q( g1 Z6 P  NSS
2 k: p# \  S+ o/ C. c+ f$ {3 U0 a5 s用于设置NSS信号由硬件NSS引脚管理或者软件SSI位管理。) N/ s0 w( t; y4 g4 }" ]# F: u
9 ]. S+ K6 Q# {7 q) y0 Y+ [6 I
  1. #define SPI_NSS_SOFT                                  SPI_CFG2_SSM7 `" g& D2 G3 ?' p/ u6 z
  2. #define SPI_NSS_HARD_INPUT                            (0x00000000UL)
    9 S" Q) |, y9 |* }, W$ e- _2 ~1 M
  3. #define SPI_NSS_HARD_OUTPUT                           SPI_CFG2_SSOE
复制代码
7 `0 e4 ?) Z- W7 B
  BaudRatePrescaler
3 i7 a* p! H  ]( s/ }8 C' S6 w用于设置SPI时钟分频,仅SPI工作在主控模式下起作用,对SPI从机模式不起作用。, u/ g4 E/ W: b7 \& [2 Y
0 h" u6 H, I  @2 v- l- g4 M
  1. #define SPI_BAUDRATEPRESCALER_2                       (0x00000000UL). Z; W  s' V8 c
  2. #define SPI_BAUDRATEPRESCALER_4                       (0x10000000UL)
    1 e5 j( |' k3 w; D# c
  3. #define SPI_BAUDRATEPRESCALER_8                       (0x20000000UL)
    ) v/ e: ]6 {& X. S9 C. j0 H. _3 y
  4. #define SPI_BAUDRATEPRESCALER_16                      (0x30000000UL)- d  n* A7 Y* p8 ], }; G
  5. #define SPI_BAUDRATEPRESCALER_32                      (0x40000000UL)
    $ T6 j0 h" x) L3 X: n5 s4 g
  6. #define SPI_BAUDRATEPRESCALER_64                      (0x50000000UL)* R& u% ?" x8 s5 T/ C& |
  7. #define SPI_BAUDRATEPRESCALER_128                     (0x60000000UL)
    7 Y2 n! c7 S8 ~) q: L6 U, N
  8. #define SPI_BAUDRATEPRESCALER_256                     (0x70000000UL)
复制代码
+ T7 n! D! \; z6 t4 i) I
  FirstBit
" a! c/ d1 o0 M. O用于设置数据传输从最高bit开始还是从最低bit开始。
9 i% I+ J( a. R, R8 V. Z$ k
  1. #define SPI_FIRSTBIT_MSB                              (0x00000000UL)
    ! Q% `- b* [, N' r2 c0 N
  2. #define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST
复制代码
8 Q  N, C5 N$ a/ n+ E3 t" R) N  s
  TIMode
; _% r  v; c% X用于设置是否使能SPI总线的TI模式。2 L- B5 S/ a( L/ z( G  n3 r/ q7 \
  1. #define SPI_TIMODE_DISABLE               (0x00000000UL)
    ! ?  v: ]( ]9 N* |7 G5 A" Y
  2. #define SPI_TIMODE_ENABLE                SPI_CFG2_SP_0
复制代码

, g8 T. S$ \4 k! Y  CRCCalculation
4 Z. s9 c: ?6 n用于设置是否使能CRC计算。  t7 D6 L4 O, A% I. m$ k0 |
  1. #define SPI_CRCCALCULATION_DISABLE                    (0x00000000UL)
    ) h3 J2 }2 I% Q' c
  2. #define SPI_CRCCALCULATION_ENABLE                     SPI_CFG1_CRCEN
复制代码

$ ~, I* G& {7 l+ ?$ z# k0 g, ^5 X" i9 |  CRCPolynomial
# N. v& g. H4 e; F用于设置CRC计算使用的多项式,必须是奇数,范围0到65535。3 _+ o  {) d6 N! h1 x( {
- w2 o' f7 Q; v. T: T3 q$ Z, s
  CRCLength) _# L6 E$ x* ]. f4 w
用于设置CRC计算时的CRC长度。大小要与同属此结构体的DataSize一致。或是DataSize的整数倍。6 Y) R! Q; P, L4 t2 F6 M
# m  G4 P- R9 F% f( Y9 j3 _5 H
  1. #define SPI_CRC_LENGTH_DATASIZE                       (0x00000000UL); l2 F9 J6 _  U. |1 Z' c6 ~% m
  2. #define SPI_CRC_LENGTH_4BIT                           (0x00030000UL)/ T2 _* G, s* n/ k. P
  3. #define SPI_CRC_LENGTH_5BIT                           (0x00040000UL)
    1 k4 K3 f+ w1 P3 g$ k2 v
  4. #define SPI_CRC_LENGTH_6BIT                           (0x00050000UL)
    . U, |7 r( y! |4 p! z! W( _
  5. #define SPI_CRC_LENGTH_7BIT                           (0x00060000UL)
    7 D$ y( C& V9 @; U' {
  6. #define SPI_CRC_LENGTH_8BIT                           (0x00070000UL)
    $ G0 o, S7 M3 Y# G1 j" d
  7. #define SPI_CRC_LENGTH_9BIT                           (0x00080000UL): C$ z# G  _0 e  R
  8. #define SPI_CRC_LENGTH_10BIT                          (0x00090000UL): J" \. _3 d/ I6 }7 ?3 E5 n) M
  9. #define SPI_CRC_LENGTH_11BIT                          (0x000A0000UL)' f' B$ O3 c4 |# i% f% e
  10. #define SPI_CRC_LENGTH_12BIT                          (0x000B0000UL)4 ]( g$ W1 u$ P* B* w# ?% Q- K4 v- x$ A6 G
  11. #define SPI_CRC_LENGTH_13BIT                          (0x000C0000UL)
    ; @1 p4 _  Y0 i5 s0 Q1 H2 }$ j
  12. #define SPI_CRC_LENGTH_14BIT                          (0x000D0000UL)
    3 R; `% V4 ^/ I( @8 k! y
  13. #define SPI_CRC_LENGTH_15BIT                          (0x000E0000UL)7 {1 s! W. z0 v+ t. k/ J
  14. #define SPI_CRC_LENGTH_16BIT                          (0x000F0000UL)4 n% v: W# {8 l# c- A3 P
  15. #define SPI_CRC_LENGTH_17BIT                          (0x00100000UL), g0 J* G6 b, [, N
  16. #define SPI_CRC_LENGTH_18BIT                          (0x00110000UL)( q% O8 A5 t" i' j! t
  17. #define SPI_CRC_LENGTH_19BIT                          (0x00120000UL)
    " Q* e, x. Z! `  m
  18. #define SPI_CRC_LENGTH_20BIT                          (0x00130000UL)/ t5 ~, T2 g) z' c. P
  19. #define SPI_CRC_LENGTH_21BIT                          (0x00140000UL)
    % d$ B! |7 ~% G5 h9 d6 J; j4 u
  20. #define SPI_CRC_LENGTH_22BIT                          (0x00150000UL)
    / F1 r6 C: B) E* g5 v1 T$ D8 x
  21. #define SPI_CRC_LENGTH_23BIT                          (0x00160000UL)
    . v& w" N0 r" v$ Y
  22. #define SPI_CRC_LENGTH_24BIT                          (0x00170000UL)+ f* c, D( `2 V* x0 x5 j4 V
  23. #define SPI_CRC_LENGTH_25BIT                          (0x00180000UL)9 c8 c, }0 Q7 ]0 L( d
  24. #define SPI_CRC_LENGTH_26BIT                          (0x00190000UL)
    ; O) ^$ f" n% ?' y: i8 O: n; k
  25. #define SPI_CRC_LENGTH_27BIT                          (0x001A0000UL)
    + J; p1 x* i" H" w, Z
  26. #define SPI_CRC_LENGTH_28BIT                          (0x001B0000UL)! ?( r5 f5 z$ e
  27. #define SPI_CRC_LENGTH_29BIT                          (0x001C0000UL)
    / L0 i! Q* Z# G
  28. #define SPI_CRC_LENGTH_30BIT                          (0x001D0000UL)9 M8 V% s, d! b2 p5 R# w/ u0 w: B
  29. #define SPI_CRC_LENGTH_31BIT                          (0x001E0000UL); M  i' G# Y: B$ K% M" Q
  30. #define SPI_CRC_LENGTH_32BIT                          (0x001F0000UL); o3 e% |( d: x2 ~% v3 }8 g( {, z- j
复制代码

6 Q, h/ e& B- k/ e  NSSPMode) f  I1 H0 N4 X
用于设置是否使能NSSP信号,可以通过SPIx_CR2寄存器的SSOM位使能。注意,只有配置为摩托罗拉SPI主控模式时设置此成员才有用。
- z1 b$ _+ x1 s9 f- ?
  1. #define SPI_NSS_PULSE_DISABLE                         (0x00000000UL): W) f4 {; S4 I; R- ^
  2. #define SPI_NSS_PULSE_ENABLE                          SPI_CFG2_SSOM
复制代码
) n* \7 F: O) W: j( i( V  K7 g
  NSSPolarity' v3 |8 d$ y8 ]( f7 ~- G
用于设置NSS引脚上的高电平或者低电平作为激活电平。
* B4 f. H6 p( x7 V" c$ w
" x: y- i4 [' K  S' S6 Z4 V
  1. #define SPI_NSS_POLARITY_LOW                          (0x00000000UL)
    0 Q) o! d0 s$ q. J! @; o
  2. #define SPI_NSS_POLARITY_HIGH                          SPI_CFG2_SSIOP
复制代码

# [$ h8 {8 C4 p  FifoThreshold+ e+ z: g" u( N
用于设置SPI的FIFO阀值。
2 B& C; ^5 D9 x# f4 t6 g! O
' f) k0 O# B$ r8 Q) A  W
  1. #define SPI_FIFO_THRESHOLD_01DATA                     (0x00000000UL)
    ) w/ V. W* P& v+ y
  2. #define SPI_FIFO_THRESHOLD_02DATA                     (0x00000020UL)# X) w4 |0 s8 |( O8 M5 U
  3. #define SPI_FIFO_THRESHOLD_03DATA                     (0x00000040UL)% K( W3 p& p0 e( d& r: h7 u6 T
  4. #define SPI_FIFO_THRESHOLD_04DATA                     (0x00000060UL)
    # ]: x8 u9 f+ a) C  T5 G. p
  5. #define SPI_FIFO_THRESHOLD_05DATA                     (0x00000080UL)) C5 }2 k; K' l1 A: l8 I
  6. #define SPI_FIFO_THRESHOLD_06DATA                     (0x000000A0UL)4 p5 d" ~5 P2 S3 x
  7. #define SPI_FIFO_THRESHOLD_07DATA                     (0x000000C0UL), p" G: r3 r: S1 T& u* Q  d6 S7 \
  8. #define SPI_FIFO_THRESHOLD_08DATA                     (0x000000E0UL)8 Y) x6 p: d: P7 g0 W$ ^
  9. #define SPI_FIFO_THRESHOLD_09DATA                     (0x00000100UL)1 ^5 w9 Y  q: R3 t. }# K8 X
  10. #define SPI_FIFO_THRESHOLD_10DATA                     (0x00000120UL)' Q: @* X- Z+ i$ r
  11. #define SPI_FIFO_THRESHOLD_11DATA                     (0x00000140UL)* i1 U4 J- t0 F/ l+ i+ q
  12. #define SPI_FIFO_THRESHOLD_12DATA                     (0x00000160UL)
    / m; u" k- {6 D& d" v: o# W
  13. #define SPI_FIFO_THRESHOLD_13DATA                     (0x00000180UL); t  J. n; M$ g
  14. #define SPI_FIFO_THRESHOLD_14DATA                     (0x000001A0UL)
    - l" u1 ?, [1 P* U
  15. #define SPI_FIFO_THRESHOLD_15DATA                     (0x000001C0UL)$ D* m3 r9 W# X/ Z  F$ I9 e  U
  16. #define SPI_FIFO_THRESHOLD_16DATA                     (0x000001E0UL)
复制代码

( D' r1 L5 l$ k2 R* s  TxCRCInitializationPattern) s( z2 Z% p8 x- S- g2 Q- M
发送CRC初始化模式。
( b/ z$ @! ]( E0 ]- B9 ^& h2 d1 d+ l
" |0 G) ]4 o5 s4 L; m4 ]7 {8 T
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    . A( {/ M) ~" j8 C
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码
5 T! m/ s2 Z: v, Z, r
  RxCRCInitializationPattern. o$ t3 ]2 E, ]) ]
接收CRC初始化模式
) A. H, r& U: t4 e- V
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    3 E! W& L2 ~) e$ V" x% [1 k1 a: Y
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码

+ t" y. H7 k8 m4 V. \6 B7 w6 P$ H MasterSSIdleness: K2 ^# h9 N( d# N& e0 S
在主模式下插入到SS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数。$ p+ `3 ~' G% a9 q
2 a  t' Z6 X; G; r+ ?3 K
  1. #define SPI_MASTER_SS_IDLENESS_00CYCLE                (0x00000000UL)
    * [% a6 d; m+ j7 v7 K; A$ T
  2. #define SPI_MASTER_SS_IDLENESS_01CYCLE                (0x00000001UL)( f5 X* I% i( r, P6 t9 ~
  3. #define SPI_MASTER_SS_IDLENESS_02CYCLE                (0x00000002UL)
    7 y6 }3 C2 y6 ?! T% a$ P# Y
  4. #define SPI_MASTER_SS_IDLENESS_03CYCLE                (0x00000003UL)
    : V0 m; `1 v% A0 _% s- d
  5. #define SPI_MASTER_SS_IDLENESS_04CYCLE                (0x00000004UL)3 i0 b, `' Q, U. G% \8 u5 l) F
  6. #define SPI_MASTER_SS_IDLENESS_05CYCLE                (0x00000005UL)
    . S2 s& K$ _9 x$ Z) n) y
  7. #define SPI_MASTER_SS_IDLENESS_06CYCLE                (0x00000006UL)/ ?2 J. T: |* s# D9 ~6 Y( F
  8. #define SPI_MASTER_SS_IDLENESS_07CYCLE                (0x00000007UL)
      h( u5 @0 E) A0 D3 b  C' S
  9. #define SPI_MASTER_SS_IDLENESS_08CYCLE                (0x00000008UL)9 Z6 K& q" o3 O/ ?$ @% o- [. |. R
  10. #define SPI_MASTER_SS_IDLENESS_09CYCLE                (0x00000009UL)! f+ T8 R+ I4 f+ j
  11. #define SPI_MASTER_SS_IDLENESS_10CYCLE                (0x0000000AUL)
    ' p% ^: g* ?8 u7 u& R
  12. #define SPI_MASTER_SS_IDLENESS_11CYCLE                (0x0000000BUL), ^5 M+ R4 B( ?: d* V
  13. #define SPI_MASTER_SS_IDLENESS_12CYCLE                (0x0000000CUL)
    + |3 ^5 ~/ C: d+ d" H3 d( Y
  14. #define SPI_MASTER_SS_IDLENESS_13CYCLE                (0x0000000DUL)& I. s" C* R& Q3 u7 V- p
  15. #define SPI_MASTER_SS_IDLENESS_14CYCLE                (0x0000000EUL)
      q1 V0 _$ R; Z* \* e
  16. #define SPI_MASTER_SS_IDLENESS_15CYCLE                (0x0000000FUL)2 G# I7 I& [  j  f% E: R
复制代码
4 R$ b' r8 B& l: l0 R2 b( N! S4 }) u
  MasterInterDataIdleness. ^% }+ L- }4 q2 `( w: L
主模式下在两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数。1 e$ F/ _1 o0 W% e$ @7 M

5 M9 E# F7 m. i3 S
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)
    7 Y/ ?# O" |7 z, `) x  ?! ?5 v2 Y4 T
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
复制代码

0 t% O. c% S4 f& H8 E  MasterReceiverAutoSusp) }( ^  i: x1 X% D. \
用于控制主器件接收器模式下的连续 SPI 传输以及自动管理,以避免出现上溢情况。% d0 J2 e0 o- E# Q$ h) [2 k

. A& I* F( ?! `6 I
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)- m3 w6 t+ H8 V% y, x5 I$ R
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
    1 [! u6 V$ p( ~
复制代码
1 U' k- m5 F+ S; L: ~
  MasterKeepIOState
7 T" s0 r8 G3 F7 p0 e  [禁止SPI后,SPI相关引脚保持当前状态,以防止出现毛刺。在从模式下,该位不应该使用。
5 @6 ~) m5 z! F
  1. #define SPI_MASTER_KEEP_IO_STATE_DISABLE              (0x00000000UL)2 ~0 `$ U# S* _0 k
  2. #define SPI_MASTER_KEEP_IO_STATE_ENABLE               SPI_CFG2_AFCNTR
复制代码

- E2 s: j( u. F: V* k: c, \, Q  m  IOSwap
. s+ N1 x. y/ B0 x" ^( q4 W用于交换MISO和MOSI引脚。
3 P! V! F3 B& q- Q2 R' |
! x& `! u) G8 O. O
  1. #define SPI_IO_SWAP_DISABLE                           (0x00000000UL)
    % a+ Z5 z6 J) w& a- O6 |
  2. #define SPI_IO_SWAP_ENABLE                            SPI_CFG2_IOSWP
复制代码

7 K' o# T/ m* q72.3.3 SPI总线句柄结构体SPI_HandleTypeDef
' w& `  W$ V& y" t, }
下面是SPI总线的初始化结构体,用到的地方比较多:
0 A' \0 o( w, r7 i' m/ r. _; u0 ~: E& `) ~7 a! E
  1. typedef struct __SPI_HandleTypeDef2 F& v; h  o- ]" i
  2. {
    " l$ _8 y: F8 T" s9 [
  3.   SPI_TypeDef                *Instance;                 " V1 [2 R3 r. n9 ?/ P' e4 a. G
  4.   SPI_InitTypeDef            Init;                        * V- B% i6 H  O
  5.   uint8_t                    *pTxBuffPtr;                 
    6 Z4 c* V9 Z  [+ |4 w) W# T
  6.   uint16_t                   TxXferSize;                  
    ) o. a, u3 H# @6 C+ G5 e) T  @3 f) A  \
  7.   __IO uint16_t              TxXferCount;                  
    6 g: r6 y3 d2 |+ b1 y' D' H
  8.   uint8_t                    *pRxBuffPtr;                " E9 [7 D5 H; l7 J% `% ~! o; f- i  C
  9.   uint16_t                   RxXferSize;                  
    5 x* |" }3 L' B3 C* g1 T
  10.   __IO uint16_t              RxXferCount;                 % C, k$ g( @6 T/ n, n
  11.   uint32_t                   CRCSize;                     7 n) j6 v# H6 u  I0 c
  12.   void (*RxISR)(struct __SPI_HandleTypeDef *hspi);      
    % |2 w. I9 B( w
  13.   void (*TxISR)(struct __SPI_HandleTypeDef *hspi);        
    2 l0 |) @9 M1 z7 a5 S& ^
  14.   DMA_HandleTypeDef          *hdmatx;                        T& C2 z  M: ]1 [( ]8 D
  15.   DMA_HandleTypeDef          *hdmarx;                     
    5 @1 w" P5 W9 d. y5 Q8 d6 K4 Z
  16.   HAL_LockTypeDef            Lock;                        * }$ m7 [$ u( ~+ ]
  17.   __IO HAL_SPI_StateTypeDef  State;                        
    : F- U8 K6 X0 `
  18.   __IO uint32_t              ErrorCode;                  
    2 q) F# x- ?) L4 z6 P
  19. #if defined(USE_SPI_RELOAD_TRANSFER)
    , R1 h- h4 L0 `
  20.   SPI_ReloadTypeDef          Reload;                     
    * b+ g/ j* Z- k( b
  21. #endif 8 l, K) \* k* D% Q' a" x
  22. # ?- `0 y3 g; T( r' Q  P" G( q
  23. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    7 s* t. r* _4 R1 j& j
  24.   void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      : Z/ ~' }0 W2 S1 I
  25.   void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      % f  H3 |" x9 i* Y
  26.   void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    7 n* a" l0 F- @! w. P& S' X
  27.   void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  
    " E9 A! Z1 C- _1 I- {3 W
  28.   void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  0 g5 Q- o1 x. ]( s% }' x
  29.   void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi); & y' M/ [3 O) \
  30.   void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi);      
    - e$ x* j1 Q! b+ K9 w, s
  31.   void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    2 _. E; k) s4 X% [, [9 I
  32.   void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi);    % e4 K/ d7 z3 I8 t. |  G1 G
  33.   void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi); . X/ z( P$ e9 e* V! H  [. _1 w. s
  34. #endif  3 m! J2 h7 O; X' t0 Q
  35. } SPI_HandleTypeDef;  j. w0 o- B. c3 o2 }- G- E4 H
复制代码
2 m4 ?, k# u. P6 M6 I- r. V
注意事项:) k! N, C3 ?6 @1 t8 u
" y+ r7 y8 ^& _/ @! W) V+ o5 n) k
条件编译USE_HAL_SPI_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:  r% r& w) f6 M! X
  E& g+ w4 A' p) }6 B
  #define   USE_HAL_SPI_REGISTER_CALLBACKS   1
7 y$ l$ t" H5 |# J
, q# @# q' G- k& M/ w通过函数HAL_SPI_RegisterCallback注册回调,取消注册使用函数HAL_SPI_UnRegisterCallback。
+ f7 Z" G, q( n+ w4 I3 f
9 T% {/ N2 Z1 A8 u- s; S" R这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。
; {  R0 p- ^: p2 Y: h3 V* h
) G8 W. L: m7 {0 ]$ p" R3 Z8 w9 a5 q  SPI_TypeDef   *Instance1 q6 F5 c$ O' e0 a& F: U
这个参数是寄存器的例化,方便操作寄存器,比如使能SPI1。2 Y) J  w9 O  p0 D7 T% I
# R: v; {3 Z4 {6 Y1 o
SET_BIT(SPI1 ->CR1,  SPI_CR1_SPE)。
; T8 E1 B' b0 y7 N! x7 [1 N& b9 D+ U$ [$ V# x1 Y) h2 T/ ^
  SPI_InitTypeDef  Init3 f+ [( I1 `  ?$ l
这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。9 T$ J/ `- Z7 p# O

9 ^- R# N& B! A2 U& B7 i& P# x  DMA_HandleTypeDef          *hdmatx               ; Q6 O. l0 G( w! f, M# K# a2 ^
  DMA_HandleTypeDef          *hdmarx; c, B3 _. \. ~) _
用于SPI句柄关联DMA句柄,方便操作调用。
& K( `! x( ~5 l+ T: D( A) W6 a* z3 c1 W2 ~1 |0 _  s1 e+ {
72.4 SPI总线源文件stm32h7xx_hal_spi.c
% {1 d/ L& _4 Z+ M' T0 y此文件涉及到的函数较多,这里把几个常用的函数做个说明:
' e& E! f- l! s$ O  B7 R; ?6 P# d8 O9 f
  HAL_SPI_Init: {7 o6 b& W  z
  HAL_SPI_DeInit- G) p" b' X6 R' L1 X
  HAL_SPI_TransmitReceive
% v, }# _/ l/ A2 w& Y  HAL_SPI_TransmitReceive_IT
" W1 d" C5 U. d% E) P  @* c' K  HAL_SPI_TransmitReceive_DMA- {9 n- U. d! [, `

0 c7 k; g5 ?8 S72.4.1 函数HAL_SPI_Init; d, u8 V1 Q9 R- p! C" U
函数原型:9 ]1 ^, z: `# ]: M8 A) M

0 W- M2 I5 W8 u/ m+ g! x
  1. HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)
    7 n2 j* e; S$ W- Z2 [8 c1 R7 A% s, w
  2. {5 M* a5 `; X. K5 C$ F3 c4 d$ T
  3.   uint32_t crc_length = 0UL;6 |4 a1 ^& x7 S, Z0 r/ O5 q# ?
  4.   uint32_t packet_length;$ W/ _, u4 w4 z0 W; m4 p, E
  5. , N. B. o: L; t
  6.   /* 省略未写 */
    $ n2 O  n$ n' ^0 e! k* h

  7. # L$ G* q) ~% b8 x# y
  8.   /* 如果数据位宽大于16bit,必须是SPI1,SPI2或者SPI3,而SPI4,SPI5和SPI6不支持大于16bit */
    % ]+ J9 s9 j- k$ D+ s
  9.   if ((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (hspi->Init.DataSize > SPI_DATASIZE_16BIT))* Q9 M6 g. u: g
  10.   {* R" n$ o4 j# J. g
  11.     return HAL_ERROR;9 f# ^5 t+ k: C
  12.   }4 `, V$ j1 v6 @* c# c4 Q; ^- Y
  13. + g0 b" Z8 O6 g% p9 q) T
  14.   /* SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit: ]8 ]: B5 d1 o/ q" E8 P# h+ x/ R
  15.      这里是查看设置的缓冲大小是否超出了FIFO支持的大小。
    4 `9 |# J  ^, L% X5 y; R
  16. */
    0 X9 I0 k# b/ E& }' L& |$ U' v$ b
  17.   packet_length = SPI_GetPacketSize(hspi);5 t$ j: p$ m  U8 _2 D
  18.   if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_LOWEND_FIFO_SIZE)) ||
    ( M" S6 Y3 ^8 L4 T3 V
  19.       ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_HIGHEND_FIFO_SIZE)))
    1 ]6 V6 Q* d% d! |: C
  20.   {0 f9 q7 q& ^8 l+ U
  21.     return HAL_ERROR;
    6 ]1 a7 J& S$ I8 }- ]8 y* _7 I
  22.   }) X/ [  _% C: M3 m
  23. 2 U0 S, S5 N% ?! \: l7 ?; A2 `% h
  24. #if (USE_SPI_CRC != 0UL)
    ) n7 W9 ^% ^, ]4 ~
  25.     /* 省略未写 */
    9 n. V3 r+ b: g, q
  26. #endif ) @# r/ ?5 q  x2 x; y
  27. 9 N0 T! {# r4 ]7 G' f
  28.   if (hspi->State == HAL_SPI_STATE_RESET)2 l; K: W( _2 P2 h6 c  G" ^# X; U
  29.   {
    + R9 P4 v$ t! O# U8 A, w
  30.     /* 解锁 */
    * M- B; w# J8 t
  31.     hspi->Lock = HAL_UNLOCKED;3 o5 b2 J, J/ |& o

  32. . |* s* x: a" s; I. K& ]
  33.     /* 使用自定义回调 */5 ^- p) s. E# K6 Y! f; o) G' N
  34. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)' A7 b) ]6 u6 D" C8 S" x
  35.     /* 设置默认回调函数 */) Y- j+ d+ c8 z. x4 w. e. L4 F4 N# |
  36.     hspi->TxCpltCallback       = HAL_SPI_TxCpltCallback;       /* Legacy weak TxCpltCallback       */
    2 g2 v( `+ E9 D. ]
  37.     hspi->RxCpltCallback       = HAL_SPI_RxCpltCallback;       /* Legacy weak RxCpltCallback       */! i1 q9 z/ I6 x5 v& I2 M4 O- `; @& \
  38.     hspi->TxRxCpltCallback     = HAL_SPI_TxRxCpltCallback;     /* Legacy weak TxRxCpltCallback     */
    ! g+ D% q' O: A( E
  39.     hspi->TxHalfCpltCallback   = HAL_SPI_TxHalfCpltCallback;   /* Legacy weak TxHalfCpltCallback   */% Z# r5 B2 Y$ D( X8 y
  40.     hspi->RxHalfCpltCallback   = HAL_SPI_RxHalfCpltCallback;   /* Legacy weak RxHalfCpltCallback   */2 {# u$ q3 N0 e# H$ k
  41.     hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */+ w# x" X, ~& l# g- N
  42.     hspi->ErrorCallback        = HAL_SPI_ErrorCallback;        /* Legacy weak ErrorCallback        */( p# ?; ~; R; T5 s. q
  43.     hspi->AbortCpltCallback    = HAL_SPI_AbortCpltCallback;    /* Legacy weak AbortCpltCallback    */3 s# `2 S/ `0 X4 U& \

  44. & L1 n$ C* Q4 x8 ]
  45.     if (hspi->MspInitCallback == NULL)
      r4 c2 ~" z% r) j  ?  y
  46.     {
    / E6 h, `  d8 H; k7 t) @
  47.       hspi->MspInitCallback = HAL_SPI_MspInit;
    - Z- P  j  @, ]) V4 ~
  48.     }+ _' A1 ~: B/ R% U  x

  49. % h0 ?* I! R9 k; e8 ~/ q4 K/ e
  50.     /* 初始化地址硬件: GPIO, CLOCK, NVIC... */; U4 M  D: x! Q- ?3 n2 d
  51.     hspi->MspInitCallback(hspi);% x0 O) q2 Z. q  V: [& c& z
  52. #else
      Y0 X8 w9 A& ~- Y
  53.     /* 初始化底层硬件: GPIO, CLOCK, NVIC... */# u  H+ I3 M9 T
  54.     HAL_SPI_MspInit(hspi);. G6 |( Q3 E; `- m+ @6 q% l
  55. #endif4 _; J+ k; C6 m  e0 x8 f$ Y
  56.   }
    # ]% E, f$ g% z7 i; A* c
  57. ) _8 m# u( H6 g0 |
  58.   hspi->State = HAL_SPI_STATE_BUSY;
    ! }5 U7 u; E* O+ g7 f

  59. 7 i, X( D1 E4 r" g) B9 X8 K
  60.   /* 禁止SPI外设 */" B) T6 e5 R1 O3 V/ a: b
  61.   __HAL_SPI_DISABLE(hspi);
    4 g2 v: y1 w# E

  62. ( \0 v+ ^% D) {- W& |
  63.   /*----------------------- SPIx CR1 & CR2 配置---------------------*/
    . d% q: H& Z* Y7 {
  64.   if ((hspi->Init.NSS == SPI_NSS_SOFT) && (hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.NSSPolarity ==
    / O1 ~; y  {) V' e) i/ Y1 w
  65. SPI_NSS_POLARITY_LOW))# p1 b. c# {% h0 X4 m8 d& d6 I
  66.   {2 I) ^& h& Q- E# i
  67.       SET_BIT(hspi->Instance->CR1, SPI_CR1_SSI);
    8 I3 U* P8 P' z+ S3 A; g* w
  68.   }' ^, A8 c1 \* j: Y) N. E0 D$ I
  69. + p; n# g+ x" |
  70.   /* SPIx CFG1配置 */( `$ K3 w7 s6 z% `3 Z' M9 E2 [" P
  71.   WRITE_REG(hspi->Instance->CFG1, (hspi->Init.BaudRatePrescaler | hspi->Init.CRCCalculation | crc_length |
    + O3 h( |" q( q# d( O( a
  72.                                    hspi->Init.FifoThreshold     | hspi->Init.DataSize));: K$ C( ?* ]2 w3 @+ j8 b6 K( s
  73. 3 F. x+ U- M  I/ N! E  L5 [" l
  74.   /* SPIx CFG2配置 */
    , h9 n8 H8 L* b! {. v- w' F9 n
  75.   WRITE_REG(hspi->Instance->CFG2, (hspi->Init.NSSPMode     | hspi->Init.TIMode           | hspi->Init.NSSPolarity  |: Q5 p$ t) U4 {. |
  76.                                    hspi->Init.NSS          | hspi->Init.CLKPolarity      | hspi->Init.CLKPhase     |
    $ f0 X0 \$ p# L3 ~, {8 i% c) X
  77.                                    hspi->Init.FirstBit     | hspi->Init.Mode             | hspi->Init.MasterInterDataIdleness |8 d: e1 O% d, T, L! G% i, M3 U8 U8 `6 O
  78.                                    hspi->Init.Direction    | hspi->Init.MasterSSIdleness | hspi->Init.IOSwap));
    3 s5 u; l5 h4 i3 i  u" q  t  w

  79. 0 E# J7 ?( X' o" T
  80. #if (USE_SPI_CRC != 0UL)
    5 V+ P2 g" n1 [7 N5 N5 A1 b
  81.   /*---------------------------- SPIx CRC配置 ------------------*/, s  L8 I5 Y) j1 r/ `( e; Z: V/ l
  82.   /* 配置SPI CRC */
    , e) q( |" v/ J
  83.   if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
    % ^  c# A5 e' k1 G/ R
  84.   {
    * |* t: e0 s" n/ n* }9 B& n
  85.     /* 初始化TX CRC初始值 */
    ' ?, W) C8 g" s# j
  86.     if (hspi->Init.TxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)
    + Q% d* o1 D; u$ C
  87.     {
    8 {, ^, q9 }" G/ u
  88.       SET_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);/ i" F/ m# L1 |$ `- B; b
  89.     }
      N9 i2 g0 X7 c/ T/ y  R1 h
  90.     else
    ! j" y, H1 N- r# H( _6 g
  91.     {
    1 i# J7 n6 g7 i/ K# i1 ^+ z9 b# T" \9 H
  92.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);  Z) d  q$ C, h: e3 d9 `
  93.     }8 C" w) W3 l  `, W2 x; g

  94. ( o7 o0 |( e$ _+ G) c$ w1 B
  95.     /* 初始化RXCRC初始值 */
    6 S3 \# F4 A" I! x+ f' V, F
  96.     if (hspi->Init.RxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)
    6 i& z$ w* G' [4 b
  97.     {: l% z4 S6 b$ z0 b
  98.       SET_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);
    , ]; W- d: G* h* `
  99.     }
    ( F  n4 j" `; Y  j6 s4 G7 L
  100.     else
    " u# N: Q# Y9 ^0 o
  101.     {: Q, z5 L8 ^; {1 y
  102.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);* H( m" @4 ^. [8 A
  103.     }2 q# m8 _  h. C  E; j! J" `& G1 n

  104. / q. w+ L+ k5 m
  105.     /* 使能 33/17 bit CRC计算 */+ s6 a: {5 ~* t$ b) d5 ?
  106.     if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (crc_length == SPI_CRC_LENGTH_16BIT)) ||
    " o( P, K" H  A0 F4 Y1 x
  107.         ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance))  && (crc_length == SPI_CRC_LENGTH_32BIT)))
    + X- P* ~$ t8 u" ^& Y
  108.     {
    7 U5 Z5 C+ p: m) `% y) F
  109.       SET_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);
    * @( I1 Z4 ~, n4 i" k
  110.     }
    ) U0 @  V) M* H1 h# C  F9 g
  111.     else
    " c5 d7 d( j2 E5 J5 s
  112.     {
    1 M4 x4 R- B& G0 e* ~1 D6 ]6 a
  113.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);
    ' k4 Y" S/ H) ~$ o, Q7 N$ X
  114.     }9 e* @4 ]8 r( a3 {: p! X2 k

  115.   d6 B/ ~. K3 Z% W7 z4 I7 w5 b. n
  116.     /* 写CRC多项式到SPI寄存器 */
    8 q4 E) U0 J) u$ G  `' s' }! g
  117.     WRITE_REG(hspi->Instance->CRCPOLY, hspi->Init.CRCPolynomial);' F3 F' p# A2 D  E6 J; }
  118.   }" A9 A/ J% p- `3 Z
  119. #endif ( T1 V. w) O/ d& y2 u3 G( y/ S5 g( \' \

  120. , B. n% Z5 r. _% q( p( Y
  121.   /* SPI从模式,下溢配置 */
    9 `# s3 A7 h) u
  122.   if (hspi->Init.Mode == SPI_MODE_SLAVE)
    8 D% m: I: T/ I; L9 Z7 Y2 S( L1 L
  123.   {
    : ^# F" `- Z9 ]0 @# X
  124.     /* 设置默认下溢配置 */
    ( @3 W+ l6 j, q7 A! k, G: a" k
  125. #if (USE_SPI_CRC != 0UL). }# C& A; X9 e+ F1 Y3 ~! e
  126.     if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_DISABLE)
    & I( R5 K* A- k) |. W1 N. b
  127. #endif
    $ y3 g" E9 c- z$ l
  128.     {1 I; M% {9 e) n. q
  129.       MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRDET, SPI_CFG1_UDRDET_0);4 s4 O' U  T( d1 @) K# l
  130.     }9 }0 A3 C' R1 ?5 V/ ?* B  Q3 y3 o, j3 G
  131.     MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRCFG, SPI_CFG1_UDRCFG_1);
    - t& g& z* b! }% V
  132.   }1 {# k3 _% U# n! H9 ^/ X6 _) i2 |

  133. ( B" b# w, @$ B* {( e
  134. #if defined(SPI_I2SCFGR_I2SMOD)% @2 w% ?% M6 T! y2 b
  135.   CLEAR_BIT(hspi->Instance->I2SCFGR, SPI_I2SCFGR_I2SMOD);3 {6 }/ {3 d' f; ^
  136. #endif
    $ w7 }! }9 o. t/ x' A
  137. 6 t3 x0 }: t6 l
  138.   /* 确保AFCNTR bit由SPI主机模式管理 */
    7 w% j  Y4 T/ V: r
  139.   if ((hspi->Init.Mode & SPI_MODE_MASTER) == SPI_MODE_MASTER)
    3 i" `/ F6 h2 m- ?; {+ \+ l
  140.   {
    7 V) ~! Y8 f& P( R# @
  141.     /* Alternate function GPIOs control */% ]( F# V: m" ^$ R7 E
  142.     MODIFY_REG(hspi->Instance->CFG2, SPI_CFG2_AFCNTR, (hspi->Init.MasterKeepIOState));
    1 w& O+ R) U) v8 z  @
  143.   }$ q7 Q7 m+ B7 K6 h

  144. , B' m  F; W( {  I" R
  145.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;; M1 O6 d" F3 O. @2 D6 H+ Z) _
  146.   hspi->State     = HAL_SPI_STATE_READY;6 Y9 j: G5 `# z, ?/ N1 _

  147. 6 U  n! i1 v/ [$ O0 R
  148.   return HAL_OK;
    " Z( \; O/ I! ^; ]! Z1 ]9 Y0 j% h
  149. }
    7 e* B) \. F3 [4 C: E
复制代码
! x  o' V9 ~3 [$ r

1 n# ^$ n& E" t函数描述:; K6 Z9 l$ q+ ~/ Q) ~
, B+ p) Y' ^. V- v& z: e
此函数用于初始化SPI。
* R6 e7 Q, \6 A8 \& P- S" u3 D0 c: h: J* S! }: ~: Q. P7 c
函数参数:. Q: ?$ H# c$ x% ^, t

7 H4 f6 G4 K. o  `5 [. {  第1个参数是SPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。3 u% ]. L1 x. C* g0 v
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
2 y8 a/ J( \* n& `" C
4 N6 Y% M3 u, o/ @
7 M# }7 P7 J/ L5 o9 e注意事项:2 ~2 v* G  J* {+ K2 u+ L: ]
函数HAL_SPI_MspInit用于初始化SPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。0 ]3 v" g! f, e# ~2 |2 S
如果形参hspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SPI_HandleTypeDef SpiHandle。
  H0 e" ^1 W8 {: P: V9 U对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SPI_STATE_RESET  = 0x00U。# {( e6 F( R1 C4 p- n: f. t

! \: c8 S3 O4 e; ?( K3 l解决办法有三& D/ p- L! w8 q  y

1 e- _" C' d% T( |- H: E方法1:用户自己初始化SPI和涉及到的GPIO等。8 f& w% [1 i, K" o0 l- F. w0 q1 J9 ~; r6 p3 T
9 ^$ o0 }  w$ O$ ]) r7 B# w  Z
方法2:定义SPI_HandleTypeDef SpiHandle为全局变量。% N' n8 E. k0 @: _; \- p4 J
: R2 R$ o( a% R( R
方法3:下面的方法
3 ^- [, H* q) X6 P8 ?1 T
& G& N7 N/ [4 z' O8 U) X
  1. if(HAL_SPI_DeInit(&SpiHandle) != HAL_OK)
    " C4 J. \# ]  r) k( m/ }$ P
  2. {1 K8 z0 `3 D& o$ c! X6 @
  3.     Error_Handler();
    " c& ~, C: ~; [! o
  4. }  
    ' R0 f) U7 q  J
  5. if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
    - K6 s: I1 a+ s* f3 g" @0 g. g
  6. {- ^2 z8 @; V* b
  7.     Error_Handler();( R4 _/ v* h- W, R2 }* N1 S1 q) q' y
  8. }
复制代码
" c. U& n( X7 q) y# X
使用举例:+ ]  ?7 e0 Y3 s& @6 D: k3 v. }
3 [: i( i0 T5 A" Q
  1. SPI_HandleTypeDef hspi = {0};) M* u5 `" K$ G4 C8 f

  2. 7 u4 Q) {6 }! N( B$ E" W
  3. /* 设置SPI参数 */$ E# Q3 b& f, F7 |4 g
  4. hspi.Instance               = SPIx;                   /* 例化SPI */8 _7 F  R5 R8 Q2 W
  5. hspi.Init.BaudRatePrescaler = _BaudRatePrescaler;     /* 设置波特率 */! [. x4 w; y- l! [9 V+ l# j
  6. hspi.Init.Direction         = SPI_DIRECTION_2LINES;   /* 全双工 */
    : m3 D5 D" s2 f
  7. hspi.Init.CLKPhase          = _CLKPhase;              /* 配置时钟相位 */
    6 Q3 d$ s2 J4 Q* h" H! z& w
  8. hspi.Init.CLKPolarity       = _CLKPolarity;           /* 配置时钟极性 */
    " i0 w& E6 D6 Z8 r
  9. hspi.Init.DataSize          = SPI_DATASIZE_8BIT;      /* 设置数据宽度 */
    1 }+ G" e: O  C/ l7 V
  10. hspi.Init.FirstBit          = SPI_FIRSTBIT_MSB;       /* 数据传输先传高位 */
    % J$ \6 l, c, K( ]' @, ~0 f
  11. hspi.Init.TIMode            = SPI_TIMODE_DISABLE;     /* 禁止TI模式  */
    ' I5 E! ?5 |, r  i( W' }% ^
  12. hspi.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;      /* 禁止CRC */
    " t2 m. D- g) g7 N& Q1 L) L
  13. hspi.Init.CRCPolynomial     = 7;                               /* 禁止CRC后,此位无效 */5 ^7 z4 O& c( a- v8 |
  14. hspi.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;             /* 禁止CRC后,此位无效 */2 r, R5 b9 E; C, ?
  15. hspi.Init.NSS               = SPI_NSS_SOFT;                    /* 使用软件方式管理片选引脚 */
    8 J: k9 q5 S! W: C( g. r
  16. hspi.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_01DATA;       /* 设置FIFO大小是一个数据项 */3 V% m& G0 P  J$ F/ Y
  17. hspi.Init.NSSPMode          = SPI_NSS_PULSE_DISABLE;           /* 禁止脉冲输出 */
    + X  ^" Z6 ]8 F9 `5 m$ J- e
  18. hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  
    8 W* `" l8 ^+ J% q: j# x" V1 D
  19. hspi.Init.Mode                  = SPI_MODE_MASTER;            /* SPI工作在主控模式 */' v  g' b- @: _
  20. 7 V! G/ O- n( @, c0 q7 L
  21. if (HAL_SPI_Init(&hspi) != HAL_OK)3 Q" v) ]4 P9 l8 |
  22. {& ]3 k4 M- l: }' J5 S: |0 Q
  23.     Error_Handler(__FILE__, __LINE__);
    1 `/ \6 e: T# ?4 G4 c
  24. }
复制代码

' _. J1 P- d4 {5 X; O1 ?- b72.4.2 函数HAL_SPI_DeInit
9 L  o# g7 S4 |  S函数原型:( f$ P3 N7 K1 W/ a3 y
  1. HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)# V$ S% n1 o6 K2 V& {+ N
  2. {* ]  ]' `, A& L
  3. /* 检测SPI句柄是否有效 */
    , h: _2 x' g5 Y
  4.   if (hspi == NULL)
    ; m& |+ r$ K, _; |3 E) j, V( m
  5.   {- G' W: b$ N. y+ O
  6.     return HAL_ERROR;8 B$ Y& I2 g6 _. {
  7.   }4 A  N' K& D0 k

  8. 4 a. b5 [6 z) z- x: V
  9. /* 检查SPI例化参数 */
    - \+ v# i$ @' S" D( v* m+ a( ]" j9 l
  10.   assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));4 V6 u2 v2 P; w- z

  11. ! p! N5 K% s) D$ d6 S1 T6 a4 j
  12.   hspi->State = HAL_SPI_STATE_BUSY;) \% {) x4 D, ]- |) G
  13. ) K. w$ x& s. e9 r1 e
  14.   /* 禁止SPI外设时钟 */
    5 I. d5 I8 E- N0 w1 g
  15.   __HAL_SPI_DISABLE(hspi);+ ^2 x  G- q" @' }1 n8 _# f- w; G. Z
  16. ) v8 j  P* E! Q/ P/ V6 q! o
  17. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)6 k2 \' i4 F" b4 g; C
  18.   if (hspi->MspDeInitCallback == NULL)
    % O6 y) |& i5 L% v
  19.   {* R! N8 K5 h  W$ ^9 J6 C
  20.     hspi->MspDeInitCallback = HAL_SPI_MspDeInit;
    7 I0 U6 a) e3 d- n: [4 n' Y9 Y" J
  21.   }
    9 ]7 V: t$ g* S, Q

  22. 5 b4 r; w) h. B! G- I
  23.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */
    / g2 N7 a6 l0 D/ C" v& o
  24.   hspi->MspDeInitCallback(hspi);
    ) ]; Q. J9 W, G6 m7 G) w4 @
  25. #else
    : H( ?3 ~5 m- c$ i3 ?# O4 M- n
  26.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */
    3 m  J2 S7 w$ T2 S- ~
  27.   HAL_SPI_MspDeInit(hspi);+ J* Q- n1 E5 Z5 S+ R# V: v
  28. #endif
    ! V. y- S& Y. B  |8 \0 \

  29. ! c& f- O+ X8 c
  30.   /* 设置无错误,复位状态标记 *// M! H- n" G/ j
  31.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;
    ( [' X  R% K, D
  32.   hspi->State = HAL_SPI_STATE_RESET;/ g' h4 U5 h* }
  33. 2 A/ ]4 J2 O7 X- L$ k
  34.   /* 解锁SPI */4 ~+ T1 w' u6 z
  35.   __HAL_UNLOCK(hspi);. C* j* e4 h. A% i2 T

  36. 1 V1 p$ e$ |2 s. N/ j4 S  N
  37.   return HAL_OK;
    : q, |: S( Z) F7 C6 I1 _# ~& _
  38. }
复制代码
/ ]( N2 Z/ c8 i! l: w! U$ v  f
函数描述:
5 o4 |9 |2 J( J: ]  ~: W0 c2 f* c' {1 d
用于复位SPI总线初始化。
) R( F. T+ h, M8 [# T5 a
' d6 z9 _% v: e  k) H6 B2 K函数参数:  |  o! o/ o& n) d

7 Z9 c4 ]0 Y- F: i% W8 c  第1个参数是SPI_HandleTypeDef类型结构体指针变量。$ R/ W2 a1 G  l" E6 D6 W
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中
* X: `  p( o" \9 S0 h
' B4 d3 C+ C. N9 g1 [
# k! c1 `+ t) x& |5 {72.4.3 函数HAL_SPI_TransmitReceive
6 i  S! y7 A: T6 e! @7 g: ^4 k函数原型:) z$ ]/ D6 H( a& A7 `) {( h& X6 Q

5 b' T- l9 J# D+ y! d
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)  U: K& o5 _* l: n6 G. `2 ]
  2. {* {5 w/ \: R, Q# p' [2 x6 h* |

  3. 5 S- }1 [4 Q4 S% n9 |5 B
  4.    /* 省略未写 */2 Q9 N! Y6 v+ f- f  U3 V  w+ n

  5. " ]' ^. }. }, D0 M) o
  6.   /* 大于16bit的数据收发 */0 g2 k! \/ J/ D2 z
  7.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)2 z+ v* S' v! B7 k+ O
  8.   {
    3 U2 e% r' g8 V2 d
  9.        /* 省略未写 */7 M2 H# S$ x. f! D
  10.   }
    ) u% a2 k; m1 B8 ~+ G7 T+ n
  11.   /* 大于8bit,小于16bi的数据收发 */
    8 Q# ]% |1 z' P  M9 d
  12.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
    7 H( q* P1 y7 X5 Q# ^8 u4 ]4 Q
  13.   {
    / {9 V) b1 Z! f8 v( T5 t: S
  14.       /* 省略未写 */( Z9 l# [' w0 Y6 `# |* \
  15.   }" r' F) V& k7 i/ U  P
  16.   /* 小于等于8bit的数据收发 */  f' t% w4 |  Z# O  [& E3 L0 O2 F
  17.   else5 f; ?  s4 ?" p9 U, o' ~
  18.   {8 }/ d0 d1 G$ E: j
  19.        /* 省略未写 */
    9 X: [$ F- c, K4 T" D" p$ L
  20.   }
    2 o: {4 o+ o4 r" b* v- ]  _% x
  21. 8 g. C/ f: {4 _* Z3 g
  22. }
复制代码
+ c4 [! U% H& l
函数描述:# E* f+ r' p/ T# ]6 k4 b
1 {) k' N% q9 Q+ V
此函数主要用于SPI数据收发,全双工查询方式。
" f/ `1 O$ P- O7 X4 _# F$ E4 v/ G, ~! g2 S
函数参数:
; f7 Y; L: }& o- C0 p8 ]4 B% G2 u; z0 N; M/ a7 ]2 H  u
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。& M7 W8 P  @6 f0 x' y$ `
  第2个参数是发送数据缓冲地址。
/ A! Z' L3 c9 |' s/ i" ]9 p  第3个参数是接收数据缓冲地址。+ K- ~% d4 n- h& o* F' A
  第4个参数是传输的数据大小,单位字节个数。, W9 U1 h) {# |6 N! q- M$ K* i# j
  第5个参数是传输过程的溢出时间,单位ms。; W5 E6 @  T/ L+ S7 o0 T
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。0 w8 y1 L' ?5 O3 P

$ [5 e" q8 C3 m# _! B+ r# G; I9 S! A: ~4 F1 m. {
使用举例:
' S8 ~' r$ G+ {& D) B) S* ^, e0 ^+ h0 d' l% Z" k& ^
  1. SPI_HandleTypeDef hspi = {0};8 k. a( D% Z8 ]) B0 J; d  y, C
  2. / M) s+ j' d& X; r
  3. if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)
    ' S) s  o1 U. r7 b
  4. {
    4 l8 y9 W" |5 E0 E' H
  5.     Error_Handler(__FILE__, __LINE__);7 W+ B$ s& g, \$ }& o# e; f
  6. }
复制代码

3 C2 p; \( `" e. P- c3 J/ E+ p, `  W/ Q72.4.4 函数HAL_SPI_TransmitReceive_IT

. ~8 m. E- c4 V- y3 Y  k. s函数原型:
6 e3 G) _: k0 l
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)6 j3 `2 z* F; Q5 h# }0 k
  2. {
    ) L2 V8 y5 ?4 v- g. [8 P
  3.    /* 省略未写 */
    1 J5 y* j: z1 u7 K  _2 ?* h
  4. ! t8 ^3 h1 F2 K2 @1 N
  5.   /* 设置传输参数 */
    5 ^0 Y6 g# t/ h0 C) e$ a
  6.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;3 L5 Q3 |# E1 x" `4 X, Y
  7.   hspi->pTxBuffPtr  = (uint8_t *)pTxData;  g; g6 q7 _- X2 p, U+ b3 B5 X
  8.   hspi->TxXferSize  = Size;
    ; c" b8 X1 e$ \( [% C
  9.   hspi->TxXferCount = Size;- ^& [/ E: H8 S# u9 f7 \& x
  10.   hspi->pRxBuffPtr  = (uint8_t *)pRxData;. p. ]& @4 Q! U  m8 a
  11.   hspi->RxXferSize  = Size;  z# J/ G1 a! h4 m/ T' t- F
  12.   hspi->RxXferCount = Size;
    % _4 S/ o4 q; \5 l" q

  13. 0 I8 b- q$ }) ?: l6 V
  14.   /* 设置中断处理 */: {# V& g$ z' M$ M5 ?
  15.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    * m% E2 e. |/ |/ D
  16.   {7 \$ X8 ?- W. v8 i3 \) X8 [0 A/ r
  17.     hspi->TxISR     = SPI_TxISR_32BIT;
    2 ?4 L- M! G, x6 y1 o: r# h
  18.     hspi->RxISR     = SPI_RxISR_32BIT;6 ~2 K2 U7 o( J5 b! K6 S' \) }
  19.   }
    * E! q; C0 e  i& l' V* M
  20.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)6 p7 j% T. Z: _% r( C
  21.   {( _5 z( t$ f8 Z  I! R( [
  22.     hspi->RxISR     = SPI_RxISR_16BIT;
    / h4 Y% n5 p) g! P% B. @( h7 j
  23.     hspi->TxISR     = SPI_TxISR_16BIT;
    2 d; D  E# [3 t! g. |. a
  24.   }
    . B: `  X9 z' U( u
  25.   else
    , ^* `; c& q( d4 J" P
  26.   {3 F7 U+ E2 W+ l5 e. b3 ~  ]
  27.     hspi->RxISR     = SPI_RxISR_8BIT;5 ?  k! L# [( x
  28.     hspi->TxISR     = SPI_TxISR_8BIT;
    ) l2 V7 a+ I" ^) Q3 k
  29.   }6 R, o1 Q2 f9 j/ U; V+ A

  30. - h# R( h% T; @7 ?% L. T/ Y
  31.   /* 设置当前传输数据大小 */
    : O( |: t" T* v/ f
  32.   MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);
    ' V! R; w4 t4 }$ M( r% r8 f

  33. # h8 z, Z$ K  \7 d8 s9 h
  34.   /* 使能SPI外设 */5 S8 _1 ]& w9 f6 O# E
  35.   __HAL_SPI_ENABLE(hspi);
    9 r9 p) A* `8 E; p% d6 ]4 ~

  36. # {4 d. k( L* G9 N4 T$ R
  37.   /* 使能各种中断标志 */' U  C, V6 D8 o7 b% M0 f
  38.   __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_EOT | SPI_IT_RXP | SPI_IT_TXP | SPI_IT_DXP | SPI_IT_UDR | SPI_IT_OVR | ' C4 o$ e  H) l, `  G" h2 ?
  39. SPI_IT_FRE | SPI_IT_MODF | SPI_IT_TSERF));
    4 J$ S3 x5 V2 a) Y& h3 P

  40. % F  `# X  C; R1 u; a7 T" r" L
  41.   if (hspi->Init.Mode == SPI_MODE_MASTER)! f4 q( {# A. ^& Q4 s1 K/ u1 r
  42.   {
    6 P0 b$ z! G# \4 d, Q4 L
  43.     /* 启动传输 */! j$ F) b3 Z% e2 H0 y. I
  44.     SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);7 ]: S/ H" R7 E; t2 v; J/ _, p
  45.   }
    & n1 O9 e+ v; |, u5 c
  46.   @* F8 [% ?$ I0 g5 C
  47.   /* 解锁 */" J: i- N8 L9 o) Y( B' u
  48.   __HAL_UNLOCK(hspi);# E3 C( v1 y6 I
  49.   return errorcode;
    + {* V* [2 N! H
  50. }0 X) C" G4 Q3 h* T
复制代码

. W* v! k$ b& y# \* l5 l函数描述:
4 Q' _) H9 y$ x2 v. S, Q
5 K( n8 X6 n- l此函数主要用于SPI数据收发,全双工中断方式。: b/ m( S* k7 `
  p* r* p9 `  v  k" h- g+ b
函数参数:7 p+ l" V/ n- }5 D
' ~' |: z9 T" n$ s" G/ v
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
  b# C" N  f$ I1 i. Y5 ]/ @  第2个参数是发送数据缓冲地址。
4 v+ A( \& w: v8 E  l/ T  第3个参数是接收数据缓冲地址。% V* m; m4 \% e% V% Q& h
  第4个参数是传输的数据大小,单位字节个数。
/ S6 R0 c# Y! J- ?5 x  y  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。1 `" j" h2 @& c3 ?

) Z* f( q* D! d1 W* `
' v: a. R" c, s. d& {' m( G6 E0 m) W使用举例:( `1 T$ X4 j- r2 q$ y4 u- x6 f
7 {! p% ^& H. M9 [. z
  1. SPI_HandleTypeDef hspi = {0};6 `# ?- V8 N+ n8 t! _; W' e1 U, _

  2. & \% s- g1 Q7 F" v( Y
  3. if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    8 ]1 Q8 g0 T+ H' L; }+ N( U$ Y8 k
  4. {& d- f9 x) s6 W- q  c/ d( n
  5.     Error_Handler(__FILE__, __LINE__);
    : Z. W) j" X& a2 b" j! L' A4 A
  6. }
复制代码

9 @5 `" ]$ T/ y72.4.5 函数HAL_SPI_TransmitReceive_DMA

4 v1 Q+ N9 X) g/ h# T函数原型:# p! w6 Z- C7 Z2 s9 Y- o. u
0 }& p% ~: d- S0 M
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,
    ! w' F# c" L3 S) U+ {
  2.                                               uint16_t Size)8 M5 [+ ~3 V- d% H" m! F: T
  3. {
    4 J+ G9 s% v1 w
  4.    /* 省略未写 */
    + j! Z2 C, Z6 J* p

  5. * c3 S5 I8 H& Q, j1 b
  6. /* 注意DMA的位宽和对齐设置 */: C& _/ k8 u. A1 ~& v5 o
  7.   if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && (hspi->hdmarx->Init.MemDataAlignment !=. p/ R5 F- B) w: h" D( S, t) U
  8. DMA_MDATAALIGN_WORD))  || # k7 h8 q. f* k5 {$ ?6 z" P9 x7 n" E7 \
  9.       ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) && ((hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_HALFWORD) && (hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_WORD)))): l  l1 \8 i  `  S
  10.   {& U9 e& F/ |. I$ K* |
  11.   }4 J" f7 t& X/ d

  12. + H8 B0 I. U* l1 C  l
  13. /* 调整DMA对齐和数据大小 */
    ' P' {2 y1 A5 Y' c
  14.   if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT). K- @* b6 f0 A$ E
  15.   {( Z; z! q3 I& y0 R1 @+ J
  16.      /* 省略未写 */4 m$ s, S: b8 L4 w4 |; _8 _9 D
  17.   }& r1 J' T5 D* V4 J) j
  18.   else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)
    4 w4 T* ?. \6 G3 q
  19.   {
    6 ?" W6 E; R1 F( T
  20.      /* 省略未写 */2 F) j5 C9 g2 E* f3 i  q2 S
  21.   }
    . ?4 d' O& K8 \
  22.   else* t3 e. ?' t: Z) {# d
  23.   {
    + H0 {4 V6 z$ [/ V
  24.       /* 省略未写 */  P- ]  @9 a+ p. Y# V9 c
  25.   }
    5 Z1 `  W. T5 {

  26. " J9 z. N- v: Y1 ~: k! _' g
  27. /*  DMA接收配置 */
    $ W1 ]; B) B  L6 A0 H. ^& [
  28.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->RXDR, (uint32_t)hspi->pRxBuffPtr,1 W; n+ X$ p. f- z6 q+ H
  29. hspi->RxXferCount))3 G: y# P' l  A; g, g2 V
  30.   {% @) n# Z# {! y
  31. ' o' d2 X0 Z, I2 D9 V
  32.   }
    # g( A% Q. y0 [8 v' Q

  33. ) ~( E4 Q( X7 t% O/ H0 Q
  34. /* DMA发送配置 */
    - d0 F* W' [) Y6 L" Y
  35.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->TXDR,
    ( Z+ l( B6 S/ C
  36. hspi->TxXferCount))
    0 l  T% J) J/ W/ M- z% S
  37.   {, L* r# {; w3 Z+ ^% r' T: F, F
  38.   }
    . l& D. {. \3 Q
  39. . T; L' r1 u( o  w1 F) I0 F6 E
  40.   /* 省略未写 */6 X, w) f1 I) R3 Y( f! f/ g" f
  41. }) |8 Z% W8 c! [) v( W# b% }7 b6 k
复制代码

2 a( C, @; |( }5 D. l5 Q函数描述:3 B. g. L9 E1 ?5 Z9 _
7 K' \/ b, M' a
此函数主要用于SPI数据收发,全双工DMA方式。! I/ P+ i, B+ w3 O- z. p: q) b

8 L4 e2 h  ^; g函数参数:9 n) r8 |7 X" n& D, t; d; p

5 y: E4 |* F: Y: x% T  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
; {$ v) e3 `. ~/ T. L7 b  第2个参数是发送数据缓冲地址。; E4 C' u" Z4 g5 W  @7 K9 Z
  第3个参数是接收数据缓冲地址。1 R8 u8 q" D8 N& u4 D: }& O! l+ I( r
  第4个参数是传输的数据大小,单位字节个数。
3 ~$ a9 [8 {3 g+ x, u  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
( W8 @8 [  w* l1 J! `  m* [) M! b- r4 @, _9 N3 y; t
$ Q( \# _( S* Y. x3 c
使用举例:# w/ d! ^7 a7 b/ s/ g: f3 k( V

; W& `' {/ }" ~9 J7 \
  1. SPI_HandleTypeDef hspi = {0};
    - V# l4 L# n- {" ]; `
  2. : L; P: ?- A' A
  3. if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)   
    & ~+ C; `  ^7 z( `1 ?9 i
  4. {9 R- _4 X. N5 {, _3 M
  5.     Error_Handler(__FILE__, __LINE__);9 L3 N0 u5 j( h; i& ]/ u& ]" f/ P
  6. }
    0 r0 ?4 j# c4 X0 E8 s
复制代码

2 f1 |" C+ ]7 a, T- h8 Q% [3 C3 @72.5 总结
( M* y7 I$ ^4 v本章节就为大家讲解这么多,要熟练掌握SPI总线的查询,中断和DMA方式的实现,因为基于SPI接口的外设芯片很多,熟练后,可以方便的驱动各种SPI接口芯片,以便选择合适的驱动方式。
# Q$ j( f. R2 b/ y7 I5 o9 X  p9 ^9 a2 ]+ [

1 v" e% T$ b% w$ A0 K! F' N5 U9 n% [( R. [* w
4 g* y! Y; [+ q+ u! T4 |% S

# c# a/ t4 G# x  m
收藏 评论0 发布时间:2021-12-20 19:00

举报

0个回答

所属标签

相似分享

官网相关资源

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