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

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

[复制链接]
STMCU小助手 发布时间:2021-12-20 19:00
72.1 初学者重要提示
( Z+ x0 i, o) t" D  STM32H7的SPI支持4到32bit数据传输,而STM32F1和F4系列仅支持8bit或者16bit。1 c0 x3 K1 m% V
  STM32H7的主频400MHz时,SPI1, 2, 3最高通信时钟是100MHz,而SPI4, 5, 6是50MHz。: J, W, q( ]2 Q- N. l6 y* D  ~
  STM32H7的MISO和MOSI引脚功能可以互换,使用比较灵活。- w3 {, `* V4 m/ K
  SPI总线的片选引脚SS在单一的主从器件配置下是可选的,一般情况下可以不使用。, K8 p4 ?( |' F/ j

5 T$ y  A& Y- h: l% t: r72.2 SPI总线基础知识
! q' j0 l2 N( }* J4 q) o0 V4 @& i72.2.1 SPI总线的硬件框图

+ B' M% }  n+ N. L4 U8 U/ u认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SPI的基本功能,然后再看手册了解细节。
1 n# e3 K# V3 ?( P- W
( l" z% f: X: g% T( o  ?  R( P
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

1 }' }) S( u0 H4 O; d
, E6 x0 T" {' I& g2 ?通过这个框图,我们可以得到如下信息:
. E% v: _8 l0 V  spi_wkup输出! ]- O& Y+ [, @5 T& H, x
+ e! |, Q* |. q" l6 ^2 o# r
低功耗唤醒信号。
' z8 A2 ~/ ^0 y! ]1 C  spi_it输出( H6 {# U0 C' O9 ]+ m, ?

6 W7 G& q1 ~, s& f+ S( k, K5 w, K6 d1 {
spi的中断请求信号。8 U: d# t- j1 f; H
  spi_tx_dma0 B$ _4 {2 W/ @8 T  B
  spi_rx_dma/ \/ z+ [2 ?2 q/ `* Z, n$ [. c. w" o

: w1 ]0 ?, T0 v' ~* Z
7 R2 R. D) |' _) X/ Sspi的DMA发送和接收请求信号。
( k3 [- s! }; i2 f  spi_pclk( C, K. w  U# t; Y# v/ U

! o5 ~- m' k! O) m
; S# j1 ]$ d. H8 q  v为寄存器提供时钟。. d  H* X" i6 R1 q
  spi_ker_ck' D7 N1 I( M  a, o/ `$ |4 @' [8 G
( J5 Q( ]( G8 N1 O1 ~

* k5 g7 m8 S2 N0 L; n4 j7 Q为spi内核时钟。9 i- K& ~8 ~5 W0 K1 E* w
  SCK(CK),Serial Clock
3 e" x3 X  C, x$ x, k) [' l9 v" F( l1 ~
- f6 _2 x, K6 G5 D7 U* D
此引脚在主机模式下用于时钟输出,从机模式下用于时钟输入。+ @# J' b9 o# l) U0 @8 j
  MISO(SDI),Master In / Slave Out data
. y' A) ~& ]) c* `) p4 E
; M$ [& }. S' E+ r) f) m3 f" J! o7 j( p$ r: w$ w' t; y! U  A, t
此引脚在从机模式下用于发送数据,主机模式下接收数据。" {" p4 f& k" s0 I0 I) T; J7 z. ]
  MOSI(SDO), Master Out / Slave In data
' l6 A- p" S# X# e
9 Z2 ^2 `. Y3 c) K! c: l! I* X# D$ d
此引脚在从机模式下用于数据接收,主机模式下发送数据。
# r' U; A& X2 m% A. B4 h1 D  SS(WS), Slave select pin; Q! H4 p7 F1 F, l

; s: B4 W7 {! f9 B
# o) A" m- s( J' S$ i4 g$ y根据SPI和SS设置,此引脚可用于:
0 ]5 ^: m  J% X& ba. 选择三个从器件进行通信。* E. [* T: D. ?9 h- n

+ K% \$ d/ a0 E1 y3 V) R1 Mb. 同步数据帧。# j, _* R3 b4 `$ H# g: ?  o: W

4 A' k6 w0 p9 Uc. 检测多个主器件之间是否存在冲突。6 o7 K6 x. R+ r& R: i" b

- {( J$ ?: O! w2 J) c# X! y通过这个框图还要认识到一点,SPI有三个时钟域,分别是寄存器所在的ABP总线时钟域,内核时钟发生器时钟域以及内核时钟发生器分频后的串行时钟域。9 p" y; ?) T0 M: B7 N+ ^( S

8 J" d: o! w& R, F* O0 O" X0 e72.2.2 SPI接口的区别和时钟源(SPI1到SPI6)
  f5 H: z- V8 f0 w: b9 q; o3 B" v
这个知识点在初学的时候容易忽视,所以我们这里整理下。1 C8 F! A2 L* e
SPI1到SPI6的区别
+ ^. D3 a$ ^7 ~* N! l  SPI1,SPI2和SPI3支持4到32bit数据传输,SPI4,SPI5和SPI6是4到16bit数据传输。. m* ]: W9 U; w' t
  SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit。: [$ i; j$ O; U& b( k  h& F% _
. a& H  g+ J" @# L0 p: B
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

7 k2 d' Y1 @1 u$ |3 T5 D/ X
3 S+ y9 b( |+ i# p; j: \. B  F  SPI1到SPI6的所在的总线(对应SPI框图的SPI_CLK时钟域)) D0 P$ z! X! V9 T$ ^  |' C

, K  K2 X0 D; s
6 Y$ u, ^0 T; i3 qSPI1,SPI4和SPI5在APB2总线,SPI2,SPI3在APB1总线,SPI6在APB4总线。注意,SPI的最高时钟不是由这些总线决定的。
/ z0 {- }7 i( n+ F) m  S2 H4 W/ p4 Y9 I9 e- B% l2 `3 [
  SPI1到SPI6的支持的最高时钟(对应SPI框图的SPI_KER_CK)- q1 w6 M5 S9 ?  \. D9 z# t! O
" @9 D# I$ ^/ a; [1 j( R

- \* B8 `) e% ?6 DSTM32H7主频在400MHz下,SPI1,SPI2和SPI3的最高时钟是200MHz,而SPI4,5,6是100MHz, 以SPI1为了,可以选择的时钟源如下:
5 n! @5 E9 x, @1 k+ Z) r3 @+ U, \" F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
9 W( q2 r0 s" v" \" w

7 P3 h# L8 L3 t& x4 {这里特别注意一点,SPI工作时最少选择二分频,也就是说SPI1,2,3实际通信时钟是100MHz,而SPI4,5,6是50MHz。( A5 X4 U- @) O4 }: D0 \: l
4 V8 b1 G0 a( g
72.2.3 SPI总线全双工,单工和半双工通信
# d. a! Z9 \$ x+ W片选信号SS在单一的主从器件配置下是可选的,一般情况下可以不使用。但需要同步数据流,或者用于TI模式时需要此信号。  ^4 j& `+ N3 L1 g
+ A7 P. m* t% ?3 @1 M; p0 ~$ h
  全双工通信0 e# X8 Y0 _" ^  S# J5 `. C
全双工就是主从器件之间同时互传数据,SPI总线的全双工模式接线方式如下:
5 [5 o( \' l  k( Q" x$ G" a
( J: I% B; a1 R$ e# X4 O  F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

, \; T9 P0 h6 q+ n1 `
7 @& {) d. J4 L2 O# A: L# [, {" [" t关于这个接线图要认识到以下几点:
/ e1 ]. `2 W  a5 h  注意接线方式,对于主器件来说MISO引脚就是输入端,从器件的MISO是输出端,即Master In / Slave Out data。MOSI也是同样道理。
5 R; w9 l9 N: u# p+ d3 _  每个时钟信号SCK的作用了,主器件的MISO引脚接收1个bit数据,MOSI引脚输出1个bit数据。1 s( e1 g6 e( ?
  这种单一的主从接线模式下,SS引脚可以不使用。; `7 \/ Z: h2 |; _1 D
5 P/ G' ]  L7 X/ m0 I
半双工通信; x9 c4 ~% Q  K$ D6 x, b
半双工就是同一个时刻只能为一个方向传输数据,SPI总线的半工模式接线方式如下:
) x8 O0 y7 t4 b6 n0 G1 i7 A7 A6 W4 N6 ^, z2 P; Q. P% M
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
+ \, Y9 p, j3 C* V; }4 T* J+ q6 X

. V0 R0 k* M1 Q  u( s  r关于这个接线图要认识到以下几点:0 l( z4 ?5 C% f& B1 g1 V% I% t

( j$ \8 u( X! L! o; s  更改通信方式时,要先禁止SPI。
0 m# _/ Y- C7 X! B0 q( Q  主器件的MISO和从器件的MISO不使用,可以继续用作标准GPIO。
+ f  `! w2 ^" I' _3 T. l  1KΩ的接线电阻很有必要,因为当主器件和从器件的通信方向不是同步变化时,容易出现其中一个输出低电平,另一个输出高电平,造成短路。9 l6 g3 h$ Q8 z7 v, x3 u5 c$ ~
  这种单一的主从接线模式下,SS引脚可以不使用。) J% o1 U4 l- U& z  \+ p
  0 e5 \8 o' V* G! ?* G7 ~, x* m1 j6 O
单工模式
- _7 z, x6 R8 ^0 s单工就是只有一种通信方向,即发送或者接收,SPI总线的全双工模式接线方式如下:
. k) E- Q1 a& r3 q& }- p5 Y6 h
: w, U) p- U5 b; ?5 s% b7 ?
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
. @4 M* f1 ^# i/ ]6 p  S, O* o

& r! E0 I/ ?. W- n% P关于这个接线图要认识到以下几点:2 c* @- ?; l1 f0 ?
3 z$ B" K7 u# C# c% D
  未用到的MOSI或者MISO可以用作标准GPIO。
+ a5 N$ g# w, T8 o7 V& e  这种单一的主从接线模式下,SS引脚可以不使用。& `' n6 p! [! M% ~6 p
# G1 W& ?8 v9 |" F! m4 h5 ~! M
72.2.4 SPI总线星型拓扑1 x6 y9 V* u7 R% A, `2 [( |+ b( t: V) f
SPI总线星型拓扑用到的地方比较多,V7开发板就是用的星型拓扑外接多种SPI器件:3 @/ ^$ d: \/ U3 l! g% H

; u4 M, v, x( I. X" a0 N- F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
. K; k$ A# ~4 `+ R& j. _

; T* q1 l/ m4 a关于这个接线图,有以下几点需要大家了解:
* p% g" R. h8 ]$ j( e6 o& G6 U  t
! h& b1 a. ?( h" @  主器件的SS引脚不使用,使用通用GPIO控制。为每个器件配一个SS引脚,方便单独片选控制。/ H. s$ K; s0 R4 e0 h, `
  从器件的MISO引脚要配置为复用开漏输出(很多外部芯片在未片选时,数据引脚是呈现高阻态)。" V5 _; n3 K4 e, J2 ~# K0 U) u

% Q% d9 H$ q# H( y
3 q" ?- f9 |) w0 S7 h! t72.2.5 SPI总线通信格式
9 X1 L& Z+ t, Y" ASPI总线主要有四种通信格式,由CPOL时钟极性和CPHA时钟相位控制:
# m+ h* c/ @( n" x9 [; Z" I3 L- d9 D! R& l& s
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
/ Z+ T, e, C& d! j
2 X  Y% d/ u$ X) v7 S" k
四种通信格式如下:  ]  U1 J% l0 u7 _% q, L3 b
  当CPOL = 1, CPHA = 1时
3 S% g! w" t7 J' r5 c; R( L3 V
" W* @- [4 c0 ?2 V! _
SCK引脚在空闲状态处于低电平,SCK引脚的第2个边沿捕获传输的第1个数据。
. p  y! S3 q+ `! i% b2 I  当CPOL = 0, CPHA = 1时
3 j! C( V2 `! U; C
4 P7 D. Z: X) ~$ z! s% Q* f7 o0 |( ]' x/ @" W/ x
SCK引脚在空闲状态处于高电平,SCK引脚的第2个边沿捕获传输的第1个数据。
+ C1 z6 d; u4 E* [; ^  当CPOL = 1, CPHA = 0时
1 r- E* m! a9 O6 k$ K' ^! F$ o# C4 `; X
1 N: U8 g" Y0 b1 k& P$ T- P5 t
SCK引脚在空闲状态处于低电平,SCK引脚的第1个边沿捕获传输的第1个数据。7 }0 [3 N5 c+ b: x% W. f( m0 Z
  当CPOL = 1, CPHA = 0时
2 n4 {4 k" S, A( [* Y' p8 i2 P
& H! ~4 Z. X& g- O# P+ Q0 ^0 ^
6 r4 }* Q0 ^# J- [* R1 |SCK引脚在空闲状态处于高电平,SCK引脚的第1个边沿捕获传输的第1个数据。; D0 Q! y5 z8 {( |' L' B- m

0 Y$ r& {+ [( S/ D3 l# e72.3 SPI总线的HAL库用法
9 f; U7 o  \: g/ _  M
72.3.1 SPI总线结构体SPI_TypeDef
. R9 s* S& C4 FSPI总线相关的寄存器是通过HAL库中的结构体SPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
, v  L* v) o7 P1 F
' n" _  s% i$ p; P! U' w
  1. typedef struct
    % `& i* n5 I# x
  2. {, a# B: j& I2 g; w- Z
  3.   __IO uint32_t CR1;           /*!< SPI/I2S Control register 1,                      Address offset: 0x00 */3 z6 {! D% `% ]% _4 C5 [
  4.   __IO uint32_t CR2;           /*!< SPI Control register 2,                          Address offset: 0x04 */
    5 l$ M7 k7 j9 e5 Z$ I3 v6 S
  5.   __IO uint32_t CFG1;          /*!< SPI Configuration register 1,                    Address offset: 0x08 */
    ! r) J. f& H5 L* M
  6.   __IO uint32_t CFG2;          /*!< SPI Configuration register 2,                    Address offset: 0x0C */: k# G/ t; o$ k7 ~& a6 B
  7.   __IO uint32_t IER;           /*!< SPI/I2S Interrupt Enable register,               Address offset: 0x10 */
    0 Y0 E6 C6 x& n# T& O
  8.   __IO uint32_t SR;            /*!< SPI/I2S Status register,                         Address offset: 0x14 */3 R1 z" I$ D0 @( A
  9.   __IO uint32_t IFCR;          /*!< SPI/I2S Interrupt/Status flags clear register,   Address offset: 0x18 */
    ) K4 x/ M# L2 l! _7 m/ O
  10.   uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                        */
    1 [9 r6 T  I3 _3 E
  11.   __IO uint32_t TXDR;          /*!< SPI/I2S Transmit data register,                  Address offset: 0x20 */  O6 l5 J4 t% F" e. @
  12.   uint32_t      RESERVED1[3];  /*!< Reserved, 0x24-0x2C                                                   */
    ! J. T, p5 E2 `3 d
  13.   __IO uint32_t RXDR;          /*!< SPI/I2S Receive data register,                   Address offset: 0x30 */" t% K$ a% I( l, a3 h0 ?- R, ~
  14.   uint32_t      RESERVED2[3];  /*!< Reserved, 0x34-0x3C                                                   */# D& f) R9 N% K+ p8 ^' L
  15.   __IO uint32_t CRCPOLY;       /*!< SPI CRC Polynomial register,                     Address offset: 0x40 */
    1 [$ r, j7 |; ]8 I+ |7 c, E
  16.   __IO uint32_t TXCRC;         /*!< SPI Transmitter CRC register,                    Address offset: 0x44 */  S2 z; t. F& Y6 C$ N, @
  17.   __IO uint32_t RXCRC;         /*!< SPI Receiver CRC register,                       Address offset: 0x48 */
    % |4 ]" [" x( F
  18.   __IO uint32_t UDRDR;         /*!< SPI Underrun data register,                      Address offset: 0x4C */
    3 v0 w" H0 ~# s" Z! w
  19.   __IO uint32_t I2SCFGR;       /*!< I2S Configuration register,                      Address offset: 0x50 *// s3 n: Z& G2 P- E# n

  20. ) L' \+ p1 Y  L4 \1 P. p3 p' y
  21. } SPI_TypeDef;
复制代码

+ j5 {% C6 `6 y3 h2 w% h: J% K% f这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
) X: Y5 |0 W$ q- d; L, r& Q, m9 R7 J% y2 X2 {& S
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
- w4 G& a" q( p+ n; N* v( _: a$ T. ]4 M) z3 S/ A7 t: O
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */  b% A* t3 i2 g& ]/ E: A2 R
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
: P. W) n9 R& c$ p
下面我们看下SPI的定义,在stm32h743xx.h文件。- Z! U# O% i/ I+ g  a
. Q; O! {: K6 U, c# n  ^
  1. #define PERIPH_BASE           (0x40000000UL)
    8 A. z$ S) h- C0 ]" a- ]1 }* ^
  2. #define D2_APB1PERIPH_BASE     PERIPH_BASE
    . c  C; @( O& K8 i( i
  3. #define D2_APB2PERIPH_BASE    (PERIPH_BASE + 0x00010000UL); A" k/ [7 r& V" i
  4. #define D3_APB1PERIPH_BASE    (PERIPH_BASE + 0x18000000UL)
      a$ |: B4 K- N6 S
  5. ( J9 e% n/ G- x1 y$ @
  6. #define SPI2_BASE             (D2_APB1PERIPH_BASE + 0x3800UL)
    $ k; i# m5 C/ o5 O
  7. #define SPI3_BASE             (D2_APB1PERIPH_BASE + 0x3C00UL)% U/ l, M. o! P9 @9 J
  8. #define SPI1_BASE             (D2_APB2PERIPH_BASE + 0x3000UL)' P# i  T5 U' a8 {/ |+ z3 q
  9. #define SPI4_BASE             (D2_APB2PERIPH_BASE + 0x3400UL)
    % s6 L' x& j) w' q( i
  10. #define SPI5_BASE             (D2_APB2PERIPH_BASE + 0x5000UL)9 E- `3 ?& d5 H" m2 S- R
  11. #define SPI6_BASE             (D3_APB1PERIPH_BASE + 0x1400UL)
    , [& i& g; P0 r# w

  12. * e- P* L6 }' T( K1 Y
  13. #define SPI1                ((SPI_TypeDef *) SPI1_BASE)0 w; Y7 a1 y0 V
  14. #define SPI2                ((SPI_TypeDef *) SPI2_BASE)
    , k/ c' \5 X; W" P) g3 ~
  15. #define SPI3                ((SPI_TypeDef *) SPI3_BASE)! c/ E" O* m1 o& e7 ~1 R
  16. #define SPI4                ((SPI_TypeDef *) SPI4_BASE)
    8 K* |- h# }0 t2 s5 k' I
  17. #define SPI5                ((SPI_TypeDef *) SPI5_BASE)1 p# l5 [+ r  U# p
  18. #define SPI6                ((SPI_TypeDef *) SPI6_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x58001400
复制代码

: }6 _8 l* V$ j/ }1 h我们访问SPI的CR1寄存器可以采用这种形式:SPI->CR1 = 0。0 P& r4 \! p7 h6 a4 {# |- }
/ v" ]& w3 g* q( F/ f9 i2 C5 K9 `
72.3.2 SPI总线初始化结构体SPI_InitTypeDef
0 H- }( H3 a+ f, S+ ~4 H. ~
下面是SPI总线的初始化结构体,用到的地方比较多:7 D- u$ S) n4 _# L# l* O* r9 y' [, W

# h/ e1 {8 t+ R2 x
  1. typedef struct
    + D7 j) m0 J8 x8 q1 H4 f
  2. {
    6 N! N7 Q( A6 T6 r1 M- i! E1 x
  3.   uint32_t Mode;                            % i- r, i+ N5 e" i2 R+ e7 s% O
  4.   uint32_t Direction;                     
    6 g4 V/ b4 C6 S' `0 b7 C* N
  5.   uint32_t DataSize;                          . V7 F! v- e8 I$ E6 o- {( P$ T
  6.   uint32_t CLKPolarity;                       
    ; z' C+ j  h! x( v
  7.   uint32_t CLKPhase;                        
    2 e5 U* ^. i. L1 q( n8 X9 R
  8.   uint32_t NSS;                             9 r1 ?) c& Y9 L7 U9 l  ?
  9.   uint32_t BaudRatePrescaler;                  Q, T. P( C5 h# {) i6 B6 X
  10.   uint32_t FirstBit;                        
    # b- d5 Z9 q7 u: h3 U
  11.   uint32_t TIMode;                          
    2 |3 W) `5 G! `  n1 ^
  12.   uint32_t CRCCalculation;                   & q" t8 c  T& G# z# m
  13.   uint32_t CRCPolynomial;                     ; Y; w5 t& l2 U! l; I; Z1 j
  14.   uint32_t CRCLength;                        
    # E1 \7 w7 O5 r( R- ?8 O; l; g
  15.   uint32_t NSSPMode;                        
    7 l: \4 @& {1 A) e, z# d, {% k
  16.   uint32_t NSSPolarity;                    
    2 P1 n2 i6 W& m1 |4 K* B: b7 {" O- U$ B) g
  17.   uint32_t TxCRCInitializationPattern;      
    ; i8 R5 S) j5 ]
  18.   uint32_t RxCRCInitializationPattern;      
    - ~; e! @% m; |* J! V' ?
  19.   uint32_t MasterSSIdleness;                 ( J! Y0 J2 g8 c, u# j5 e# i) q9 B
  20.   uint32_t MasterInterDataIdleness;           
    / Q$ w8 m, x5 M* }, Q; @
  21.   uint32_t MasterReceiverAutoSusp;         
    ) }, f$ Z3 P( j- Y- V  S: {- O6 C
  22.   uint32_t MasterKeepIOState;               - Y* E% T- S: k/ f+ l4 V
  23.   uint32_t IOSwap;                          
    9 q4 h0 n% [. ?2 F! V5 C
  24. } SPI_InitTypeDef;
复制代码
, _4 t' ]5 E/ g: n/ a. G8 H! s
下面将结构体成员逐一做个说明:
; D# g+ N6 `1 z% W, B5 u# i7 Q: Z  Mode
8 |* R& e8 I1 X' U$ S% {7 @5 j  F6 Z
用于设置工作在主机模式还是从机模式。  n# W. a3 z/ z
  1. #define SPI_MODE_SLAVE              (0x00000000UL)
    " w& d4 N5 Z9 Y  M! _7 x- e
  2. #define SPI_MODE_MASTER             SPI_CFG2_MASTER
复制代码
& u7 B9 k9 ?) G7 l' I9 a/ F
  Direction
+ z, ?. K; Q8 T. n用于设置SPI工作在全双工,单工,还是半双工模式。
3 s. X2 I. B+ a) b5 D1 S' d, I! C6 {
  1. #define SPI_DIRECTION_2LINES           (0x00000000UL)     /* 全双工 */
    5 m$ n; x* f4 O- [- F3 b3 I0 f& S
  2. #define SPI_DIRECTION_2LINES_TXONLY     SPI_CFG2_COMM_0   /* 单工,仅发送 */
    2 F; S9 @4 }$ Z* K; x, i# l
  3. #define SPI_DIRECTION_2LINES_RXONLY     SPI_CFG2_COMM_1   /* 单工,仅接收 */* b! V- i( J! L. B- t5 z
  4. #define SPI_DIRECTION_1LINE             SPI_CFG2_COMM     /* 半双工 */
复制代码

$ [% i1 \; L: a+ O/ [+ l  DataSize  s" ]# Y& q3 f/ \2 x% l( Z% m
用于设置SPI总线数据收发的位宽,支持4-32bit。9 l% L2 |3 `/ F% J  [# z

1 W) h8 Z6 D, g7 c$ l; \
  1. #define SPI_DATASIZE_4BIT                             (0x00000003UL)7 `" o8 s& v% b# Q
  2. #define SPI_DATASIZE_5BIT                             (0x00000004UL)0 o: }; D* ^! d9 }
  3. #define SPI_DATASIZE_6BIT                             (0x00000005UL)
    9 E  I( F  r  ?7 H. r, `6 s
  4. #define SPI_DATASIZE_7BIT                             (0x00000006UL)
    0 u  L7 l: x) T2 y) _3 W4 Y1 x
  5. #define SPI_DATASIZE_8BIT                             (0x00000007UL)
    ! U) Q: y6 J0 X- e; Z
  6. #define SPI_DATASIZE_9BIT                             (0x00000008UL)
    " r; S( ^  \# \6 s; ^4 Q* a
  7. #define SPI_DATASIZE_10BIT                            (0x00000009UL)
    + O3 l* t' c- r2 i% [
  8. #define SPI_DATASIZE_11BIT                            (0x0000000AUL)! C. M) m  z5 ^+ x# V- r
  9. #define SPI_DATASIZE_12BIT                            (0x0000000BUL): ?! o$ ^6 k% X
  10. #define SPI_DATASIZE_13BIT                            (0x0000000CUL)
    ! F6 J0 F3 G* c. n% {8 y, z
  11. #define SPI_DATASIZE_14BIT                            (0x0000000DUL)8 w0 [9 `1 [7 C% ?7 f( @1 A
  12. #define SPI_DATASIZE_15BIT                            (0x0000000EUL)# q. \$ a# z+ ^1 T
  13. #define SPI_DATASIZE_16BIT                            (0x0000000FUL)
    2 W0 p$ q( f$ T: r
  14. #define SPI_DATASIZE_17BIT                            (0x00000010UL)
    0 l+ Q& |! v& P* W* r4 `: Y/ t
  15. #define SPI_DATASIZE_18BIT                            (0x00000011UL)
    5 s2 I" i5 n( n: e% s9 o9 b3 j3 C
  16. #define SPI_DATASIZE_19BIT                            (0x00000012UL)
    4 F5 i) {" I+ J" q7 [
  17. #define SPI_DATASIZE_20BIT                            (0x00000013UL)
      l0 ?6 Z; g" G
  18. #define SPI_DATASIZE_21BIT                            (0x00000014UL)0 C) q9 {+ X' x( l
  19. #define SPI_DATASIZE_22BIT                            (0x00000015UL)
    ( ^- O& z: @/ }; s: k( h
  20. #define SPI_DATASIZE_23BIT                            (0x00000016UL)8 ^$ i3 v0 A8 R$ A- q: R
  21. #define SPI_DATASIZE_24BIT                            (0x00000017UL)
    7 h/ [' v  H3 X3 Z/ t5 w% v" w
  22. #define SPI_DATASIZE_25BIT                            (0x00000018UL): M; d# D- D8 w, z3 L
  23. #define SPI_DATASIZE_26BIT                            (0x00000019UL)
    ! ?6 b) N9 U! |
  24. #define SPI_DATASIZE_27BIT                            (0x0000001AUL)
    2 k( A% n2 {% D' @) m' W: z
  25. #define SPI_DATASIZE_28BIT                            (0x0000001BUL)
    8 z# z5 Y- C4 L4 r: t, J/ v0 ^
  26. #define SPI_DATASIZE_29BIT                            (0x0000001CUL)& R0 h8 c0 ]' H
  27. #define SPI_DATASIZE_30BIT                            (0x0000001DUL)8 J3 u* W5 m6 A+ z" i+ p
  28. #define SPI_DATASIZE_31BIT                            (0x0000001EUL)  R: M; C3 `% c8 o9 ~3 T- |
  29. #define SPI_DATASIZE_32BIT                            (0x0000001FUL)+ f3 t; z& N8 ?% d- \. \
复制代码

) J( k) C6 w. R& W' t+ ]* |: s/ w4 W
8 m% r) F* {: q5 d/ l0 l  CLKPolarity4 B8 }, x' M, L4 C( i- L# Y" H
用于设置空闲状态时,CLK是高电平还是低电平。# N" e8 j( _6 T: ?
  1. #define SPI_POLARITY_LOW       (0x00000000UL)# |/ D3 A; _: Y) r! C# P
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码
# e& a/ G5 ~$ t  Z7 m4 U) o' y
  NSS
& G' w% W3 G4 X用于设置NSS信号由硬件NSS引脚管理或者软件SSI位管理。
% M' ~: U2 H$ u5 A8 D
! V6 r8 R1 C' ^7 t
  1. #define SPI_NSS_SOFT                                  SPI_CFG2_SSM# d( M$ F. U) V/ ~
  2. #define SPI_NSS_HARD_INPUT                            (0x00000000UL)4 a, A' o8 }4 M7 y3 f* N
  3. #define SPI_NSS_HARD_OUTPUT                           SPI_CFG2_SSOE
复制代码

$ P: Z8 g+ R- v" t0 c  BaudRatePrescaler
4 E, x% g. P( F& |% E用于设置SPI时钟分频,仅SPI工作在主控模式下起作用,对SPI从机模式不起作用。
" I, C. |* M; v3 W( t" E1 K+ ]' G' d9 L1 R' p# A! P
  1. #define SPI_BAUDRATEPRESCALER_2                       (0x00000000UL)
    0 b4 J% l, @7 q
  2. #define SPI_BAUDRATEPRESCALER_4                       (0x10000000UL)
    " O" Q& x0 f; n* |
  3. #define SPI_BAUDRATEPRESCALER_8                       (0x20000000UL)
    - V) R+ }1 P( F9 Q6 L
  4. #define SPI_BAUDRATEPRESCALER_16                      (0x30000000UL)+ |6 C4 Q; n' u% N! e
  5. #define SPI_BAUDRATEPRESCALER_32                      (0x40000000UL)* V3 L4 v+ E3 W2 e! g' }' x
  6. #define SPI_BAUDRATEPRESCALER_64                      (0x50000000UL)
    & l4 _: c0 q/ N2 r" y7 u* B/ E+ K
  7. #define SPI_BAUDRATEPRESCALER_128                     (0x60000000UL)5 b; b- _& ~& j' v
  8. #define SPI_BAUDRATEPRESCALER_256                     (0x70000000UL)
复制代码

2 Y" ~0 d% d: M. ]+ k1 o% i  FirstBit! X! L+ m: L6 {
用于设置数据传输从最高bit开始还是从最低bit开始。
5 ~! o& V/ S7 ^+ ^/ O3 R) X
  1. #define SPI_FIRSTBIT_MSB                              (0x00000000UL)+ O2 Z9 |# }$ A0 o- |
  2. #define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST
复制代码

6 O! E. Y# p  J: z  TIMode
, C  b4 T% x2 q用于设置是否使能SPI总线的TI模式。
$ {! J& w8 p+ G- k1 l5 h/ H6 A
  1. #define SPI_TIMODE_DISABLE               (0x00000000UL)  {! A+ K# g$ K! {7 r- S  C. M
  2. #define SPI_TIMODE_ENABLE                SPI_CFG2_SP_0
复制代码
& F4 [3 p: ]8 o
  CRCCalculation
/ D8 @8 H8 M: O8 G4 f. z7 K用于设置是否使能CRC计算。- |% e. g3 ?4 f, i* w
  1. #define SPI_CRCCALCULATION_DISABLE                    (0x00000000UL)
    $ y' r9 q- w/ n) C/ @4 O/ g
  2. #define SPI_CRCCALCULATION_ENABLE                     SPI_CFG1_CRCEN
复制代码
" G$ c) q' T5 F2 `
  CRCPolynomial& g9 l# F4 T6 k* m. I$ k- W( A3 u
用于设置CRC计算使用的多项式,必须是奇数,范围0到65535。
- W! Y+ H6 j6 w/ W' B: z; c
+ ^4 a7 t4 C6 q; u: c- Q  CRCLength
! W" R& Q7 f9 }2 H用于设置CRC计算时的CRC长度。大小要与同属此结构体的DataSize一致。或是DataSize的整数倍。
: q2 N* |) @  g3 ]& Y
& A, }% l/ s. U
  1. #define SPI_CRC_LENGTH_DATASIZE                       (0x00000000UL)8 O3 g' t! E/ a8 Y9 p
  2. #define SPI_CRC_LENGTH_4BIT                           (0x00030000UL)* M5 j7 L+ l. E  ~& L
  3. #define SPI_CRC_LENGTH_5BIT                           (0x00040000UL)
    . h, @' Q$ S+ L- F1 Y
  4. #define SPI_CRC_LENGTH_6BIT                           (0x00050000UL)$ H4 l9 ?$ x5 g% [$ Z5 Y
  5. #define SPI_CRC_LENGTH_7BIT                           (0x00060000UL)
    ; o- @& R8 q' Y' ?% |
  6. #define SPI_CRC_LENGTH_8BIT                           (0x00070000UL)
    4 \5 Y3 f% H8 [
  7. #define SPI_CRC_LENGTH_9BIT                           (0x00080000UL)7 K2 b# R2 f+ M3 e
  8. #define SPI_CRC_LENGTH_10BIT                          (0x00090000UL)8 {0 w% y6 w" }. F
  9. #define SPI_CRC_LENGTH_11BIT                          (0x000A0000UL). a9 b+ V6 f9 V6 S( n
  10. #define SPI_CRC_LENGTH_12BIT                          (0x000B0000UL)  b: R# k- T/ ~1 z
  11. #define SPI_CRC_LENGTH_13BIT                          (0x000C0000UL)
    ( K* v4 @  q5 p$ [5 J  ?
  12. #define SPI_CRC_LENGTH_14BIT                          (0x000D0000UL)$ K! i3 ^4 c) s8 x% ~
  13. #define SPI_CRC_LENGTH_15BIT                          (0x000E0000UL)
    1 T$ p  [* @, k( k1 f4 o9 U
  14. #define SPI_CRC_LENGTH_16BIT                          (0x000F0000UL)  t; J0 W5 \# R% S" g. j
  15. #define SPI_CRC_LENGTH_17BIT                          (0x00100000UL)
    $ o$ }4 y8 m& x7 |0 I" V2 E0 f+ s
  16. #define SPI_CRC_LENGTH_18BIT                          (0x00110000UL)1 w& Q/ F8 S( N9 x9 i
  17. #define SPI_CRC_LENGTH_19BIT                          (0x00120000UL)
    # s/ r1 W1 r1 w$ ~8 e
  18. #define SPI_CRC_LENGTH_20BIT                          (0x00130000UL)
    / |, T2 S2 B7 O& E7 o- i; O- {
  19. #define SPI_CRC_LENGTH_21BIT                          (0x00140000UL)+ i! Q: ]4 }1 N+ `
  20. #define SPI_CRC_LENGTH_22BIT                          (0x00150000UL)
    * P5 P- @3 R7 s& ^
  21. #define SPI_CRC_LENGTH_23BIT                          (0x00160000UL)
    4 M( m/ U5 D2 ^* w; P$ z% d
  22. #define SPI_CRC_LENGTH_24BIT                          (0x00170000UL)
    % p) I; @; {2 m; b9 P' u! ~# E1 E
  23. #define SPI_CRC_LENGTH_25BIT                          (0x00180000UL)
    4 k7 M# v3 Z0 j$ m4 J, \/ I6 f2 z
  24. #define SPI_CRC_LENGTH_26BIT                          (0x00190000UL)# A8 Q# J, j: p1 B6 G1 ], |- G
  25. #define SPI_CRC_LENGTH_27BIT                          (0x001A0000UL)
    - ~: E- b- Q9 X
  26. #define SPI_CRC_LENGTH_28BIT                          (0x001B0000UL)
    ) C, t0 g& \' b, T% C1 f
  27. #define SPI_CRC_LENGTH_29BIT                          (0x001C0000UL)
    ) C! K! o/ Z: q) {) ]2 o2 j
  28. #define SPI_CRC_LENGTH_30BIT                          (0x001D0000UL)
    0 L; x# }7 J2 m$ f6 R
  29. #define SPI_CRC_LENGTH_31BIT                          (0x001E0000UL)
    0 q$ {" B6 y% D5 N3 H. j* b9 |
  30. #define SPI_CRC_LENGTH_32BIT                          (0x001F0000UL)
    & F) b, H# X/ {$ D8 W
复制代码
3 I# K4 o$ x/ A% f# Y
  NSSPMode
/ Z: A& P' b) y. g用于设置是否使能NSSP信号,可以通过SPIx_CR2寄存器的SSOM位使能。注意,只有配置为摩托罗拉SPI主控模式时设置此成员才有用。5 M9 ?1 k& H: T4 r3 f( U8 ~
  1. #define SPI_NSS_PULSE_DISABLE                         (0x00000000UL)
    & i1 z& F  {+ u& v* u
  2. #define SPI_NSS_PULSE_ENABLE                          SPI_CFG2_SSOM
复制代码
4 w: e5 }) j$ T% p% D& h% R: |
  NSSPolarity
: h4 X- J( f4 `+ w6 C用于设置NSS引脚上的高电平或者低电平作为激活电平。
4 j; d* `$ S* g' x, q6 r# L" ?! v
  1. #define SPI_NSS_POLARITY_LOW                          (0x00000000UL)- T, r$ F: z; o" Y) z' L' |
  2. #define SPI_NSS_POLARITY_HIGH                          SPI_CFG2_SSIOP
复制代码

1 y1 T" S4 W1 O/ `  FifoThreshold
1 o. T6 X& M8 x$ }* h用于设置SPI的FIFO阀值。1 s5 J! Z6 \9 }) B) a

% `' }9 |& B$ r( p$ h
  1. #define SPI_FIFO_THRESHOLD_01DATA                     (0x00000000UL)/ Z$ f  j0 D7 j/ L
  2. #define SPI_FIFO_THRESHOLD_02DATA                     (0x00000020UL)2 e. }, O, g7 L1 h, h% A+ _( H
  3. #define SPI_FIFO_THRESHOLD_03DATA                     (0x00000040UL)% A3 }9 M" ~7 s  {& K
  4. #define SPI_FIFO_THRESHOLD_04DATA                     (0x00000060UL)' E/ ?, d1 u6 ?" F; S& y
  5. #define SPI_FIFO_THRESHOLD_05DATA                     (0x00000080UL)0 w+ v2 y# R" c5 ~) a/ V
  6. #define SPI_FIFO_THRESHOLD_06DATA                     (0x000000A0UL)
      ^9 d# p: P" q) M# A; S8 Y
  7. #define SPI_FIFO_THRESHOLD_07DATA                     (0x000000C0UL)  ^1 s: }- z2 V  `7 t0 t
  8. #define SPI_FIFO_THRESHOLD_08DATA                     (0x000000E0UL)
    - ?* R7 D  N8 P1 i
  9. #define SPI_FIFO_THRESHOLD_09DATA                     (0x00000100UL)
    3 X7 X5 \8 R% v+ }3 v0 G3 K  {
  10. #define SPI_FIFO_THRESHOLD_10DATA                     (0x00000120UL)1 E1 `8 l1 z; ?' T
  11. #define SPI_FIFO_THRESHOLD_11DATA                     (0x00000140UL)
    ! l+ h1 l, i0 w. c2 o
  12. #define SPI_FIFO_THRESHOLD_12DATA                     (0x00000160UL)7 j1 I/ i! z/ U) \
  13. #define SPI_FIFO_THRESHOLD_13DATA                     (0x00000180UL)
    ! J$ n  L: u& v2 S) p
  14. #define SPI_FIFO_THRESHOLD_14DATA                     (0x000001A0UL)
    ( q1 B, [2 B7 \: Q  n3 O! ^! h
  15. #define SPI_FIFO_THRESHOLD_15DATA                     (0x000001C0UL)8 A% j  m& }( {& W3 t
  16. #define SPI_FIFO_THRESHOLD_16DATA                     (0x000001E0UL)
复制代码
- ]; o3 J( s- a" q
  TxCRCInitializationPattern7 ?) \( e+ D* p$ w- J9 W: `
发送CRC初始化模式。
) q4 W! R8 L4 j6 U  a9 G
& ?9 [0 A. b1 Y7 j$ A5 U# y
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    ) ~" g. L) I# z, g
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码

3 k7 x; G( r& M, \) Z% B2 g0 w! `) u- y  RxCRCInitializationPattern1 Z9 D1 ?7 ?( z1 y6 z
接收CRC初始化模式
3 d5 }$ U1 Q: f4 C0 V9 j% b4 l
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    - u' y9 }$ V/ i. C& ?0 [
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码

3 R# o* t8 g9 J0 g* t4 b MasterSSIdleness
! M: r. L! h7 r8 o在主模式下插入到SS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数。' J5 V( c: a. p) c
/ r3 Q; \1 `$ _; a. e; t, x8 x
  1. #define SPI_MASTER_SS_IDLENESS_00CYCLE                (0x00000000UL)
    + J$ H5 t9 s4 c# i% \
  2. #define SPI_MASTER_SS_IDLENESS_01CYCLE                (0x00000001UL)
    3 ~3 j! T& q9 z6 o. r1 U
  3. #define SPI_MASTER_SS_IDLENESS_02CYCLE                (0x00000002UL)
    ! y1 E% H% Z" x6 `; S
  4. #define SPI_MASTER_SS_IDLENESS_03CYCLE                (0x00000003UL). c2 U2 @" t7 ~! \& ~; A4 {
  5. #define SPI_MASTER_SS_IDLENESS_04CYCLE                (0x00000004UL)
    , K) K. f4 h% l7 }
  6. #define SPI_MASTER_SS_IDLENESS_05CYCLE                (0x00000005UL)
    : v4 |$ |* F# r+ f# j
  7. #define SPI_MASTER_SS_IDLENESS_06CYCLE                (0x00000006UL)6 D# j6 D* r( i$ F1 Z1 L/ u0 m4 E/ d
  8. #define SPI_MASTER_SS_IDLENESS_07CYCLE                (0x00000007UL)
    : A0 O5 L9 ~& O  {
  9. #define SPI_MASTER_SS_IDLENESS_08CYCLE                (0x00000008UL)
    ! H8 k+ l  r+ W, r6 l
  10. #define SPI_MASTER_SS_IDLENESS_09CYCLE                (0x00000009UL)
    , u( M+ p& l' F- n4 b8 h2 @
  11. #define SPI_MASTER_SS_IDLENESS_10CYCLE                (0x0000000AUL)
    ( {3 b" [& y( G  V
  12. #define SPI_MASTER_SS_IDLENESS_11CYCLE                (0x0000000BUL): J  N; O/ ]" j' M1 K- ]  G
  13. #define SPI_MASTER_SS_IDLENESS_12CYCLE                (0x0000000CUL)
    3 |* |# r' [. Z; z5 e
  14. #define SPI_MASTER_SS_IDLENESS_13CYCLE                (0x0000000DUL)8 |+ u& |4 Z8 c4 ?( t: e" k
  15. #define SPI_MASTER_SS_IDLENESS_14CYCLE                (0x0000000EUL); _0 w; o7 S1 }6 O- y# c
  16. #define SPI_MASTER_SS_IDLENESS_15CYCLE                (0x0000000FUL)
    * H+ r0 }1 Q5 K& N1 F2 U, M, u
复制代码

" U" w' [* B" A# i6 l  MasterInterDataIdleness
! X1 w2 c1 S/ E' E9 v9 b主模式下在两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数。
( {! }" s  G% G- b+ h
0 y# r* L6 t$ B0 F
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)! L, m) T* m' n. a5 C
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
复制代码

, h! R' ?* h- ]( Y  MasterReceiverAutoSusp
) K% ^; l' @2 z$ g用于控制主器件接收器模式下的连续 SPI 传输以及自动管理,以避免出现上溢情况。
% A" [. e2 z1 W2 m6 r- y( O
1 S( o8 E8 ]7 m
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)# T  z; Q) d! z, F) X4 r1 }: Y9 [
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
    3 n0 c1 J. J, }) t8 K+ t) k
复制代码
( u& o: Q7 c6 U: c1 x! j
  MasterKeepIOState; Y7 n2 m8 u. H; Q2 u/ @/ g( w. p
禁止SPI后,SPI相关引脚保持当前状态,以防止出现毛刺。在从模式下,该位不应该使用。+ a+ a, u( d2 C$ B
  1. #define SPI_MASTER_KEEP_IO_STATE_DISABLE              (0x00000000UL)
    . A0 D  g# D/ E' M) r, f$ m. V3 M
  2. #define SPI_MASTER_KEEP_IO_STATE_ENABLE               SPI_CFG2_AFCNTR
复制代码
' a. {& u# y+ f/ u0 p
  IOSwap3 o/ d. {1 v8 n& X5 H( [
用于交换MISO和MOSI引脚。
& V, C8 `1 A# x" [
+ R$ a! F! `& m; z; c) e; ~
  1. #define SPI_IO_SWAP_DISABLE                           (0x00000000UL)
    ' T! T8 k" U! m4 W7 ]9 u" G
  2. #define SPI_IO_SWAP_ENABLE                            SPI_CFG2_IOSWP
复制代码
2 N9 w1 v  @7 ~. e% h
72.3.3 SPI总线句柄结构体SPI_HandleTypeDef

; o4 N* q. u- W下面是SPI总线的初始化结构体,用到的地方比较多:8 e) \& [7 E" v" U
- g8 ~* P) Z( |2 Z2 H+ }9 [
  1. typedef struct __SPI_HandleTypeDef; k$ D, y6 B' s( g$ ]
  2. {6 p# |; f: Q# v- p- E" k
  3.   SPI_TypeDef                *Instance;                   |1 o+ S1 ~, x* g9 _$ h2 _
  4.   SPI_InitTypeDef            Init;                        
    ; Z8 p- A0 d' e7 q
  5.   uint8_t                    *pTxBuffPtr;                 
      L5 a" J# Y# u  v% a# n7 _* ~; `" K
  6.   uint16_t                   TxXferSize;                   ! G( t) Y& D( N1 k) D
  7.   __IO uint16_t              TxXferCount;                  
    . p" t; _# ]$ r
  8.   uint8_t                    *pRxBuffPtr;               
    4 S7 \6 ?) L) b  w, {
  9.   uint16_t                   RxXferSize;                  / K" O) a* X) s! a4 I0 y
  10.   __IO uint16_t              RxXferCount;                 
    ' a7 ]6 S' [4 p. Q# ?
  11.   uint32_t                   CRCSize;                     7 e. N* W5 {# {5 W! G( ]% f- A
  12.   void (*RxISR)(struct __SPI_HandleTypeDef *hspi);      
    . K3 _* s/ H( l, U3 l
  13.   void (*TxISR)(struct __SPI_HandleTypeDef *hspi);        
    + w2 S4 f7 x1 d) t# O5 Q
  14.   DMA_HandleTypeDef          *hdmatx;                     
    " j7 x0 i1 _) X; c6 Q! D
  15.   DMA_HandleTypeDef          *hdmarx;                     
    * _* e0 I- e. {1 h2 i+ v
  16.   HAL_LockTypeDef            Lock;                        
    + \0 o% x, r9 Z' T1 O) S
  17.   __IO HAL_SPI_StateTypeDef  State;                        
    ) t9 O8 l5 Y/ q& S1 @- S  u
  18.   __IO uint32_t              ErrorCode;                  
    7 `5 j8 z; q# [. _- x' f' s
  19. #if defined(USE_SPI_RELOAD_TRANSFER)  O# @+ g; [6 ?( n
  20.   SPI_ReloadTypeDef          Reload;                     
    * f) a* o) M9 S0 o+ a
  21. #endif
    ! t, E" a; W3 q, W
  22. 3 s- p' i8 z" u# u
  23. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)$ q/ a9 E; v! K3 h3 r4 e
  24.   void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      ! s# J: p; _  B
  25.   void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      ( w7 N# U: R/ X, s
  26.   void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    4 F% N0 Y, b$ I0 @* g* t. x& `
  27.   void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  - Z/ Q6 `/ D7 Q* o/ i6 P
  28.   void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  ; ?% x% G1 t$ T: ^2 `
  29.   void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi); 5 R8 T6 g* }' w" O; ]
  30.   void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi);       9 R  _& u' }0 I9 f7 Z' a/ J1 a  Z
  31.   void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
      k9 |4 y6 F, W$ X1 h# l
  32.   void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi);   
    - c& o+ s) J5 U
  33.   void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi); . I8 W. Z, E4 H/ a1 M
  34. #endif  8 o, F$ H' k, g" j
  35. } SPI_HandleTypeDef;! p$ h7 H- N* B: B+ I3 r/ N
复制代码

8 v( t( G4 _, l& m8 C/ k4 d注意事项:: a" G% o/ J9 k  `2 Q

9 @9 j8 o) _9 F+ V2 u" H" R9 [条件编译USE_HAL_SPI_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:
1 v- N2 u1 I# |! u2 I1 ^' W4 N! N7 d" v* V; I
  #define   USE_HAL_SPI_REGISTER_CALLBACKS   1/ G& A$ V7 l! c6 w  Y
; Z- W$ c  _) ?# j
通过函数HAL_SPI_RegisterCallback注册回调,取消注册使用函数HAL_SPI_UnRegisterCallback。
5 U/ S  b* l  L) w' {- e9 G9 z; E+ I
这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。  y. e( a+ [. m/ A, o( m
: r! ?8 H1 c6 {. m8 k" o3 w
  SPI_TypeDef   *Instance
6 e2 W' L3 Q. {2 A, N这个参数是寄存器的例化,方便操作寄存器,比如使能SPI1。
3 r! w/ p8 b- u$ a/ s: a2 Q0 S& I
4 j+ w& M. g. n8 Z7 ySET_BIT(SPI1 ->CR1,  SPI_CR1_SPE)。/ k6 p, ]6 l& a# m7 {+ N8 T( Y) ?
- m! j  v0 T2 H) j- t$ H$ a
  SPI_InitTypeDef  Init  U2 _" t' {8 t6 g+ ^
这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。5 H$ M( G& s3 l) R1 }) R6 h" F

1 ]: v- l* s) Z/ U  DMA_HandleTypeDef          *hdmatx               ( d+ }/ N5 ]0 c7 W4 x# s
  DMA_HandleTypeDef          *hdmarx
, i' B% ~6 H- z& i- [& \" Y! p用于SPI句柄关联DMA句柄,方便操作调用。' r3 l  U& R: t0 u/ T0 C: a
, x6 X9 k6 g+ X7 X
72.4 SPI总线源文件stm32h7xx_hal_spi.c
7 ~: H/ h- ^& k: e此文件涉及到的函数较多,这里把几个常用的函数做个说明:
* k9 d" M. E1 l9 n
" H0 G8 A; D& R7 k) D  HAL_SPI_Init
+ N8 ~( b) n$ {6 J6 l  HAL_SPI_DeInit
0 u& @! |1 W. ?( t  HAL_SPI_TransmitReceive, T9 \: [" v4 T# m. J- u
  HAL_SPI_TransmitReceive_IT
# y" m; J0 k. ]- m! S! L( m  HAL_SPI_TransmitReceive_DMA
* [' P6 h3 X- M, M: D) f, b
) h7 J: p0 q( x1 }4 n0 s$ ]72.4.1 函数HAL_SPI_Init
$ `' Z9 i7 x0 d/ v: j函数原型:2 U- b/ l6 V1 W0 n& f( ^$ q
, q% x  W! |! s% ?2 z" y
  1. HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)
    + J5 i% V( W3 f/ z9 m4 Y" i0 w" G
  2. {
    $ i0 ?& j9 b& s( O7 [; y2 D  @, q
  3.   uint32_t crc_length = 0UL;8 y/ r8 \( M- y! ^, l+ Y% `
  4.   uint32_t packet_length;* ^; Y. ^0 u: z5 L- R

  5. , N$ c3 ~# E+ O% U* A
  6.   /* 省略未写 */
    : j" o0 K' D  v. m
  7. " n, H+ w2 P! z( n* G! M* s
  8.   /* 如果数据位宽大于16bit,必须是SPI1,SPI2或者SPI3,而SPI4,SPI5和SPI6不支持大于16bit */
    $ I! m, e' a3 m6 R. s$ K
  9.   if ((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (hspi->Init.DataSize > SPI_DATASIZE_16BIT))# _+ n. W3 O+ Q8 e
  10.   {
    9 J1 |* X# I1 p% V& r; }
  11.     return HAL_ERROR;/ N+ q  [- _1 Q) Q! \2 x5 ~& N* m
  12.   }  R' N$ v1 _8 r/ b1 m" g5 D

  13. . K. V3 P0 Z# L
  14.   /* SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit
    2 b% b# @" p2 j  N# \; p& r. X# g8 b
  15.      这里是查看设置的缓冲大小是否超出了FIFO支持的大小。
    ' I, {% H7 s- a
  16. */  y6 Y. v  C4 q) O: Z
  17.   packet_length = SPI_GetPacketSize(hspi);; K0 |" h$ G0 F. C
  18.   if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_LOWEND_FIFO_SIZE)) ||
    $ b9 X( |9 E1 P" _6 A
  19.       ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_HIGHEND_FIFO_SIZE)))$ `0 R* N. m5 |7 x$ p6 x# h! L
  20.   {
    5 r- f- d, I% W) |- g  v; {' T
  21.     return HAL_ERROR;) b/ Q( ?/ q4 n. k* f1 Y$ u, b3 T/ I
  22.   }2 R) \# _* n2 T; I
  23. 3 g1 L3 ^- L' `. a! X6 ^
  24. #if (USE_SPI_CRC != 0UL)
    1 y$ e" x) J2 X3 p. z3 `
  25.     /* 省略未写 */
    - Z+ C* Y% n3 {. v4 h. E
  26. #endif , d9 H% ]  |2 E, ^- K
  27. + v7 ?/ l, {! V9 I2 S
  28.   if (hspi->State == HAL_SPI_STATE_RESET)
    2 a7 M5 Z  z& v/ A2 Q
  29.   {
    - w( ~8 H  w8 Z) k4 Z: x) z% P( {
  30.     /* 解锁 */
    * u' y  U! F/ T' c) Z
  31.     hspi->Lock = HAL_UNLOCKED;+ S- W( q$ J' K0 F
  32. 7 J1 [. ~9 L( D
  33.     /* 使用自定义回调 */' j7 {) d5 K  s# J2 ~& ^0 D
  34. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    5 m  k9 G# `: J- j- X6 p7 Y
  35.     /* 设置默认回调函数 */% D1 s- \) ?5 C
  36.     hspi->TxCpltCallback       = HAL_SPI_TxCpltCallback;       /* Legacy weak TxCpltCallback       */% O' {! l: O, Q3 e
  37.     hspi->RxCpltCallback       = HAL_SPI_RxCpltCallback;       /* Legacy weak RxCpltCallback       */
    8 A9 Z* r/ n1 h+ R5 K
  38.     hspi->TxRxCpltCallback     = HAL_SPI_TxRxCpltCallback;     /* Legacy weak TxRxCpltCallback     */# L9 `6 ?$ R0 w" ^
  39.     hspi->TxHalfCpltCallback   = HAL_SPI_TxHalfCpltCallback;   /* Legacy weak TxHalfCpltCallback   */! S; U, O( `% f4 s
  40.     hspi->RxHalfCpltCallback   = HAL_SPI_RxHalfCpltCallback;   /* Legacy weak RxHalfCpltCallback   */2 n5 }( [: v, o) D
  41.     hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */
    * a3 L4 I6 M1 o. n$ C2 P5 m
  42.     hspi->ErrorCallback        = HAL_SPI_ErrorCallback;        /* Legacy weak ErrorCallback        */$ @; q: N" y" o. T9 H4 y3 Z) {
  43.     hspi->AbortCpltCallback    = HAL_SPI_AbortCpltCallback;    /* Legacy weak AbortCpltCallback    */
    * r5 ]) u5 I2 k  k) c

  44. ) r" g. F3 }+ y) E( K: }# h0 W# U
  45.     if (hspi->MspInitCallback == NULL)2 d/ X3 m* e: l
  46.     {
    $ C2 h$ v6 V, r4 s" ~2 Q
  47.       hspi->MspInitCallback = HAL_SPI_MspInit;
    ( b0 A. Y! R7 T3 J! h: D
  48.     }. C7 J$ J' _  c0 [
  49.   G! J' O1 \  Y0 l1 a5 i  `
  50.     /* 初始化地址硬件: GPIO, CLOCK, NVIC... */4 l( F  k- \0 X' M0 ]  O
  51.     hspi->MspInitCallback(hspi);  X# G, j0 C( {; I
  52. #else
    . }, E5 w; W& T& `. t: k/ _
  53.     /* 初始化底层硬件: GPIO, CLOCK, NVIC... */( I# u: v5 S6 o
  54.     HAL_SPI_MspInit(hspi);+ l/ x4 \3 H+ ]6 z# k- P% {
  55. #endif
    ' D- b" _# X! h  R
  56.   }
    ) j* W* F5 o0 J
  57. , x! t# X4 w1 O" I+ P
  58.   hspi->State = HAL_SPI_STATE_BUSY;
    & I: s. Y) `3 z7 m' d

  59. 6 W! `' }+ `- F- Y8 ?
  60.   /* 禁止SPI外设 *// O- `4 {  Q: @
  61.   __HAL_SPI_DISABLE(hspi);) N+ o5 c! t  k! F  ^6 |" h: z

  62. & a+ S* z* g9 M/ g/ A- J
  63.   /*----------------------- SPIx CR1 & CR2 配置---------------------*/
    , f' x# i! ~$ e$ |
  64.   if ((hspi->Init.NSS == SPI_NSS_SOFT) && (hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.NSSPolarity ==
    , c8 w' i, y1 p: x
  65. SPI_NSS_POLARITY_LOW))& q; O8 |: f0 J3 ?# p* A
  66.   {/ k2 N4 _, N4 ~% Z3 o
  67.       SET_BIT(hspi->Instance->CR1, SPI_CR1_SSI);
    1 t' ]+ l2 D  r& z/ Y
  68.   }' S+ E6 I7 k3 }

  69. 6 W* x$ x8 j0 ^& b6 @5 K" M
  70.   /* SPIx CFG1配置 */
    ; Z  A* |5 ~  [3 O% @  G' Z/ o' e
  71.   WRITE_REG(hspi->Instance->CFG1, (hspi->Init.BaudRatePrescaler | hspi->Init.CRCCalculation | crc_length |
    - D9 p; o+ v: f1 c( T" r$ v/ z
  72.                                    hspi->Init.FifoThreshold     | hspi->Init.DataSize));
    , u  g' T9 v2 c
  73. * M7 @: w3 b' s) o9 A
  74.   /* SPIx CFG2配置 */
    ( M: K( l% o' p
  75.   WRITE_REG(hspi->Instance->CFG2, (hspi->Init.NSSPMode     | hspi->Init.TIMode           | hspi->Init.NSSPolarity  |
    4 D+ @* e/ I3 m& w
  76.                                    hspi->Init.NSS          | hspi->Init.CLKPolarity      | hspi->Init.CLKPhase     |+ c- r. w' Q& C' A" h3 @) l5 x# l9 }% g
  77.                                    hspi->Init.FirstBit     | hspi->Init.Mode             | hspi->Init.MasterInterDataIdleness |
      H6 c5 B6 U% A' O( ?
  78.                                    hspi->Init.Direction    | hspi->Init.MasterSSIdleness | hspi->Init.IOSwap));3 A9 \- Z1 X9 V9 X- Q+ O

  79. ! Q9 a, G* F, Z+ a
  80. #if (USE_SPI_CRC != 0UL)5 y8 F% A" m& e
  81.   /*---------------------------- SPIx CRC配置 ------------------*/
    8 b+ F. |4 ]# @3 Y4 ^; _
  82.   /* 配置SPI CRC */
    & z6 }6 M  g' B7 u# W
  83.   if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
    0 s& {# w* c, }, l
  84.   {
    1 V4 h3 l6 Y- H
  85.     /* 初始化TX CRC初始值 */
    3 {& r  {; y& W! q% M2 H
  86.     if (hspi->Init.TxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)
    2 v! j! E1 t( F( ?, w3 d
  87.     {
    0 D0 p& m8 g1 W- w! O5 Q( V
  88.       SET_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);
    9 F, l/ D: u4 w1 ^5 A
  89.     }
    $ f# X7 I$ u9 y; v" {
  90.     else9 u; Y& [$ y, d0 Z( c( q
  91.     {
    7 M1 B/ s5 X" k$ J( i, {' t% d
  92.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);
    3 c$ x+ O8 m* f
  93.     }
    / E  C8 S. _1 G* o8 z
  94. - p6 B8 t  O' j
  95.     /* 初始化RXCRC初始值 */
    9 A9 z+ N) }' M; p) [
  96.     if (hspi->Init.RxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)
    / Y! x5 v2 ]: Y# p
  97.     {
    4 i7 d3 @5 M0 M! @" h
  98.       SET_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);# x' W) \" o2 O, X
  99.     }* o- [1 l. `% p1 O
  100.     else
    : g# _$ ~$ y8 q7 m& u+ Y/ N
  101.     {
    9 Y. ?  Y& e$ r. ^7 h, f! L2 C. K
  102.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);* q9 M; Q, d  a0 @
  103.     }
    6 O2 L7 y) Y$ w$ O5 |2 P6 P# ~

  104. 7 r2 U' U$ ^8 J" Z$ u
  105.     /* 使能 33/17 bit CRC计算 */
    / U2 u0 K- z! ?0 M' T
  106.     if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (crc_length == SPI_CRC_LENGTH_16BIT)) ||
    : Y% z! D/ G: K  W' S
  107.         ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance))  && (crc_length == SPI_CRC_LENGTH_32BIT)))
    9 ?5 o3 W& ^- x+ n  r# v
  108.     {
    2 I9 O4 X# E. g
  109.       SET_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);7 u! q/ G! `; X  \
  110.     }
    4 |$ M5 }9 B) U  }6 r/ U0 T
  111.     else
    8 _' O+ V# ?' [5 v
  112.     {
    & t% p+ ], u+ W# j
  113.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);
    # Y% {5 {5 \- _$ |5 l# \
  114.     }" g- ?/ F" p+ L5 `; \" T
  115.   h( `; x. [: M' g  q
  116.     /* 写CRC多项式到SPI寄存器 */( S" I# g0 P. q) O7 C' @
  117.     WRITE_REG(hspi->Instance->CRCPOLY, hspi->Init.CRCPolynomial);
    + W4 E& {8 T% h0 c2 `0 r
  118.   }* q' S) b1 X) [* d" }
  119. #endif
    ) m/ o7 a% A5 Q: m& M
  120. 1 `+ I: w& |, k  u  A
  121.   /* SPI从模式,下溢配置 */
    + k- {; V0 e! E! w! t# ?
  122.   if (hspi->Init.Mode == SPI_MODE_SLAVE)
    0 o4 @( h! v0 p& G9 b2 ?
  123.   {' N5 X" k6 l8 f* B
  124.     /* 设置默认下溢配置 */
      D" _  P. U, d7 E
  125. #if (USE_SPI_CRC != 0UL)
    8 L" {, x) K1 Y
  126.     if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_DISABLE)
    1 I3 N2 E8 J, U7 [/ t8 O
  127. #endif
    * O$ \0 ^9 p: p) F5 `9 Q, {4 I% ~
  128.     {
    ( b/ \7 r. W' b2 |* b
  129.       MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRDET, SPI_CFG1_UDRDET_0);
    $ J4 Q# ~, a+ e! t  q* a+ n) Y
  130.     }* ]5 d# T& W7 t- p
  131.     MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRCFG, SPI_CFG1_UDRCFG_1);6 i" r3 l3 d/ Z+ \! t
  132.   }$ V  E7 A; ^6 F( T; Z! ]6 i3 Z
  133. 4 ]/ }) _7 D2 p+ A" {, U5 i
  134. #if defined(SPI_I2SCFGR_I2SMOD)4 N6 n% c& k% g3 b, N" D
  135.   CLEAR_BIT(hspi->Instance->I2SCFGR, SPI_I2SCFGR_I2SMOD);' p  Z5 j  x4 h7 G# w
  136. #endif ) L3 m$ i' v$ y

  137. 9 w$ [1 {5 D  |* N9 L2 P4 `
  138.   /* 确保AFCNTR bit由SPI主机模式管理 */
    ' \7 C/ q; m( {! P# J. L1 _
  139.   if ((hspi->Init.Mode & SPI_MODE_MASTER) == SPI_MODE_MASTER)
    4 L- p* H6 Y' Z
  140.   {, v1 X  ^6 e0 y2 Y+ L
  141.     /* Alternate function GPIOs control */
    " w# z1 ]/ d2 ]% c8 D
  142.     MODIFY_REG(hspi->Instance->CFG2, SPI_CFG2_AFCNTR, (hspi->Init.MasterKeepIOState));
    . P0 a8 X) B/ r8 z6 b2 O
  143.   }
    + |1 f1 o/ L! U% _3 R0 w

  144. $ _" `2 A& p% E+ ^( }: v
  145.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;
    3 c3 P, q9 P1 o8 }
  146.   hspi->State     = HAL_SPI_STATE_READY;* e+ _& Z6 d* ^, E4 K6 W2 Y
  147. ' L, V+ i- u) c- o( _5 G
  148.   return HAL_OK;' m0 ?8 b1 c* `2 d( o0 u* e
  149. }
    , s3 I' j, U' {6 h. K9 z$ O1 w
复制代码
7 a$ \" ?$ `$ h) r* c& i. `8 e

0 O7 u# g+ p7 M; S, Q0 `函数描述:; b5 Z% k- o2 d; P
! O9 u$ z% E+ ]# X1 Z  e) R
此函数用于初始化SPI。
+ J7 `3 Y3 j8 ^
; h: n9 C# t5 C+ q( `6 \# z函数参数:
+ g% U. O7 O/ K0 E  d. p+ v6 i  j) }; O( `
  第1个参数是SPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。, T/ O: V6 D% q6 C6 m9 ]
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。) m/ T! q; o7 v$ K( a

7 c1 m. g8 c& O; t' }7 }
' K  d- E& y' C) n0 U$ x2 ?注意事项:
; S' w* {2 g2 \& Q2 |& d% K函数HAL_SPI_MspInit用于初始化SPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。/ \- ]+ t0 ?8 n( H
如果形参hspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SPI_HandleTypeDef SpiHandle。
. l1 C5 }) p8 N* n& L对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SPI_STATE_RESET  = 0x00U。
: ~6 d: U# X- m, k- c
$ x; @6 V8 c% P  a$ G解决办法有三
: m! \1 e3 t/ P% |( k- A) L$ o+ X0 T9 [
9 k1 p" R8 H4 q  c方法1:用户自己初始化SPI和涉及到的GPIO等。
5 Z& F$ m/ y4 W; R& E. b9 @( `" R7 [; U: Z  b6 ?- L) `8 i
方法2:定义SPI_HandleTypeDef SpiHandle为全局变量。
( Z) z" C: I/ S3 u/ U! P$ x3 g+ S
方法3:下面的方法
5 e" o0 H3 e8 o9 i7 d8 n
9 B9 [2 b+ @5 O2 U, Y
  1. if(HAL_SPI_DeInit(&SpiHandle) != HAL_OK)
    * j$ _' N, M& Q  |4 m2 `
  2. {9 z' z$ O' x- ?7 h
  3.     Error_Handler();3 B! t# F: C. `9 c
  4. }  
    8 p5 i7 C2 j, o2 B& \, y
  5. if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
    9 A& e0 {1 m5 Y& W  R  g  u* d5 A
  6. {
    1 Q2 _: c- d1 m& T2 e
  7.     Error_Handler();
    ! m. ?/ \8 p( F' j$ W2 i! t/ y
  8. }
复制代码

+ ~* t4 P3 C' n使用举例:6 c% R, k/ C/ H2 M8 K

: `" m7 ^6 [! j9 f9 T# e5 G$ {8 N
  1. SPI_HandleTypeDef hspi = {0};
    & B1 g) I& O9 m( i, O

  2. % M* _0 h# |) p2 q, [/ L
  3. /* 设置SPI参数 *// `( [6 T: N* ^4 c9 F+ y
  4. hspi.Instance               = SPIx;                   /* 例化SPI *// k. {/ p2 [! _3 N. a6 s4 j
  5. hspi.Init.BaudRatePrescaler = _BaudRatePrescaler;     /* 设置波特率 */
    7 G; v7 h. h' {# b
  6. hspi.Init.Direction         = SPI_DIRECTION_2LINES;   /* 全双工 */5 A: a# Q7 G  ?' r8 G3 K9 j/ O7 K
  7. hspi.Init.CLKPhase          = _CLKPhase;              /* 配置时钟相位 */' w3 f- u+ d1 [5 l
  8. hspi.Init.CLKPolarity       = _CLKPolarity;           /* 配置时钟极性 */
    9 j/ C  {2 t. a- A, c3 ~$ V
  9. hspi.Init.DataSize          = SPI_DATASIZE_8BIT;      /* 设置数据宽度 */; h; ]  ?  y1 v/ y, ?9 k
  10. hspi.Init.FirstBit          = SPI_FIRSTBIT_MSB;       /* 数据传输先传高位 */
    5 U1 W& @4 P& Z' T6 Z/ O. n
  11. hspi.Init.TIMode            = SPI_TIMODE_DISABLE;     /* 禁止TI模式  */
    : [- ~; q+ m7 `
  12. hspi.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;      /* 禁止CRC */1 q) |' `& i; K1 U
  13. hspi.Init.CRCPolynomial     = 7;                               /* 禁止CRC后,此位无效 */
    " s' _% r2 K6 }( ]; _
  14. hspi.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;             /* 禁止CRC后,此位无效 */
    8 ~9 g+ m; u4 o7 j/ M& A5 |2 I1 P) P
  15. hspi.Init.NSS               = SPI_NSS_SOFT;                    /* 使用软件方式管理片选引脚 */
    3 N( R, G0 @7 W7 g% o
  16. hspi.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_01DATA;       /* 设置FIFO大小是一个数据项 */
    * ]5 b2 g3 a+ x4 ]$ I9 a8 @
  17. hspi.Init.NSSPMode          = SPI_NSS_PULSE_DISABLE;           /* 禁止脉冲输出 */; f% u# }& {) F4 r9 Z
  18. hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  1 k; V2 o* B4 N4 _
  19. hspi.Init.Mode                  = SPI_MODE_MASTER;            /* SPI工作在主控模式 */
    % A4 _( {. b% ?" [

  20. # y4 Z  G; h/ \/ p
  21. if (HAL_SPI_Init(&hspi) != HAL_OK)4 Y' L' V  q9 v) I( ?( S
  22. {
    " J% e2 @8 V2 o. [/ U
  23.     Error_Handler(__FILE__, __LINE__);2 u7 M5 l. q8 p3 J7 ~$ ~
  24. }
复制代码
, f2 |- ^0 S1 f
72.4.2 函数HAL_SPI_DeInit
+ |2 v& l& n0 p+ s函数原型:' J: l7 B' R/ }& Q* \% W
  1. HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)3 D) ?, c! l1 e0 @4 x
  2. {; s% S2 u4 v! x% Z/ N
  3. /* 检测SPI句柄是否有效 */
    , W: u# `0 d/ E- \
  4.   if (hspi == NULL)
    ! W3 s' ?$ g6 ^  o
  5.   {# I# A( P/ N& V- d! u8 s( M
  6.     return HAL_ERROR;
    " [  U7 D' _, r1 Q3 Q2 {4 x
  7.   }8 X' N( R) J& p2 V% `

  8. ; e) \: H4 w" L
  9. /* 检查SPI例化参数 */5 B6 ]) h8 C: _3 }" J8 N$ t
  10.   assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));9 R# X* ~2 u# G/ q
  11. - d9 ]( c; c5 f6 I! h* O
  12.   hspi->State = HAL_SPI_STATE_BUSY;
    2 L" H2 j3 l% ^1 C
  13. " t' y( ^9 @. }, w. x, l+ \9 r, x
  14.   /* 禁止SPI外设时钟 */
    * D3 s2 |: g$ ?
  15.   __HAL_SPI_DISABLE(hspi);* c. `( T' E/ {1 v; u  w
  16. # B( [6 M% Y9 ~0 B% c1 W' u. c" D
  17. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    , C& R, y& f. S2 t
  18.   if (hspi->MspDeInitCallback == NULL); q3 ?. U% x, K3 _7 y
  19.   {1 Y0 i1 E1 b& |  ~4 l* |# ?
  20.     hspi->MspDeInitCallback = HAL_SPI_MspDeInit; 4 j; A5 W" F& u3 @( l
  21.   }/ H* l% N# L+ n) T5 Y+ L# e

  22. 4 T4 K- Q' ~$ o2 A
  23.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */
    * j8 P: D+ E) x) e: ]2 `; B) V
  24.   hspi->MspDeInitCallback(hspi);9 V+ s$ j$ ]; J; H& h
  25. #else
    1 o) Y/ e3 p7 }4 C& M9 O; e
  26.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */! S2 T$ E6 u* J: g: Y, p
  27.   HAL_SPI_MspDeInit(hspi);% t( f4 w" ~, t( L$ @0 O$ M3 f
  28. #endif
    / E9 Q7 {6 y; C, {

  29. ( Z* g" F5 T# Y+ f2 {
  30.   /* 设置无错误,复位状态标记 */2 [3 k8 ]& ~. H4 `9 l, \: E
  31.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;& b, F2 k# v/ a3 b
  32.   hspi->State = HAL_SPI_STATE_RESET;- K! W, w- p+ s* |) u

  33. / ^7 Z" ]1 C" W4 c
  34.   /* 解锁SPI */: A8 ]3 @8 l$ P3 ?0 U
  35.   __HAL_UNLOCK(hspi);9 H/ I2 N9 D) Q

  36. + I4 R! v; A+ X9 }4 p9 \- J1 ^0 ~$ `
  37.   return HAL_OK;
    , ?- F! ^' W  J8 e% ]
  38. }
复制代码

2 c( w+ Y( Y. o. N, @) l3 U, \函数描述:
4 w" K3 J5 w: X- i, c8 R9 k7 E, @0 B5 A- M4 ~
用于复位SPI总线初始化。
8 w8 `: c+ ^, _. q2 ]% @+ r% ^3 J1 P
函数参数:
- x% |8 P( Z8 |0 I6 N
. e+ n% Z# y: C  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
  r  M7 e, b" d9 k! s$ \  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中3 x( A" z3 s& d

( H' B  @/ P" w, Y/ a  G) m1 b
( N6 J0 V  v8 D$ b72.4.3 函数HAL_SPI_TransmitReceive
& A3 m3 t/ ~. r6 s$ Y! |函数原型:' `8 w1 c' m! H2 f5 p' v

+ _0 p- Q  X# I
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
    ) J1 j4 |" a0 n0 `; r& T, F
  2. {1 `  H3 H3 y/ i4 d+ e3 [! U$ p, D
  3. + c( x4 w1 |$ _, c" y4 K2 L
  4.    /* 省略未写 */
    . @' _6 ?: Q. c+ o
  5. ) I# U) B+ d8 l$ W( W2 s% v
  6.   /* 大于16bit的数据收发 */
    - u0 z. J# n) Q7 k4 h
  7.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    5 \7 T- F5 q. `0 X
  8.   {' D& S8 ?" M% i0 [/ y2 Q# M% t
  9.        /* 省略未写 */
    - j1 k( O2 \& z5 V6 ^
  10.   }
      E& \% q. j# T( W: d! O
  11.   /* 大于8bit,小于16bi的数据收发 */
    5 K; @; W, W" a* j0 k; N7 \
  12.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
    : f3 w7 y) M) v8 S
  13.   {
    # D0 a8 E. ]) W
  14.       /* 省略未写 */9 `) H, p4 P* A, U+ E
  15.   }
    # p2 q' j7 F9 F
  16.   /* 小于等于8bit的数据收发 */
    ! D0 c0 {2 f( Y5 p& a* U9 j6 {
  17.   else
    ; Y/ j$ t) @( D
  18.   {
    9 B7 F9 \+ b4 }- `2 d5 ^) R/ @
  19.        /* 省略未写 */9 o# P6 N! l* k# y7 I' X9 V
  20.   }+ ?, a0 k, q2 m3 S
  21. 2 \5 j* Y' Z8 Z. f
  22. }
复制代码

* a6 A8 T8 `  r8 n; u' B  p函数描述:
+ N7 E9 I+ C% |2 a
9 U" A* ]# t; I4 Z$ D  c- |& }6 Z  P此函数主要用于SPI数据收发,全双工查询方式。1 N. D4 O$ D+ s$ \  ?$ Q+ C

( \  n% y. F# X函数参数:
4 t: k9 f; z, n1 [1 a& i0 d) ~$ U  u8 Q- R
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。$ W$ @8 b4 @, O' D4 D
  第2个参数是发送数据缓冲地址。
# @9 w5 z, D/ n/ H# b4 P  第3个参数是接收数据缓冲地址。
& g: b" Y: n4 j( ?; z+ d+ i  第4个参数是传输的数据大小,单位字节个数。, R. e4 ?9 m3 t) [
  第5个参数是传输过程的溢出时间,单位ms。
8 I0 z, B2 Y) a$ p0 j& [. m) @* ^  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
6 B" D. s1 L7 Y2 w1 K" r% T; n( L
2 M' V# x/ N1 ?( l1 O
使用举例:
. G" i+ r) n/ `" ?+ @0 f" x0 `# `4 {; \) Q
3 g! E4 @, u. n
  1. SPI_HandleTypeDef hspi = {0};( H8 Y, F4 A0 w. @# v1 k- h
  2. / j" J  H/ m( U# J( c( n
  3. if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)8 w2 W# X$ j. O+ D: Z9 x: e
  4. {1 @' ]/ D3 s+ O( F" I/ I! Y
  5.     Error_Handler(__FILE__, __LINE__);
    3 P: q( N; q2 o; O& e& V, P
  6. }
复制代码
; s- H( p1 i8 ?- y
72.4.4 函数HAL_SPI_TransmitReceive_IT
1 e; H9 E9 ~5 @% |: N4 \/ [
函数原型:
8 c, ^* ^5 g6 k* k) P% m% s
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)* c) g9 z! }* W" L
  2. {4 N% _9 z0 f! y! r
  3.    /* 省略未写 */4 u' o$ K( b# F

  4. 1 ?2 Q' a+ E  q3 b( Y( W
  5.   /* 设置传输参数 */
    - K4 N1 r5 P" t% f: _/ t, W
  6.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;) U* F" D/ N9 E( t& u/ k/ I2 S# g
  7.   hspi->pTxBuffPtr  = (uint8_t *)pTxData;
    ; M# p! z$ n# @5 U$ S8 g7 K! H. y3 I: G
  8.   hspi->TxXferSize  = Size;
    " T# n4 U3 K- ^5 W) C; ?3 p
  9.   hspi->TxXferCount = Size;! }' Z: s: j4 ~3 [: s
  10.   hspi->pRxBuffPtr  = (uint8_t *)pRxData;; @+ v/ S6 V" V
  11.   hspi->RxXferSize  = Size;& P# V! G6 B+ L3 M, Q$ t+ J7 \
  12.   hspi->RxXferCount = Size;6 |/ O& R& X# h0 [8 r  F( O6 ]' K
  13. 6 [% d0 G- u  L, V3 Q; [' Q0 N
  14.   /* 设置中断处理 */% i9 b; A5 a7 L/ R- u- r0 F
  15.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    - ]: ~3 `5 u/ L$ J$ l# E
  16.   {9 P  V0 K& i' l
  17.     hspi->TxISR     = SPI_TxISR_32BIT;$ k4 \- u$ I/ a: H4 N  }. q
  18.     hspi->RxISR     = SPI_RxISR_32BIT;3 D, U7 J- Y, N
  19.   }% I2 Y! y2 V) z% [4 M  V2 g, y
  20.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
    9 T' |8 E8 T4 o9 c: B( G( S  p& Y
  21.   {
    ' p1 m1 W& [" M7 V( O
  22.     hspi->RxISR     = SPI_RxISR_16BIT;0 S0 p. H6 u: u) v. S6 b  S
  23.     hspi->TxISR     = SPI_TxISR_16BIT;( e7 I1 ]* \; \6 k' f
  24.   }. u! V7 J8 W! P' ^4 T& ~  u
  25.   else& F7 c7 h  d, R8 x0 ~% D
  26.   {
    : `# ^. B0 S4 p3 i6 A- [
  27.     hspi->RxISR     = SPI_RxISR_8BIT;( C6 }0 N* k( Q2 w
  28.     hspi->TxISR     = SPI_TxISR_8BIT;. H; R3 I( b4 ~& J2 ^- v6 [& L, V
  29.   }$ f, R; V( x; O8 z/ w7 ?
  30. 5 U6 }1 E. X4 J" @; t$ v3 M
  31.   /* 设置当前传输数据大小 */
    4 L- A' }. t4 {9 w
  32.   MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);  {* U* m8 r$ y, _9 e) D8 Z, s
  33. / @  D# ]1 l/ A7 ]
  34.   /* 使能SPI外设 */- n+ s- u9 l$ ?( W4 L) u
  35.   __HAL_SPI_ENABLE(hspi);
    7 f$ T8 N- M" B1 F. @, I
  36. 0 k) s" n  O6 i8 J+ z
  37.   /* 使能各种中断标志 */3 v" a7 [; L$ u
  38.   __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_EOT | SPI_IT_RXP | SPI_IT_TXP | SPI_IT_DXP | SPI_IT_UDR | SPI_IT_OVR |
    3 z0 m+ q: k& X1 e- G: {
  39. SPI_IT_FRE | SPI_IT_MODF | SPI_IT_TSERF));
    2 c8 _; Y% K- ]' M$ O( R

  40. * g7 H' j. p# k2 l
  41.   if (hspi->Init.Mode == SPI_MODE_MASTER)0 a+ x5 M$ l6 f  ]/ Q
  42.   {
    7 O7 S, L6 b2 W4 B3 x
  43.     /* 启动传输 */
    4 I; S* [* N2 d  f
  44.     SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);
    # T0 O4 a( u: r; P6 A6 ?6 G8 w: A. Z3 i
  45.   }
    7 D" u2 `3 Y) [- ?

  46. ' z! _, x' D) s7 R  f, M
  47.   /* 解锁 */' H% v0 m& u/ [1 P$ h5 A
  48.   __HAL_UNLOCK(hspi);
    5 x0 U: ~  [* B9 C+ |$ w
  49.   return errorcode;- z/ z! Y/ z2 U: E+ g2 G& \
  50. }! g5 u" ^6 k4 ]5 t
复制代码
& D3 h, O$ c+ u( x& O% p4 V
函数描述:
2 W! {2 O2 Q/ U9 t: W
# t; c) M; k. ^此函数主要用于SPI数据收发,全双工中断方式。
4 _, c$ w  q& Z! }2 P( M% h3 a9 o4 J4 ~1 J$ Y
函数参数:( A) P9 ^/ `8 d! k

6 T/ {& t3 o2 A  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
8 i) r( E+ P  D* j/ J9 b# `  第2个参数是发送数据缓冲地址。4 u3 I( m0 T7 K
  第3个参数是接收数据缓冲地址。
1 A* @% A4 y9 Y' X  _  第4个参数是传输的数据大小,单位字节个数。0 x$ |7 u  Y9 ]2 F6 E* g
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。! Y) f  V1 y! m! |+ p
# l9 q. W2 |  G) h& g/ y9 m

% e0 v0 `2 S% _使用举例:" a* j" `$ n5 Y& c7 ]" l& |+ J8 N% l

3 ~3 O& R3 i# }, y& t
  1. SPI_HandleTypeDef hspi = {0};
      T8 l$ n/ P% M

  2. / i: n) C2 n. o: A- Q7 C! ]
  3. if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)   
    ; @% b9 f0 ]# i. N* E8 J
  4. {
    0 y( j7 _5 O# ?0 h2 f( m
  5.     Error_Handler(__FILE__, __LINE__);
    9 ~. _1 z. e( c+ i5 ^
  6. }
复制代码

' t) b8 @* o+ x3 {  G1 @72.4.5 函数HAL_SPI_TransmitReceive_DMA

5 K5 o# y( I% {8 I% M. H- ?& o函数原型:- l8 D- E+ u0 j* N; }4 `6 M7 F

1 q; j7 _* x3 F3 ^1 R
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,) t. g6 y6 L7 R3 v- n5 Q5 F" A8 R
  2.                                               uint16_t Size)
    ; a2 W: l8 X. b+ Q; k9 z
  3. {
      E! n7 a$ k; }5 u, `9 {" J$ |: d1 y
  4.    /* 省略未写 */
    $ |& K/ q+ a/ v

  5. ! ]. [- d. x9 Y1 Z# ?
  6. /* 注意DMA的位宽和对齐设置 */+ {' |/ E% D! @8 ?" Q4 `. u
  7.   if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && (hspi->hdmarx->Init.MemDataAlignment !=
    # j/ I! p- F: N/ z- g
  8. DMA_MDATAALIGN_WORD))  || ) N7 W4 b  [! w3 x& ?+ q
  9.       ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) && ((hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_HALFWORD) && (hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_WORD))))
    9 r; i7 c5 u. Y; N7 M" c
  10.   {) `* T$ m5 Y0 h+ f+ G9 m
  11.   }
    3 }/ L$ j3 b: {5 M

  12. ) w/ p7 T/ v4 I4 z# j7 B% A: P$ H
  13. /* 调整DMA对齐和数据大小 */
    / E& U, J4 C7 @
  14.   if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)! R! _$ M# }5 |' {5 J! M
  15.   {
    $ G6 x0 z: q! A1 D$ q- b
  16.      /* 省略未写 */( B2 I* [1 v) U7 s; d4 O
  17.   }
    % Q+ u7 A) N$ l9 g, |
  18.   else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)9 ]8 H  {1 m+ Q6 o! O
  19.   {8 h# ]8 S  \) G- H3 |
  20.      /* 省略未写 */
      n* ?: R0 w5 |
  21.   }
    2 y. ], i$ ^4 c. b
  22.   else
    1 P( B+ ?4 Z" \6 p- k
  23.   {
    ! q6 J% I# T8 n
  24.       /* 省略未写 */, ]# e& r& k" C8 y% Q
  25.   }- e+ {0 z8 b  A" R0 C$ C( {
  26.   {7 w6 H% ?* @2 S9 B
  27. /*  DMA接收配置 */
    * M4 o5 k. R# `+ a% u
  28.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->RXDR, (uint32_t)hspi->pRxBuffPtr,
    3 C4 l0 A: q8 [, Y. [: ]1 s
  29. hspi->RxXferCount))9 G8 ?; v" O" |6 ~; u) [. `- o
  30.   {
    . f- R- a6 V& H. X9 E8 ^( \
  31. ; K9 E% J- G% b
  32.   }
    & n) {3 d) D+ C. \' D  @& _

  33. 4 `! u; |9 o( {
  34. /* DMA发送配置 */7 @4 d' W- T% b* p6 p( S6 u
  35.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->TXDR,
    + ^& F0 ~2 P/ y% n* }
  36. hspi->TxXferCount))4 M9 _  w: c* p/ ]/ l+ G' ^
  37.   {" c: Z2 ]" b; M& C0 ?; r- M
  38.   }- W# R* A6 X3 u
  39. + |  Q# t+ D: Z8 l
  40.   /* 省略未写 */3 ?1 r2 y+ ?9 c2 h( X5 {% y
  41. }
    / a3 B2 G; d  G' ^
复制代码
; _1 W" K( d  V0 g
函数描述:1 E; b5 p' G% T/ C  q0 E! e

  D. E4 @% `  s+ E- P8 v" X* s6 x此函数主要用于SPI数据收发,全双工DMA方式。; B( `/ ~+ V& p! ]

4 R. f) B  \" @% W! f+ f8 P$ o函数参数:  A0 ?8 Z8 C  q. y3 |0 X5 d# \6 p

) w' U) P8 O' |* P; @  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
: i8 \' u8 b) j  w* C  第2个参数是发送数据缓冲地址。
* M2 f8 I! H) i- |, V9 p  第3个参数是接收数据缓冲地址。
8 \8 u1 Z" q# o8 ^+ v0 v  第4个参数是传输的数据大小,单位字节个数。
. B9 ~$ t, s" d. E2 F  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。. s+ K3 I4 M  b/ g9 Q

! u, B9 h& g5 m! @
1 e+ r; h/ S& o5 W) t  f使用举例:
( V, T& a( Q3 ~4 h' ?( M
5 f+ s5 W$ y/ z
  1. SPI_HandleTypeDef hspi = {0};3 {2 v; R+ k. W" `
  2. ; ]8 C: [- Q# h5 W
  3. if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    $ F& y( |& J# k' }
  4. {6 [9 _8 Q( h2 S# E7 y
  5.     Error_Handler(__FILE__, __LINE__);
    + _8 g( [% o! c4 l4 P# h0 e
  6. }9 {2 r2 y: E# i* z0 W5 q
复制代码

# ^& y3 p' k) w7 n6 T; o72.5 总结$ z9 d/ v  h# U- g9 K6 e: Z- x8 E
本章节就为大家讲解这么多,要熟练掌握SPI总线的查询,中断和DMA方式的实现,因为基于SPI接口的外设芯片很多,熟练后,可以方便的驱动各种SPI接口芯片,以便选择合适的驱动方式。
; A* f; z3 M. n4 S7 I' I5 `; s9 I: M; l) f

) y/ j! w# C' d/ }; T3 w
6 w0 S8 G0 `* b  q& n% s0 z6 t0 @# k2 [+ F3 ?$ z( r
) x- `. T0 ]# S$ {. A
收藏 评论0 发布时间:2021-12-20 19:00

举报

0个回答

所属标签

相似分享

官网相关资源

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