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

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

[复制链接]
STMCU小助手 发布时间:2021-12-20 19:00
72.1 初学者重要提示1 h: B& B! m5 m: I. ^5 n
  STM32H7的SPI支持4到32bit数据传输,而STM32F1和F4系列仅支持8bit或者16bit。
( g- F0 e+ E; p+ a  STM32H7的主频400MHz时,SPI1, 2, 3最高通信时钟是100MHz,而SPI4, 5, 6是50MHz。& U: O  ^+ H) Y8 T+ |
  STM32H7的MISO和MOSI引脚功能可以互换,使用比较灵活。$ t; d- k# U' ~) r$ D/ G
  SPI总线的片选引脚SS在单一的主从器件配置下是可选的,一般情况下可以不使用。
6 M" Z* I4 I5 P1 d$ [- g
! G! @% u: u9 n* {72.2 SPI总线基础知识
' V% @  k5 n) `72.2.1 SPI总线的硬件框图

8 q0 H; u+ O+ G$ c7 q认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SPI的基本功能,然后再看手册了解细节。
; |, x2 |! q& |$ q$ ?* w) O' c0 b- @0 |# m- m- t1 R
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

: }1 v$ U. _: a# n7 V
" V% {* ^4 Q6 ~# T* l2 r" J通过这个框图,我们可以得到如下信息:' l, e, R* p: r6 }1 }
  spi_wkup输出
; u( P, I  Q0 K# f* B+ e
" O. G8 U( q$ W低功耗唤醒信号。) g0 r9 f) N8 E6 ]% @: K" z
  spi_it输出6 q% A- k; e! L' E5 ?3 V% b8 v

+ ~0 J9 {! s! `8 C! q% i9 c1 M( e7 H4 K
spi的中断请求信号。; o4 _% a9 L" I# E7 V
  spi_tx_dma
3 @# d9 i0 f1 `: a- ^2 R4 O( a  spi_rx_dma
* N4 r6 R7 Z( A, q/ s' Q+ w5 t4 p6 t+ F; j2 Z

1 Z# Z$ I( _! y+ l; |spi的DMA发送和接收请求信号。
8 g" u, S+ D" H5 ]8 ]# x  spi_pclk8 x  l' ^! M$ P' z
7 q7 f) P/ x+ Y  h* M0 J0 Q
1 X& T  k& z" f* k
为寄存器提供时钟。0 \  y, X0 J' d" x8 N. Z1 u
  spi_ker_ck' K# \, |* d  @* ^0 h, `) A
; a% t2 Z/ Y( y& s2 A
4 g; N$ p% S# \% L
为spi内核时钟。
6 s: \& k( [; _  SCK(CK),Serial Clock1 E! ]$ A% ^0 U, H
/ |- [- Z. E4 @/ ^" ^' M% ~

9 W. q0 l0 m* H: v" u此引脚在主机模式下用于时钟输出,从机模式下用于时钟输入。
" y' N9 |- x% G2 c) R  MISO(SDI),Master In / Slave Out data; d! g, ]# B% ^  w7 j/ `

3 K' J. u# V0 j7 B" X+ `+ }& n2 {4 o. ~8 h& f7 e* y# C
此引脚在从机模式下用于发送数据,主机模式下接收数据。
6 I4 C- M! S8 ?. n# w! r  MOSI(SDO), Master Out / Slave In data
/ y! d$ V/ {: N2 N% j0 ~7 N+ M( ^# g# d" z6 P) V7 T
; v9 r- V& x6 _, I$ B8 s
此引脚在从机模式下用于数据接收,主机模式下发送数据。1 X& H) A$ M5 r# s! K% k
  SS(WS), Slave select pin
0 y0 P& s* n, h' X/ |7 v7 @* Q/ e; K) Y

5 R/ S! k) @5 n/ Z3 c根据SPI和SS设置,此引脚可用于:- |$ f3 o2 ~2 o+ Z3 D( ], ]# @  W
a. 选择三个从器件进行通信。- O# w- w- s2 z' G

1 A$ K9 e' Y" u1 {- lb. 同步数据帧。9 N) d6 N# K- n' c

7 \8 B  a, b- }+ a- j9 oc. 检测多个主器件之间是否存在冲突。; c& i6 P, R3 l. y

+ ~: M* m. P* h, [8 e通过这个框图还要认识到一点,SPI有三个时钟域,分别是寄存器所在的ABP总线时钟域,内核时钟发生器时钟域以及内核时钟发生器分频后的串行时钟域。0 t5 u; G3 X" ]% c

" q- p1 O+ C. y9 T72.2.2 SPI接口的区别和时钟源(SPI1到SPI6)
5 Z( ^: `$ P) A5 e7 `
这个知识点在初学的时候容易忽视,所以我们这里整理下。
* x. i* k# l8 {- ?5 z( K' ~SPI1到SPI6的区别& O/ ~8 D* ~) j) Z
  SPI1,SPI2和SPI3支持4到32bit数据传输,SPI4,SPI5和SPI6是4到16bit数据传输。2 C( f3 v8 |! V% @
  SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit。
$ {) G3 v1 Y+ _+ p( x: j8 Q
/ E9 M( Q: P3 \) ^9 g. K
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

! `& Q, y" Y2 L
  ~; ^4 F3 e) w6 }6 i  SPI1到SPI6的所在的总线(对应SPI框图的SPI_CLK时钟域)* r$ v' L, R* Z% A; |

1 l2 e- P7 `+ B" G" v0 N4 q' j/ ?' q2 _  \2 H6 k& u0 V5 A
SPI1,SPI4和SPI5在APB2总线,SPI2,SPI3在APB1总线,SPI6在APB4总线。注意,SPI的最高时钟不是由这些总线决定的。' U. l) ^' l- s1 K7 g

; l1 T3 R1 m" W* i3 W' ?  SPI1到SPI6的支持的最高时钟(对应SPI框图的SPI_KER_CK)
$ j  x  H! x1 _4 l0 R3 j( B
0 y$ i: }  T9 l+ ^5 ~! m4 O# Q9 d2 z1 @
STM32H7主频在400MHz下,SPI1,SPI2和SPI3的最高时钟是200MHz,而SPI4,5,6是100MHz, 以SPI1为了,可以选择的时钟源如下:. C3 e& _1 q! `) f

( P8 R* W4 k# }) O
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
$ E( M# e1 W  [+ x3 [- L: c
4 {% O# p, D- K
这里特别注意一点,SPI工作时最少选择二分频,也就是说SPI1,2,3实际通信时钟是100MHz,而SPI4,5,6是50MHz。/ c. H. T, G$ I0 o

% P- M. K% c1 o8 D, `* z6 K- }72.2.3 SPI总线全双工,单工和半双工通信+ n/ u9 E/ H+ T; h1 V# |* s2 C
片选信号SS在单一的主从器件配置下是可选的,一般情况下可以不使用。但需要同步数据流,或者用于TI模式时需要此信号。7 s0 B. ^5 I, G9 ]3 ]& k- T

$ A, ^8 \1 T2 C  全双工通信7 b( }/ H  N2 t& f9 \4 x" F" T# m
全双工就是主从器件之间同时互传数据,SPI总线的全双工模式接线方式如下:
3 ~: ^0 k% a# K- @* k6 o9 f
9 P' g1 O/ [2 d' h
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
  I- G7 p9 b. E% |+ k5 ^8 u8 W
* B9 Q4 w, E* d1 J: M1 U
关于这个接线图要认识到以下几点:' Q0 t+ |. i- F$ [* e7 d
  注意接线方式,对于主器件来说MISO引脚就是输入端,从器件的MISO是输出端,即Master In / Slave Out data。MOSI也是同样道理。
1 v! Q% c* U' f+ d- I# k  每个时钟信号SCK的作用了,主器件的MISO引脚接收1个bit数据,MOSI引脚输出1个bit数据。
/ H9 a& _2 B4 P3 w' s  _  这种单一的主从接线模式下,SS引脚可以不使用。: Q9 H1 A: _9 `: i1 E3 j) S1 t# R6 {# a

" z/ a; `3 T+ y$ @3 P  n, k半双工通信
7 _( Z# a9 ]" P半双工就是同一个时刻只能为一个方向传输数据,SPI总线的半工模式接线方式如下:! q: @: n5 y! |/ W! g0 ]

+ R0 N3 K; f. [. r% F  q3 V: |
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
8 c% Z8 |& O1 c) u$ k
2 I- j- z" Z# g% I1 \, ~
关于这个接线图要认识到以下几点:
3 _% h7 Y7 T3 i# I% i* R2 b* q) \# ^
  更改通信方式时,要先禁止SPI。
" {6 @4 U4 w, z( o0 N; S  主器件的MISO和从器件的MISO不使用,可以继续用作标准GPIO。& ]6 X' q$ H- Z, B$ x+ m  w- B
  1KΩ的接线电阻很有必要,因为当主器件和从器件的通信方向不是同步变化时,容易出现其中一个输出低电平,另一个输出高电平,造成短路。0 M* E+ i) F6 R, U  K( \/ y
  这种单一的主从接线模式下,SS引脚可以不使用。
' ~9 Y4 y# H  \3 C. x$ K  o. C7 [    `0 D% X4 F- A* ]. Q( `
单工模式  K8 q! L, m+ Q
单工就是只有一种通信方向,即发送或者接收,SPI总线的全双工模式接线方式如下:5 X/ w+ k8 D1 u7 M/ U

5 W5 n1 D' s: A. m% }7 {
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
2 S- O# u2 y. q: B
+ F6 a+ W, p2 X6 w& n
关于这个接线图要认识到以下几点:2 J3 X; h. @6 D4 q

( I: u1 e9 d2 i+ L8 A- y  a& N& i  未用到的MOSI或者MISO可以用作标准GPIO。. ]7 O  s; ?6 N4 i/ s) s
  这种单一的主从接线模式下,SS引脚可以不使用。/ s: H4 @2 x4 a0 W' ?
* `; a3 t- o  b0 Y8 k. F, d
72.2.4 SPI总线星型拓扑
: f1 n9 T: B4 Y( p5 j9 I/ eSPI总线星型拓扑用到的地方比较多,V7开发板就是用的星型拓扑外接多种SPI器件:
3 X/ Y4 s9 N. A3 O1 }& R& g. }$ \, S. T: d7 b
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

! A3 \/ y: \9 ^. r% i/ Z& r
/ R, g9 f# K. W1 K  a( ^/ f关于这个接线图,有以下几点需要大家了解:  M, y- ]6 @2 M! m
4 {" p; V6 J7 \' Y0 ^8 l: b( c9 \
  主器件的SS引脚不使用,使用通用GPIO控制。为每个器件配一个SS引脚,方便单独片选控制。
1 X, _* M1 N% K! T6 c  从器件的MISO引脚要配置为复用开漏输出(很多外部芯片在未片选时,数据引脚是呈现高阻态)。
/ ^8 ^0 }7 S7 @# n+ J2 c
: g; X' L+ r5 O" R; _3 T, ?3 D" `9 S. j: n6 _% S
72.2.5 SPI总线通信格式* G, Z' W7 i* }! ?& \
SPI总线主要有四种通信格式,由CPOL时钟极性和CPHA时钟相位控制:
0 ~. B8 R* x' `! }* S* R
8 X; B% p) {! N* B5 w9 [" u' p
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

) l/ y, b2 I% n( Q1 W; E5 z9 S% \" u$ ]3 v) A' b$ w2 s0 V
四种通信格式如下:
2 s; n2 C+ @# y  K1 ]* m  当CPOL = 1, CPHA = 1时; o% ^) ~4 q, M/ G4 ~

( v5 I/ U; N& L) Q4 E; \
* \; D6 }: H# D: RSCK引脚在空闲状态处于低电平,SCK引脚的第2个边沿捕获传输的第1个数据。* J8 B1 @1 l( l
  当CPOL = 0, CPHA = 1时$ r7 {3 `7 c0 T! e

/ u9 y; Y% w) ^  B, D' O
- E7 v' @! A5 l0 w1 G* Y: jSCK引脚在空闲状态处于高电平,SCK引脚的第2个边沿捕获传输的第1个数据。1 @) v5 T' O# g/ M! q' c
  当CPOL = 1, CPHA = 0时
& z( n/ q* v8 n7 q7 ]$ y; C
6 o; Z2 Q! J" m  W9 H+ b1 B" b+ {7 c* A: c5 ~/ G
SCK引脚在空闲状态处于低电平,SCK引脚的第1个边沿捕获传输的第1个数据。
# n  K  i" b' `) }& ?2 |  当CPOL = 1, CPHA = 0时
: j8 ^- e4 R4 q( [! }
/ |$ `% q* E0 D; a4 `! u
6 ?+ X7 D; g4 d0 rSCK引脚在空闲状态处于高电平,SCK引脚的第1个边沿捕获传输的第1个数据。
1 F; `9 p8 ]$ l* b) R* n6 K1 b" k/ c- Z* l" ^  R$ {0 H2 y) c
72.3 SPI总线的HAL库用法

9 h1 w. S6 m0 k; Y72.3.1 SPI总线结构体SPI_TypeDef* k! Y/ D, f' l+ K& }
SPI总线相关的寄存器是通过HAL库中的结构体SPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:% f7 M, v! I1 `! T/ M

$ @! x' V6 M$ u& `0 a2 y" ^# ]
  1. typedef struct
    / `' w0 v, j( k2 o9 [$ w5 k% w
  2. {
    8 ?5 m$ R0 j2 A& b/ s9 O( E
  3.   __IO uint32_t CR1;           /*!< SPI/I2S Control register 1,                      Address offset: 0x00 */
    ! z0 n. K9 k* B" g
  4.   __IO uint32_t CR2;           /*!< SPI Control register 2,                          Address offset: 0x04 */! D, H3 ?: v. b4 r2 r1 y
  5.   __IO uint32_t CFG1;          /*!< SPI Configuration register 1,                    Address offset: 0x08 */  Z+ ]% P7 W. D9 F. }0 A! `
  6.   __IO uint32_t CFG2;          /*!< SPI Configuration register 2,                    Address offset: 0x0C */; ~7 {& @+ ^# R% N* f* N& t
  7.   __IO uint32_t IER;           /*!< SPI/I2S Interrupt Enable register,               Address offset: 0x10 */
    ; S2 U( J9 ]$ [  X* E9 e7 m
  8.   __IO uint32_t SR;            /*!< SPI/I2S Status register,                         Address offset: 0x14 */6 M5 L. K  x) ~
  9.   __IO uint32_t IFCR;          /*!< SPI/I2S Interrupt/Status flags clear register,   Address offset: 0x18 */" y1 D8 d7 \' P0 B
  10.   uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                        */. s8 N/ G7 R. m3 g5 k5 x
  11.   __IO uint32_t TXDR;          /*!< SPI/I2S Transmit data register,                  Address offset: 0x20 */5 E, q$ \( g: w/ y( C
  12.   uint32_t      RESERVED1[3];  /*!< Reserved, 0x24-0x2C                                                   */
    ' h0 i6 `) ^3 k
  13.   __IO uint32_t RXDR;          /*!< SPI/I2S Receive data register,                   Address offset: 0x30 */
    + y- D2 K1 N; T# z. M5 q; f3 f( {
  14.   uint32_t      RESERVED2[3];  /*!< Reserved, 0x34-0x3C                                                   */
    4 d: [; r3 _, }/ p3 T
  15.   __IO uint32_t CRCPOLY;       /*!< SPI CRC Polynomial register,                     Address offset: 0x40 */- m5 W0 I  m+ E9 n6 L7 d2 t! E( v
  16.   __IO uint32_t TXCRC;         /*!< SPI Transmitter CRC register,                    Address offset: 0x44 */
    8 N4 A6 p: k6 R  c
  17.   __IO uint32_t RXCRC;         /*!< SPI Receiver CRC register,                       Address offset: 0x48 */) j/ m5 T& d9 r. ~3 g
  18.   __IO uint32_t UDRDR;         /*!< SPI Underrun data register,                      Address offset: 0x4C */7 v* d) f0 W2 u0 i; G( p; @
  19.   __IO uint32_t I2SCFGR;       /*!< I2S Configuration register,                      Address offset: 0x50 */
    . Q, u; w; N. g; g8 k' T
  20. ) `6 H2 L3 v+ `" [: u& [
  21. } SPI_TypeDef;
复制代码
8 d3 X3 o% ?( G% ?. D/ x; ?
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
$ I  T3 c9 r5 O/ ^0 Y; R
( @% D5 \# Q8 x& k+ U__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:# c) A5 S$ e3 d

8 `8 p( F4 M( E, R
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */- y7 d! I$ c% w! |
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
- N  J) @: q9 q
下面我们看下SPI的定义,在stm32h743xx.h文件。6 ]" E% y8 q5 C1 A( u& e' y

: p) {7 k% f+ @5 b
  1. #define PERIPH_BASE           (0x40000000UL) 5 y) D- j; Q- x1 P
  2. #define D2_APB1PERIPH_BASE     PERIPH_BASE
    / a' c  {! ?' X" @. ~. ^( F' `
  3. #define D2_APB2PERIPH_BASE    (PERIPH_BASE + 0x00010000UL)
    " v4 l5 l: S# \7 A3 y( p
  4. #define D3_APB1PERIPH_BASE    (PERIPH_BASE + 0x18000000UL)
    5 R8 C% [+ T  h/ s' I  v1 z  d' x

  5. 4 l: o* T; u2 _
  6. #define SPI2_BASE             (D2_APB1PERIPH_BASE + 0x3800UL)
    9 {0 n' r- E/ k$ y3 e- `7 T
  7. #define SPI3_BASE             (D2_APB1PERIPH_BASE + 0x3C00UL)4 Q2 k3 ~  H0 E7 ^4 V% S1 M
  8. #define SPI1_BASE             (D2_APB2PERIPH_BASE + 0x3000UL)% i1 o. g8 R* s/ o7 F. Q- d; O
  9. #define SPI4_BASE             (D2_APB2PERIPH_BASE + 0x3400UL)1 ]( a# ]% |  N9 B6 K
  10. #define SPI5_BASE             (D2_APB2PERIPH_BASE + 0x5000UL)
    4 O, ~4 N+ \2 G5 T6 o( G
  11. #define SPI6_BASE             (D3_APB1PERIPH_BASE + 0x1400UL)
    ( B9 v7 `3 X8 [( ^( p8 V

  12.   J% o! Z" q& d$ q7 E9 o) v& m
  13. #define SPI1                ((SPI_TypeDef *) SPI1_BASE)
    . V5 N% y$ e: ^( V& R) o
  14. #define SPI2                ((SPI_TypeDef *) SPI2_BASE)
    8 q7 M% d" r2 k: w6 t5 ~
  15. #define SPI3                ((SPI_TypeDef *) SPI3_BASE)
    * e8 F2 G# n) z* k& Q% z( Q
  16. #define SPI4                ((SPI_TypeDef *) SPI4_BASE)
    , d$ D* q5 G) n& H5 ^2 ]# a0 [
  17. #define SPI5                ((SPI_TypeDef *) SPI5_BASE)& S8 ?$ P/ K7 a5 {8 @& g
  18. #define SPI6                ((SPI_TypeDef *) SPI6_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x58001400
复制代码

5 h* p, A/ r1 K8 r, a我们访问SPI的CR1寄存器可以采用这种形式:SPI->CR1 = 0。( W/ y% o  [' P7 G

& j) H" x: P/ Z0 K8 C3 d  M, r$ c72.3.2 SPI总线初始化结构体SPI_InitTypeDef

. B6 Y7 J8 @7 u( z. _$ x2 G7 _下面是SPI总线的初始化结构体,用到的地方比较多:6 p+ M/ w& d% I4 v
" w+ R1 n- D: g' u' f& E: i% N
  1. typedef struct7 e3 G/ Y' C1 L: \* [
  2. {1 ~; j- t( M" S) J" ^/ {- @- I
  3.   uint32_t Mode;                            7 f& x' J  s/ T0 ~0 N
  4.   uint32_t Direction;                      6 G; z  v' |' d& L8 E* x
  5.   uint32_t DataSize;                            \2 I9 U! ?4 G  n  ?2 C7 y
  6.   uint32_t CLKPolarity;                       ( [3 D- Q0 K  I& ^
  7.   uint32_t CLKPhase;                         3 I6 G! H6 M" d1 S% c$ b- r0 _5 I
  8.   uint32_t NSS;                             
    9 h$ `* ?) t6 o3 Y; E# ]+ {
  9.   uint32_t BaudRatePrescaler;               
    / C+ d/ |& b8 X% K
  10.   uint32_t FirstBit;                         7 q3 ?% N, W8 m! N2 M9 a' r* I
  11.   uint32_t TIMode;                          
    ' W; P, [& x( d8 ]1 I/ C
  12.   uint32_t CRCCalculation;                   & K. a! F0 J4 o% f0 ?2 }" y; e/ M
  13.   uint32_t CRCPolynomial;                     5 {: Q& k; p! @% E1 }
  14.   uint32_t CRCLength;                        * u7 M  C3 g  T* N
  15.   uint32_t NSSPMode;                        
    7 j0 R( E# Q; v
  16.   uint32_t NSSPolarity;                    
    / X9 Q6 m% B. _8 _4 d
  17.   uint32_t TxCRCInitializationPattern;       8 a) a) \7 o5 T0 @
  18.   uint32_t RxCRCInitializationPattern;       ! y' t+ ]' L- ~' S& l
  19.   uint32_t MasterSSIdleness;                 / Y' @7 `- \; p) N5 X  @; h+ @9 D
  20.   uint32_t MasterInterDataIdleness;           
    9 Z! o; I5 f' o9 |' B: \6 u
  21.   uint32_t MasterReceiverAutoSusp;         
    7 p8 `& `) f: V% f9 \+ V7 Z3 P
  22.   uint32_t MasterKeepIOState;               ! P% h" G6 U+ p' f# z$ m  ^+ e# a% G
  23.   uint32_t IOSwap;                          
    - n, k+ `# V* ?9 u: z0 [
  24. } SPI_InitTypeDef;
复制代码

0 g2 a$ A# Y' I% E* \- t下面将结构体成员逐一做个说明:
( u) l  ]& O( A% L2 o6 p+ e. m6 ]  Mode9 E" Y: _9 ?* S; s4 r2 ?: r  Y
9 Z! g. @+ }9 e' _/ ^
用于设置工作在主机模式还是从机模式。4 a$ @' {' i+ b/ g! {
  1. #define SPI_MODE_SLAVE              (0x00000000UL)
    4 J( H6 U! z" ~4 w% h, ?$ m
  2. #define SPI_MODE_MASTER             SPI_CFG2_MASTER
复制代码

- N+ z2 G' [5 |- z; c8 J& ^% R  Direction$ ?  O! [. e. Z1 L2 [3 ?! z, P, n) B' i" F
用于设置SPI工作在全双工,单工,还是半双工模式。
! K" G6 f1 _3 ], Q
. L( w$ P- u( u3 }3 t# \
  1. #define SPI_DIRECTION_2LINES           (0x00000000UL)     /* 全双工 */
    4 Y0 m* v4 [  d: I
  2. #define SPI_DIRECTION_2LINES_TXONLY     SPI_CFG2_COMM_0   /* 单工,仅发送 */1 G3 o0 U! q, N, {# N
  3. #define SPI_DIRECTION_2LINES_RXONLY     SPI_CFG2_COMM_1   /* 单工,仅接收 */1 a3 I2 a' N6 s1 X
  4. #define SPI_DIRECTION_1LINE             SPI_CFG2_COMM     /* 半双工 */
复制代码

, t' w9 H: c  S4 x  DataSize
$ a' Y4 B- e/ d用于设置SPI总线数据收发的位宽,支持4-32bit。/ s' ]+ V% [& h) b
, Y; S, g* F& @; J7 _  C7 F
  1. #define SPI_DATASIZE_4BIT                             (0x00000003UL)3 E4 n  k1 b" i; U$ n, h% A
  2. #define SPI_DATASIZE_5BIT                             (0x00000004UL)
    - B7 Z# f, s$ u% U/ o3 `3 L$ f5 b
  3. #define SPI_DATASIZE_6BIT                             (0x00000005UL). t) q, S! X: u" j6 ^0 o/ F
  4. #define SPI_DATASIZE_7BIT                             (0x00000006UL)( ^/ p' {7 W7 A. e( h
  5. #define SPI_DATASIZE_8BIT                             (0x00000007UL)- r. |6 u. P: j# j7 X- r
  6. #define SPI_DATASIZE_9BIT                             (0x00000008UL)$ d3 ]+ W; o% A
  7. #define SPI_DATASIZE_10BIT                            (0x00000009UL)
    ! l/ ?; h! I9 E5 k' H% O8 _. v
  8. #define SPI_DATASIZE_11BIT                            (0x0000000AUL)
    4 I7 ^- [" r) m+ T2 z- q
  9. #define SPI_DATASIZE_12BIT                            (0x0000000BUL)& \2 |& R& e# {: X
  10. #define SPI_DATASIZE_13BIT                            (0x0000000CUL)
    1 C3 X3 \- x# h5 K/ W
  11. #define SPI_DATASIZE_14BIT                            (0x0000000DUL)+ J3 ?3 ^! o. O8 g
  12. #define SPI_DATASIZE_15BIT                            (0x0000000EUL)2 t, R1 I/ a6 E3 `  Q
  13. #define SPI_DATASIZE_16BIT                            (0x0000000FUL)  x7 G0 m& ]( }1 L% l5 y
  14. #define SPI_DATASIZE_17BIT                            (0x00000010UL)
    $ v4 j) |; Q5 C9 _! m; u; U
  15. #define SPI_DATASIZE_18BIT                            (0x00000011UL)2 {6 z! P2 F, C6 h/ ~; p
  16. #define SPI_DATASIZE_19BIT                            (0x00000012UL)
    6 W* \  S) [3 H
  17. #define SPI_DATASIZE_20BIT                            (0x00000013UL)
    0 P$ {( K( M& G" E$ ?9 Q% C
  18. #define SPI_DATASIZE_21BIT                            (0x00000014UL)
    - z! f4 P9 e; p
  19. #define SPI_DATASIZE_22BIT                            (0x00000015UL)- ~$ g9 o0 G! P# ~6 f
  20. #define SPI_DATASIZE_23BIT                            (0x00000016UL)4 n$ {& y' e7 ?) {/ q" R* m
  21. #define SPI_DATASIZE_24BIT                            (0x00000017UL)) {) ?8 M* [1 y; E% X. {5 k3 L
  22. #define SPI_DATASIZE_25BIT                            (0x00000018UL)
    2 ^8 @& Y. }: b9 x& d3 g
  23. #define SPI_DATASIZE_26BIT                            (0x00000019UL)
      K9 W9 B& V! J' k9 {1 c1 U
  24. #define SPI_DATASIZE_27BIT                            (0x0000001AUL)0 ^, u$ M2 P! w9 [* n6 X3 d" S
  25. #define SPI_DATASIZE_28BIT                            (0x0000001BUL)7 b2 T( k# }; {& ]9 p5 p- y
  26. #define SPI_DATASIZE_29BIT                            (0x0000001CUL). e" f5 x6 X) O
  27. #define SPI_DATASIZE_30BIT                            (0x0000001DUL)
    5 w9 q* D6 x: A3 ^, n+ f/ t
  28. #define SPI_DATASIZE_31BIT                            (0x0000001EUL)0 g5 j8 \9 J8 x) {& _* j" W
  29. #define SPI_DATASIZE_32BIT                            (0x0000001FUL)
    ' |" U/ f* K; s
复制代码
4 N2 c" M, U. I% l9 W& `2 j4 v
3 Y) |- W8 o: V0 ]% D/ c1 o  \8 @
  CLKPolarity6 {$ E1 A3 }4 e3 l  F" s
用于设置空闲状态时,CLK是高电平还是低电平。9 F' i8 H0 O7 F' {: v0 t
  1. #define SPI_POLARITY_LOW       (0x00000000UL)
    - f8 K3 F! ?* g9 ^+ f
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码

& O9 N* s$ ?5 _6 G9 }6 k; i  NSS
8 [. i! g: u( m1 l" K! N用于设置NSS信号由硬件NSS引脚管理或者软件SSI位管理。
4 L/ B* u1 A, R& Q
' p) ~( F7 w% u
  1. #define SPI_NSS_SOFT                                  SPI_CFG2_SSM- V( ~$ v2 ]5 r: w( O3 a, M0 _: I0 |
  2. #define SPI_NSS_HARD_INPUT                            (0x00000000UL)6 @- D- N& w$ F3 Y+ J
  3. #define SPI_NSS_HARD_OUTPUT                           SPI_CFG2_SSOE
复制代码

  r9 H3 O9 L. d+ f6 c" N  BaudRatePrescaler" ~- m  }& J" s
用于设置SPI时钟分频,仅SPI工作在主控模式下起作用,对SPI从机模式不起作用。) U' [; R; u$ ^! Y7 F3 i0 N

0 x; S% F! ]  R" N9 L8 [
  1. #define SPI_BAUDRATEPRESCALER_2                       (0x00000000UL)4 p' \9 L0 I( X8 O8 p( E, e6 I
  2. #define SPI_BAUDRATEPRESCALER_4                       (0x10000000UL)9 \+ o, {( C$ @; N4 \
  3. #define SPI_BAUDRATEPRESCALER_8                       (0x20000000UL)
    3 I8 Z! {& G( P# {; H
  4. #define SPI_BAUDRATEPRESCALER_16                      (0x30000000UL)
    " {) j  r! F; o' m% w+ C
  5. #define SPI_BAUDRATEPRESCALER_32                      (0x40000000UL)
    . `' |7 j7 R/ c) ]/ r8 P
  6. #define SPI_BAUDRATEPRESCALER_64                      (0x50000000UL)
    ! r) p% z& ~% q
  7. #define SPI_BAUDRATEPRESCALER_128                     (0x60000000UL)* h9 }: D0 q& ~2 r0 o: ^$ A; ~
  8. #define SPI_BAUDRATEPRESCALER_256                     (0x70000000UL)
复制代码

( W& q1 ?7 H% ?% F  FirstBit
* `% q& K5 Q! s. Y; v) s' g# d$ w" m用于设置数据传输从最高bit开始还是从最低bit开始。$ y" G: B3 M2 \8 R* ~, e
  1. #define SPI_FIRSTBIT_MSB                              (0x00000000UL)9 ^4 M! f6 j" |" d9 o( w2 P
  2. #define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST
复制代码
$ k0 y& O0 _. v# I( X. m+ Y
  TIMode: A! V0 j' I' V
用于设置是否使能SPI总线的TI模式。1 R2 y, R6 M8 R8 X  e. i
  1. #define SPI_TIMODE_DISABLE               (0x00000000UL)
    $ F, V" L' Q4 B/ L7 D- J9 i$ C
  2. #define SPI_TIMODE_ENABLE                SPI_CFG2_SP_0
复制代码

9 B; K. L: _" g, y0 @  CRCCalculation' ~2 R& {5 L5 X+ l
用于设置是否使能CRC计算。
( a' l9 B. P: b$ c; y8 Q/ b  n
  1. #define SPI_CRCCALCULATION_DISABLE                    (0x00000000UL)
    % B8 P# S# H5 A
  2. #define SPI_CRCCALCULATION_ENABLE                     SPI_CFG1_CRCEN
复制代码
# O  H( H: F8 F. f/ J  g
  CRCPolynomial8 E8 J* K0 N2 |7 r  e
用于设置CRC计算使用的多项式,必须是奇数,范围0到65535。8 O* O; \/ v% L/ D
+ o. i& I5 p6 D) j6 ]. S' k
  CRCLength: P, C+ O1 N* T' N8 u4 W
用于设置CRC计算时的CRC长度。大小要与同属此结构体的DataSize一致。或是DataSize的整数倍。
2 ^% i$ L9 O! A
4 S- @. j" p4 F1 @9 J, i: u* h9 Q
  1. #define SPI_CRC_LENGTH_DATASIZE                       (0x00000000UL)
    . I5 s4 p  K' g1 ?/ o
  2. #define SPI_CRC_LENGTH_4BIT                           (0x00030000UL)
    0 R' \+ r7 _1 s
  3. #define SPI_CRC_LENGTH_5BIT                           (0x00040000UL)
    6 y7 q8 s9 O! d  G: [/ K. M
  4. #define SPI_CRC_LENGTH_6BIT                           (0x00050000UL)% U! Q+ X0 x% `" P
  5. #define SPI_CRC_LENGTH_7BIT                           (0x00060000UL)
    . L# x( `/ o9 M! U
  6. #define SPI_CRC_LENGTH_8BIT                           (0x00070000UL)* \* l5 q7 m( j- ]' n) `" q
  7. #define SPI_CRC_LENGTH_9BIT                           (0x00080000UL)
    + c% |+ v9 H  Z8 C( D
  8. #define SPI_CRC_LENGTH_10BIT                          (0x00090000UL)
    ; x2 I7 Q( o$ U* N% Z3 |8 f
  9. #define SPI_CRC_LENGTH_11BIT                          (0x000A0000UL)" |4 T& h" W6 ~- L
  10. #define SPI_CRC_LENGTH_12BIT                          (0x000B0000UL)0 n, i* |4 E0 M, C, u  |( T
  11. #define SPI_CRC_LENGTH_13BIT                          (0x000C0000UL)* `: |* ~% l! L
  12. #define SPI_CRC_LENGTH_14BIT                          (0x000D0000UL)
      ~3 a3 }% h  }) i0 N: F/ A
  13. #define SPI_CRC_LENGTH_15BIT                          (0x000E0000UL)9 c7 |9 _5 }' w0 ~
  14. #define SPI_CRC_LENGTH_16BIT                          (0x000F0000UL)/ A; Q0 d9 ^( S  G" r/ c" Q! H
  15. #define SPI_CRC_LENGTH_17BIT                          (0x00100000UL)' d. p, d3 ]$ g
  16. #define SPI_CRC_LENGTH_18BIT                          (0x00110000UL)
    " ]" K( N6 W. Q, f
  17. #define SPI_CRC_LENGTH_19BIT                          (0x00120000UL)$ k3 e* R2 r6 t# i+ o4 ^
  18. #define SPI_CRC_LENGTH_20BIT                          (0x00130000UL)
    ' y, n. k8 u' l2 o- u9 e
  19. #define SPI_CRC_LENGTH_21BIT                          (0x00140000UL)
    8 ~) w9 `! p1 Q* E7 b) J7 f% ?
  20. #define SPI_CRC_LENGTH_22BIT                          (0x00150000UL)
    : A6 {# [3 [, c' X
  21. #define SPI_CRC_LENGTH_23BIT                          (0x00160000UL)
    + l. U+ Q- W0 a
  22. #define SPI_CRC_LENGTH_24BIT                          (0x00170000UL)2 e- s  G- y6 o8 }' T0 ~
  23. #define SPI_CRC_LENGTH_25BIT                          (0x00180000UL)' b. o- n# }; h4 h/ q9 m8 j% D$ F! Q
  24. #define SPI_CRC_LENGTH_26BIT                          (0x00190000UL)
    6 O- M9 O9 y3 g# `0 b3 p) Q- t  M
  25. #define SPI_CRC_LENGTH_27BIT                          (0x001A0000UL)
    ) Z1 l; q  S  J" C' T
  26. #define SPI_CRC_LENGTH_28BIT                          (0x001B0000UL)$ j, o5 Q4 i" x2 H$ K3 Z
  27. #define SPI_CRC_LENGTH_29BIT                          (0x001C0000UL)
    4 j, g) r2 ^2 S! w0 T+ _2 {7 E
  28. #define SPI_CRC_LENGTH_30BIT                          (0x001D0000UL)1 s; m2 M1 I+ {, l; T9 Y
  29. #define SPI_CRC_LENGTH_31BIT                          (0x001E0000UL)
    , l0 p' Z/ s7 h- Y1 k' \9 |
  30. #define SPI_CRC_LENGTH_32BIT                          (0x001F0000UL)% d" n5 l" J: |
复制代码

2 ~' ~: t  s+ [( z# k6 w7 d: ?  NSSPMode
+ ^2 D$ _# U" g1 f& K. `用于设置是否使能NSSP信号,可以通过SPIx_CR2寄存器的SSOM位使能。注意,只有配置为摩托罗拉SPI主控模式时设置此成员才有用。# y- t3 ~1 c5 l# x3 r
  1. #define SPI_NSS_PULSE_DISABLE                         (0x00000000UL)- g- {" i" N" [8 o
  2. #define SPI_NSS_PULSE_ENABLE                          SPI_CFG2_SSOM
复制代码

* [+ V* k& t0 Z) F/ i: g  NSSPolarity
( \0 f, M* X, ]用于设置NSS引脚上的高电平或者低电平作为激活电平。
+ v1 \  \) Q4 F2 \% y5 H
2 U& w! ^' c3 W1 i6 @3 S: U
  1. #define SPI_NSS_POLARITY_LOW                          (0x00000000UL)
    3 u2 D$ s8 G' g, F, V/ S% `- \
  2. #define SPI_NSS_POLARITY_HIGH                          SPI_CFG2_SSIOP
复制代码
! Q" S7 I5 e# u  l% h
  FifoThreshold1 |6 m+ c5 d1 R
用于设置SPI的FIFO阀值。+ e: g9 Z& \; W4 `# M

' }* s% O' u1 K% P0 f1 u( A
  1. #define SPI_FIFO_THRESHOLD_01DATA                     (0x00000000UL)- F) M8 H7 F) D
  2. #define SPI_FIFO_THRESHOLD_02DATA                     (0x00000020UL)! b5 `! k# O$ u2 p! g
  3. #define SPI_FIFO_THRESHOLD_03DATA                     (0x00000040UL)
    ' z7 i/ b0 ]1 r' m3 s# ^: G
  4. #define SPI_FIFO_THRESHOLD_04DATA                     (0x00000060UL)
    * y, `5 U8 ~% N% h
  5. #define SPI_FIFO_THRESHOLD_05DATA                     (0x00000080UL)
    6 y" o0 f" a& a4 D
  6. #define SPI_FIFO_THRESHOLD_06DATA                     (0x000000A0UL)& L3 S2 G7 I" D3 U; g9 R( P4 i/ L
  7. #define SPI_FIFO_THRESHOLD_07DATA                     (0x000000C0UL)
    " ^: i( E& u. d" R
  8. #define SPI_FIFO_THRESHOLD_08DATA                     (0x000000E0UL)
    8 s( U: q. h* C8 `6 |/ x/ b
  9. #define SPI_FIFO_THRESHOLD_09DATA                     (0x00000100UL)- F" Y% N) x+ A* x; e5 j! U7 M
  10. #define SPI_FIFO_THRESHOLD_10DATA                     (0x00000120UL)# \3 T, S& \* _  B. Y: C
  11. #define SPI_FIFO_THRESHOLD_11DATA                     (0x00000140UL)1 M- i. S! I- Y' G
  12. #define SPI_FIFO_THRESHOLD_12DATA                     (0x00000160UL)
    3 I* x4 |! @8 M
  13. #define SPI_FIFO_THRESHOLD_13DATA                     (0x00000180UL)# J7 \' x8 A1 M
  14. #define SPI_FIFO_THRESHOLD_14DATA                     (0x000001A0UL)% g! f% v$ {4 p" m
  15. #define SPI_FIFO_THRESHOLD_15DATA                     (0x000001C0UL)4 t. b! ]$ [' o( v; K
  16. #define SPI_FIFO_THRESHOLD_16DATA                     (0x000001E0UL)
复制代码

- P8 U( w+ x7 o' r  TxCRCInitializationPattern
; ~7 F: |+ ]0 {' Q) W9 m# g发送CRC初始化模式。8 B) Z. G, I( t# l

( D# u& w& {& j# o" \
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    % K! d2 @3 }1 J
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码
7 N, H- ~. I2 \" V, \- t
  RxCRCInitializationPattern
* T# H# k. j! Q# @! c( U" o接收CRC初始化模式
4 o4 U# h8 x7 R) |1 `
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    , O$ v. R6 q4 v1 w
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码

* g$ w! t+ B/ t; c# H" B MasterSSIdleness
; ?* j% X4 {4 v) ~5 T; I在主模式下插入到SS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数。
( G, |' ]( t& G! n0 ]2 a3 P2 q6 S* L/ \* K" X6 c6 q0 J2 E" _
  1. #define SPI_MASTER_SS_IDLENESS_00CYCLE                (0x00000000UL)
    # G/ ~) `9 ~1 o5 l/ y: v
  2. #define SPI_MASTER_SS_IDLENESS_01CYCLE                (0x00000001UL)
    ; {7 Q% }" ^' C0 Z/ a6 C
  3. #define SPI_MASTER_SS_IDLENESS_02CYCLE                (0x00000002UL)
    - y; m* ]1 w, b- N, i+ w( O
  4. #define SPI_MASTER_SS_IDLENESS_03CYCLE                (0x00000003UL)6 ]- P! N4 X, S' a3 H7 X7 j  D
  5. #define SPI_MASTER_SS_IDLENESS_04CYCLE                (0x00000004UL)' }/ n, m' Q% s6 E9 W# W% `/ u
  6. #define SPI_MASTER_SS_IDLENESS_05CYCLE                (0x00000005UL)6 q+ R2 U) m* o
  7. #define SPI_MASTER_SS_IDLENESS_06CYCLE                (0x00000006UL)) P. ?/ g, l/ T- w
  8. #define SPI_MASTER_SS_IDLENESS_07CYCLE                (0x00000007UL)
    " w$ H2 y) a. W7 D7 t. A
  9. #define SPI_MASTER_SS_IDLENESS_08CYCLE                (0x00000008UL)
    - e3 u$ C. m, n* g
  10. #define SPI_MASTER_SS_IDLENESS_09CYCLE                (0x00000009UL)
    : j( G: `- u. b8 ]0 g/ C
  11. #define SPI_MASTER_SS_IDLENESS_10CYCLE                (0x0000000AUL)2 h* N4 j/ R5 r" ]& c' ]
  12. #define SPI_MASTER_SS_IDLENESS_11CYCLE                (0x0000000BUL)1 D0 x/ N- h7 E' g
  13. #define SPI_MASTER_SS_IDLENESS_12CYCLE                (0x0000000CUL)
    & x+ r' F! y/ K1 X# o" I9 ?% v& j/ ?
  14. #define SPI_MASTER_SS_IDLENESS_13CYCLE                (0x0000000DUL)0 J* h" P0 x% F5 C/ e
  15. #define SPI_MASTER_SS_IDLENESS_14CYCLE                (0x0000000EUL)
    / y# d8 _$ q. p$ y
  16. #define SPI_MASTER_SS_IDLENESS_15CYCLE                (0x0000000FUL)
    : _; }$ o% n1 h! S- T
复制代码

; j* A: E0 l# ]5 E  MasterInterDataIdleness
( o' n( L$ H: L5 ~, R' D主模式下在两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数。/ g) L& j5 T. {) q+ M% X3 k' f

) S1 ?5 E' B8 L2 \$ E
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)
    : d4 x9 v( o( D  h5 c3 U* l8 s+ S
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
复制代码

/ ]) J( {4 x* S% b: k4 V  MasterReceiverAutoSusp
  F% ^2 ~0 L1 M% M  e用于控制主器件接收器模式下的连续 SPI 传输以及自动管理,以避免出现上溢情况。
& T$ f. J7 W* ]! d2 ]( Y: j
2 ?# ~% I# |0 A2 ]$ o
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)
    # a- @- v1 ^9 F& Z0 c7 W
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
    ! k- J) b5 G: }8 v0 z; ?
复制代码

( `4 d) v0 V! }9 C# @  MasterKeepIOState+ r. i6 z% V1 h3 D) M- [7 y  f
禁止SPI后,SPI相关引脚保持当前状态,以防止出现毛刺。在从模式下,该位不应该使用。) q+ z/ l6 p$ t; R5 u" q
  1. #define SPI_MASTER_KEEP_IO_STATE_DISABLE              (0x00000000UL)' Z# B7 A2 o7 @' w+ \  X4 I
  2. #define SPI_MASTER_KEEP_IO_STATE_ENABLE               SPI_CFG2_AFCNTR
复制代码
! m; N& \: l% b! P( N$ g
  IOSwap
5 y/ _, X. F; F8 X) N+ w, x! {4 G4 @用于交换MISO和MOSI引脚。+ M7 j. W" B; h. w3 n; n

, w' i1 g7 s+ j+ O0 i, x2 S+ t
  1. #define SPI_IO_SWAP_DISABLE                           (0x00000000UL)8 y: l) I5 _$ Q. I* N* z/ I, j# h
  2. #define SPI_IO_SWAP_ENABLE                            SPI_CFG2_IOSWP
复制代码

! V. K* `, ^* b$ b4 t( x72.3.3 SPI总线句柄结构体SPI_HandleTypeDef

( o; o, V2 C7 Q* ~/ t下面是SPI总线的初始化结构体,用到的地方比较多:: G4 m) T' ~6 N6 s  v, B

# [. Z* \2 }4 Z. a: B; y" M$ v
  1. typedef struct __SPI_HandleTypeDef4 ?4 ^' U! {( g' O# S( w$ F
  2. {- j% }8 e- I$ [' r, B
  3.   SPI_TypeDef                *Instance;                 ( M8 t, L2 @7 ~! H9 b% _( B
  4.   SPI_InitTypeDef            Init;                        . b* g: f- o- Q! P* n, S. S
  5.   uint8_t                    *pTxBuffPtr;                 
    2 J4 Z1 f# h* I: b/ j- {; u0 @5 b
  6.   uint16_t                   TxXferSize;                   ' _& O+ O1 ^# i8 v/ p
  7.   __IO uint16_t              TxXferCount;                  * g$ a, k4 q; p3 w
  8.   uint8_t                    *pRxBuffPtr;               
    , s0 _) I% C' U0 \
  9.   uint16_t                   RxXferSize;                    O$ T5 u# l7 M; X2 h; F2 u0 _
  10.   __IO uint16_t              RxXferCount;                 
    # L6 T- i! C) u# Z- V5 @
  11.   uint32_t                   CRCSize;                     
    ; L8 t: _9 ^. x8 N; H
  12.   void (*RxISR)(struct __SPI_HandleTypeDef *hspi);       8 j. G; i) @6 X; s, Y9 P% r8 b% v6 Y. S
  13.   void (*TxISR)(struct __SPI_HandleTypeDef *hspi);        
    5 w" H, N) I( c* J! Y
  14.   DMA_HandleTypeDef          *hdmatx;                     
    % j( y9 Q# n" Q- a
  15.   DMA_HandleTypeDef          *hdmarx;                     
    ; S& Q. n1 V  m9 c0 Y1 ]  d+ i
  16.   HAL_LockTypeDef            Lock;                        
    . ^# }9 S: a  n1 m
  17.   __IO HAL_SPI_StateTypeDef  State;                        
    ; {9 K4 S& ^5 p2 o; B, A& @/ n
  18.   __IO uint32_t              ErrorCode;                  
    0 |7 {9 J! H+ |3 L% {
  19. #if defined(USE_SPI_RELOAD_TRANSFER). l# P3 U5 e. \# {9 e- E
  20.   SPI_ReloadTypeDef          Reload;                      ) T0 Y" D% S) X! s$ H
  21. #endif % u$ g2 {: e8 c

  22. 4 q) @6 n2 ?) E7 d
  23. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    - \$ a" P/ F* {: o6 M
  24.   void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      
    . J7 ?# M7 u3 M
  25.   void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      9 x# }2 k& w5 G9 ]+ e; L
  26.   void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi);    4 T$ r, l1 o7 D. ^! v( d
  27.   void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  ; |! i2 x: m4 o' T: j. e/ G# R
  28.   void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  
    ( g6 ^0 a+ A6 }- `. s
  29.   void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);
    4 b+ C- W7 {. W) l3 t4 @) }/ o
  30.   void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi);       " L3 L) d' n# C7 M
  31.   void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    3 u: h' h+ n9 P/ F$ m! R+ O
  32.   void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi);   
    + U* R; A* v' t
  33.   void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi);
    & o' I7 {/ K' S% k' J
  34. #endif  
    : ?) }# l% M, _1 S. O# a* L
  35. } SPI_HandleTypeDef;: I: L# t+ i) |# ~, U
复制代码

5 V1 s" }2 N( S: ]; J) L注意事项:% {- W. a* x+ _9 R- V% l
# J, k) \" U5 Z' h6 j
条件编译USE_HAL_SPI_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:$ t- t5 s7 ?: ^$ ?6 r
  b: a; H6 J/ F6 k
  #define   USE_HAL_SPI_REGISTER_CALLBACKS   1
  t% K3 w$ O6 h( z) d6 P# C1 o
+ d$ }; `) _( S4 o' f通过函数HAL_SPI_RegisterCallback注册回调,取消注册使用函数HAL_SPI_UnRegisterCallback。
8 V' z/ |: z( T* L9 S6 B7 T
: {8 z" i+ M7 a, X+ `$ j这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。/ @( @( f2 P4 k8 m+ F# S: {* H, F' G" y

* R4 |3 U' z! A% j" D2 M% `8 t0 t  SPI_TypeDef   *Instance7 u- ~' M) u6 B6 |1 [
这个参数是寄存器的例化,方便操作寄存器,比如使能SPI1。  R9 D1 j1 w/ i

* h# @2 l' T$ @: ~$ ISET_BIT(SPI1 ->CR1,  SPI_CR1_SPE)。5 U8 y1 O+ M  y- y4 T9 |. z* b

! C- ]& R8 X+ d) ^; F! n  SPI_InitTypeDef  Init
+ c4 r) z  i1 g! W9 G5 P" Z这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。
5 H3 C  N4 ^( |% f' U; I, T! E$ J6 A7 X
  DMA_HandleTypeDef          *hdmatx               
  a1 d8 D. w4 h9 n9 S& O# ~  DMA_HandleTypeDef          *hdmarx
' S7 L* X' e$ t9 ]用于SPI句柄关联DMA句柄,方便操作调用。
* ~  l& f" o+ ~8 l' k1 n9 r( B1 b/ t* U9 W
72.4 SPI总线源文件stm32h7xx_hal_spi.c
+ C' F) W: N3 G8 n6 q1 ?+ x此文件涉及到的函数较多,这里把几个常用的函数做个说明:3 \7 [6 h2 }" [
: I7 C' M4 X# m% }3 n, Z6 b
  HAL_SPI_Init
% Q. t( U: G- `) y! y3 x4 q  HAL_SPI_DeInit/ L0 Y( P" Y; R! E7 o7 }
  HAL_SPI_TransmitReceive
* P) o! o  k$ F2 u4 R  HAL_SPI_TransmitReceive_IT" @$ k* r  P  Z& `, B5 [
  HAL_SPI_TransmitReceive_DMA1 R2 F8 v9 i& l! V  N! X  N
* X* O* |: l- F* y7 D
72.4.1 函数HAL_SPI_Init
' F4 `. k1 u3 w; X函数原型:
& f. m8 G. A$ n9 {  h
" Z7 B' L/ f8 x
  1. HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)1 G6 C& t' m5 W
  2. {6 A0 \+ ^! e) J! x3 t# Z1 Z# L  G
  3.   uint32_t crc_length = 0UL;
    " E' |% C. I# d! u
  4.   uint32_t packet_length;" T; ?* L7 u/ |  L# h; J, B
  5. ) }% `2 ?7 c& e: g+ p& ?
  6.   /* 省略未写 */6 f8 {0 D7 `! @# ]: O

  7. $ Y) {# D2 [+ h2 U1 J1 A
  8.   /* 如果数据位宽大于16bit,必须是SPI1,SPI2或者SPI3,而SPI4,SPI5和SPI6不支持大于16bit */$ y. o9 r3 P" Y8 }2 N1 y1 A& x
  9.   if ((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (hspi->Init.DataSize > SPI_DATASIZE_16BIT))& Z8 X) k5 A8 p2 r
  10.   {% b4 B5 q1 R6 o" @
  11.     return HAL_ERROR;
    7 x4 C+ D$ E& T  q3 z$ z- N
  12.   }) A( ~+ _" K) ^& Y5 }+ Z% e- h& i
  13. ; o+ F* l' n' B% u2 N! ?$ D: d
  14.   /* SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit
    ) T3 C( ]5 p7 _( M
  15.      这里是查看设置的缓冲大小是否超出了FIFO支持的大小。
    & D) ]( j$ n% Y
  16. */" z4 o$ W1 D4 _+ m) C
  17.   packet_length = SPI_GetPacketSize(hspi);, \8 K# p# e# ?9 G/ U
  18.   if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_LOWEND_FIFO_SIZE)) ||
    + O- l* v, i9 V0 c. f- l$ ~
  19.       ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_HIGHEND_FIFO_SIZE)))+ }' L% C* z5 {2 w. P: p
  20.   {
    ' u  ~4 k5 L1 C/ H; A1 x( j( k/ K5 @
  21.     return HAL_ERROR;
    4 n; H7 [8 X" t0 o9 c
  22.   }
    4 n4 b9 s3 z. ]* r. ?
  23. + y! ^3 p/ U! \: e! `
  24. #if (USE_SPI_CRC != 0UL)
    2 n+ u5 B1 [+ J+ }& _8 m
  25.     /* 省略未写 */9 K. ~" ]: Y( G, h6 ]
  26. #endif ( t2 J! d4 G8 v$ p, U& D
  27. ) V& }1 ~% R* o6 y* k; o* L8 h) ]
  28.   if (hspi->State == HAL_SPI_STATE_RESET)
    ; U( x7 e' z& w5 w8 g5 c+ ?* O
  29.   {  v/ ]2 _  x5 y8 X: _
  30.     /* 解锁 */
    # q1 k. t8 C) e* P: ?$ J
  31.     hspi->Lock = HAL_UNLOCKED;
    + [/ _5 h9 a1 M
  32. 8 f; ^6 |' c% _0 n% H& b
  33.     /* 使用自定义回调 */+ ]* F, {& o% L3 n0 }
  34. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    , K8 o0 o. G8 y! k2 R# k
  35.     /* 设置默认回调函数 */
    , R( P! O: o! ?# A3 R3 M& Q
  36.     hspi->TxCpltCallback       = HAL_SPI_TxCpltCallback;       /* Legacy weak TxCpltCallback       */
    ) r; [5 r% h1 L& @! ~
  37.     hspi->RxCpltCallback       = HAL_SPI_RxCpltCallback;       /* Legacy weak RxCpltCallback       */( G: I% ~- Z/ P- t9 R
  38.     hspi->TxRxCpltCallback     = HAL_SPI_TxRxCpltCallback;     /* Legacy weak TxRxCpltCallback     */
      h/ Z7 ]4 x# H1 t3 Q
  39.     hspi->TxHalfCpltCallback   = HAL_SPI_TxHalfCpltCallback;   /* Legacy weak TxHalfCpltCallback   */1 s; T6 h; X+ F& U# d. D
  40.     hspi->RxHalfCpltCallback   = HAL_SPI_RxHalfCpltCallback;   /* Legacy weak RxHalfCpltCallback   */
    ; S7 b3 _3 R( b3 N5 V
  41.     hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */
    5 q( t$ ^3 o( {/ |
  42.     hspi->ErrorCallback        = HAL_SPI_ErrorCallback;        /* Legacy weak ErrorCallback        */
    2 [$ R% |% Y# ~7 I( M2 k; P1 v2 P
  43.     hspi->AbortCpltCallback    = HAL_SPI_AbortCpltCallback;    /* Legacy weak AbortCpltCallback    */
    1 S+ \' M, r9 I6 J5 }8 s
  44. ! F# \$ ^& ]8 A: s: ^8 ~% K
  45.     if (hspi->MspInitCallback == NULL)
    # ^" i" w! X, n
  46.     {8 ^7 b0 Y. t7 E% b& a- {
  47.       hspi->MspInitCallback = HAL_SPI_MspInit; & U1 q' v! G4 u* ^7 {/ I
  48.     }6 P0 e" X, R/ W' k
  49. 6 a# B3 g- A# Y8 x# w/ n
  50.     /* 初始化地址硬件: GPIO, CLOCK, NVIC... */! \& t! K: T' U- E
  51.     hspi->MspInitCallback(hspi);+ a# `: J! w! l6 h3 {$ ?
  52. #else
    1 C. `: e2 C. R! m$ h
  53.     /* 初始化底层硬件: GPIO, CLOCK, NVIC... */
    , z' s$ _" K  c% |4 j# G% X
  54.     HAL_SPI_MspInit(hspi);6 R0 s9 W9 b% t2 N; f% C+ s# [" w
  55. #endif4 x/ G9 t# ^3 y( |
  56.   }/ p8 U( J: m! I: \
  57. 8 A7 S  E  |7 G- a' {
  58.   hspi->State = HAL_SPI_STATE_BUSY;
    - i% |* i9 h3 U( c& |4 p
  59. ; @  y/ D' w3 M, \
  60.   /* 禁止SPI外设 */# i0 _- z# n  `9 L
  61.   __HAL_SPI_DISABLE(hspi);8 B& D# O% j2 m6 ~: j+ }9 }5 ]: ^
  62. 0 Z4 l: Q* l5 N6 k5 G8 N
  63.   /*----------------------- SPIx CR1 & CR2 配置---------------------*/0 T1 Z4 P" Z8 q# L0 O. N5 t
  64.   if ((hspi->Init.NSS == SPI_NSS_SOFT) && (hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.NSSPolarity ==
    5 b% `/ G) E1 C. k
  65. SPI_NSS_POLARITY_LOW))
    1 L5 u) N5 i! \" r" [
  66.   {
      ~. A" J- D% m9 i9 V9 e# m
  67.       SET_BIT(hspi->Instance->CR1, SPI_CR1_SSI);
    , W2 G, e. d4 ~( P/ J- U
  68.   }+ W# N. r4 Q' C/ J* K

  69. 7 Y5 c; \3 j' |% x
  70.   /* SPIx CFG1配置 */
    7 H! H- @, F9 A, U
  71.   WRITE_REG(hspi->Instance->CFG1, (hspi->Init.BaudRatePrescaler | hspi->Init.CRCCalculation | crc_length |
    / @' f! w% @4 M( n0 r4 O6 I$ w
  72.                                    hspi->Init.FifoThreshold     | hspi->Init.DataSize));
    1 M9 Q# @$ S3 d. X# g
  73. 3 A$ K8 i. B% x( p
  74.   /* SPIx CFG2配置 */
    % j- x+ ]2 X% H  @4 S: |/ C
  75.   WRITE_REG(hspi->Instance->CFG2, (hspi->Init.NSSPMode     | hspi->Init.TIMode           | hspi->Init.NSSPolarity  |
    + `3 }% l' t( X, \; R+ i0 W/ p
  76.                                    hspi->Init.NSS          | hspi->Init.CLKPolarity      | hspi->Init.CLKPhase     |) p5 @5 R% ~2 S6 H
  77.                                    hspi->Init.FirstBit     | hspi->Init.Mode             | hspi->Init.MasterInterDataIdleness |
    5 j% n% Q: R1 x
  78.                                    hspi->Init.Direction    | hspi->Init.MasterSSIdleness | hspi->Init.IOSwap));7 D/ W  \" E, @0 w5 p& ?& K

  79. ( X, h, G2 I  w7 v# T* g1 x! w
  80. #if (USE_SPI_CRC != 0UL)' U( E5 y+ F+ G2 Z
  81.   /*---------------------------- SPIx CRC配置 ------------------*/
    ) E$ l$ A, k6 g, c# b0 W  U; G  F2 ?
  82.   /* 配置SPI CRC */
    , k' t2 G# q( j
  83.   if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)# N" F/ @' m4 `; @8 a: a2 I# {
  84.   {
    " w5 m! R: x1 M3 p1 q( e" V1 X
  85.     /* 初始化TX CRC初始值 */! E4 T! \' J* z7 e5 I7 s6 T5 E
  86.     if (hspi->Init.TxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)
    1 U# A2 l7 k) _, \9 C! Q  O
  87.     {
    9 Z, C% u' a' N) L- d0 A$ q
  88.       SET_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);( [7 U; ^2 e- o
  89.     }
    . y# H+ b9 `: c/ j/ e. o
  90.     else/ a* [3 [3 }1 f
  91.     {
    ) d9 P( _/ [+ u
  92.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);8 k& W1 S7 I; l6 V% M
  93.     }
    & p% l; w* l" E- j  Y2 e

  94. - G; D6 `  }* f
  95.     /* 初始化RXCRC初始值 */# d! A/ ?& G9 g, ]
  96.     if (hspi->Init.RxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)
    ( \1 Z; `1 s+ L# E0 H
  97.     {6 s, [1 w& @+ G% c4 Y  R0 X/ f
  98.       SET_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);
    1 [" J" f: P! I; a$ |, S- H8 [
  99.     }
    . G# B. u, Q4 B, I  d, g
  100.     else% F  s$ @- w. Z& g# M- I
  101.     {
    % X. l: W5 q9 L- K' D
  102.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);
    & I5 ^' j) L" |' M( @
  103.     }
    8 E! z- v4 c7 h

  104. . t9 ^' r' a+ i4 w
  105.     /* 使能 33/17 bit CRC计算 */
    6 z$ I, ^. N! j' V! e
  106.     if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (crc_length == SPI_CRC_LENGTH_16BIT)) ||* W# X5 {9 e3 M( R& f; z  K( F, k
  107.         ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance))  && (crc_length == SPI_CRC_LENGTH_32BIT)))
    6 a; A9 m, ~$ x+ s7 M
  108.     {
    ( c# O) y2 A0 C- W* @% s
  109.       SET_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);; Z( h3 a& `* p( r$ v
  110.     }. x( ~, _9 I: u7 w2 q& v0 z- [
  111.     else5 x/ f! o& E0 ?6 H
  112.     {/ p4 d/ |( n+ {8 X
  113.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);
    0 M2 ~* }2 U) U" Y+ r
  114.     }) q  H; Q, F& _
  115. 1 D' f7 E4 W% L$ i1 ^+ {8 Z+ U/ B5 q6 L
  116.     /* 写CRC多项式到SPI寄存器 */0 `$ y0 ~/ S' C# E: e' h, p0 y& a
  117.     WRITE_REG(hspi->Instance->CRCPOLY, hspi->Init.CRCPolynomial);4 d' T8 `1 L9 `* t" W1 K
  118.   }
    0 i% E; ?7 ~) r/ e/ Z
  119. #endif * n) J* [9 y6 A" L4 s

  120. , c  g6 ]' a* N. @- E0 E+ _1 D) G
  121.   /* SPI从模式,下溢配置 */) E0 D' U" p3 R5 \) B' V5 b% [
  122.   if (hspi->Init.Mode == SPI_MODE_SLAVE)
    7 `7 M4 G! r! R! }
  123.   {
    + r1 C* Q0 X) |5 @  q
  124.     /* 设置默认下溢配置 */& W7 p6 d8 O( |5 v
  125. #if (USE_SPI_CRC != 0UL)0 M' Z# p0 h, {4 w# K
  126.     if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_DISABLE)
    0 P6 ~- z" L" d! b
  127. #endif
      ]- [" V2 j7 I% v1 C, _& J
  128.     {$ A9 B/ l+ s5 @$ M
  129.       MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRDET, SPI_CFG1_UDRDET_0);# n( h+ J8 _- s4 h
  130.     }" T' Y' t2 k- x- Q
  131.     MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRCFG, SPI_CFG1_UDRCFG_1);
    % ^) E. L2 ?6 L+ m; t$ \$ E( I
  132.   }
    " c2 K% W# _& Z: [
  133. 2 [' A% S1 }- ?; M3 {8 `- r
  134. #if defined(SPI_I2SCFGR_I2SMOD)1 m/ s2 o& U8 z' e* I6 X: u/ D+ d
  135.   CLEAR_BIT(hspi->Instance->I2SCFGR, SPI_I2SCFGR_I2SMOD);$ [# j6 E2 n/ A9 Q, O0 }& p
  136. #endif
    ( Z% }: J; Y+ h5 \: {+ ?7 p4 t

  137. $ z! ^1 I7 p" m5 W' w+ e
  138.   /* 确保AFCNTR bit由SPI主机模式管理 */
    4 Y0 J: L2 F) @+ ?! B
  139.   if ((hspi->Init.Mode & SPI_MODE_MASTER) == SPI_MODE_MASTER)
    " `$ I5 p) d4 F# Z7 w! Y
  140.   {8 G* m; o* p" r, s6 b
  141.     /* Alternate function GPIOs control */
    # L, A$ b, @. r9 v
  142.     MODIFY_REG(hspi->Instance->CFG2, SPI_CFG2_AFCNTR, (hspi->Init.MasterKeepIOState));
    0 s. E; {/ b: o, [- q
  143.   }
    2 ?% _* \1 L: |0 V% b' G& N# Z
  144. : Y; K- v- z' ?- K% L; b, \- s$ N# J
  145.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;
    0 v1 A; |+ V( e7 Z7 W- e
  146.   hspi->State     = HAL_SPI_STATE_READY;1 _% \: x  ?0 G7 M4 F

  147. 2 ~5 ]/ X+ {# J/ o( i2 ^
  148.   return HAL_OK;
    ; x& A2 f& X" y2 T- q
  149. }
    ; Q& Y" R; g1 g. Q* b0 \# c
复制代码
0 k; D" y3 L! u) U7 {2 u/ M

, @, E; |- d7 T3 L$ o函数描述:
' W# C9 s! S0 N3 \
# x6 j4 B- A, l5 x7 r此函数用于初始化SPI。
2 d2 r1 {9 S$ }3 F* v4 ]
  B. d& ~9 `8 U* w函数参数:# s5 M6 H5 X; O, f6 U

& Q/ O+ Y9 p. `1 O( X3 m; r* x  第1个参数是SPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
1 _2 Q, d! S$ @+ D6 O  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
# v" [# H0 M! j+ o0 [% [: Z
: T! E* N0 r9 _  D% Y' G& N! x, W/ Y+ A; D" u
注意事项:
- h) N3 M6 G4 e; {2 V函数HAL_SPI_MspInit用于初始化SPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。; M4 j. F2 z4 j1 I/ i9 r) W' u) ^
如果形参hspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SPI_HandleTypeDef SpiHandle。1 f6 i, ]- ]4 f1 }# M" l
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SPI_STATE_RESET  = 0x00U。/ r  m& r/ M% N9 M* n' Z( X0 G

6 g, p4 ]- A, @# ^7 T: k  `* V6 i解决办法有三
$ ~. ?( c( S' w% Z9 |
8 X& s. F, _: n: M2 ~方法1:用户自己初始化SPI和涉及到的GPIO等。8 d! ?" Y$ Z; \* r. R- v) q) d5 h1 v
) L- E9 _$ @& q/ u! m% E
方法2:定义SPI_HandleTypeDef SpiHandle为全局变量。
% b6 {  j* x$ n* Q5 B+ a
, Q3 z: Z) M: b7 v' }: }: V4 e, `! Z( y方法3:下面的方法
: a3 h6 Y  a1 A" ~  g: x# E3 u( Y  G
, W, l0 w7 J( l" q; L4 v
  1. if(HAL_SPI_DeInit(&SpiHandle) != HAL_OK)) c4 s: A; N8 b% _: C! H0 Q+ z
  2. {9 T$ @! g& `( Q
  3.     Error_Handler();1 M$ m# C8 }) |" p
  4. }  
    2 L* |5 Y5 _2 d) f  L. I  n: S
  5. if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
    " m$ T. E+ x; Y
  6. {
    7 J5 g. W# p, h7 |/ j5 U
  7.     Error_Handler();
    3 c& T) S  n' H, z2 E& e9 V1 L
  8. }
复制代码
& U8 e1 V/ E1 {3 X% p
使用举例:
4 U" S, B. y$ g4 i4 A' K9 @' H
& q5 Q5 @3 y- I
  1. SPI_HandleTypeDef hspi = {0};
    / {6 X# [; H( ~( z# w, n! b. s
  2. ) F$ A* J6 y8 o! a8 D$ J8 w
  3. /* 设置SPI参数 */
    ) |( ~. s: z2 Z
  4. hspi.Instance               = SPIx;                   /* 例化SPI */0 R! Z+ k! _0 o9 d* C
  5. hspi.Init.BaudRatePrescaler = _BaudRatePrescaler;     /* 设置波特率 */1 I  r* ^5 ^9 m+ ]. P2 n
  6. hspi.Init.Direction         = SPI_DIRECTION_2LINES;   /* 全双工 */0 Y2 F- q) e) D" ]
  7. hspi.Init.CLKPhase          = _CLKPhase;              /* 配置时钟相位 */
    * h- a' B  n/ Z* y6 ~& H
  8. hspi.Init.CLKPolarity       = _CLKPolarity;           /* 配置时钟极性 */
    * n( {9 D8 |; w9 |) |+ e2 e  G
  9. hspi.Init.DataSize          = SPI_DATASIZE_8BIT;      /* 设置数据宽度 */
    0 {  k/ L( e$ T- \- k$ W
  10. hspi.Init.FirstBit          = SPI_FIRSTBIT_MSB;       /* 数据传输先传高位 */
    # v# \! J4 w* D, T! N' Q9 f
  11. hspi.Init.TIMode            = SPI_TIMODE_DISABLE;     /* 禁止TI模式  */4 B2 D( A% G1 s" c6 d
  12. hspi.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;      /* 禁止CRC */9 f, n# c* l' x
  13. hspi.Init.CRCPolynomial     = 7;                               /* 禁止CRC后,此位无效 */
    % D7 T. V" o9 d+ _( Z! y6 }
  14. hspi.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;             /* 禁止CRC后,此位无效 */
    6 d" o- i7 N7 q$ L5 e/ D
  15. hspi.Init.NSS               = SPI_NSS_SOFT;                    /* 使用软件方式管理片选引脚 */
    ! j( ^& x& L- b
  16. hspi.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_01DATA;       /* 设置FIFO大小是一个数据项 */
    + D: C* B  Z! ]* ]2 b7 R( m
  17. hspi.Init.NSSPMode          = SPI_NSS_PULSE_DISABLE;           /* 禁止脉冲输出 */
    / X, d7 V; I# z' g4 I" }9 ~
  18. hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  
    / p. S0 I7 e- w) e
  19. hspi.Init.Mode                  = SPI_MODE_MASTER;            /* SPI工作在主控模式 *// s: Q1 G! {" V* E
  20. & ?! x$ [8 Q( j/ r1 \. I
  21. if (HAL_SPI_Init(&hspi) != HAL_OK)
    . c+ i% C0 h( y8 g# z
  22. {5 }4 z0 w% P, i9 f9 m  t
  23.     Error_Handler(__FILE__, __LINE__);
    & O$ ^2 a, [5 z) C1 R  P
  24. }
复制代码
$ i. V+ g# J* J$ V
72.4.2 函数HAL_SPI_DeInit) S% C  L  I% H  I  K7 D1 s
函数原型:
9 w, x9 k% t" B0 }8 _5 w7 O# }
  1. HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)) q( F) A6 W  y% M) w
  2. {$ ]+ ^; a# t" Z. E2 h& V2 @
  3. /* 检测SPI句柄是否有效 */
    ( L! s. t4 m. H3 G3 Y* ?- l5 U
  4.   if (hspi == NULL)
    0 T3 F1 r( g5 C5 J8 k- L
  5.   {7 L/ }" l  u2 x7 f+ F3 v! b
  6.     return HAL_ERROR;& C# H& n' e& q' e7 \1 I
  7.   }" C- ~/ {0 z& h* {: E* F4 }
  8. 1 X/ |# ]3 }# w8 [2 _. `1 @3 y
  9. /* 检查SPI例化参数 */
      v- X% [; _( z$ P' s( q
  10.   assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));- j& Y2 B$ ]; {  u; X
  11. $ w8 D+ ?5 L' z0 a+ }
  12.   hspi->State = HAL_SPI_STATE_BUSY;
    * r; V) B9 t. @" l7 M" z
  13. * t7 [0 y1 v0 T- {5 `
  14.   /* 禁止SPI外设时钟 */: k  k1 Q" a# _& \# M/ B- s
  15.   __HAL_SPI_DISABLE(hspi);: g3 q3 z/ V6 d2 K
  16. ( R" e& ?, T# H! D9 Z' N
  17. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)9 E7 q5 @5 m. g
  18.   if (hspi->MspDeInitCallback == NULL)
    0 F4 X* s, [$ W
  19.   {
    & Q5 q- Z" a! n1 }" t# ^* U
  20.     hspi->MspDeInitCallback = HAL_SPI_MspDeInit; - J2 [) X9 y: [& z
  21.   }
    + {9 @, D% A5 H0 M. L3 v) |0 I
  22. 4 _# }; y$ q& G" B  y) h: D  b/ R
  23.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */. S4 W& P9 F* q, Z1 ~
  24.   hspi->MspDeInitCallback(hspi);, ?( e# i- Q1 I: {2 M
  25. #else# [& h( S0 {* ^7 V- P( Q- g
  26.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */, y2 M0 j$ h$ E2 b2 r% ^+ A
  27.   HAL_SPI_MspDeInit(hspi);. ?- Z7 T9 c& Q1 Y4 Y% x& _
  28. #endif
    ( B: [* t; Y5 J9 U* W
  29. / b4 Y$ S* r. ?; N; P9 i6 U9 g
  30.   /* 设置无错误,复位状态标记 */# s. m2 D% P0 F  V
  31.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;
    9 ~5 `* _# \5 B1 T- X2 N
  32.   hspi->State = HAL_SPI_STATE_RESET;
    & l$ v6 @/ v6 y, u3 x- e$ [% S- m

  33. 4 g# @" Y3 D; m* _! Z4 p
  34.   /* 解锁SPI */+ ?9 ^- T0 p) w2 C0 U
  35.   __HAL_UNLOCK(hspi);
    7 j9 n) `0 X' |# A6 V( i

  36. , j3 J$ P# j2 W" l  o* O( a
  37.   return HAL_OK;6 s7 b/ U1 H1 m, N+ {7 ]
  38. }
复制代码
$ y- r" H2 Q$ V
函数描述:
% n+ I: q  x9 m- V: @% a6 r/ H9 H8 j8 h% q8 u
用于复位SPI总线初始化。
& ~, g5 ]5 [6 O5 j1 E8 u
) ~. V5 n6 D! M4 n0 R0 m函数参数:) ~! C& X/ @! R& c% T
  `1 n+ A9 o) O. U6 f" O7 n
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。$ _& p' H. X9 A1 K! O, v* R/ Z
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中
; [  D. M9 R# I/ X  l" p2 ]9 M
0 x% J2 H( V# C  I2 v2 L, S+ v, g6 V& S6 y% ~3 t9 R0 R
72.4.3 函数HAL_SPI_TransmitReceive3 s0 k  o4 u6 X
函数原型:
0 z8 m) b7 \/ x5 j# W, [  ~( R, n9 t6 E/ K$ o. ?9 r8 D
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
    " K0 ^; y5 v1 V9 b. N
  2. {% X5 }1 @. ?  [7 n- @
  3. # g+ `" Y6 p$ v5 o& |  i( I5 x1 U
  4.    /* 省略未写 */9 d- m' B8 x$ a$ b. t1 X% G
  5. 4 v9 z- H4 x% _. R1 X- U
  6.   /* 大于16bit的数据收发 */% `) M% c" }6 C+ Q
  7.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    3 y0 \! @7 L- W) m1 ?
  8.   {
    - C9 b8 u9 _4 A' b( a
  9.        /* 省略未写 */
    + A( Y6 j: p1 f/ \; w2 N
  10.   }
    : N5 P! s/ q" ~: H8 P+ m, H
  11.   /* 大于8bit,小于16bi的数据收发 */' x" [% _3 u2 m* k% Z$ |: |
  12.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
    * |4 N# g2 u2 Q( x
  13.   {
    8 m9 Z9 _& Q7 ~2 B; {1 R8 R
  14.       /* 省略未写 */4 w* W, O8 ]+ ]+ P
  15.   }
    ) h- y1 o2 q0 H( P' T) [1 R7 h
  16.   /* 小于等于8bit的数据收发 */) E3 w) M( K0 ?  K
  17.   else
    # J. y( |% M9 l$ V, e6 P
  18.   {7 E4 T& x, a/ y. F- z# g: ^7 [
  19.        /* 省略未写 */6 _1 j6 q4 M; _& B  l8 W4 ^* U3 H8 ^
  20.   }' H3 R/ w1 {( }! C1 n$ \7 w9 }+ b
  21. 1 q+ \5 p3 ?4 V  o( ~
  22. }
复制代码

5 _, R6 ?. F+ B4 o) V% o  W函数描述:, T6 I2 U1 p: a: n; Z. {1 i5 J* A
1 q. j# O" n9 w3 ^/ M
此函数主要用于SPI数据收发,全双工查询方式。# L* w* h; D" \$ k
4 }2 ?7 s) v, |5 M. c2 }5 D
函数参数:
: X" u6 s7 q8 Q, j" r2 T( I1 S* ^$ q* J8 J
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。' d& X  T: y  n+ G" Z: f3 e9 }
  第2个参数是发送数据缓冲地址。$ A% c% X" B5 r$ q4 \& J9 B5 @# Q
  第3个参数是接收数据缓冲地址。+ b; f+ w, D* ~: ~" L+ N7 b
  第4个参数是传输的数据大小,单位字节个数。# q6 ~1 ^& Q8 m0 B* n6 ?% c* X" T
  第5个参数是传输过程的溢出时间,单位ms。, ~7 o( v+ U2 D# A# C6 y
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。9 B0 \6 T/ R# h. ]  m9 q
; s8 e" t5 u3 O) d
+ I0 m0 e. R) W% p
使用举例:* i" W, u- Z6 \; H& I/ g+ ^' Z! K
! q* Q- b6 l6 I# ^/ |6 ]
  1. SPI_HandleTypeDef hspi = {0};
    5 ?" q& H  _$ e9 D  V

  2. ( _! X/ H- b& N7 R  V% F+ B
  3. if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)
    1 c" q7 v2 y* v$ w
  4. {
    & m# N; \! L9 N8 ?( q
  5.     Error_Handler(__FILE__, __LINE__);
    ; `$ p0 P' L" ^  Z" }* w
  6. }
复制代码
8 i! |, {* ^/ j: s8 U5 y2 L" i
72.4.4 函数HAL_SPI_TransmitReceive_IT
0 q) v& W; \; J" R) ]1 ~, ?( B
函数原型:9 y8 |" ]4 U2 w* m/ {4 H0 N
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)
    ! C5 y0 f. H+ [7 {/ `# A
  2. {# P0 D  _! s" Y- I/ w3 o
  3.    /* 省略未写 */
    # {' T% \' u3 Y5 h' U9 }1 r, e
  4. 5 X% q! V  Z* e6 m8 R
  5.   /* 设置传输参数 */
    : B4 O! h: G) N' _: M* ^
  6.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;, m; i$ F* }* H: t7 Z* T9 M
  7.   hspi->pTxBuffPtr  = (uint8_t *)pTxData;* m9 R" P. C- e9 [& z
  8.   hspi->TxXferSize  = Size;" p" a  }% x) ^6 P
  9.   hspi->TxXferCount = Size;$ x2 K4 f( Z) C+ u4 U7 P! f
  10.   hspi->pRxBuffPtr  = (uint8_t *)pRxData;
    / m0 L4 d0 I" X2 b0 _/ ?
  11.   hspi->RxXferSize  = Size;2 p& J7 e! _( R2 O' b. x* w! ^5 ~! l
  12.   hspi->RxXferCount = Size;0 J/ R+ ]" X4 d
  13. 9 d/ I4 R1 f6 p  p8 V
  14.   /* 设置中断处理 */7 e& k) ^+ y- X8 G8 E6 _- e" z
  15.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    0 x3 G, z- y7 q$ E3 H# q# r6 \
  16.   {
    $ L& S1 m# \, y/ N+ O3 @; w
  17.     hspi->TxISR     = SPI_TxISR_32BIT;4 K! E+ c" ?% R6 l- y! e# i: n
  18.     hspi->RxISR     = SPI_RxISR_32BIT;; s, `; c/ v$ ?& f1 w
  19.   }
    : V) O2 Q- x% d+ @4 k
  20.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
    3 T- Q- i# j" r' Q' g/ L! ^
  21.   {" [* B4 j4 r) X2 d/ g1 I6 h# r
  22.     hspi->RxISR     = SPI_RxISR_16BIT;3 ?# ]4 o9 v- z% m
  23.     hspi->TxISR     = SPI_TxISR_16BIT;
    ; ^2 s6 [, m$ k
  24.   }$ N4 ^) {# ]4 \" y6 L
  25.   else
    / n' d- k" K) ~. i# q$ t2 _) q6 l
  26.   {
    ) ^' @, X: d6 O; y) J
  27.     hspi->RxISR     = SPI_RxISR_8BIT;5 g/ H* D6 ^# L, v" A$ f
  28.     hspi->TxISR     = SPI_TxISR_8BIT;
    ; ~5 {3 b+ c; B6 p5 P
  29.   }
    ) j% b" W) B9 O( s
  30. / k- N, I( Y  [( G+ x/ R! k
  31.   /* 设置当前传输数据大小 */( d/ y- M/ Y" T, P
  32.   MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);; a& H  A" p8 n$ b
  33.   ]8 C5 c1 N1 w
  34.   /* 使能SPI外设 */! Y9 t/ S$ @: n4 }: b
  35.   __HAL_SPI_ENABLE(hspi);
    ) J/ Y6 c* `/ Y% c) ~0 N: a& ?
  36. " S- _0 U" n9 n* I+ s) K. V. X. B
  37.   /* 使能各种中断标志 */
    % ~; V" [1 L/ \/ ^6 |
  38.   __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_EOT | SPI_IT_RXP | SPI_IT_TXP | SPI_IT_DXP | SPI_IT_UDR | SPI_IT_OVR |
    0 n% @) H1 s4 L
  39. SPI_IT_FRE | SPI_IT_MODF | SPI_IT_TSERF));
    % h( T! p# K/ u* `0 T! o4 R" a
  40. + {! L( h- u( o5 i: h
  41.   if (hspi->Init.Mode == SPI_MODE_MASTER)
    & Y/ }. p2 |, h  N' d7 u
  42.   {
    % L# N7 Q  \( k8 B/ M
  43.     /* 启动传输 */
    6 m+ j1 [* {& U
  44.     SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);
    3 W! x. Q& ]% R6 z& P
  45.   }, d' @+ Z5 _* q/ L! \  _9 {

  46. + j  u+ g" a1 c8 E0 L. D
  47.   /* 解锁 */, U. A6 {. l# N6 L+ M' N& H2 m' K
  48.   __HAL_UNLOCK(hspi);
    4 L+ u% F8 G6 Y' W7 B0 J  f% |
  49.   return errorcode;
    ( Q" w8 Q% g' i
  50. }5 d  O* \! H7 ]& K$ `6 r$ A/ r& |) [
复制代码
6 `  B* F% c  H2 t. i: K
函数描述:, {% o: E- ]1 X, I0 q6 k( O( k

6 N/ n6 ]% ~  E1 \6 Q! x此函数主要用于SPI数据收发,全双工中断方式。
$ V' W% ^8 y" q2 X3 l- \2 l0 F; r$ p9 e4 u
函数参数:( d9 T* A8 d1 Y4 r, q8 h5 |2 G

* B6 ~0 Y/ |3 ?' U3 y3 B% v& }  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
. \" f0 N+ J$ V6 ?  第2个参数是发送数据缓冲地址。
% a$ W5 a$ E% W& g7 m5 J% c  第3个参数是接收数据缓冲地址。
1 \( P4 K1 H0 ]. }  第4个参数是传输的数据大小,单位字节个数。
' P, r2 f+ U, W: i7 `! }  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
" N9 }' O% F+ n* I' H2 K
9 A3 o7 i, W5 ?  n4 \& v. M: B6 @0 D1 R" k$ n
使用举例:
1 N( V" m6 o3 m5 x# O- c. y$ I& I$ C) L. W8 ?: a
  1. SPI_HandleTypeDef hspi = {0};
    / Y; e3 c& ]2 u- A7 U7 V

  2. % K* Z6 Z0 Q1 j/ A3 X! c
  3. if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)   
    5 j" s6 j8 g4 S/ }3 s
  4. {
    2 d3 s  k( H* M" y" G+ A
  5.     Error_Handler(__FILE__, __LINE__);6 b+ Q. P1 s$ ^: K1 X2 S) H
  6. }
复制代码
; x9 t- J6 j! ?/ \
72.4.5 函数HAL_SPI_TransmitReceive_DMA
, `" {5 M9 t" {# q' ~
函数原型:, |" _7 s- c9 h( x; n" N

1 k5 c; Z% d* e& C7 l8 i: _/ |
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,
    & J, ^+ \9 U4 @! s% v' L: e& i
  2.                                               uint16_t Size), T9 L4 G- n5 W: i, |5 J. E3 P1 M
  3. {
    , V# u' K: \$ k' ?$ y6 U
  4.    /* 省略未写 */9 K+ C7 X0 d; n5 d" l1 x/ m
  5. . d5 L; Q* F; \
  6. /* 注意DMA的位宽和对齐设置 */
    0 J6 A6 N, g& e: `
  7.   if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && (hspi->hdmarx->Init.MemDataAlignment !=
    + E6 B0 l! f* w0 o
  8. DMA_MDATAALIGN_WORD))  ||
    # n$ l2 T6 o$ w  C" \
  9.       ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) && ((hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_HALFWORD) && (hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_WORD))))
    + \% u' B) w' F. d. N5 F
  10.   {
    9 }  X9 e5 _: X5 z2 Y0 W1 C
  11.   }
    " Q( G7 p4 p' D7 F- J" ?( n

  12. 7 J! W5 M+ x# u0 R$ m
  13. /* 调整DMA对齐和数据大小 */
    ! J$ |0 j% X, a( ?0 P& H6 S; V% a
  14.   if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT). J5 ~. h) q: l2 [4 Z
  15.   {
    / m, k6 V( i/ q  B3 W( W
  16.      /* 省略未写 */
    : i  w/ `/ w& G$ ~
  17.   }& o  q) U# L0 J: l4 F2 S( ?. M
  18.   else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)- b# o8 j  j; U) V" ^* @* E
  19.   {
    2 R) @9 F- E/ F, k" e2 b- @6 r/ V
  20.      /* 省略未写 */
    * g% P0 q4 v) x# B  o
  21.   }
    & q8 U# J0 t4 R7 i, Z7 O0 x. c
  22.   else
    & u$ ^- G! e# m. n/ Z
  23.   {$ }% t! m7 t$ W( [) e* h
  24.       /* 省略未写 */! ~, |" h1 G7 L6 k& b; p* v) M
  25.   }
    , O+ B4 V3 v4 T3 d

  26. 6 v) M9 P. F5 V+ ^( @. G9 V
  27. /*  DMA接收配置 */( ~$ e4 ^: S( i, D: O
  28.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->RXDR, (uint32_t)hspi->pRxBuffPtr,
    + P6 x+ p  G1 y: U! V% x9 x  I
  29. hspi->RxXferCount))
    . k/ ?. t% y3 }5 u8 n
  30.   {
    ' O6 W* e% W) l/ X6 O$ [5 |

  31. 2 j: E3 i# Z, n; h6 J+ i
  32.   }6 g9 }( ^8 u' A

  33. % w* T- H& {& ~$ [% T. p! e' ^
  34. /* DMA发送配置 */
    & @! d+ s1 j4 G% M. O+ m* s
  35.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->TXDR,4 H0 C- _1 a  A5 I: _3 i! W
  36. hspi->TxXferCount))
    8 S( T# J6 s( \' P5 t* K. k' Z  e% T
  37.   {
    ( {2 c& I5 k7 M* x8 `
  38.   }
    * X5 q, {7 h5 v5 u
  39. 5 S5 j& J7 w) b
  40.   /* 省略未写 */
    / q% y2 l/ J2 b7 S. _1 Y. ]' F
  41. }
    . f; U# r3 b5 K+ S4 ?8 }3 K) Q. I. L
复制代码
  U0 K) O" p" U8 ~0 D1 A6 v8 Q
函数描述:
' ?- _4 V8 y) A$ U" w! r2 h1 r* @2 _- m5 g) I* ?$ i
此函数主要用于SPI数据收发,全双工DMA方式。# Y' h7 t0 O/ q& g" w
" c( V  a! b0 P/ @
函数参数:! [3 }9 P: ]$ V# o2 g

, p2 |5 i# p! M) d  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
( o+ V( j, h& \; z7 @  第2个参数是发送数据缓冲地址。: x9 A& ?- x) u5 {
  第3个参数是接收数据缓冲地址。" p6 |1 {9 d0 w* l  ]. E
  第4个参数是传输的数据大小,单位字节个数。& J' y( V1 q; o2 K% r0 Z
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
0 [9 z4 N& {; e. G$ F5 ?0 @
2 |4 X/ b% I9 W! R  @
% ?* ?' U' ]& E+ i4 l使用举例:
2 }" K# _) L* X% ?4 p, F; ]0 h. s2 \! F
  1. SPI_HandleTypeDef hspi = {0};4 P7 d- }& k9 V- |  |5 W
  2. : @3 s& w7 _! O9 g
  3. if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)   
    # V- E+ W' S& O" `! l7 a+ p$ p8 C
  4. {
    # i+ Z/ k) i/ x
  5.     Error_Handler(__FILE__, __LINE__);
    ' ^* X! |# Z- S  V5 Y7 X* e' d- [
  6. }: c" @0 H! l0 G* k
复制代码

5 `+ p0 y+ @. D7 {3 M' V2 c72.5 总结6 _' z0 W9 M; c0 T5 w
本章节就为大家讲解这么多,要熟练掌握SPI总线的查询,中断和DMA方式的实现,因为基于SPI接口的外设芯片很多,熟练后,可以方便的驱动各种SPI接口芯片,以便选择合适的驱动方式。% \* x% K7 w4 n0 p4 }. x' E+ E

2 [/ o; k3 {/ |2 D" y1 q, ~0 _, q

: x; k1 g+ |* ]  d! O, N- r: s4 T: w. p, M: v( o% L9 M
, {$ V, P% K2 R$ m
收藏 评论0 发布时间:2021-12-20 19:00

举报

0个回答

所属标签

相似分享

官网相关资源

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