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

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

[复制链接]
STMCU小助手 发布时间:2021-12-20 19:00
72.1 初学者重要提示, {9 c+ D6 ?5 \6 W! t2 b1 ?
  STM32H7的SPI支持4到32bit数据传输,而STM32F1和F4系列仅支持8bit或者16bit。
+ L" ]  S( m( Y; a  STM32H7的主频400MHz时,SPI1, 2, 3最高通信时钟是100MHz,而SPI4, 5, 6是50MHz。
# {! P- w9 I# w  J' l  STM32H7的MISO和MOSI引脚功能可以互换,使用比较灵活。
% p8 O. S3 k9 X) N! i  SPI总线的片选引脚SS在单一的主从器件配置下是可选的,一般情况下可以不使用。
% }7 v6 x2 [5 P3 ~# k% k  v
8 w2 d' ~( Z) ^* K  G: P72.2 SPI总线基础知识
. J. N' m3 G4 l: a9 h! j72.2.1 SPI总线的硬件框图
) X- u7 I8 [/ v5 V% }
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SPI的基本功能,然后再看手册了解细节。
: a# L0 T( m# T8 K  z
3 r. d' [- I0 v+ s6 i
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
$ [: u* O& k/ |3 m* C

' h7 ]+ A! S2 w# N: X2 T0 M6 W& \通过这个框图,我们可以得到如下信息:9 b8 k& L0 T5 X" h8 o" M: ]
  spi_wkup输出
0 s& z; P+ U3 e$ W3 M7 H) n) W
) e* h) x, g% w- e5 ]  `  B9 D4 A低功耗唤醒信号。# ^- |, p2 u5 q/ z9 o( F! }! t
  spi_it输出
2 F; G  B! ^: Q
, z* j0 x9 M: {. y/ H( s* @! A3 i# [! w8 T3 L$ z5 u4 J7 Z5 m# g5 s) q( L
spi的中断请求信号。+ ^6 H: i1 M. V& q0 N6 ~
  spi_tx_dma
$ [4 L" Q/ D' q. i* H& S  spi_rx_dma
' N/ p0 M0 t$ \
& U. I' s3 \/ x  ]# \7 A$ a( M2 K- I1 I
spi的DMA发送和接收请求信号。  `: z8 ^4 b8 r( F
  spi_pclk
# q, F: H" F6 B0 H' C2 @4 c$ g
0 Y0 Z6 K3 V4 a0 [5 c: ~
" `4 n- j% o; E为寄存器提供时钟。. {) L, v3 \8 ?
  spi_ker_ck
$ {/ [1 Y/ k: O( M# M+ L  |
/ |. _4 d* H5 a
3 w5 I2 e* q3 u为spi内核时钟。
. N2 L2 s' j3 R$ G( k4 ?3 E7 a& p  SCK(CK),Serial Clock# p2 L4 X: \- t
2 V9 R3 X( R1 f" T

* S- y& l0 h' M+ l" j. D& x此引脚在主机模式下用于时钟输出,从机模式下用于时钟输入。
/ l2 G# Z3 T+ B% t: v2 ^* R, _) v  MISO(SDI),Master In / Slave Out data) u" [( U8 n) n

  t9 g" ^. c+ g( ]) G! j0 f6 b* q% i: \4 j; V+ l0 n; A
此引脚在从机模式下用于发送数据,主机模式下接收数据。
& a6 ]) X8 r9 o2 _$ a  MOSI(SDO), Master Out / Slave In data
. [% h: a: m0 Q9 w0 V& A/ V" }4 B3 r* f/ H' S& N

* H4 C# i5 j0 f此引脚在从机模式下用于数据接收,主机模式下发送数据。
2 [% D: P3 @% V  a+ @, ^7 j  SS(WS), Slave select pin& ^0 C4 x. o' C5 P" D) \; R0 D
1 S. q( `6 R: b, q$ a$ s& P
0 }1 ?$ a* X  V: t" [9 c0 [; h
根据SPI和SS设置,此引脚可用于:+ Z* ]8 \/ d$ \3 e" F# V7 C
a. 选择三个从器件进行通信。* v4 a2 D6 L% }, a6 {
4 z3 {+ D4 t& n0 d. B5 {
b. 同步数据帧。
# r+ D5 I6 x" r9 Q& ]
3 W0 f# `6 K. `0 Y0 G% G) x+ g! gc. 检测多个主器件之间是否存在冲突。- m$ d9 X# K8 F" ^

$ M+ M! ^* ?; B( L. y+ a通过这个框图还要认识到一点,SPI有三个时钟域,分别是寄存器所在的ABP总线时钟域,内核时钟发生器时钟域以及内核时钟发生器分频后的串行时钟域。
: Q1 U# c  g; X0 U5 L. Z7 o! B) z, f( a% [7 R) ]
72.2.2 SPI接口的区别和时钟源(SPI1到SPI6)

8 s) J( [: S6 {0 b- Q- U这个知识点在初学的时候容易忽视,所以我们这里整理下。
2 E) t/ C0 B; Q1 R  {SPI1到SPI6的区别
2 a5 N. {4 q) y  SPI1,SPI2和SPI3支持4到32bit数据传输,SPI4,SPI5和SPI6是4到16bit数据传输。8 S4 Q" P; y3 C* H1 b7 S, j! L- f' k
  SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit。# o7 o5 o9 o* m) B, V3 m2 i$ m
0 J' i# k: k$ h6 H/ b* H: b
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
! @) B1 ~$ R$ l

, u, W4 m/ W% g( `6 C  SPI1到SPI6的所在的总线(对应SPI框图的SPI_CLK时钟域)( T: r4 ?$ r2 ~% a. S
! I# Y; j8 U" i6 V4 l* s, ^: Q
9 J4 l+ x$ Y, x! [  C7 u
SPI1,SPI4和SPI5在APB2总线,SPI2,SPI3在APB1总线,SPI6在APB4总线。注意,SPI的最高时钟不是由这些总线决定的。
' r3 V* I) g8 n. y9 }+ W# m, t$ n9 G+ O7 K
  SPI1到SPI6的支持的最高时钟(对应SPI框图的SPI_KER_CK)
. e7 h! a0 v; }4 z/ M" V; c1 \8 L; E5 s$ B* T
3 `% C% e7 a4 q- O6 X
STM32H7主频在400MHz下,SPI1,SPI2和SPI3的最高时钟是200MHz,而SPI4,5,6是100MHz, 以SPI1为了,可以选择的时钟源如下:
& ~* H5 L$ h2 l1 [, J4 }* Y2 I* m$ F( T3 V% |8 ~0 X
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
/ l6 E* @1 t0 B6 E2 n2 p/ y
) A/ Y, M% ?( P  u. j# e, a) y
这里特别注意一点,SPI工作时最少选择二分频,也就是说SPI1,2,3实际通信时钟是100MHz,而SPI4,5,6是50MHz。
* }: y9 v3 d/ r
# }: k5 d( Y3 A. o: ~72.2.3 SPI总线全双工,单工和半双工通信
0 \9 V' K' ^7 s" Z2 l9 Y! w9 w片选信号SS在单一的主从器件配置下是可选的,一般情况下可以不使用。但需要同步数据流,或者用于TI模式时需要此信号。
. _5 A1 T9 \. G$ h' |' T
; N  W) _' a  Y' J, _6 j2 a+ w  全双工通信
' u7 ~8 ~; t, q7 G全双工就是主从器件之间同时互传数据,SPI总线的全双工模式接线方式如下:& x  }  @2 d; k6 U

8 E( t/ o. k# h% p) }
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

0 i7 |" t9 N* H- w  ^9 U6 X, r/ S/ }# A
关于这个接线图要认识到以下几点:5 n* n4 |* E& }0 O  e2 T) _
  注意接线方式,对于主器件来说MISO引脚就是输入端,从器件的MISO是输出端,即Master In / Slave Out data。MOSI也是同样道理。7 @9 N% G% n$ V  u0 A1 b
  每个时钟信号SCK的作用了,主器件的MISO引脚接收1个bit数据,MOSI引脚输出1个bit数据。
9 o4 T! h9 h- V5 x  这种单一的主从接线模式下,SS引脚可以不使用。6 L5 b- {% i' u1 |6 t+ U1 N8 A
% ~6 W) Y$ y0 k/ R) w
半双工通信2 ~8 `7 u# D6 p
半双工就是同一个时刻只能为一个方向传输数据,SPI总线的半工模式接线方式如下:$ M/ j3 Q2 H5 F1 x2 T, ^0 Z

! G! o* M2 T8 M9 h% n
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

% `% ]: V5 ]9 h* k
8 u1 A* B. V% D8 `) k8 b关于这个接线图要认识到以下几点:7 n7 l6 }) \+ f. }4 \- r

) [2 J" H! ^9 L! H% h- V  更改通信方式时,要先禁止SPI。
! Q/ l( {* p+ ~, D  主器件的MISO和从器件的MISO不使用,可以继续用作标准GPIO。
% P# s/ u7 ~, @' B1 q! H. j" A  1KΩ的接线电阻很有必要,因为当主器件和从器件的通信方向不是同步变化时,容易出现其中一个输出低电平,另一个输出高电平,造成短路。
7 c; f" S9 z4 p# V7 x  这种单一的主从接线模式下,SS引脚可以不使用。& J7 u- G( x2 n1 }3 Y% S
  3 O; \4 m$ c7 U# b- M
单工模式8 E6 C) P  M! s0 `2 ?
单工就是只有一种通信方向,即发送或者接收,SPI总线的全双工模式接线方式如下:
) w! P. v: C/ m
! ]( y4 V. g% i1 O
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
' V2 N+ O' L. K

* x9 n" H( A0 X% _8 l$ u关于这个接线图要认识到以下几点:
: H# m- L( h! M8 j1 @4 }& d# F
& ]: W5 M/ R1 L) ]' ]9 G9 I5 j1 |  未用到的MOSI或者MISO可以用作标准GPIO。
; l: g, `9 T& _) \7 F( f+ F! E4 y  这种单一的主从接线模式下,SS引脚可以不使用。7 q0 Z* e" o) w7 t; c

# n: Q8 q6 j) s( C1 L3 ^% L72.2.4 SPI总线星型拓扑
  z, }4 V3 U1 `  ]# CSPI总线星型拓扑用到的地方比较多,V7开发板就是用的星型拓扑外接多种SPI器件:
% n/ F. [0 q# z+ J2 F- R0 ?. E. ^7 i2 }
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

: g4 L- U2 q- d
% k! }  ^* E5 O' ?$ Z$ z关于这个接线图,有以下几点需要大家了解:
! G1 ^& S$ A$ w+ ^
0 e1 t% h$ v7 e8 ]" J5 ?  主器件的SS引脚不使用,使用通用GPIO控制。为每个器件配一个SS引脚,方便单独片选控制。1 }' Q) D. H5 _& p! E! w: s
  从器件的MISO引脚要配置为复用开漏输出(很多外部芯片在未片选时,数据引脚是呈现高阻态)。
# c( Y+ J$ \! o- n6 ~: G+ [6 h6 I6 i& z: g, I% ^
  h2 M. c( t; K$ H2 k
72.2.5 SPI总线通信格式
; M- e- l: M- N+ x' rSPI总线主要有四种通信格式,由CPOL时钟极性和CPHA时钟相位控制:
# ~/ P1 }5 z# n+ _9 w# E3 j+ r5 ~* |, J
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
6 G; {( H4 V# [  t3 A; l: e. q+ g
9 D8 p, m) N1 Q1 G  Q, X; Z
四种通信格式如下:
! D. ^. Y: L, V$ d. Z9 \  当CPOL = 1, CPHA = 1时
$ ~* B* z  F2 m4 Y& z% Z5 M0 C+ S" v5 t; m

& n2 L' }6 @3 s% USCK引脚在空闲状态处于低电平,SCK引脚的第2个边沿捕获传输的第1个数据。
/ L; o% B6 x) z: \% v% D3 ]  当CPOL = 0, CPHA = 1时1 d, H% E- _+ N: y

( U) s% }3 p6 J1 q( ?+ s& R' V) H# |+ I6 b
SCK引脚在空闲状态处于高电平,SCK引脚的第2个边沿捕获传输的第1个数据。% _& U" x! K7 r, b# ?- c6 j4 B
  当CPOL = 1, CPHA = 0时7 A* I& S  ?. D4 V
5 A3 G- F& g) @" }: ~9 \
" d9 G/ c4 o9 n: x6 y" y" X, I# o
SCK引脚在空闲状态处于低电平,SCK引脚的第1个边沿捕获传输的第1个数据。
3 p1 d8 {& E9 K) S. s$ S1 S! R6 s: [  当CPOL = 1, CPHA = 0时
" s9 t' e" `8 ~  j" f* g+ f8 l) m1 d
$ }! ^" X* b) N8 |7 `+ ~* z) P4 g
5 b& s2 {$ J3 d6 wSCK引脚在空闲状态处于高电平,SCK引脚的第1个边沿捕获传输的第1个数据。
( V# ?+ O9 K' K& Y' q2 Z( s2 P6 I  Y& D" l2 p7 Q- J$ q. c
72.3 SPI总线的HAL库用法
) A) c7 f9 q# F* h3 [/ {
72.3.1 SPI总线结构体SPI_TypeDef
. X4 G8 X  g, u/ z: LSPI总线相关的寄存器是通过HAL库中的结构体SPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
0 X2 |& `7 [, V, {
1 l! s0 G- N. _: n- B
  1. typedef struct& {2 _9 q8 d# ]
  2. {. q& ]1 |5 k+ w
  3.   __IO uint32_t CR1;           /*!< SPI/I2S Control register 1,                      Address offset: 0x00 */& v/ X3 i( _6 w) V
  4.   __IO uint32_t CR2;           /*!< SPI Control register 2,                          Address offset: 0x04 */  H/ B3 Y7 w: M7 L, t4 Z
  5.   __IO uint32_t CFG1;          /*!< SPI Configuration register 1,                    Address offset: 0x08 */1 Y+ r+ ^; o" L1 s0 o
  6.   __IO uint32_t CFG2;          /*!< SPI Configuration register 2,                    Address offset: 0x0C */
      `1 R, k. A6 j  b) {
  7.   __IO uint32_t IER;           /*!< SPI/I2S Interrupt Enable register,               Address offset: 0x10 */
    ' n4 @( p+ M* v7 t# C4 @6 @% E
  8.   __IO uint32_t SR;            /*!< SPI/I2S Status register,                         Address offset: 0x14 */
    . K2 m6 _& I; O
  9.   __IO uint32_t IFCR;          /*!< SPI/I2S Interrupt/Status flags clear register,   Address offset: 0x18 */
    : d5 b1 G* \+ X+ z
  10.   uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                        */
    / V/ k) e6 Y# g$ e  e% L) u# ^
  11.   __IO uint32_t TXDR;          /*!< SPI/I2S Transmit data register,                  Address offset: 0x20 */
    5 {# B2 h. E) _- M0 K% n6 R
  12.   uint32_t      RESERVED1[3];  /*!< Reserved, 0x24-0x2C                                                   */
    % B! T* X% A; O) {
  13.   __IO uint32_t RXDR;          /*!< SPI/I2S Receive data register,                   Address offset: 0x30 */  I# p5 p4 C; F* ^; O
  14.   uint32_t      RESERVED2[3];  /*!< Reserved, 0x34-0x3C                                                   */
    8 A+ S( k6 p3 `! f9 Z# j. E
  15.   __IO uint32_t CRCPOLY;       /*!< SPI CRC Polynomial register,                     Address offset: 0x40 */8 v9 Z0 l5 Z9 L( e& v
  16.   __IO uint32_t TXCRC;         /*!< SPI Transmitter CRC register,                    Address offset: 0x44 */1 C( X/ S$ F' a) V7 F% H
  17.   __IO uint32_t RXCRC;         /*!< SPI Receiver CRC register,                       Address offset: 0x48 */
    : i2 k. Z+ ?: {( D5 I
  18.   __IO uint32_t UDRDR;         /*!< SPI Underrun data register,                      Address offset: 0x4C */! U' t: O1 |" P- n
  19.   __IO uint32_t I2SCFGR;       /*!< I2S Configuration register,                      Address offset: 0x50 */" s* o  H. j, {

  20. . |- m) m$ }- P
  21. } SPI_TypeDef;
复制代码
6 |9 ^. ^; E& }/ R) A5 A8 I( Y6 k; H
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
# D! E/ ~) {" L* d) I0 d) F  @" F/ {) J
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:4 P2 `0 V  N  T% G0 ?* N0 D" s

1 P  {, K+ O/ q) X
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */+ [' y2 |+ B3 j5 D0 r+ C
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
* E! `- v2 M# o+ M
下面我们看下SPI的定义,在stm32h743xx.h文件。
0 B( q( p: u% ?6 Y, T: S! w! ^
5 S- t$ S, `" I+ G: e* q8 _/ b
  1. #define PERIPH_BASE           (0x40000000UL) 5 r/ {5 k9 K2 q  Z# r
  2. #define D2_APB1PERIPH_BASE     PERIPH_BASE( U, _( {' z" z9 s1 T2 \# D0 {
  3. #define D2_APB2PERIPH_BASE    (PERIPH_BASE + 0x00010000UL)9 q) s8 c3 \8 q0 [- b0 h
  4. #define D3_APB1PERIPH_BASE    (PERIPH_BASE + 0x18000000UL)
    " }2 Q* S. a: E7 {' _

  5. 0 u! O3 n9 S9 i6 G) B
  6. #define SPI2_BASE             (D2_APB1PERIPH_BASE + 0x3800UL)
    1 P4 t( b* A7 }( a
  7. #define SPI3_BASE             (D2_APB1PERIPH_BASE + 0x3C00UL)0 Y: u6 d5 X" b% e+ x3 t
  8. #define SPI1_BASE             (D2_APB2PERIPH_BASE + 0x3000UL). i2 P# B% j; O2 s
  9. #define SPI4_BASE             (D2_APB2PERIPH_BASE + 0x3400UL)
    : R0 P: a: I" a1 ^* {! \
  10. #define SPI5_BASE             (D2_APB2PERIPH_BASE + 0x5000UL)" F: O# b% O! j7 O
  11. #define SPI6_BASE             (D3_APB1PERIPH_BASE + 0x1400UL)
    , x9 v* V0 B' ]

  12. " O2 D% Q, f7 ?8 A' d( h6 @1 |9 S( }
  13. #define SPI1                ((SPI_TypeDef *) SPI1_BASE)0 A/ L0 ~" ?, t" j% m
  14. #define SPI2                ((SPI_TypeDef *) SPI2_BASE)3 i" ^+ K. A3 V6 ]7 n
  15. #define SPI3                ((SPI_TypeDef *) SPI3_BASE), u% i6 v  z& f
  16. #define SPI4                ((SPI_TypeDef *) SPI4_BASE)7 ~* k. N" [4 [5 y4 L$ Z2 i, R
  17. #define SPI5                ((SPI_TypeDef *) SPI5_BASE)
    , F4 m3 C" K/ `( v1 s
  18. #define SPI6                ((SPI_TypeDef *) SPI6_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x58001400
复制代码
% B# s* p+ Q$ q4 y+ g' K4 r1 U
我们访问SPI的CR1寄存器可以采用这种形式:SPI->CR1 = 0。/ p- a" z( l. l; `- O0 @: p7 q

7 E) |" L2 S% U/ P1 B2 n& d6 n72.3.2 SPI总线初始化结构体SPI_InitTypeDef
* j. J7 m3 E8 X/ }
下面是SPI总线的初始化结构体,用到的地方比较多:
4 T- z& V/ o( b) @0 V1 c& t
2 |* B7 j5 ]3 y; f  e
  1. typedef struct
    0 N" Z7 W' z4 l$ Z% s
  2. {8 n6 q% [. N8 Y0 F7 k9 m" y; x1 a
  3.   uint32_t Mode;                            ) J: H9 R" s% D6 y5 g* K9 \
  4.   uint32_t Direction;                      2 X- K" X% x# ?- m# \1 m
  5.   uint32_t DataSize;                          1 U/ Q2 K4 f8 Q- M5 K% N
  6.   uint32_t CLKPolarity;                       . [1 C  t0 \  {0 [' v2 a- l
  7.   uint32_t CLKPhase;                        
    % K3 a. z+ z3 M- {9 ~$ `
  8.   uint32_t NSS;                             
    ; ]2 K, q' d  S. I% {/ s  h
  9.   uint32_t BaudRatePrescaler;               
    ! C3 M* B5 W. L  e" A& i
  10.   uint32_t FirstBit;                         + x- v7 P2 o" ^" @
  11.   uint32_t TIMode;                          
    9 w, c% S3 L$ b0 j  F
  12.   uint32_t CRCCalculation;                  
    7 h% ]( x  u" b+ ]; o
  13.   uint32_t CRCPolynomial;                     0 a: F, P9 \* ~2 q
  14.   uint32_t CRCLength;                        4 D9 e3 \  G: O  e7 m& e
  15.   uint32_t NSSPMode;                        
    7 ^2 s3 c0 _; ]4 x# K
  16.   uint32_t NSSPolarity;                    ) j) g0 w) o" `7 ^' C9 R0 Z# a
  17.   uint32_t TxCRCInitializationPattern;       2 u0 P  g3 B; _3 |3 C
  18.   uint32_t RxCRCInitializationPattern;      
    4 b5 _7 A! ~2 ~: \: Z
  19.   uint32_t MasterSSIdleness;                 % o: z6 m& ~/ O) s7 [
  20.   uint32_t MasterInterDataIdleness;           ! t5 W  X2 V# R! f
  21.   uint32_t MasterReceiverAutoSusp;         
    $ i- c2 B* U/ x
  22.   uint32_t MasterKeepIOState;               
    + N- l- B4 J' h9 i7 F/ D2 x' ~
  23.   uint32_t IOSwap;                          ! _; h# T! g1 a7 k! l0 _1 g( x: f
  24. } SPI_InitTypeDef;
复制代码

2 C' d8 a6 A: v9 |( E- z下面将结构体成员逐一做个说明:
6 R/ o# y* z% N! @- }- a+ O; y  Mode
) ?* V. w6 F" ?* G: }
7 f1 k* w4 [/ M' Q$ V用于设置工作在主机模式还是从机模式。1 _- S) e" i* p% B( @
  1. #define SPI_MODE_SLAVE              (0x00000000UL)0 Y( j- O8 v( E& {
  2. #define SPI_MODE_MASTER             SPI_CFG2_MASTER
复制代码

& r2 a* ]1 w: N, ~  Direction8 C' |: Q' D/ @' J5 ?; f3 A( ?
用于设置SPI工作在全双工,单工,还是半双工模式。
- q, W0 u5 J: P1 f+ @3 T
8 ^( Y' P% b4 G# r0 L5 [
  1. #define SPI_DIRECTION_2LINES           (0x00000000UL)     /* 全双工 */
    & e# O* P7 U5 Z; H5 ~- }
  2. #define SPI_DIRECTION_2LINES_TXONLY     SPI_CFG2_COMM_0   /* 单工,仅发送 */
    5 O/ Q% Z  O! N5 i, z' a- R
  3. #define SPI_DIRECTION_2LINES_RXONLY     SPI_CFG2_COMM_1   /* 单工,仅接收 */
    . N( ^9 j1 ^6 Q! p4 _
  4. #define SPI_DIRECTION_1LINE             SPI_CFG2_COMM     /* 半双工 */
复制代码
/ x& L" u. ~8 J* n, {
  DataSize
6 ~! Z) K: m9 N& x用于设置SPI总线数据收发的位宽,支持4-32bit。7 [3 W, S: ~" t
6 C. X) d- Y6 D) [  r
  1. #define SPI_DATASIZE_4BIT                             (0x00000003UL)
    - T0 _, ^+ Q4 y
  2. #define SPI_DATASIZE_5BIT                             (0x00000004UL)
    % @) i& R- H$ M% U9 M" C9 i% ?. F
  3. #define SPI_DATASIZE_6BIT                             (0x00000005UL)6 v3 S5 Z) k' M: Z" x6 T' i, R8 r7 {  C
  4. #define SPI_DATASIZE_7BIT                             (0x00000006UL)- e! @1 K& L2 m0 Q2 ^
  5. #define SPI_DATASIZE_8BIT                             (0x00000007UL)
    4 X/ U) D! j2 U$ E! j8 a# p
  6. #define SPI_DATASIZE_9BIT                             (0x00000008UL)5 B6 [, \- s1 w5 H2 j  n4 o" |
  7. #define SPI_DATASIZE_10BIT                            (0x00000009UL)) X" B: F8 u4 ^; P4 `8 a$ f
  8. #define SPI_DATASIZE_11BIT                            (0x0000000AUL)$ B( @* _" }. }2 B
  9. #define SPI_DATASIZE_12BIT                            (0x0000000BUL)# }" r: x2 U5 Q/ U/ f
  10. #define SPI_DATASIZE_13BIT                            (0x0000000CUL)
    # I" o1 {2 F  a: Z+ x
  11. #define SPI_DATASIZE_14BIT                            (0x0000000DUL)& b9 r& t& f$ o3 k. Z. a* |0 p4 ^8 q
  12. #define SPI_DATASIZE_15BIT                            (0x0000000EUL)  v- F+ m& P$ j; d# K
  13. #define SPI_DATASIZE_16BIT                            (0x0000000FUL)
    - k/ z! |$ N: N9 a1 q
  14. #define SPI_DATASIZE_17BIT                            (0x00000010UL)
      ?! V7 J1 k( A) O% s
  15. #define SPI_DATASIZE_18BIT                            (0x00000011UL)
      t7 Q3 z( B' d$ I# j8 K; |. G% l
  16. #define SPI_DATASIZE_19BIT                            (0x00000012UL)! J' X/ o: s% \. A/ X; }; u5 @
  17. #define SPI_DATASIZE_20BIT                            (0x00000013UL)
    9 y- g5 v  j' [5 I) p; F# S  ^
  18. #define SPI_DATASIZE_21BIT                            (0x00000014UL)" X, d& s$ y" ^3 p- Y6 l+ i/ d
  19. #define SPI_DATASIZE_22BIT                            (0x00000015UL)0 v- j' Z6 l( Q3 p! ^
  20. #define SPI_DATASIZE_23BIT                            (0x00000016UL)
      ^. n. q7 _. R5 q6 x9 V# ]
  21. #define SPI_DATASIZE_24BIT                            (0x00000017UL)3 ?8 s( E+ u+ P9 X1 D  a9 N+ S
  22. #define SPI_DATASIZE_25BIT                            (0x00000018UL)
    1 D+ w2 N8 I, e( @+ z. f1 ]% R
  23. #define SPI_DATASIZE_26BIT                            (0x00000019UL)
    : l8 Q' M" P% q# Q/ _" H3 ^
  24. #define SPI_DATASIZE_27BIT                            (0x0000001AUL)* z5 }9 i  R* g. e; `6 q% Y
  25. #define SPI_DATASIZE_28BIT                            (0x0000001BUL)
    # U/ p% K% {" w4 @* B* M/ c
  26. #define SPI_DATASIZE_29BIT                            (0x0000001CUL)
    % w/ `! a. _! d  M
  27. #define SPI_DATASIZE_30BIT                            (0x0000001DUL): O1 b# a* [+ E6 L! u
  28. #define SPI_DATASIZE_31BIT                            (0x0000001EUL)3 ~( o9 B' w* L+ V
  29. #define SPI_DATASIZE_32BIT                            (0x0000001FUL)3 ]0 T! _7 @4 S# {$ a6 S
复制代码

: r& o1 w+ M7 t1 u& p% K" @! O3 o. ?3 w
  CLKPolarity
. {9 @; h" ?1 X, L& R& T用于设置空闲状态时,CLK是高电平还是低电平。& b$ k6 Q5 ^( H5 N# L4 |
  1. #define SPI_POLARITY_LOW       (0x00000000UL)9 l/ I9 d& I/ y/ C
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码
: C9 f: N( I3 o5 V) z- N* U- w
  NSS
3 X7 k0 E2 N% N" z: B5 ]用于设置NSS信号由硬件NSS引脚管理或者软件SSI位管理。
4 m7 b4 |+ O. H6 H  P
( T, w4 y* D* @* l: g
  1. #define SPI_NSS_SOFT                                  SPI_CFG2_SSM
    ) W' Z1 P+ R" M! _9 n3 ]) t9 z
  2. #define SPI_NSS_HARD_INPUT                            (0x00000000UL)8 _7 D( J7 W* Z- R. t+ @4 h8 e. ?
  3. #define SPI_NSS_HARD_OUTPUT                           SPI_CFG2_SSOE
复制代码

: U" r) g% r% T2 w# |  BaudRatePrescaler, w5 j3 w3 h$ v7 h  p, b) d6 W
用于设置SPI时钟分频,仅SPI工作在主控模式下起作用,对SPI从机模式不起作用。
8 s: B$ C. g8 a# a
( l% y  f& x: [' Z1 E' H  y
  1. #define SPI_BAUDRATEPRESCALER_2                       (0x00000000UL)3 A2 a6 c. L* r/ P# `/ E! x, r
  2. #define SPI_BAUDRATEPRESCALER_4                       (0x10000000UL)
    * {& c: Q! ^5 T% d
  3. #define SPI_BAUDRATEPRESCALER_8                       (0x20000000UL)
    : E6 w$ ]/ ~6 [& M7 I7 z9 ~
  4. #define SPI_BAUDRATEPRESCALER_16                      (0x30000000UL)
    # U  T1 s: V; ?; u
  5. #define SPI_BAUDRATEPRESCALER_32                      (0x40000000UL)
    7 j# a7 W: n- p7 K0 B8 ~8 h
  6. #define SPI_BAUDRATEPRESCALER_64                      (0x50000000UL)
    + i3 `7 N0 U0 v# o
  7. #define SPI_BAUDRATEPRESCALER_128                     (0x60000000UL)
    : b8 |' H  d9 d* x0 q0 n7 `# W
  8. #define SPI_BAUDRATEPRESCALER_256                     (0x70000000UL)
复制代码

7 L+ }5 Q! ]- M  FirstBit5 M) ]: C; e5 C, W8 V/ G7 H- u7 q
用于设置数据传输从最高bit开始还是从最低bit开始。
6 {, [' N1 j* K  }( }; q; l1 v
  1. #define SPI_FIRSTBIT_MSB                              (0x00000000UL)' R7 n3 H: `- F/ y" K/ A
  2. #define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST
复制代码
5 }+ Z+ b9 A3 D" W- ^; V( i* Y
  TIMode
9 R( f3 Y9 h1 u* m% B- K  {用于设置是否使能SPI总线的TI模式。; A5 p' C' s8 T* D, B
  1. #define SPI_TIMODE_DISABLE               (0x00000000UL)
    ) |, L5 z* p" R7 r
  2. #define SPI_TIMODE_ENABLE                SPI_CFG2_SP_0
复制代码

# N9 e/ _% d- F9 ^) _- x  CRCCalculation
) O( A2 e2 u1 X& K/ L4 }; K用于设置是否使能CRC计算。/ {1 l$ K5 j& C$ E2 {' Q
  1. #define SPI_CRCCALCULATION_DISABLE                    (0x00000000UL)) {) h) r! A1 G8 d! ^4 V) T# Z* H
  2. #define SPI_CRCCALCULATION_ENABLE                     SPI_CFG1_CRCEN
复制代码
& b" i1 C  @3 W
  CRCPolynomial
# M# U/ D1 P8 a3 {& @6 {用于设置CRC计算使用的多项式,必须是奇数,范围0到65535。
* Z: u6 x4 q, ^+ ~. o5 n, x
: D$ T8 a: O" \* B: ]; A3 P! L; w( e  CRCLength
( p/ r& Z5 p  P8 U/ x& Z  H用于设置CRC计算时的CRC长度。大小要与同属此结构体的DataSize一致。或是DataSize的整数倍。+ A4 k% f' G' c! f# h
" l& a+ z! X! }0 l* ?
  1. #define SPI_CRC_LENGTH_DATASIZE                       (0x00000000UL)1 B% a, K2 _  P, c/ D
  2. #define SPI_CRC_LENGTH_4BIT                           (0x00030000UL)& \8 l% P1 q! A
  3. #define SPI_CRC_LENGTH_5BIT                           (0x00040000UL). f9 [  S( d' h$ T* c
  4. #define SPI_CRC_LENGTH_6BIT                           (0x00050000UL)
      L2 B/ W) o. {1 I! G7 O0 L4 {
  5. #define SPI_CRC_LENGTH_7BIT                           (0x00060000UL)( b; R3 P! d, I9 n) Z/ @
  6. #define SPI_CRC_LENGTH_8BIT                           (0x00070000UL)2 j: K1 `4 ~: `, f
  7. #define SPI_CRC_LENGTH_9BIT                           (0x00080000UL)7 \' N! o8 V9 @8 U. a  Z' T7 ]
  8. #define SPI_CRC_LENGTH_10BIT                          (0x00090000UL)
    2 ]6 d/ a6 U' x$ o; f
  9. #define SPI_CRC_LENGTH_11BIT                          (0x000A0000UL)- i" H3 {% d4 X- X, P* _
  10. #define SPI_CRC_LENGTH_12BIT                          (0x000B0000UL)2 V7 X& f  C  a# p. b) I0 g1 G5 i
  11. #define SPI_CRC_LENGTH_13BIT                          (0x000C0000UL)
      m  Z+ V; |$ U0 b& A8 k
  12. #define SPI_CRC_LENGTH_14BIT                          (0x000D0000UL)" Q- K) o9 P7 H) C: }: Z* i+ y
  13. #define SPI_CRC_LENGTH_15BIT                          (0x000E0000UL)
    8 {. V' i' A* c% a1 Y
  14. #define SPI_CRC_LENGTH_16BIT                          (0x000F0000UL)  Q3 t- u4 N# n  j
  15. #define SPI_CRC_LENGTH_17BIT                          (0x00100000UL)
    " r" W% {9 Q6 s9 X0 ~2 u4 w
  16. #define SPI_CRC_LENGTH_18BIT                          (0x00110000UL)  G  E' w2 h/ y; }
  17. #define SPI_CRC_LENGTH_19BIT                          (0x00120000UL)
    # A% |8 y( u& @  K" l  S
  18. #define SPI_CRC_LENGTH_20BIT                          (0x00130000UL)
    0 K' D4 x4 I7 c
  19. #define SPI_CRC_LENGTH_21BIT                          (0x00140000UL)' d; ?/ {0 S2 D! _- x" O# _
  20. #define SPI_CRC_LENGTH_22BIT                          (0x00150000UL)5 z& Q  y: A0 Y5 `, V$ r& u
  21. #define SPI_CRC_LENGTH_23BIT                          (0x00160000UL)! A+ X+ e: f: [& s/ O3 h% a
  22. #define SPI_CRC_LENGTH_24BIT                          (0x00170000UL)% Z! H! c, [$ d. t/ |0 [  @
  23. #define SPI_CRC_LENGTH_25BIT                          (0x00180000UL); s" T: R$ M& u. f: z
  24. #define SPI_CRC_LENGTH_26BIT                          (0x00190000UL)
    : e- k4 y. [* n/ e
  25. #define SPI_CRC_LENGTH_27BIT                          (0x001A0000UL)( D8 F* S) f3 t/ k# [
  26. #define SPI_CRC_LENGTH_28BIT                          (0x001B0000UL)* w( z! }  s. k1 Y
  27. #define SPI_CRC_LENGTH_29BIT                          (0x001C0000UL)" L! |  F% W: V& Q
  28. #define SPI_CRC_LENGTH_30BIT                          (0x001D0000UL)3 |* z3 Q7 ?+ j! f
  29. #define SPI_CRC_LENGTH_31BIT                          (0x001E0000UL)
    1 o7 @& {3 r7 s. n7 E  f
  30. #define SPI_CRC_LENGTH_32BIT                          (0x001F0000UL)9 v2 b: ^" N  m& j0 w4 c  O- Z- Q( I2 ?
复制代码

* X4 U* }- H5 ]6 N/ {/ ?6 h  NSSPMode0 g" ], b, o# e
用于设置是否使能NSSP信号,可以通过SPIx_CR2寄存器的SSOM位使能。注意,只有配置为摩托罗拉SPI主控模式时设置此成员才有用。# j. h5 S, T! `  \% u! I
  1. #define SPI_NSS_PULSE_DISABLE                         (0x00000000UL)/ Z7 M7 `, Z% ?" I! N$ U0 _6 H* z
  2. #define SPI_NSS_PULSE_ENABLE                          SPI_CFG2_SSOM
复制代码

( [2 Z3 E$ Q" j. i1 @7 S) c/ h2 k; p! g$ k  NSSPolarity, q: Q+ [3 ^6 x; v, v
用于设置NSS引脚上的高电平或者低电平作为激活电平。' b2 z7 l% I; D3 F( T; b+ b; M
' g3 ^$ E+ F$ n  A
  1. #define SPI_NSS_POLARITY_LOW                          (0x00000000UL); x- h7 U8 ?/ p3 N. V7 m
  2. #define SPI_NSS_POLARITY_HIGH                          SPI_CFG2_SSIOP
复制代码
1 b9 [; B5 N8 o7 d8 Z! d; r9 d
  FifoThreshold, |5 V$ ^* _& z0 E
用于设置SPI的FIFO阀值。
3 ]/ s4 `, C. }+ \2 T: Z$ h4 [  ~; i0 P* [# l
  1. #define SPI_FIFO_THRESHOLD_01DATA                     (0x00000000UL)7 x$ u! M' F# B- n# H3 l
  2. #define SPI_FIFO_THRESHOLD_02DATA                     (0x00000020UL)
    2 t# o8 e# j- U2 m6 ?
  3. #define SPI_FIFO_THRESHOLD_03DATA                     (0x00000040UL)
    5 E$ E6 W( ^" y) H3 i4 F# p
  4. #define SPI_FIFO_THRESHOLD_04DATA                     (0x00000060UL): w  c- r! k( r9 ~$ l
  5. #define SPI_FIFO_THRESHOLD_05DATA                     (0x00000080UL)
    " }5 `- F* q3 s+ f6 m& N
  6. #define SPI_FIFO_THRESHOLD_06DATA                     (0x000000A0UL)
    5 _# Y" z% M# t3 a
  7. #define SPI_FIFO_THRESHOLD_07DATA                     (0x000000C0UL)
    * D6 }$ M/ R# [0 B3 R
  8. #define SPI_FIFO_THRESHOLD_08DATA                     (0x000000E0UL)3 S: ~- J) p, o
  9. #define SPI_FIFO_THRESHOLD_09DATA                     (0x00000100UL)
    * S' T! A- t2 k& u' R" u
  10. #define SPI_FIFO_THRESHOLD_10DATA                     (0x00000120UL)
    * ^/ l8 I5 h- d- i& h# K' I  ]% O
  11. #define SPI_FIFO_THRESHOLD_11DATA                     (0x00000140UL)7 Q+ _- s/ D& Y1 A- f' T6 F2 h
  12. #define SPI_FIFO_THRESHOLD_12DATA                     (0x00000160UL)
    2 Y: }8 ~+ b+ k& O- j
  13. #define SPI_FIFO_THRESHOLD_13DATA                     (0x00000180UL)( z! h: t0 R' m
  14. #define SPI_FIFO_THRESHOLD_14DATA                     (0x000001A0UL)$ G3 e5 [' }8 q, t) G- A
  15. #define SPI_FIFO_THRESHOLD_15DATA                     (0x000001C0UL)
    0 q$ O/ r* s7 f: `
  16. #define SPI_FIFO_THRESHOLD_16DATA                     (0x000001E0UL)
复制代码

( v5 G9 b! l4 _, A2 s& t& \3 ^7 u  TxCRCInitializationPattern+ \6 J2 g2 k# M
发送CRC初始化模式。9 c( m  q/ X5 a% h/ w$ |: d
6 l& b$ k4 ^4 ]& u3 ]+ P: X
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    $ o$ z/ d& T8 W2 A. A
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码
8 w/ E7 }" W) V" |$ l% g
  RxCRCInitializationPattern
/ `4 x% X) |5 ]$ y* l接收CRC初始化模式5 E& K6 I& d1 K2 ~
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    9 i0 r3 v, D+ A% i$ S4 _
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码

, Z: q4 J; I& T* o  i: v% q$ G MasterSSIdleness
4 b- o. M9 \) H在主模式下插入到SS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数。
$ B8 b4 B: F2 X2 u2 U4 G3 ?1 E) N9 z4 J9 n7 ?1 n
  1. #define SPI_MASTER_SS_IDLENESS_00CYCLE                (0x00000000UL)1 ~- @9 t) D. n( Z: T* i* F
  2. #define SPI_MASTER_SS_IDLENESS_01CYCLE                (0x00000001UL)/ l  M0 z/ N1 W; V& c0 a* i- N
  3. #define SPI_MASTER_SS_IDLENESS_02CYCLE                (0x00000002UL)5 w# H2 Q4 c* i8 t
  4. #define SPI_MASTER_SS_IDLENESS_03CYCLE                (0x00000003UL)
    # f: O) U# W* m. v4 J% L
  5. #define SPI_MASTER_SS_IDLENESS_04CYCLE                (0x00000004UL)1 Q. K$ T. [( X7 U
  6. #define SPI_MASTER_SS_IDLENESS_05CYCLE                (0x00000005UL)
    * P, X- c) l3 ?$ \2 `1 }# ?
  7. #define SPI_MASTER_SS_IDLENESS_06CYCLE                (0x00000006UL)) h; b. G" r* T
  8. #define SPI_MASTER_SS_IDLENESS_07CYCLE                (0x00000007UL)2 \* @. w* j2 m7 @# S6 _
  9. #define SPI_MASTER_SS_IDLENESS_08CYCLE                (0x00000008UL)( x" `  s# ^6 [& @1 [  m
  10. #define SPI_MASTER_SS_IDLENESS_09CYCLE                (0x00000009UL)3 _; O( x/ f6 G, y
  11. #define SPI_MASTER_SS_IDLENESS_10CYCLE                (0x0000000AUL)
    : t- Z- f: x5 {, r+ y6 l. h( q' u
  12. #define SPI_MASTER_SS_IDLENESS_11CYCLE                (0x0000000BUL)
    * C# h% y5 ~7 F8 \, t6 Q
  13. #define SPI_MASTER_SS_IDLENESS_12CYCLE                (0x0000000CUL)
    $ r+ s. E4 ]$ e, ?& H& t
  14. #define SPI_MASTER_SS_IDLENESS_13CYCLE                (0x0000000DUL)- T1 O$ b4 z+ b0 F: d" ~
  15. #define SPI_MASTER_SS_IDLENESS_14CYCLE                (0x0000000EUL)
    3 j' w# n) A7 C5 {: {4 d( S
  16. #define SPI_MASTER_SS_IDLENESS_15CYCLE                (0x0000000FUL)
    6 I% m, Q* b  A0 \: |
复制代码
+ y9 @7 g8 f# p" s; l+ a
  MasterInterDataIdleness; Q. |. [" w8 C3 t0 y7 \
主模式下在两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数。: Y2 s3 K! L" k+ y
* n" w$ z3 _5 H" Y& R1 m
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)& z. m5 F8 v, i  D$ C8 p
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
复制代码
1 w: A5 ^& w) p8 W* V: n! N
  MasterReceiverAutoSusp
2 ~5 o/ l; z5 k3 p4 \用于控制主器件接收器模式下的连续 SPI 传输以及自动管理,以避免出现上溢情况。
% G# l8 q9 d& D# r, G$ b: C1 Y* Y3 A5 z( Z' [
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)/ \: ^5 Q" n) s; n! z" g
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX! m% m" j+ Y# }6 |" e" w
复制代码
" V" `% J4 s! p) ^+ F; a
  MasterKeepIOState
% ~( A/ @% f/ K7 {% l! g2 y禁止SPI后,SPI相关引脚保持当前状态,以防止出现毛刺。在从模式下,该位不应该使用。# t/ A- e$ t7 _  Q7 r
  1. #define SPI_MASTER_KEEP_IO_STATE_DISABLE              (0x00000000UL)2 Y* N( l9 e6 N/ t$ N
  2. #define SPI_MASTER_KEEP_IO_STATE_ENABLE               SPI_CFG2_AFCNTR
复制代码
1 m7 L$ l+ t" J" U
  IOSwap
" l" d" @0 S: C4 y( V/ N- P% T用于交换MISO和MOSI引脚。
6 O+ H4 L; o9 v# c  p7 U& J: s, p: c; j+ U3 r1 v* K
  1. #define SPI_IO_SWAP_DISABLE                           (0x00000000UL)
    + a9 [& i6 P# A! [  z" F) |
  2. #define SPI_IO_SWAP_ENABLE                            SPI_CFG2_IOSWP
复制代码
2 R' p, l7 L1 Q3 Y
72.3.3 SPI总线句柄结构体SPI_HandleTypeDef
  X3 y) r+ ?* B
下面是SPI总线的初始化结构体,用到的地方比较多:
' x6 s: O3 o$ [# F9 `" r* v' V4 n' \( U. `1 |9 `! ]& w7 I
  1. typedef struct __SPI_HandleTypeDef
    % j! v8 j3 v+ `
  2. {
    8 v3 s6 [/ w( h1 I. Y4 v1 }
  3.   SPI_TypeDef                *Instance;                 % g* k8 v, p) y) R/ C; E- [0 ^# M! K
  4.   SPI_InitTypeDef            Init;                        
      E! Z$ T  I! r/ S
  5.   uint8_t                    *pTxBuffPtr;                 5 }5 X. _. h& X2 e+ O* L
  6.   uint16_t                   TxXferSize;                   , u% z' j/ c3 G7 }
  7.   __IO uint16_t              TxXferCount;                  
    ! }/ C, ?6 Q# W' X% R1 k) g
  8.   uint8_t                    *pRxBuffPtr;               
    , Y' |$ W% q& H
  9.   uint16_t                   RxXferSize;                  
    * i& i# Y, ?( u" x$ [& e  O
  10.   __IO uint16_t              RxXferCount;                 % s$ _; b. X7 \
  11.   uint32_t                   CRCSize;                     8 a/ ?: E( f2 A" G" E5 ?& ?
  12.   void (*RxISR)(struct __SPI_HandleTypeDef *hspi);      
    : d1 }0 i6 L5 M  L* o  U/ F! Y* }% u
  13.   void (*TxISR)(struct __SPI_HandleTypeDef *hspi);        
    + V3 n4 V. Z' g
  14.   DMA_HandleTypeDef          *hdmatx;                      / A- O& Y5 o; x% E9 _- m
  15.   DMA_HandleTypeDef          *hdmarx;                     
    4 z- R0 ^; Y) e9 \/ O( {
  16.   HAL_LockTypeDef            Lock;                        
    : k* f& o6 y3 A! I5 D8 d
  17.   __IO HAL_SPI_StateTypeDef  State;                        
    7 x" e) O- F4 X8 e% L
  18.   __IO uint32_t              ErrorCode;                   / [% f8 ]/ ~. m+ M% V
  19. #if defined(USE_SPI_RELOAD_TRANSFER)6 d9 u  ]1 b8 n3 [. n' {
  20.   SPI_ReloadTypeDef          Reload;                      5 }* m& ^, ]* J2 z
  21. #endif . q) h0 e6 `% e- x" l) @
  22. . `! r. D* M/ O
  23. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)8 z0 I3 X# }: {0 x
  24.   void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      
    % Y9 J' E; K" l' T; f$ F9 v& q
  25.   void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      7 N' y+ c, e$ _2 x' n+ Q: l/ Q
  26.   void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      r& L8 }7 G5 R& z5 R" V: h
  27.   void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  
    ! [, A# G$ W+ N  D4 h6 G1 N4 P
  28.   void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  
    & ~/ @- ]* v1 V6 M, ?
  29.   void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);
    ' @& M( E5 j, G9 Q- H0 ?
  30.   void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi);      
    2 m6 [# [, |; o: s# Q
  31.   void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    ( y! n0 m' `0 B$ o7 H! C% L
  32.   void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi);    . Z  E1 }  b, j0 i2 ~  J# P! H
  33.   void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi);
    ' g: y( e7 H$ [, Y/ |3 j
  34. #endif  
    , P; y1 `8 F$ y# @6 {
  35. } SPI_HandleTypeDef;) A" w1 N7 w5 h7 M* p
复制代码
" z) I! y! d$ Y! h! I' o+ }
注意事项:
& K- g1 Z! r6 m2 a& Y
1 T' j* o5 A3 K( F9 A条件编译USE_HAL_SPI_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:. M, |: s2 ^/ _

2 J0 d! }3 J/ ^" _4 w  #define   USE_HAL_SPI_REGISTER_CALLBACKS   13 V0 B" ?& R' e$ K7 Y4 R! U
% a% Y! L0 [$ w0 v  r: s) l
通过函数HAL_SPI_RegisterCallback注册回调,取消注册使用函数HAL_SPI_UnRegisterCallback。3 v, _, q- ^9 ^- P1 v/ H4 T" O
/ q8 y0 ~/ {6 F6 S. n2 p# P3 ~
这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。
% Y) r9 b5 N" E1 B: A" g! L; k' O. j- J' R, A1 @, N8 J8 S% e6 W
  SPI_TypeDef   *Instance
7 p5 c2 k4 u6 |$ F+ L- o) g这个参数是寄存器的例化,方便操作寄存器,比如使能SPI1。  U6 a. u" W; W- t+ Q: L6 m. |
! r8 U4 g; \& O3 E: D
SET_BIT(SPI1 ->CR1,  SPI_CR1_SPE)。
+ T* }( n6 g+ ?: G/ @5 J( @, h/ S* H
  SPI_InitTypeDef  Init
+ ]" J8 r5 V: S- y" @; D这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。* j) x/ C, S) [# \2 P
' J) |9 O& D: R. a' N
  DMA_HandleTypeDef          *hdmatx               & \& E# a6 J6 W5 H$ |
  DMA_HandleTypeDef          *hdmarx
% O! ^# ?' S& L9 [; y- ~用于SPI句柄关联DMA句柄,方便操作调用。
/ j; i$ v  [. ]# M# g) [8 [  G- u: l- ]9 O3 E+ p0 W- j) \
72.4 SPI总线源文件stm32h7xx_hal_spi.c
' l0 Y2 N$ G5 p0 j此文件涉及到的函数较多,这里把几个常用的函数做个说明:
; @  [& @6 N" t' F4 Y$ a* |
" ~! H1 J0 B/ j+ w: E  HAL_SPI_Init) f: v1 \" Y( U  n2 y
  HAL_SPI_DeInit7 a, X5 w* r4 s: m; j. a
  HAL_SPI_TransmitReceive3 \( b  R  }9 U6 Y# z
  HAL_SPI_TransmitReceive_IT
' r/ L+ b* y- x6 |  r: }: [7 V/ ~8 Y  HAL_SPI_TransmitReceive_DMA
/ q/ U5 e0 v4 C' Y) l. H; c# ^! e1 r9 Y6 F/ I1 f3 N
72.4.1 函数HAL_SPI_Init1 O6 {- z6 }8 V/ x3 v
函数原型:
/ F5 `7 ^1 f6 p5 H- Q. ]. v5 V2 J
6 J) V* c* N, x$ j3 ?
  1. HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)
      o5 T6 {5 ?+ s1 q) o/ E+ B. K
  2. {5 t3 X1 p, T$ a3 _. o1 q
  3.   uint32_t crc_length = 0UL;
    8 J8 H  t4 s) n0 X! q
  4.   uint32_t packet_length;& g5 Y& L, E1 T+ b" \- r& C3 ^
  5. 5 I. Z5 P; b( P5 U. R( w
  6.   /* 省略未写 */1 ^: [0 S6 F/ Z1 d+ Y0 ]6 a* f. Y

  7. 5 d6 ~2 c, h& u  R: K# W" Y* T
  8.   /* 如果数据位宽大于16bit,必须是SPI1,SPI2或者SPI3,而SPI4,SPI5和SPI6不支持大于16bit */
    9 I% E/ z$ r% }8 k
  9.   if ((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (hspi->Init.DataSize > SPI_DATASIZE_16BIT))
    . T8 ^) y2 A6 m( h
  10.   {4 T$ P! _8 ?; o. `9 l7 Z
  11.     return HAL_ERROR;
    / I9 S0 C; P% K
  12.   }: z$ A  w5 P2 @( |. \2 j
  13. 2 w0 O  h0 j' V( c# |8 A
  14.   /* SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit; i  E! s$ _6 q
  15.      这里是查看设置的缓冲大小是否超出了FIFO支持的大小。
    ; K, y& v0 z" f# c  t6 v1 e
  16. */
    3 V& l5 V" U% c) G+ B7 h
  17.   packet_length = SPI_GetPacketSize(hspi);
    & O# B+ ]$ |; x
  18.   if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_LOWEND_FIFO_SIZE)) ||
    5 {6 b" b! e, T6 o
  19.       ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_HIGHEND_FIFO_SIZE)))
    ( J  ]& p7 P/ f# x
  20.   {9 O9 s/ j$ [* f6 Q% A6 H
  21.     return HAL_ERROR;
    . _. q3 j, _+ i7 ^; t
  22.   }
    3 q+ ~, @6 W* _5 s  s5 Q

  23. 3 S: W; w3 F: `  ^
  24. #if (USE_SPI_CRC != 0UL)( j& L9 I# ?- h6 b! s$ n/ [/ C
  25.     /* 省略未写 */* m5 I1 C5 c( \& P" S' C* _/ V
  26. #endif
    ! D/ `. x- i! y" I6 S
  27. 3 A& V. k( h. w) Q
  28.   if (hspi->State == HAL_SPI_STATE_RESET)! b7 j9 _7 j, c4 h
  29.   {- }2 f( ^) B) u6 r" w
  30.     /* 解锁 */( p7 E& k8 w; G5 y6 I) i( u
  31.     hspi->Lock = HAL_UNLOCKED;5 h# f; ]% C, d3 E6 |! W% _) I0 B
  32. 7 y0 u1 I8 P  k$ B
  33.     /* 使用自定义回调 */
    7 U2 T, L; k# B; `
  34. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)" }9 e, W- E+ N; x- B; G! Z
  35.     /* 设置默认回调函数 */! T% N6 k# T2 [: R" a' i( y; j
  36.     hspi->TxCpltCallback       = HAL_SPI_TxCpltCallback;       /* Legacy weak TxCpltCallback       */
    ; \5 e+ i2 r/ E6 D  n& u% g
  37.     hspi->RxCpltCallback       = HAL_SPI_RxCpltCallback;       /* Legacy weak RxCpltCallback       */
    1 c2 ?) M6 X& @2 [. U: B& T
  38.     hspi->TxRxCpltCallback     = HAL_SPI_TxRxCpltCallback;     /* Legacy weak TxRxCpltCallback     */
    ) |, b. v! H9 J7 Y  t
  39.     hspi->TxHalfCpltCallback   = HAL_SPI_TxHalfCpltCallback;   /* Legacy weak TxHalfCpltCallback   */
    ; M. K6 M* v. l  H, x1 I3 K: J' c/ ]
  40.     hspi->RxHalfCpltCallback   = HAL_SPI_RxHalfCpltCallback;   /* Legacy weak RxHalfCpltCallback   */
    : A0 T0 g8 V- `8 m0 F- n0 z
  41.     hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */
    # M6 {" l6 C# M& O) P: _5 }; [! r
  42.     hspi->ErrorCallback        = HAL_SPI_ErrorCallback;        /* Legacy weak ErrorCallback        */
    " g1 a9 m/ a7 r/ @8 s
  43.     hspi->AbortCpltCallback    = HAL_SPI_AbortCpltCallback;    /* Legacy weak AbortCpltCallback    */' I$ [' m& S% _7 l! ~! X3 b% Y
  44. 5 I! n/ x& i2 m6 p" W7 R
  45.     if (hspi->MspInitCallback == NULL)
    : S) U! M2 a+ e, r! V
  46.     {
    8 X  S: j) h/ A1 N$ s6 L, O
  47.       hspi->MspInitCallback = HAL_SPI_MspInit; # F# r9 L( t3 _7 E1 n' C
  48.     }+ V1 ^1 [8 F, v$ ?. F  L, u4 \
  49. ! L) D2 s* P9 |3 J3 v* L
  50.     /* 初始化地址硬件: GPIO, CLOCK, NVIC... */7 t& Q: K& y9 g* y" g
  51.     hspi->MspInitCallback(hspi);
    - t: d' @) H; K$ S8 F, [
  52. #else
    * `- e5 `  G* N
  53.     /* 初始化底层硬件: GPIO, CLOCK, NVIC... */7 i5 n& |+ y) L
  54.     HAL_SPI_MspInit(hspi);6 n( Y  s4 d: h' X4 j. h, `6 p
  55. #endif
    % e: c( O: E" e# g/ E
  56.   }
    3 i# S$ D- \* j9 z# V
  57. 4 V7 G" s* E3 b3 Y
  58.   hspi->State = HAL_SPI_STATE_BUSY;' r& S# k, b/ B  \3 f

  59. & ]* m7 B2 x! Z# G' N
  60.   /* 禁止SPI外设 */1 s0 }4 X, @0 T$ F/ n3 m6 B+ t* O
  61.   __HAL_SPI_DISABLE(hspi);2 f/ Z9 e- S# M; o7 C

  62. # c9 X5 f* g# ^6 E
  63.   /*----------------------- SPIx CR1 & CR2 配置---------------------*/' E2 M# H" q7 r: q6 L. L: d
  64.   if ((hspi->Init.NSS == SPI_NSS_SOFT) && (hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.NSSPolarity ==3 x! a7 Z+ N1 Z: ]9 t4 h4 w6 y
  65. SPI_NSS_POLARITY_LOW))3 w* ^- E; B6 O9 U( G+ O$ p# G
  66.   {% _0 Q6 M1 m" x0 d! P
  67.       SET_BIT(hspi->Instance->CR1, SPI_CR1_SSI);" J2 I" \( Y! k7 I
  68.   }
    5 H( J( t, F0 K' m1 p( h

  69. " i; h7 D# d; }7 h  c  O# B
  70.   /* SPIx CFG1配置 */" H* ~6 K6 u4 L5 J3 g
  71.   WRITE_REG(hspi->Instance->CFG1, (hspi->Init.BaudRatePrescaler | hspi->Init.CRCCalculation | crc_length |/ U- E. M! A  u
  72.                                    hspi->Init.FifoThreshold     | hspi->Init.DataSize));& |4 x* D0 u: e

  73. # P; Q% R+ r0 a
  74.   /* SPIx CFG2配置 */+ n* j( J9 L$ s/ |
  75.   WRITE_REG(hspi->Instance->CFG2, (hspi->Init.NSSPMode     | hspi->Init.TIMode           | hspi->Init.NSSPolarity  |
    ) ?# [, ^) l" a1 E1 @8 S; X9 \5 \
  76.                                    hspi->Init.NSS          | hspi->Init.CLKPolarity      | hspi->Init.CLKPhase     |
    * M9 ?' J7 z5 Y: C  p( y
  77.                                    hspi->Init.FirstBit     | hspi->Init.Mode             | hspi->Init.MasterInterDataIdleness |4 Y; Q) V8 N/ ]: G& C
  78.                                    hspi->Init.Direction    | hspi->Init.MasterSSIdleness | hspi->Init.IOSwap));& M! K% t, X! H, P9 ?/ K

  79. ; B; d! o: N7 e) V" G3 k+ r. I
  80. #if (USE_SPI_CRC != 0UL)2 L) D* F) c5 |
  81.   /*---------------------------- SPIx CRC配置 ------------------*/
    ) r% o: {9 y" J/ U  G6 I' A$ O7 |
  82.   /* 配置SPI CRC */) t& I* X; i3 |' i, @$ B; k; C
  83.   if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
    / m" p7 \9 k( U3 ]' F
  84.   {! x! G" `3 J/ E1 ?1 w
  85.     /* 初始化TX CRC初始值 */) e9 J7 e3 `8 {6 c
  86.     if (hspi->Init.TxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)' B7 d- I6 H& }/ j
  87.     {
    $ C" M# T7 B3 t- g
  88.       SET_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);; U# g. y& F8 f6 E1 D
  89.     }: q# E4 N* P, g! k7 r) E
  90.     else
    ' {9 P% Z% L+ |5 C
  91.     {
      |+ m& j& T6 Z7 b% E% M7 @& r4 M5 S/ J
  92.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);
    $ i: I' ^8 r  D" P
  93.     }% e- z% N8 ?9 v9 P

  94. 7 w. t* @& {( L, `8 u
  95.     /* 初始化RXCRC初始值 */$ Z& o' X* T/ h8 H# v
  96.     if (hspi->Init.RxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)" E, h8 S" j* ~8 N/ d' }1 p
  97.     {' ]) e6 d! R& ]% G2 J! f
  98.       SET_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);7 D- z7 L; Y( U- N
  99.     }
    6 T4 Z8 r( E$ H' R8 X3 A
  100.     else3 {2 X4 ]4 V# g; F# ?
  101.     {
    : r: F: `  d% |& ^) D  L
  102.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);
    , C  @$ p0 J) d, O
  103.     }
    3 L2 @" ?2 N- e: |, @
  104. ; h5 o6 ^5 f& C# \! S9 G3 ]
  105.     /* 使能 33/17 bit CRC计算 */
    ( f7 F0 x9 H8 v
  106.     if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (crc_length == SPI_CRC_LENGTH_16BIT)) ||# Y, w6 E3 n0 j$ g" E. o* Q- A
  107.         ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance))  && (crc_length == SPI_CRC_LENGTH_32BIT)))
    + G, F- M, w: _9 d
  108.     {. q5 g! @( ]# C' `: {& n
  109.       SET_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);+ }2 g. {! U/ J3 `; L. W4 q& {6 N
  110.     }! N) \6 |$ J! Z) R6 U3 G
  111.     else
    - c; S8 J% D! d# K, S/ p1 L
  112.     {4 Z# n% @' i5 `5 _
  113.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);
    9 Z2 [8 K+ S& r3 m7 E
  114.     }
    ! P1 D) m8 @+ w$ Z2 Z' G

  115. $ h6 u# g2 C8 l) E. V- ^0 F5 m
  116.     /* 写CRC多项式到SPI寄存器 */
    ' M6 k% y4 a9 N/ b9 ]* A
  117.     WRITE_REG(hspi->Instance->CRCPOLY, hspi->Init.CRCPolynomial);
    ) U2 K. r7 Y' v# @
  118.   }
    3 I- k  S3 D  B+ T8 y: E
  119. #endif ( C( b, b- I3 F8 z9 k5 g  X7 t
  120. 6 a' W% n: W  y& G7 _& T
  121.   /* SPI从模式,下溢配置 */, _( Q) U+ z2 t* Y% B  Z5 X
  122.   if (hspi->Init.Mode == SPI_MODE_SLAVE)% b+ f- b3 L0 ~% F, s3 h4 f$ R
  123.   {" B; \! T4 |( w5 W& P% P" c. a
  124.     /* 设置默认下溢配置 */
    0 _7 l* W3 t# `0 F, ~- ~
  125. #if (USE_SPI_CRC != 0UL), \' x1 w' J1 m* n3 A
  126.     if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_DISABLE)5 N. A1 }/ u9 m1 P: c
  127. #endif+ _& e9 n! t( z" @- w6 x1 \
  128.     {
    , ?8 a1 i+ N7 P. l, F
  129.       MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRDET, SPI_CFG1_UDRDET_0);
    / c* C0 q* I9 l* M# R: X
  130.     }2 d+ j- D2 L$ m7 Z* b. q
  131.     MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRCFG, SPI_CFG1_UDRCFG_1);' z; X. `/ X, ^9 Z0 x+ c4 C
  132.   }
    ' Y% f$ `% l* I5 I7 K
  133. 8 b6 x; I$ R$ a) S6 l( x- H5 t; `
  134. #if defined(SPI_I2SCFGR_I2SMOD). B& h2 o( k3 ?8 y
  135.   CLEAR_BIT(hspi->Instance->I2SCFGR, SPI_I2SCFGR_I2SMOD);. o( D8 w9 W2 c4 a# r) \) L7 L
  136. #endif , |9 Y1 X# I5 P6 b, L
  137. % y- a7 C, P' C+ p4 Z
  138.   /* 确保AFCNTR bit由SPI主机模式管理 */
    8 y1 s1 w* B& b! p1 Z
  139.   if ((hspi->Init.Mode & SPI_MODE_MASTER) == SPI_MODE_MASTER)$ |# `4 e6 h! \1 T4 P5 a  d
  140.   {
    - p4 n# M3 r! ]9 d/ Y
  141.     /* Alternate function GPIOs control */3 [& X7 x5 K6 P2 J' s" [1 w) x) g
  142.     MODIFY_REG(hspi->Instance->CFG2, SPI_CFG2_AFCNTR, (hspi->Init.MasterKeepIOState));2 ~3 G. h. g* g, c8 \
  143.   }
    $ L8 W% C/ |/ ?8 f
  144. " P' Y3 }" G1 I! g( v
  145.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;+ C7 u  G( `7 q
  146.   hspi->State     = HAL_SPI_STATE_READY;
    " d/ u. A: n! o) D6 Q# ^

  147. - J6 Y$ L3 X6 x
  148.   return HAL_OK;+ V2 q' z' \$ W
  149. }
    ( `" K' |, u& ?0 [# i. w; F
复制代码
. T. I/ u5 S# I

. }% D" |( y: Y5 o3 R7 p$ h8 {9 ]函数描述:
/ ~  w* E; A# i1 Z" J
' h; ]; q6 {- M! R. Q9 X0 I此函数用于初始化SPI。
+ }& ^, I- ?+ C0 F4 m( |; m6 C# f" b: c+ M$ U& v5 Z# B
函数参数:
. J! h7 ^0 H- I6 d7 C! }
) V5 b. t& ]( o) p  j  第1个参数是SPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。* Y; L  F2 `2 d) t
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。; |, b7 n6 [& V5 M0 c; s( C
8 ^" Z, H7 V, z: ?( c! p. ^' n
; q2 f1 \; c8 i5 a; x" C$ s% f
注意事项:% |& h% D0 Y  {4 H. }
函数HAL_SPI_MspInit用于初始化SPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。2 Y" u, S% Z6 s- z6 M" @& {
如果形参hspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SPI_HandleTypeDef SpiHandle。
$ h' F6 `4 f% v$ `( G5 }对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SPI_STATE_RESET  = 0x00U。
' m9 y( p: \$ f0 ~: j# @( n7 l, Y% @. r  Y& A" l- V9 f
解决办法有三# F* _) y* D) R! b1 p' s+ w5 A
4 B+ A1 u  ^1 V: o
方法1:用户自己初始化SPI和涉及到的GPIO等。8 w7 {( ?) m% p) P/ w

' p0 \- }+ H* I方法2:定义SPI_HandleTypeDef SpiHandle为全局变量。
6 _& h' b+ ~$ _' h# W+ B7 f5 _6 ?, p0 F) ]+ L) e0 c( \
方法3:下面的方法
0 F3 r, J/ e( y" y. Y. {! s; Z" Y0 i; X0 _7 }; J
  1. if(HAL_SPI_DeInit(&SpiHandle) != HAL_OK)
    7 \1 K) E. A$ W9 h5 |: \
  2. {2 n& l9 ]7 s$ \, V  n. m# d9 `
  3.     Error_Handler();
    ) I( A3 K. m% I. E+ g
  4. }  
    $ E% K  _1 M8 V8 u: J- t* }1 t
  5. if(HAL_SPI_Init(&SpiHandle) != HAL_OK)' ~! P& m- w% x" ~, `& N2 Y2 Q
  6. {
    / ^) V" [- T& i5 f2 B* f% z
  7.     Error_Handler();. [: n9 i% J) L6 L7 ?. d
  8. }
复制代码
) f) ^; @  _! N
使用举例:# U" [- c& _3 c0 B/ a' G" a; _' S
5 T! {8 ]4 A7 M8 w) n$ N! j8 |
  1. SPI_HandleTypeDef hspi = {0};
    1 [+ r' b" |5 X" |1 \" a

  2. + t) _; H9 o0 i, p0 X
  3. /* 设置SPI参数 */
    ( v# A. Q7 a* y: ?/ \
  4. hspi.Instance               = SPIx;                   /* 例化SPI */% A. N4 |9 i9 Y  v- f
  5. hspi.Init.BaudRatePrescaler = _BaudRatePrescaler;     /* 设置波特率 */0 Y# c5 E7 \: B4 `# A5 P
  6. hspi.Init.Direction         = SPI_DIRECTION_2LINES;   /* 全双工 */
    % D+ [! C3 E7 X6 s$ M7 b
  7. hspi.Init.CLKPhase          = _CLKPhase;              /* 配置时钟相位 */9 ]# c' t9 O2 A6 F6 T* R
  8. hspi.Init.CLKPolarity       = _CLKPolarity;           /* 配置时钟极性 */3 }, n. ?# q4 Y4 E
  9. hspi.Init.DataSize          = SPI_DATASIZE_8BIT;      /* 设置数据宽度 */
    # V0 x& F; |) A
  10. hspi.Init.FirstBit          = SPI_FIRSTBIT_MSB;       /* 数据传输先传高位 */$ a' D/ w& L" F/ y1 u7 Z  |
  11. hspi.Init.TIMode            = SPI_TIMODE_DISABLE;     /* 禁止TI模式  */& H* ~3 h* x5 U4 J6 S' g
  12. hspi.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;      /* 禁止CRC */7 L2 _+ G1 ^9 [1 l9 T! H+ h
  13. hspi.Init.CRCPolynomial     = 7;                               /* 禁止CRC后,此位无效 */
    ! p* P0 l6 \8 ]. Y
  14. hspi.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;             /* 禁止CRC后,此位无效 */2 k% e/ A/ d3 ^) J, _
  15. hspi.Init.NSS               = SPI_NSS_SOFT;                    /* 使用软件方式管理片选引脚 */
    9 l( N8 m2 t6 y0 x1 U- q0 |  W  m1 [
  16. hspi.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_01DATA;       /* 设置FIFO大小是一个数据项 */
      l( h" L5 {# Z* t4 N3 z  Y' D" o( n
  17. hspi.Init.NSSPMode          = SPI_NSS_PULSE_DISABLE;           /* 禁止脉冲输出 */
    4 R* G0 M, ^5 C- J# v
  18. hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  4 s( B5 b, T4 b/ u9 E% e- _
  19. hspi.Init.Mode                  = SPI_MODE_MASTER;            /* SPI工作在主控模式 */: z% ^9 z1 z* Z0 J1 b. D6 j; Z, W* ?
  20. ) s; p. e0 ]1 b; k9 i& e& B/ B
  21. if (HAL_SPI_Init(&hspi) != HAL_OK)+ \- D( f8 H6 A
  22. {( u% m- x9 K/ N; P- s. i
  23.     Error_Handler(__FILE__, __LINE__);
    5 ]: {& s8 B1 h+ g7 S) U
  24. }
复制代码
' b) e+ f0 P3 _' d2 c
72.4.2 函数HAL_SPI_DeInit
# f& y  D4 m! n- q$ [函数原型:2 m+ w+ h* i; V, \2 i# y+ d
  1. HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)
    7 C! M8 J& e* j3 f" a7 ~' k
  2. {
    4 W/ K" F! M- f8 r4 Y
  3. /* 检测SPI句柄是否有效 */
    2 _1 N- S5 q" l
  4.   if (hspi == NULL)7 c" h! V+ y$ k' |! A  }
  5.   {
    0 R5 v0 D: R8 z6 C: d) X, b
  6.     return HAL_ERROR;
    / T; X1 `. z  ~5 ]! e! Z# {
  7.   }) D4 T8 r# I) r; A, R7 P0 ~
  8. 5 B6 H4 e9 `! |
  9. /* 检查SPI例化参数 *// q! W( j5 M0 R
  10.   assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));; e+ K' B& i. D1 w+ ^4 }* [4 P" @
  11. / N( k( L. o2 d, S, d% r
  12.   hspi->State = HAL_SPI_STATE_BUSY;. o( m( U4 o5 w( g
  13. ! V6 G( o7 P$ R, b( t& A( X
  14.   /* 禁止SPI外设时钟 */
    - G$ `' k* q; D8 S% P  `
  15.   __HAL_SPI_DISABLE(hspi);
    ) p/ y$ @) ^7 e2 S3 M
  16. ! L* y2 L- p" O" ^/ [+ ~- l0 \
  17. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    " y3 o8 G( y" ?7 P, D. N" P2 g
  18.   if (hspi->MspDeInitCallback == NULL)( \8 Q. y; N) m; e/ G' H: [
  19.   {
    # e* @9 N( S; Z) [8 i( k
  20.     hspi->MspDeInitCallback = HAL_SPI_MspDeInit;
    ' ]- n9 X3 d2 Z2 f) p3 b$ K5 y
  21.   }
    8 H" `) U" y6 h+ u7 Y! e+ b$ b
  22. 0 F3 ^% t8 l5 b. {
  23.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */
    $ a7 O, M2 i" \9 T" D( @5 J' L+ Q
  24.   hspi->MspDeInitCallback(hspi);( T7 {0 ~, L4 S: m) {  I! P
  25. #else
    - A% n* ~2 p7 r
  26.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */7 W! s" v. x5 ?1 v
  27.   HAL_SPI_MspDeInit(hspi);+ y* ^1 m" [6 D0 k5 v" q
  28. #endif
    ! A6 z$ b$ r1 {  S+ |/ i
  29. 5 D1 p: A$ O3 o8 w8 q2 H
  30.   /* 设置无错误,复位状态标记 */
    6 \1 W1 X7 s8 F
  31.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;
    5 \1 P$ S& ^8 d7 b2 S* B
  32.   hspi->State = HAL_SPI_STATE_RESET;7 {" c2 ~- H4 k/ C* W# h

  33. ; r5 T6 \7 K1 f' F6 Y) c4 Q6 |
  34.   /* 解锁SPI */
    ' `7 v5 ]$ r+ a- e
  35.   __HAL_UNLOCK(hspi);
    3 O1 K3 X& f) {

  36. $ Q! n7 f0 E' `- C9 Q
  37.   return HAL_OK;
    " h/ A- Z; M+ [! A
  38. }
复制代码

6 {' N: ]  n* `5 @& L函数描述:
2 ]* @) I$ B) e% \# t! ^: R6 T' P$ A: J' w1 m  w
用于复位SPI总线初始化。
, U9 Y9 a0 L: O8 l% B1 W0 ~" k) U3 l. @* O
函数参数:. T7 g: `: j/ [3 Q1 d3 Q$ ^7 X! ?% x
: c9 Q1 ]( Y* P0 D2 Y
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。; X& F5 B  u  m% }. Y" y7 m) v' }
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中8 L; q7 [; O& G0 h" m8 n$ b

* y+ b, _+ j3 V# m0 N0 Q
  \  X1 K7 ^- R" Q3 H72.4.3 函数HAL_SPI_TransmitReceive
3 m* V7 e( e0 P, N: |' F" H5 J函数原型:/ v) P8 x; P; x' v. }
  e: E/ U  L  c/ G6 q3 d
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
    + t( ^% |* S6 g# R4 k7 C
  2. {
      M- a, @6 }6 ?/ K8 p

  3. 8 J. d3 x; h) [8 C) C! y
  4.    /* 省略未写 */
    0 l+ J( X+ \' r# ^

  5. + C; H& k- W$ K$ V" S- W; |: q# ]
  6.   /* 大于16bit的数据收发 */7 l* O: f, n0 D; W$ s
  7.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)3 l1 K( x( o' f# A1 K
  8.   {
    " e0 |' L7 ]8 H0 p$ p! s- n
  9.        /* 省略未写 */
    * Q: P( ]4 _2 u$ F: f) `1 H
  10.   }" e2 d$ Y6 H9 S0 o8 A. y& h, F
  11.   /* 大于8bit,小于16bi的数据收发 */. |4 Y: m" ]* l$ r
  12.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
    ; d+ N6 w/ v- g
  13.   {
    2 l! u4 \# C3 q, t& {% l9 M
  14.       /* 省略未写 */3 F! A* [& V6 [( \
  15.   }
    4 G  g& N* h7 b5 ~+ S8 H
  16.   /* 小于等于8bit的数据收发 */3 {8 o' I  _: R, V/ i4 i/ b
  17.   else
    , s! T) U9 j7 _1 L- T0 F: X
  18.   {
    8 L- F: l& O) L# @; _5 f
  19.        /* 省略未写 */
    ) ]5 Y* N- r% i3 V# f4 Z& x
  20.   }6 ~6 \0 S' d" _! p  t$ M. a: ^7 A7 x
  21. ) Z" h2 O% j! h/ u1 \: g1 T
  22. }
复制代码
' H$ n1 [( o0 K" n# x. V" q
函数描述:
' U4 d! F5 {/ Z! r
, X% ]" d, ~- i  t此函数主要用于SPI数据收发,全双工查询方式。4 B6 E% o6 s5 u- l' r8 w
; H' r) @! b5 O& n  Z7 W7 f* Y6 `
函数参数:
/ _( W! L; ?$ g$ l: R4 D, O
+ }: H( h3 |( m: O) q7 A  第1个参数是SPI_HandleTypeDef类型结构体指针变量。! z0 R' r: U# V+ T: Y
  第2个参数是发送数据缓冲地址。$ s; _9 J3 y; q" b/ e5 @5 ?
  第3个参数是接收数据缓冲地址。+ J% v5 z7 R. o! }, N" s
  第4个参数是传输的数据大小,单位字节个数。. ~  _) Z' n/ \! [3 k
  第5个参数是传输过程的溢出时间,单位ms。
2 ?! M1 p& _0 r+ X8 T# M  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
. S- @, D7 F1 M* O7 x9 Q# ^( k, B' z4 j7 \& c
3 Q" i" s" e/ a0 t2 @
使用举例:- s. D6 b/ ]  V" t
# I5 g, b7 K8 b- M% s8 R3 a6 h
  1. SPI_HandleTypeDef hspi = {0};
    9 h( J4 k- Z- T6 V

  2. 5 u  K' w. S7 g% T  m. ]* ]8 @; h! C
  3. if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)7 w; f" Q4 D; S; E4 J% H& H
  4. {
    ' }1 P% Y: a. ?8 X2 P& o+ S: l
  5.     Error_Handler(__FILE__, __LINE__);. B5 X, F  }" f5 f" g
  6. }
复制代码
( J* k+ S9 O, y9 z7 B- v
72.4.4 函数HAL_SPI_TransmitReceive_IT

3 T9 O7 j* v8 A( e函数原型:( B- s) k% ]# [7 H5 r) M
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)
    - E" a0 K( P# {" W+ l0 ]
  2. {
    2 f" u' G7 `2 i& s& B5 j
  3.    /* 省略未写 */
    0 R9 s" M/ ~' D2 P0 f7 {5 ~2 S

  4. 5 B) t6 l: l1 `
  5.   /* 设置传输参数 */. M9 _3 c6 _/ G" R
  6.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
      K3 Q7 l) B& Y* L& b8 }
  7.   hspi->pTxBuffPtr  = (uint8_t *)pTxData;
    2 h. M3 ?! f+ N) C* }# D4 ?
  8.   hspi->TxXferSize  = Size;8 Z0 d: T7 Y& D8 v3 e
  9.   hspi->TxXferCount = Size;: _  W7 i8 b* L# K, g. B
  10.   hspi->pRxBuffPtr  = (uint8_t *)pRxData;) x0 u0 s7 n' |- k" m
  11.   hspi->RxXferSize  = Size;
    & D4 K4 _7 `& l( p2 B: \
  12.   hspi->RxXferCount = Size;
    % l5 X' n' H7 l% o0 M

  13. 0 O( x" i1 L0 f7 L( Y) U1 S  [
  14.   /* 设置中断处理 */
    1 s, d) t- b) \$ ~1 @* n
  15.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    & `9 }2 x' f2 e
  16.   {
    8 P$ o! V% m+ O5 e" u4 e7 x: m
  17.     hspi->TxISR     = SPI_TxISR_32BIT;
    % _5 o0 p* r& R: E) H
  18.     hspi->RxISR     = SPI_RxISR_32BIT;
    + E$ y: v9 [+ \( j3 Y! ^" B* {8 V
  19.   }7 X3 \) o: ^* f& q: i
  20.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)5 u6 E7 l; ~) d7 }' Y: T, u
  21.   {
    " G: c0 x" @- v( k* v- @, @
  22.     hspi->RxISR     = SPI_RxISR_16BIT;
    ; G: T' y0 ^) s6 Y% d  c$ V. r
  23.     hspi->TxISR     = SPI_TxISR_16BIT;
    ! h7 m% g; `  N( F+ c4 o
  24.   }
    ( [7 O8 I/ h8 U) {! q+ A
  25.   else; U" v: f8 R/ d  w
  26.   {6 ^7 @+ X9 v/ v( i, u& ^% e5 N
  27.     hspi->RxISR     = SPI_RxISR_8BIT;
    5 z% p3 }2 Q6 P6 |/ j
  28.     hspi->TxISR     = SPI_TxISR_8BIT;! b2 s* j2 P/ q) C  a" m0 }
  29.   }
    ' h$ N# G5 v+ i$ j! t8 }

  30. % q+ q3 x$ w6 j8 S& ]1 I
  31.   /* 设置当前传输数据大小 */
    ; j( ?" G+ j$ \: g
  32.   MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);
    & ^7 V5 |# o/ e9 V2 b& C5 ~6 m
  33. 9 D# t& R' U" u0 E. q# `' G& I
  34.   /* 使能SPI外设 */% X" w3 b( r# {5 {  ?8 C
  35.   __HAL_SPI_ENABLE(hspi);
    % ^. C7 \6 A8 u0 [" Q( c
  36. & R; b+ B/ M& y) P  A
  37.   /* 使能各种中断标志 */  s- w6 b% g  c3 ]$ g' @
  38.   __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_EOT | SPI_IT_RXP | SPI_IT_TXP | SPI_IT_DXP | SPI_IT_UDR | SPI_IT_OVR | 1 W4 q& m1 P+ E$ C0 R
  39. SPI_IT_FRE | SPI_IT_MODF | SPI_IT_TSERF));+ \! V" Y' _- [6 H7 \  D1 x

  40. - K- D; }  O% @& P% l
  41.   if (hspi->Init.Mode == SPI_MODE_MASTER)# T4 X- g1 z% p  p- D3 ?5 P# d1 c
  42.   {  e# k  z/ k* ^) i' l; a
  43.     /* 启动传输 */
    8 Z% S9 b% W) R3 a4 z1 k
  44.     SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);# Y2 e! S) c6 y5 z
  45.   }
    + D9 \5 p1 U4 n1 C, r" x

  46. 5 p4 v( {# {9 A1 k1 W1 h" h% W
  47.   /* 解锁 */% n& w3 H2 F7 [, S
  48.   __HAL_UNLOCK(hspi);
    . S: H$ g4 P, _) _6 X
  49.   return errorcode;0 r- J' R% |/ @/ N. A8 `( S
  50. }/ l7 u& U- I0 k
复制代码
  J( v" U  S+ T
函数描述:
7 D1 x9 ]$ c) a- h0 F- R* e# Z! B6 R) m8 S4 R! J4 A) `/ ^6 j
此函数主要用于SPI数据收发,全双工中断方式。+ {  }$ d# q) w5 G* R- B

; v4 h& a/ i# q$ o$ z, H" h函数参数:% }7 l# w  A9 x5 k6 R9 O  N& }

# u; m% j9 n: g3 j  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
, D  g% j1 _8 [2 m  第2个参数是发送数据缓冲地址。1 s" v  ?" S, S: v* D
  第3个参数是接收数据缓冲地址。
% X" X0 `0 w) o8 R- g( r  第4个参数是传输的数据大小,单位字节个数。
1 a# B0 J' l9 y" A, _* Z4 C  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
4 N! S, `$ v7 @1 X+ s. `& V& H3 ~  Y, J8 F+ o

6 _% ]1 A( X0 H" v0 e: l# G1 a使用举例:
& |  t! C' z! h, s* S3 _  i$ B  t+ f4 @
  1. SPI_HandleTypeDef hspi = {0};
    : s; a& j) U/ [$ ]
  2. 0 O) Q% Y- T. f; X. g3 b
  3. if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)   
    0 L& g5 M' S* R4 `7 L3 T/ v
  4. {
    + x8 S  V2 ]5 G1 @* B; X4 V
  5.     Error_Handler(__FILE__, __LINE__);
    / _- b' h& c- u1 m$ R! }7 F. \
  6. }
复制代码

5 f6 z" i4 y/ f1 Q. @$ h0 T5 m72.4.5 函数HAL_SPI_TransmitReceive_DMA

$ J/ f7 `3 b7 l函数原型:
, @3 U' N. I- D; d0 E5 \% t. x) \/ l1 g1 N. K; k: c" v3 k0 `
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,
    0 C6 t! |( H0 M2 H
  2.                                               uint16_t Size)3 c  ~) H! m. p; M+ E  `" o( T
  3. {
    3 n, R/ R  w6 p$ T; J
  4.    /* 省略未写 */
    - ~4 J# d' P: @+ v/ _% ]3 n7 H

  5. ) X3 s# d# S9 G
  6. /* 注意DMA的位宽和对齐设置 */* u4 p; M4 g2 {4 n
  7.   if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && (hspi->hdmarx->Init.MemDataAlignment !=
    $ @7 f2 F# U: t, H% m
  8. DMA_MDATAALIGN_WORD))  || . C8 W& [) b# h8 n- Z
  9.       ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) && ((hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_HALFWORD) && (hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_WORD))))
    ! u( g) g- D4 z! E0 B, _" X5 X1 d  K
  10.   {
    6 k5 Y& p3 h' f# \
  11.   }. u$ {( d1 x4 n
  12. , ^% k1 r! {6 h; @" A
  13. /* 调整DMA对齐和数据大小 */
    6 V1 |& T1 X# ^5 u+ K2 T
  14.   if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)
    . K+ L) X4 W1 w2 ]; }1 @
  15.   {% r( n6 |' f3 U, A, E' _( N, v
  16.      /* 省略未写 */
    * g8 p2 U  W! v0 f. H
  17.   }
      m" P" Q4 i( E8 v4 F2 h
  18.   else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)
    . |3 `: n1 ?1 M4 c
  19.   {
    0 ~  M9 [$ k' ?& H- J: d# ^
  20.      /* 省略未写 */9 f% i1 K) d. V# z3 U" x
  21.   }5 {0 T$ m4 z7 N
  22.   else
    1 ^2 t4 M0 m( y- `/ u
  23.   {
    ; ~' K2 ^! E$ z
  24.       /* 省略未写 */1 I2 Y; y  L- `& r. z, G
  25.   }
    : e) c) t( N. f( I/ U5 g: D

  26. 6 L1 y* M9 K! R" B, G
  27. /*  DMA接收配置 */2 w. m: B# }8 v) F  z; Q8 Y8 k
  28.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->RXDR, (uint32_t)hspi->pRxBuffPtr,2 k" [0 [" B5 O. a  ^2 C
  29. hspi->RxXferCount))
    ) ?! f! B6 m3 p4 L
  30.   {
    $ M7 V( E/ \/ m2 r

  31. 2 f$ p2 ]2 p& q/ G6 i0 }
  32.   }( k0 [! G; n, l5 R8 k, k
  33. 2 d& o& \0 Q9 j$ [$ g
  34. /* DMA发送配置 */
    + _5 B' F: P% K7 ^' n( ~5 P/ w6 @. o3 q
  35.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->TXDR,
    ! R" l) s8 q4 r& A
  36. hspi->TxXferCount))' [7 }' X7 r) @( m( P& X
  37.   {6 }8 `9 s0 I* k) I: n9 Y3 v
  38.   }
    + f" C* b/ i: ~7 f, I. |6 ~
  39. 1 v9 k+ k* R; i: M& Y$ a
  40.   /* 省略未写 */
    : n0 d! V, n# }! ~. L
  41. }
      v) m& k1 ^( I8 g
复制代码
8 V" M' s# c* N# P' b* i
函数描述:
# v0 `7 Z: U8 W* ~! d& l% B0 c3 y8 G4 k. S4 C' `% L+ z
此函数主要用于SPI数据收发,全双工DMA方式。
" d& n' m0 _- ?1 E& L9 H6 u! M; ]- M4 M5 y) P
函数参数:* s6 p) P0 Q! r8 T1 K- U0 P$ M& e

. O. L6 ]% Z$ z( X- h  k1 D  第1个参数是SPI_HandleTypeDef类型结构体指针变量。+ D: Q( d1 Z* I3 p
  第2个参数是发送数据缓冲地址。
" }+ P3 O" \; c; q: ?: p, ^8 v' g) z  第3个参数是接收数据缓冲地址。8 O! P1 ~) |$ R9 o6 e" _
  第4个参数是传输的数据大小,单位字节个数。+ [4 N) ]) `4 ^! r' U8 u5 b
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。4 P/ U% F. n( L/ R7 E+ [4 S7 U/ ^& {# Q

* E  v/ K0 \" e1 Z' K0 Z. t. _' B+ V: y3 x7 j
使用举例:
& I) R! c8 J; \2 P' K
. ?4 e' F* d! v) L4 {
  1. SPI_HandleTypeDef hspi = {0};; S( l0 _- ^& Q" q4 r

  2. , R( x& c' M6 O; o# b
  3. if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    ' h# A" t; I$ z, u( c
  4. {7 |8 W+ {  E8 Q& _8 N
  5.     Error_Handler(__FILE__, __LINE__);  G2 _; a9 @: Y
  6. }
    . h  q) l: L2 _: Q; f8 ?; ~1 P/ [# k. T
复制代码
  {  b! H9 W5 I$ ?1 d" x- j
72.5 总结
$ I5 _& ~& F( |/ S+ w本章节就为大家讲解这么多,要熟练掌握SPI总线的查询,中断和DMA方式的实现,因为基于SPI接口的外设芯片很多,熟练后,可以方便的驱动各种SPI接口芯片,以便选择合适的驱动方式。
. f4 c! a+ H( N! o4 G# z7 S
: G& l4 n- w8 ]4 S% C- l
0 C1 \# D: ^& w! L+ s4 E0 N; V  a% M

- ^- E6 [6 j0 R: ^6 A, M
. @3 X* i6 m3 t0 Y4 E
收藏 评论0 发布时间:2021-12-20 19:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版