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

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

[复制链接]
STMCU小助手 发布时间:2021-11-3 10:15
72.1 初学者重要提示2 H, D* Q9 V9 Y% U) }- o
  STM32H7的SPI支持4到32bit数据传输,而STM32F1和F4系列仅支持8bit或者16bit。
: \. ?) l& f( m  f: s( R8 a; i  STM32H7的主频400MHz时,SPI1, 2, 3最高通信时钟是100MHz,而SPI4, 5, 6是50MHz。9 c6 G" K/ n, ~  v+ p
  STM32H7的MISO和MOSI引脚功能可以互换,使用比较灵活。
/ ]7 o4 w; F8 S3 }. f  SPI总线的片选引脚SS在单一的主从器件配置下是可选的,一般情况下可以不使用。
& n" d3 K( k7 a$ T" v! |( E! B
0 c4 v) O- J, J5 Y( V! C, H* j, ]72.2 SPI总线基础知识/ L: Q4 B+ c- S" R! g9 M" W
72.2.1 SPI总线的硬件框图! G+ Q4 U2 @& h1 c9 v' Y% p
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SPI的基本功能,然后再看手册了解细节。3 r* b% n9 k* N% h) a

" g! S6 f8 b; M
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
- c) r" L3 ~! D' |  s7 S2 R0 W

1 c% K" B+ @0 g& f# }: ^% y- |通过这个框图,我们可以得到如下信息:- R+ R0 V0 C5 m' R# E
0 w' \& l% @' }7 ]: z: V
  spi_wkup输出
# y% V& [6 U6 `+ T/ X低功耗唤醒信号。, u4 O' R5 A  X4 G% e
& X: H/ O3 N! L. {, u$ }6 }
  spi_it输出* H! y3 Y5 Z( a
spi的中断请求信号。
) N, P0 g' `4 {( ~# j5 P" e
8 _$ X/ X( h, G" j2 d0 m, [  spi_tx_dma! D# a) U* k% Y# }; m
spi_rx_dma
4 _/ V' O; b! O3 W" @% j4 z6 q5 A6 kspi的DMA发送和接收请求信号。
6 p' \2 h) E! ~  o9 }' x0 z
1 ]# \- y" e- i6 P  spi_pclk% H6 T( _6 V* C3 q
为寄存器提供时钟。
* e5 @7 L" l7 |/ I" t4 O) r6 o' R/ ?2 B0 ?0 O4 X# d% S3 v
  spi_ker_ck
% {. {: S2 a* Y# W  K5 ?9 Z为spi内核时钟。
  J7 F  d6 r& Z6 N4 H7 S% d/ \' i9 @" a# Q7 H
  SCK(CK),Serial Clock
) H' R* L! ~+ a# r5 w5 h  ~# J此引脚在主机模式下用于时钟输出,从机模式下用于时钟输入。) F- C' d0 O. g
$ H, p+ W7 W) x4 f1 U! s! f
  MISO(SDI),Master In / Slave Out data
* Z* B! g2 I: z3 b( ]6 b此引脚在从机模式下用于发送数据,主机模式下接收数据。5 {! B3 c: S" V7 q! w- _

- @" U( G) w9 D5 L7 ~  MOSI(SDO), Master Out / Slave In data
; g5 R! r; e9 V此引脚在从机模式下用于数据接收,主机模式下发送数据。
/ S6 |; d: R+ p% Q, z% }" {
% T- ]9 u$ b! Y4 J" G: |' c8 T  SS(WS), Slave select pin
" C4 C$ X3 m$ U. V# A! K根据SPI和SS设置,此引脚可用于:* P7 @8 R: O( U
. U3 u4 `$ N, ?! W5 u) Z" l8 i1 g
a. 选择三个从器件进行通信。7 I  B7 S1 \% |) ^5 Q0 M, U
! c- `$ a3 o# g% K2 x
b. 同步数据帧。: C5 d3 V8 M# y3 g8 z' {

2 q6 T6 s9 o# h# j) o; }c. 检测多个主器件之间是否存在冲突。4 U0 D2 l' I7 o  V: ^" r  h

8 U- d. h2 K3 ^. O- R通过这个框图还要认识到一点,SPI有三个时钟域,分别是寄存器所在的ABP总线时钟域,内核时钟发生器时钟域以及内核时钟发生器分频后的串行时钟域。
. V  v  N0 D5 a& Z% [8 |( G( [" X& w6 |( ^
72.2.2 SPI接口的区别和时钟源(SPI1到SPI6)5 x- r1 X  r* B0 u( E4 t
这个知识点在初学的时候容易忽视,所以我们这里整理下。: E* ]  V+ O# q8 o2 R
; V2 x3 Q& m, ^4 n4 w3 p; M
  SPI1到SPI6的区别9 f8 n8 E! f- Y! K8 F
  SPI1,SPI2和SPI3支持4到32bit数据传输,SPI4,SPI5和SPI6是4到16bit数据传输。
7 i3 t" S$ J) i9 f% f$ R0 |' u  SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit。, E# ]- L8 |8 Y3 U
& h- e# r7 W* E! w5 V* @7 ^+ ^
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
" D2 X& r* V4 M& M- T8 O3 E
4 ]. m7 v' s8 X9 V) B, u& P
  SPI1到SPI6的所在的总线(对应SPI框图的SPI_CLK时钟域)
' q0 g# H& ~! m; L1 D' jSPI1,SPI4和SPI5在APB2总线,SPI2,SPI3在APB1总线,SPI6在APB4总线。注意,SPI的最高时钟不是由这些总线决定的。
  ~; o3 f( s7 q1 W4 D; Y5 a0 s2 J& Q$ h5 {1 F( }
  SPI1到SPI6的支持的最高时钟(对应SPI框图的SPI_KER_CK)) d2 ^1 `7 M4 {* N8 e  f1 X
STM32H7主频在400MHz下,SPI1,SPI2和SPI3的最高时钟是200MHz,而SPI4,5,6是100MHz, 以SPI1为了,可以选择的时钟源如下:* ?( E( ?. o  @; Q  ^

  a3 b- |% @5 h5 l
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

3 w# v5 G4 j5 U. d, g. a6 d$ J. h! F1 [% G  {8 ]
这里特别注意一点,SPI工作时最少选择二分频,也就是说SPI1,2,3实际通信时钟是100MHz,而SPI4,5,6是50MHz。
  {! P$ e' b+ |% ]& n: P& N) c9 C/ A" @% @, L
72.2.3 SPI总线全双工,单工和半双工通信" Y8 ^. |6 U, A: G- a
片选信号SS在单一的主从器件配置下是可选的,一般情况下可以不使用。但需要同步数据流,或者用于TI模式时需要此信号。4 I: [0 F5 b" r7 @* L; u, z
3 @% {- L- X' |; G, N" w
  全双工通信
2 C4 X9 d. |  M2 d8 I0 u( E+ k全双工就是主从器件之间同时互传数据,SPI总线的全双工模式接线方式如下:+ _  F/ y' H& H. v6 m
5 W; Z* `4 i$ {  G: R
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
& v8 F% ~% G% }2 @! `9 E; |! G

  P8 M8 Q8 T  l% ~# P& Y关于这个接线图要认识到以下几点:4 s4 u3 K" r4 }  w+ F

( a9 `* g3 |" G' q4 d- N/ Z% I  注意接线方式,对于主器件来说MISO引脚就是输入端,从器件的MISO是输出端,即Master In / Slave Out data。MOSI也是同样道理。
) z5 I% Z  [0 O0 g2 F  每个时钟信号SCK的作用了,主器件的MISO引脚接收1个bit数据,MOSI引脚输出1个bit数据。: {, l5 s- o) @3 `+ Z
  这种单一的主从接线模式下,SS引脚可以不使用。
2 S- k1 s7 _* f# a0 }$ q& K; |  半双工通信- i2 q  e! ~8 ~7 Q. R- u: O
半双工就是同一个时刻只能为一个方向传输数据,SPI总线的半工模式接线方式如下:( U2 B4 j0 i' f: \, ~$ Y

0 o& ]5 b& |) {' A  @
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

1 h5 a. N% x  P9 a: p# P- ]. p" f; [0 y& v: E
关于这个接线图要认识到以下几点:- t2 t( q% |) t' S, v
8 _  @1 E' K& m
  更改通信方式时,要先禁止SPI。$ x9 ]* }2 {% m$ ~
  主器件的MISO和从器件的MISO不使用,可以继续用作标准GPIO。8 y% j$ `- e8 Z# r$ O9 n7 g6 @5 Z
  1KΩ的接线电阻很有必要,因为当主器件和从器件的通信方向不是同步变化时,容易出现其中一个输出低电平,另一个输出高电平,造成短路。
6 s% o6 I' j; X  这种单一的主从接线模式下,SS引脚可以不使用。
! l9 u& U7 \( B. |- O' B  单工模式( d8 u# O- k, i% I
单工就是只有一种通信方向,即发送或者接收,SPI总线的全双工模式接线方式如下:6 Z5 ]1 ]* B( O' G5 u  Y; C

$ g8 L! a8 U- _  D# E, i
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
1 ~& W$ H1 K: a

9 B+ C$ n2 Y7 T* X: y7 z关于这个接线图要认识到以下几点:% D8 Q  @* p7 |$ a* @/ d8 X3 b
$ P: j  z9 c; X
  未用到的MOSI或者MISO可以用作标准GPIO。1 B% b) @! T1 l& n& Q6 \, m
  这种单一的主从接线模式下,SS引脚可以不使用。
# x7 y9 O6 M3 [: H4 Y, h72.2.4 SPI总线星型拓扑2 R% \6 U, |5 G6 [, A( R
SPI总线星型拓扑用到的地方比较多,V7开发板就是用的星型拓扑外接多种SPI器件:9 c% L5 s) `+ B$ c( S$ X% b' A
! I8 ]2 ]( w- q% C9 z+ r
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
+ e( t3 e3 F% }0 L( w

& m. v( O$ ^  a! u  {+ ^  T关于这个接线图,有以下几点需要大家了解:. w& D5 H" ~$ j- @% v
% {* h. c8 W, u/ h7 o3 b% ?8 V
  主器件的SS引脚不使用,使用通用GPIO控制。为每个器件配一个SS引脚,方便单独片选控制。
9 x; I, k+ j+ {  从器件的MISO引脚要配置为复用开漏输出(很多外部芯片在未片选时,数据引脚是呈现高阻态)。
/ `6 J2 C6 w$ l7 m2 Q$ n7 ~72.2.5 SPI总线通信格式
/ m! V( v9 F2 A1 A# k$ r3 @SPI总线主要有四种通信格式,由CPOL时钟极性和CPHA时钟相位控制:( e3 V& ^, s) }& w+ Z# I
/ r+ e9 ^2 U. w6 n
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

3 |* q2 k+ }9 j4 F! H
4 s: h& ]4 c& w" e6 P4 W四种通信格式如下:
9 m+ H( p! h' j# S2 J
/ b& v$ ~2 |% g6 G# [  当CPOL = 1, CPHA = 1时
7 h7 l% J& z+ ]0 n7 G, OSCK引脚在空闲状态处于低电平,SCK引脚的第2个边沿捕获传输的第1个数据。
1 R+ Z8 k, u$ z- R7 X, f9 x
! l, b0 z2 ]9 @- {: z4 o* ]! T  当CPOL = 0, CPHA = 1时. H$ r: |, f( |9 s" n) I
SCK引脚在空闲状态处于高电平,SCK引脚的第2个边沿捕获传输的第1个数据。: B/ E( S/ c, f* z5 o6 O
% X) A3 q0 V/ M8 @# l# y
  当CPOL = 1, CPHA = 0时
! ]7 I1 h8 G) p/ ^SCK引脚在空闲状态处于低电平,SCK引脚的第1个边沿捕获传输的第1个数据。
4 r  {* S% J& k" d" W* i+ d* p- h
  当CPOL = 1, CPHA = 0时: d- O; q, u0 P6 x+ Z
SCK引脚在空闲状态处于高电平,SCK引脚的第1个边沿捕获传输的第1个数据。. h- D# ~3 M, O4 d1 E4 H
$ M# \" ?. \4 r" F- H) {  m
72.3 SPI总线的HAL库用法9 m0 a( R% I. D: |4 N0 ?8 G* F
72.3.1 SPI总线结构体SPI_TypeDef
  [. r4 }& u% n: zSPI总线相关的寄存器是通过HAL库中的结构体SPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
- o0 J' _7 R% [/ C8 T' d+ ?6 J' i: }% h
  1. typedef struct: Y/ f) ^/ e4 c2 H- t0 j
  2. {
    5 U+ h( O% Q6 b* j
  3.   __IO uint32_t CR1;           /*!< SPI/I2S Control register 1,                      Address offset: 0x00 */4 H  o3 ]. y7 t
  4.   __IO uint32_t CR2;           /*!< SPI Control register 2,                          Address offset: 0x04 */) G. Q. f# ^$ D8 s
  5.   __IO uint32_t CFG1;          /*!< SPI Configuration register 1,                    Address offset: 0x08 */; o' b  k3 t0 G5 T1 i, K
  6.   __IO uint32_t CFG2;          /*!< SPI Configuration register 2,                    Address offset: 0x0C */* i2 I' \. \* X$ @8 ^9 G9 I. g
  7.   __IO uint32_t IER;           /*!< SPI/I2S Interrupt Enable register,               Address offset: 0x10 */
    ( L: a, K* `, z5 M( V1 h
  8.   __IO uint32_t SR;            /*!< SPI/I2S Status register,                         Address offset: 0x14 */
    & ]9 {, R/ n8 X0 X( S4 b& v$ a" u
  9.   __IO uint32_t IFCR;          /*!< SPI/I2S Interrupt/Status flags clear register,   Address offset: 0x18 */
    - i2 g' B; d8 s2 t  F2 Z
  10.   uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                        */; `6 {7 e9 _* z, ?
  11.   __IO uint32_t TXDR;          /*!< SPI/I2S Transmit data register,                  Address offset: 0x20 */1 a+ l! o7 ~6 ^1 K9 U- `+ T8 `. Q
  12.   uint32_t      RESERVED1[3];  /*!< Reserved, 0x24-0x2C                                                   */
    - [7 V) _$ N8 t! |9 }$ ~
  13.   __IO uint32_t RXDR;          /*!< SPI/I2S Receive data register,                   Address offset: 0x30 */
    . X' A3 Q% |  x8 D
  14.   uint32_t      RESERVED2[3];  /*!< Reserved, 0x34-0x3C                                                   */. C! V* j+ I" y$ h+ @
  15.   __IO uint32_t CRCPOLY;       /*!< SPI CRC Polynomial register,                     Address offset: 0x40 */1 p9 Z* O/ {7 y. [
  16.   __IO uint32_t TXCRC;         /*!< SPI Transmitter CRC register,                    Address offset: 0x44 */( {' e* n5 N* l3 w( k: v
  17.   __IO uint32_t RXCRC;         /*!< SPI Receiver CRC register,                       Address offset: 0x48 */
    0 q1 l% s* a0 r# G" d0 {
  18.   __IO uint32_t UDRDR;         /*!< SPI Underrun data register,                      Address offset: 0x4C */$ |( B" z' N5 G0 ?% K( [
  19.   __IO uint32_t I2SCFGR;       /*!< I2S Configuration register,                      Address offset: 0x50 */
    * \# A# V* `8 `, I

  20. - ?& U4 G6 I% Y, a$ g
  21. } SPI_TypeDef;
复制代码
4 a+ K0 Y9 E" P* \& l! |* l; k; W
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。  B. E( }6 l) j" b7 l' G4 n+ e0 C
. M/ h% l# C. }! T$ K
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:( N5 C8 x1 s+ c1 Q# y
2 q6 y  _8 X2 f+ i) W
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    8 |. M& ?" l9 ?% s9 A  s
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

6 C- U; c; b, a" U: ?- h( @; }下面我们看下SPI的定义,在stm32h743xx.h文件。
' w' z/ u* [7 [, H
5 E. R" {1 y$ M
  1. #define PERIPH_BASE           (0x40000000UL) : z$ ^0 A$ H$ t. }- G6 f
  2. #define D2_APB1PERIPH_BASE     PERIPH_BASE9 X# E: b1 ~7 H0 B6 r% ^8 {
  3. #define D2_APB2PERIPH_BASE    (PERIPH_BASE + 0x00010000UL)4 D. z( k: b; b5 y: P
  4. #define D3_APB1PERIPH_BASE    (PERIPH_BASE + 0x18000000UL)
    " \3 N$ |8 G- a! m$ {
  5. ) p0 o9 @7 W3 w4 S! X& I4 o: d  T
  6. #define SPI2_BASE             (D2_APB1PERIPH_BASE + 0x3800UL)6 E& i2 N3 n/ y$ F& ^
  7. #define SPI3_BASE             (D2_APB1PERIPH_BASE + 0x3C00UL)
    & D) N2 v+ h* a
  8. #define SPI1_BASE             (D2_APB2PERIPH_BASE + 0x3000UL)% L8 k4 e" ^1 ^3 e, i
  9. #define SPI4_BASE             (D2_APB2PERIPH_BASE + 0x3400UL)- s9 B* K0 C$ p6 A* g
  10. #define SPI5_BASE             (D2_APB2PERIPH_BASE + 0x5000UL)
    * ~3 r/ L5 z+ }2 T( F+ R
  11. #define SPI6_BASE             (D3_APB1PERIPH_BASE + 0x1400UL)
    , K5 F( I. n: R$ a- ^  x6 }
  12. " i! Y9 f1 b; j- j0 q' }
  13. #define SPI1                ((SPI_TypeDef *) SPI1_BASE)
    / J- m& t' w* N4 Q2 h" Y
  14. #define SPI2                ((SPI_TypeDef *) SPI2_BASE)
    , O* \+ v8 V8 J6 Q
  15. #define SPI3                ((SPI_TypeDef *) SPI3_BASE)3 e4 m" c6 v, ]3 w7 }  F
  16. #define SPI4                ((SPI_TypeDef *) SPI4_BASE)  B8 N' P1 h# E) H0 z4 Y
  17. #define SPI5                ((SPI_TypeDef *) SPI5_BASE)
    & h! v8 T% i& c' c2 g/ c
  18. #define SPI6                ((SPI_TypeDef *) SPI6_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x58001400
复制代码
+ h  Y* I# d( k$ d2 Z
我们访问SPI的CR1寄存器可以采用这种形式:SPI->CR1 = 0。/ z% r2 K$ t, L, x: w* D- y

. I0 e, u) p; q4 z1 W72.3.2 SPI总线初始化结构体SPI_InitTypeDef
( J+ p' \  v$ v4 \3 b4 i3 K( x; D下面是SPI总线的初始化结构体,用到的地方比较多:6 x3 a& Z" g- s5 T
2 s9 z! Z6 G" C5 H& O7 F+ S
  1. typedef struct7 a1 ^$ ?% o1 H8 a" W0 C
  2. {
    . Z$ k) z; t* }4 i/ d
  3.   uint32_t Mode;                           
    0 _/ c0 h+ a( t8 I# _/ x
  4.   uint32_t Direction;                      7 {5 c, V) I2 V
  5.   uint32_t DataSize;                          
    # E, |& f; B! t
  6.   uint32_t CLKPolarity;                       
    7 ^8 k+ e" C6 v* v
  7.   uint32_t CLKPhase;                         , }# e( R! s# n9 T) Q2 ^
  8.   uint32_t NSS;                             
    - E- c# a! A. r, M4 }$ E
  9.   uint32_t BaudRatePrescaler;               
    3 u9 p! m7 [9 n( I/ k! {2 A
  10.   uint32_t FirstBit;                        
    4 a0 w3 {3 ^: w! u& [- n2 x
  11.   uint32_t TIMode;                            \5 W6 R# @7 {' O
  12.   uint32_t CRCCalculation;                   : ]! ~9 s% Y- T  b2 v2 T
  13.   uint32_t CRCPolynomial;                     ! e* a' H1 h1 }; k; {8 n2 ?9 Y, {6 v- l
  14.   uint32_t CRCLength;                        
    3 D" {6 v5 `' N& b1 h2 Z# _9 G  }
  15.   uint32_t NSSPMode;                         5 G4 V( g) c6 l2 M3 U6 y
  16.   uint32_t NSSPolarity;                    
    # V4 G8 M/ A* ~6 e4 Q, O; r
  17.   uint32_t TxCRCInitializationPattern;       $ ~1 d# I) h  @& P5 Y
  18.   uint32_t RxCRCInitializationPattern;      
    ) `! x0 }- j4 p0 Z' P( l
  19.   uint32_t MasterSSIdleness;                   w. J! @7 v2 }* E& w. a. C3 K
  20.   uint32_t MasterInterDataIdleness;           
    9 z; L' {2 h& M) n, z, j) @
  21.   uint32_t MasterReceiverAutoSusp;         
    1 R- i; q0 E3 g/ i$ }8 P3 w
  22.   uint32_t MasterKeepIOState;               
    - e* k4 @0 y& F: O
  23.   uint32_t IOSwap;                          - h' }. @& ?" M8 @  o
  24. } SPI_InitTypeDef;
复制代码
0 p  u# ?9 t% ?6 g2 `; n, }3 w
下面将结构体成员逐一做个说明:
, O. D2 f$ ]( M# f3 L9 M. c
* Y3 ~; @' S0 ^- C  Mode* N1 C% j2 P  P# i# n
用于设置工作在主机模式还是从机模式。
6 I" |" P0 Y, E- v$ r. [1 J- T2 M/ F
  1. #define SPI_MODE_SLAVE              (0x00000000UL)
    ; I" e! s/ s  S& ]+ v3 U
  2. #define SPI_MODE_MASTER             SPI_CFG2_MASTER
复制代码

  T$ X- `  A; s1 }8 ]" o  Direction
; q6 I- L. c$ c6 \% Z! s. A% }用于设置SPI工作在全双工,单工,还是半双工模式。
0 a* Q+ W2 n* \) L/ p% b+ L* _% I
  1. #define SPI_DIRECTION_2LINES           (0x00000000UL)     /* 全双工 */
    9 c  ?2 R! u2 l# W) S$ \
  2. #define SPI_DIRECTION_2LINES_TXONLY     SPI_CFG2_COMM_0   /* 单工,仅发送 */
    3 n' D$ o; C- m2 a# w. J
  3. #define SPI_DIRECTION_2LINES_RXONLY     SPI_CFG2_COMM_1   /* 单工,仅接收 */
    * i4 C/ X% K& g$ x1 V. D
  4. #define SPI_DIRECTION_1LINE             SPI_CFG2_COMM     /* 半双工 */
复制代码

! y( p7 O* U( I$ w4 p, z  DataSize. T0 t. V1 H9 R. |5 A" x
用于设置SPI总线数据收发的位宽,支持4-32bit。
+ J" ~: g5 L( g- `3 ^$ G3 |( o8 k: Q$ _" `3 f
  1. #define SPI_DATASIZE_4BIT                             (0x00000003UL)
    4 F) V6 s7 L& [/ g
  2. #define SPI_DATASIZE_5BIT                             (0x00000004UL)
    7 p: P% G# V5 W7 x7 X, C  }# B/ e
  3. #define SPI_DATASIZE_6BIT                             (0x00000005UL)! D0 T# u: q8 ?* k
  4. #define SPI_DATASIZE_7BIT                             (0x00000006UL)' }% t5 h! `0 Y% W% }, c
  5. #define SPI_DATASIZE_8BIT                             (0x00000007UL)
    * C/ t# c# ]* |2 Y& b
  6. #define SPI_DATASIZE_9BIT                             (0x00000008UL)
    7 W* |8 j  ?/ Y- P% G. ]. E6 O
  7. #define SPI_DATASIZE_10BIT                            (0x00000009UL)$ @( n$ a7 F( \  H7 I8 L
  8. #define SPI_DATASIZE_11BIT                            (0x0000000AUL). y- X' S' @5 {  S% b4 y
  9. #define SPI_DATASIZE_12BIT                            (0x0000000BUL)
    , J! k! u! B$ H& b5 i1 @
  10. #define SPI_DATASIZE_13BIT                            (0x0000000CUL)& z! u, l5 S& F4 {, t
  11. #define SPI_DATASIZE_14BIT                            (0x0000000DUL)
    9 [9 A: ]* }0 ~  e  Q* d- u
  12. #define SPI_DATASIZE_15BIT                            (0x0000000EUL)6 \& l7 l( h' B+ D. I  V! r1 w
  13. #define SPI_DATASIZE_16BIT                            (0x0000000FUL)7 S, g0 ]& h+ p( ^$ n1 s( c0 w
  14. #define SPI_DATASIZE_17BIT                            (0x00000010UL)& k4 N/ C+ D- U' J0 s
  15. #define SPI_DATASIZE_18BIT                            (0x00000011UL)8 U4 L6 q: F0 Z$ F! r
  16. #define SPI_DATASIZE_19BIT                            (0x00000012UL)
    # C" w) S8 f0 Z9 u. r; R
  17. #define SPI_DATASIZE_20BIT                            (0x00000013UL)% I$ o( Q) L( [9 r5 `) E' D
  18. #define SPI_DATASIZE_21BIT                            (0x00000014UL)9 o7 R9 N$ g6 o* w: ~
  19. #define SPI_DATASIZE_22BIT                            (0x00000015UL)
    ) c( u/ n' Y/ v- P# n5 X0 y
  20. #define SPI_DATASIZE_23BIT                            (0x00000016UL)
      f/ n+ e/ i3 W2 F* k
  21. #define SPI_DATASIZE_24BIT                            (0x00000017UL)
    2 A1 d4 p; X0 b: W' I& T: v
  22. #define SPI_DATASIZE_25BIT                            (0x00000018UL)
    + L2 x; Q( C7 I9 E( h
  23. #define SPI_DATASIZE_26BIT                            (0x00000019UL). s; i- n# v' U1 D" j# J4 g0 Z
  24. #define SPI_DATASIZE_27BIT                            (0x0000001AUL)
    6 ]3 n# T4 S: T1 \0 U6 W* [
  25. #define SPI_DATASIZE_28BIT                            (0x0000001BUL)
    8 V. A; M5 W: h/ l
  26. #define SPI_DATASIZE_29BIT                            (0x0000001CUL)( A* u) S& L6 L& q0 m( E
  27. #define SPI_DATASIZE_30BIT                            (0x0000001DUL)
    3 l; }! ]; Q( u4 x, H1 n+ Q: x& e
  28. #define SPI_DATASIZE_31BIT                            (0x0000001EUL)
    ( @& z1 k3 O& V# Y/ d$ S
  29. #define SPI_DATASIZE_32BIT                            (0x0000001FUL)
复制代码

4 ^" _: O& L5 V5 c  CLKPolarity3 \. f9 O6 F, K) W
用于设置空闲状态时,CLK是高电平还是低电平。
8 k. D* a1 \7 ~  B$ x
; M2 s9 t8 V2 b& E, M1 j
  1. #define SPI_POLARITY_LOW       (0x00000000UL)
    2 E) B/ Y, k' J' N* C* A: ^
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码

- }8 [' V3 f$ z3 o% E$ {. r  NSS. _. ]) q4 O' m6 x- C* ?/ V
用于设置NSS信号由硬件NSS引脚管理或者软件SSI位管理。
1 Q9 ^' k& Y9 d7 I$ W% c# q" g4 O! e  `9 @
  1. #define SPI_NSS_SOFT                                  SPI_CFG2_SSM9 G/ U) T+ ~7 {- Z; M
  2. #define SPI_NSS_HARD_INPUT                            (0x00000000UL)' T6 G, e' w' b& u& p* t
  3. #define SPI_NSS_HARD_OUTPUT                           SPI_CFG2_SSOE
复制代码
' f7 \5 K4 a$ z2 n4 x
  BaudRatePrescaler5 Q- @" k* D# `+ M: m& ~  q
用于设置SPI时钟分频,仅SPI工作在主控模式下起作用,对SPI从机模式不起作用。0 W" I# ]. B1 f1 H3 \( c( ]$ C- E
+ D4 s( U. |. O0 i
  1. #define SPI_BAUDRATEPRESCALER_2                       (0x00000000UL)
      i0 N( y) U; Q! m: \# s
  2. #define SPI_BAUDRATEPRESCALER_4                       (0x10000000UL)( x0 [. M- `9 X! L  c0 i" `. z
  3. #define SPI_BAUDRATEPRESCALER_8                       (0x20000000UL)
    / J8 u3 n+ e7 @  N2 [( a- ?
  4. #define SPI_BAUDRATEPRESCALER_16                      (0x30000000UL)
    2 E$ y6 h' o/ w# L6 O
  5. #define SPI_BAUDRATEPRESCALER_32                      (0x40000000UL)
    0 w. ^* \6 y8 ]" g* K7 K; J
  6. #define SPI_BAUDRATEPRESCALER_64                      (0x50000000UL)3 F& O( K" L0 d- }" C: F
  7. #define SPI_BAUDRATEPRESCALER_128                     (0x60000000UL)+ z1 N4 t3 c; o
  8. #define SPI_BAUDRATEPRESCALER_256                     (0x70000000UL)
复制代码

, f' u, D$ M* E* @: o4 y" g  FirstBit
9 Y- S: c  b& Z1 T5 J5 r" y5 L用于设置数据传输从最高bit开始还是从最低bit开始。8 l. v' e! m; _$ f& _6 V* Q3 o: H

2 P4 ]: t# K) c7 L% b. r) d' z
  1. #define SPI_FIRSTBIT_MSB                              (0x00000000UL)1 o! o4 D- n& \7 x
  2. #define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST
    5 z) q; ?. q+ q( l
复制代码

* M5 j( P1 V( e5 O5 ?1 `$ \. }. e  TIMode
" n+ t8 N! k; d9 N* r& t1 r用于设置是否使能SPI总线的TI模式。7 p5 t' d) x9 u4 m' _7 @9 ~2 ~; ?3 d5 k

0 Q0 ~5 }  I+ u2 G7 Z# r$ Y
  1. #define SPI_TIMODE_DISABLE               (0x00000000UL)
    9 P* D, |! d* }% C. |* y2 o
  2. #define SPI_TIMODE_ENABLE                SPI_CFG2_SP_0
复制代码

) T1 t/ E" C; d6 }  CRCCalculation
+ h( o" y* @) j1 q9 |, s" i/ @; C用于设置是否使能CRC计算。
! o! Q$ e) s- G0 K: I5 ]
8 Q+ b, V. j0 B3 k9 `% v
  1. #define SPI_CRCCALCULATION_DISABLE                    (0x00000000UL)) H+ T) |, c! {! L$ D( N
  2. #define SPI_CRCCALCULATION_ENABLE                     SPI_CFG1_CRCEN
复制代码
# f# u  h- @! b* t- U+ t
  CRCPolynomial( l# u/ Q( l$ |. O! {: }
用于设置CRC计算使用的多项式,必须是奇数,范围0到65535。' K+ o$ U- ~, {

2 Y$ w( v' N" V1 ~  CRCLength
- {1 {$ [, N6 K0 j用于设置CRC计算时的CRC长度。大小要与同属此结构体的DataSize一致。或是DataSize的整数倍。! w1 O: {& k7 C4 d

$ t! ~/ K; g& W
  1. #define SPI_CRC_LENGTH_DATASIZE                       (0x00000000UL)5 B, K3 h% p+ L' F, o/ ~; ]
  2. #define SPI_CRC_LENGTH_4BIT                           (0x00030000UL)
    & G. U, l% k/ ~: s2 s( z
  3. #define SPI_CRC_LENGTH_5BIT                           (0x00040000UL)# T$ Y% ~+ ]' l' i+ Q
  4. #define SPI_CRC_LENGTH_6BIT                           (0x00050000UL)
    + [) j5 Z+ g% L  G3 f
  5. #define SPI_CRC_LENGTH_7BIT                           (0x00060000UL)3 |$ \8 A* I% ]
  6. #define SPI_CRC_LENGTH_8BIT                           (0x00070000UL)' e: Z. q: x1 d7 E: F: K: a
  7. #define SPI_CRC_LENGTH_9BIT                           (0x00080000UL)9 X% b. e6 i% q; _8 e. T
  8. #define SPI_CRC_LENGTH_10BIT                          (0x00090000UL)
    8 ~2 V# v2 E2 i
  9. #define SPI_CRC_LENGTH_11BIT                          (0x000A0000UL)( Q$ L; J* w" d- V0 V# z) d
  10. #define SPI_CRC_LENGTH_12BIT                          (0x000B0000UL)2 a& b& c1 |2 b- [
  11. #define SPI_CRC_LENGTH_13BIT                          (0x000C0000UL)8 R7 E) p& A/ c$ _. X
  12. #define SPI_CRC_LENGTH_14BIT                          (0x000D0000UL)1 r- R$ m- @! N$ Y9 R( R7 p, L1 j
  13. #define SPI_CRC_LENGTH_15BIT                          (0x000E0000UL)
    1 G: H! c* w- G! g
  14. #define SPI_CRC_LENGTH_16BIT                          (0x000F0000UL)
    + l- T% k  `3 a( d' K7 a% g
  15. #define SPI_CRC_LENGTH_17BIT                          (0x00100000UL)  O5 F% ?4 N. p3 |* I
  16. #define SPI_CRC_LENGTH_18BIT                          (0x00110000UL)% F: u' g* D* H! l2 {" g+ t+ H; M& k
  17. #define SPI_CRC_LENGTH_19BIT                          (0x00120000UL), V. Z0 k1 v. l0 l0 f( s1 W
  18. #define SPI_CRC_LENGTH_20BIT                          (0x00130000UL): n( i: @8 E# F2 {  D& g9 [
  19. #define SPI_CRC_LENGTH_21BIT                          (0x00140000UL)! `: _- v) E8 y; W7 `* C
  20. #define SPI_CRC_LENGTH_22BIT                          (0x00150000UL)
    * I6 Y1 q" a7 M, s$ X
  21. #define SPI_CRC_LENGTH_23BIT                          (0x00160000UL)
    . b! |" _# W8 l
  22. #define SPI_CRC_LENGTH_24BIT                          (0x00170000UL)
    % C7 _3 C3 z- Y) E
  23. #define SPI_CRC_LENGTH_25BIT                          (0x00180000UL)
    ) k. K+ ]2 C; `5 `9 u3 ?
  24. #define SPI_CRC_LENGTH_26BIT                          (0x00190000UL)% E# c0 \( S* x% O; [
  25. #define SPI_CRC_LENGTH_27BIT                          (0x001A0000UL)" A) W( m* q& m- {
  26. #define SPI_CRC_LENGTH_28BIT                          (0x001B0000UL)
    0 }) A5 n: Z, |& s$ i7 G
  27. #define SPI_CRC_LENGTH_29BIT                          (0x001C0000UL)
    + @% f- h' O, ^5 t  U7 i$ y7 u. |
  28. #define SPI_CRC_LENGTH_30BIT                          (0x001D0000UL)
    % P, T( Q3 k4 K1 f
  29. #define SPI_CRC_LENGTH_31BIT                          (0x001E0000UL)& k* {7 P. M9 c4 W* d
  30. #define SPI_CRC_LENGTH_32BIT                          (0x001F0000UL)
复制代码
0 m  X; \2 A* f, k
5 n; M- O& L- v8 f* V; U

6 f! p4 \  q3 {& M) _7 l. g  NSSPMode
( y+ o: C+ Y) y用于设置是否使能NSSP信号,可以通过SPIx_CR2寄存器的SSOM位使能。注意,只有配置为摩托罗拉SPI主控模式时设置此成员才有用。: T1 U- I# ?" M1 W

7 Q, j  @6 ^) Y+ u
  1. #define SPI_NSS_PULSE_DISABLE                         (0x00000000UL)
    # S& d- R# y. P% y$ j$ D3 y( Z4 n
  2. #define SPI_NSS_PULSE_ENABLE                          SPI_CFG2_SSOM
复制代码
4 H' p) E$ R& g2 N
  NSSPolarity) V: Z6 `, [7 w( K" ?% p* y
用于设置NSS引脚上的高电平或者低电平作为激活电平。
& a) N6 a. [' c9 C5 M
" l% M; {5 K. \5 F3 }
  1. #define SPI_NSS_POLARITY_LOW                          (0x00000000UL)1 {, \- J/ D0 ?
  2. #define SPI_NSS_POLARITY_HIGH                          SPI_CFG2_SSIOP
复制代码

! [3 u0 W1 x0 y7 Z8 ^  FifoThreshold, |1 K! O, h/ W; h7 `5 s" B
用于设置SPI的FIFO阀值。
* ~1 T, |! t: ]2 s$ x
% j) m+ {: Z. O
  1. #define SPI_FIFO_THRESHOLD_01DATA                     (0x00000000UL)
    ! Q8 g* ^+ l7 x
  2. #define SPI_FIFO_THRESHOLD_02DATA                     (0x00000020UL)
    " P- M7 D' ?! ], T
  3. #define SPI_FIFO_THRESHOLD_03DATA                     (0x00000040UL)
    ! o  u0 J2 I& o" y
  4. #define SPI_FIFO_THRESHOLD_04DATA                     (0x00000060UL)
    : T+ V$ i1 K9 g2 L
  5. #define SPI_FIFO_THRESHOLD_05DATA                     (0x00000080UL)
    * K! n+ G8 q  ]. A1 X% U
  6. #define SPI_FIFO_THRESHOLD_06DATA                     (0x000000A0UL)2 P  }; N" d0 }" P
  7. #define SPI_FIFO_THRESHOLD_07DATA                     (0x000000C0UL)
    . k0 Y. _$ v! q; W) P
  8. #define SPI_FIFO_THRESHOLD_08DATA                     (0x000000E0UL)0 b: W2 u, k8 ^2 c: i/ j
  9. #define SPI_FIFO_THRESHOLD_09DATA                     (0x00000100UL), C9 @9 F+ P5 K1 a9 T! n  I# P
  10. #define SPI_FIFO_THRESHOLD_10DATA                     (0x00000120UL)  H0 c! D, z1 F, m: l
  11. #define SPI_FIFO_THRESHOLD_11DATA                     (0x00000140UL)
    * @$ Y- P. r0 m& i, v  \, O
  12. #define SPI_FIFO_THRESHOLD_12DATA                     (0x00000160UL)
    : I/ [! F4 W3 z7 z! [
  13. #define SPI_FIFO_THRESHOLD_13DATA                     (0x00000180UL)
    1 E9 Q% d* w+ m% b" b. f* e
  14. #define SPI_FIFO_THRESHOLD_14DATA                     (0x000001A0UL)
    : m' I4 d# m% m
  15. #define SPI_FIFO_THRESHOLD_15DATA                     (0x000001C0UL)" Z" r5 X+ J" [( _: l/ A
  16. #define SPI_FIFO_THRESHOLD_16DATA                     (0x000001E0UL)4 ^6 f" G4 X. Z# C; j
复制代码
: y2 b8 U, E; O: l+ |0 N1 w: a

3 X% x5 L& X" o: Z2 Q" {  TxCRCInitializationPattern
7 s, x' i: q" z, ~+ B/ q7 U发送CRC初始化模式。
" {& c; C) \9 S, D$ S6 i7 I! s  |9 O! h# k/ A' Z2 q
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    4 n0 ?& r. k2 G" f: S/ `& o
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL). c+ g' C; u3 {# W
复制代码

9 o# b$ o! r5 Q- v5 t/ E  RxCRCInitializationPattern$ n1 K: Q1 G; \1 |
接收CRC初始化模式8 j- C; i8 R- p0 c

' \7 {1 x" E" t* x7 y0 z  @6 e* x
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    $ Y% S/ ?- D2 F
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码
* }' a, I2 p) I# \1 u5 V
MasterSSIdleness
' }3 Z7 h  Z& N+ |在主模式下插入到SS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数。9 C  B4 w: M) r

; Q$ X* X% u, u* m+ b, w% x
  1. #define SPI_MASTER_SS_IDLENESS_00CYCLE                (0x00000000UL)# d! q6 @3 @$ c: O+ h7 i& y8 Q
  2. #define SPI_MASTER_SS_IDLENESS_01CYCLE                (0x00000001UL)
    + Y9 [9 ^$ k# E2 |7 O
  3. #define SPI_MASTER_SS_IDLENESS_02CYCLE                (0x00000002UL)/ g7 D5 g1 N6 C4 J9 R
  4. #define SPI_MASTER_SS_IDLENESS_03CYCLE                (0x00000003UL)) w! }, G4 n2 q- j/ S- @0 g
  5. #define SPI_MASTER_SS_IDLENESS_04CYCLE                (0x00000004UL)
    7 s* t' R) _+ j
  6. #define SPI_MASTER_SS_IDLENESS_05CYCLE                (0x00000005UL)$ @' G4 n! C( A- E; P
  7. #define SPI_MASTER_SS_IDLENESS_06CYCLE                (0x00000006UL)
    ! }- u. ?( y8 ~2 f- f* T4 o
  8. #define SPI_MASTER_SS_IDLENESS_07CYCLE                (0x00000007UL)( h+ J! B, E( M7 O% i6 V" o
  9. #define SPI_MASTER_SS_IDLENESS_08CYCLE                (0x00000008UL)- Z: S9 x* H5 \8 k
  10. #define SPI_MASTER_SS_IDLENESS_09CYCLE                (0x00000009UL)
    - Y# N+ ]% E7 q' d( u
  11. #define SPI_MASTER_SS_IDLENESS_10CYCLE                (0x0000000AUL)
    7 |2 r: u8 o2 u! ]* X
  12. #define SPI_MASTER_SS_IDLENESS_11CYCLE                (0x0000000BUL)
    9 S3 e0 W1 h# |( _. z: T7 O5 A' u
  13. #define SPI_MASTER_SS_IDLENESS_12CYCLE                (0x0000000CUL)
    " g. f$ M0 X) t
  14. #define SPI_MASTER_SS_IDLENESS_13CYCLE                (0x0000000DUL)
    8 ^: u2 |5 p/ e% W8 }6 W! K. G
  15. #define SPI_MASTER_SS_IDLENESS_14CYCLE                (0x0000000EUL)+ W2 }% Q! Q/ p
  16. #define SPI_MASTER_SS_IDLENESS_15CYCLE                (0x0000000FUL)9 o# s( K6 P; B& R% p# l4 [# Z! Q# j+ E" w
复制代码
3 t0 e# U/ z/ I% U) W6 D0 q$ W

! R9 B8 Z* G* u5 O' W; ?8 t  MasterInterDataIdleness
- a0 b/ b- V* X* t1 o/ v主模式下在两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数。: a9 P7 z0 l( e4 Z2 L
5 H* Q& B* Z5 W) h
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)
    ; t5 f! ^/ v9 z, d+ p( W: H9 a
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
复制代码

# _% s; f7 Z) h5 G( E5 ?( I& Q  MasterReceiverAutoSusp
, o5 ~+ U0 S: [# F5 _5 ^0 c用于控制主器件接收器模式下的连续 SPI 传输以及自动管理,以避免出现上溢情况。
/ G" M/ ?! e' u" A8 b! `, ]" @: \- `- G
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)) X6 {, Z" O# \0 D: x& U
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
    + [) q" K6 n* t! W$ X' H: {# J
复制代码
* c/ f. y  y$ Z) T" o' ?
  MasterKeepIOState
4 ]- t9 D9 o* v6 M' d& \禁止SPI后,SPI相关引脚保持当前状态,以防止出现毛刺。在从模式下,该位不应该使用。+ ^4 o4 j& o: ?: i( a1 z

1 C5 `! U' j8 O" U  V: f* j
  1. #define SPI_MASTER_KEEP_IO_STATE_DISABLE              (0x00000000UL)
    ) r" @0 u- F9 }3 O9 Z) {: |
  2. #define SPI_MASTER_KEEP_IO_STATE_ENABLE               SPI_CFG2_AFCNTR
复制代码

3 ~# G* a. V, L% ~6 M/ ^  t  IOSwap0 A% g( s  x# Z5 n
用于交换MISO和MOSI引脚。% K7 V+ {# a( k# Q4 [: W( |

: V+ E$ @, U1 w) P' Q0 n
  1. #define SPI_IO_SWAP_DISABLE                           (0x00000000UL)
    + \! M6 z$ R  n* p
  2. #define SPI_IO_SWAP_ENABLE                            SPI_CFG2_IOSWP
复制代码

( g; F6 n+ |; }; O. h72.3.3 SPI总线句柄结构体SPI_HandleTypeDef, r( c; q$ M) F$ [" a% q- J
下面是SPI总线的初始化结构体,用到的地方比较多:
7 U3 t3 h$ \6 v" V; ]* r+ [% }, f7 h) Y' W' y
  1. typedef struct __SPI_HandleTypeDef
    3 w4 g) U7 y* c8 Z% d4 N/ K
  2. {+ y  L1 [, O) P0 j( \$ F+ Q
  3.   SPI_TypeDef                *Instance;                 
    ' o  P1 f$ H( z+ k
  4.   SPI_InitTypeDef            Init;                        0 _+ F# W6 i) b- M
  5.   uint8_t                    *pTxBuffPtr;                 / v. l* @) p( y  N1 R2 d% [
  6.   uint16_t                   TxXferSize;                  
    0 a" i- a( c9 j4 [; \5 Q4 l
  7.   __IO uint16_t              TxXferCount;                  + f# x$ m0 \9 B" q
  8.   uint8_t                    *pRxBuffPtr;                + g9 b$ z9 ~8 @7 P( A( j; _3 d1 {; t" Z
  9.   uint16_t                   RxXferSize;                  0 h4 `5 P- t. R
  10.   __IO uint16_t              RxXferCount;                 
    ; v1 W% c' |6 |* s+ ]& T
  11.   uint32_t                   CRCSize;                     
    - }5 z# e( Q  v
  12.   void (*RxISR)(struct __SPI_HandleTypeDef *hspi);       / P9 M# f: H+ D8 k- \
  13.   void (*TxISR)(struct __SPI_HandleTypeDef *hspi);        2 ~2 H" |5 h3 K
  14.   DMA_HandleTypeDef          *hdmatx;                     
      J2 h2 n8 F. Q  |- y
  15.   DMA_HandleTypeDef          *hdmarx;                     9 e/ G/ s+ f4 b1 ^7 g1 O
  16.   HAL_LockTypeDef            Lock;                        9 {& L" A# S/ e4 ]+ J" E
  17.   __IO HAL_SPI_StateTypeDef  State;                        
    7 ]: R) F2 K4 U& e  \+ u; z: D
  18.   __IO uint32_t              ErrorCode;                   / O8 @4 a' {* d! v: a* U5 m
  19. #if defined(USE_SPI_RELOAD_TRANSFER)
    : Q3 m# Q' g4 S8 \8 }) E5 {# k7 n
  20.   SPI_ReloadTypeDef          Reload;                     
    / y' ^7 o8 v0 _2 _7 }& R3 t/ z
  21. #endif
    $ C) v0 N* C  p) m9 ^% r

  22. 0 l3 b, j( n+ I- J- Q: ^
  23. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)  U8 h2 v/ f% Z* ?1 g7 S& E
  24.   void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      
    - B% Q7 `3 b) X% b; K% M" g) Q2 o
  25.   void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      0 [+ X. L5 P+ c. X% z! j0 i
  26.   void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    5 o5 K# b( ~6 O
  27.   void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  
    " q! k: G: B1 M  ~  G+ v% s
  28.   void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  * p4 O8 f2 x* p6 {; ^+ u
  29.   void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);
    4 O( R5 ~' Z* y; V# ~3 O- g, {
  30.   void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi);       ) }' ^% b: H+ n/ o$ y* F, w
  31.   void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi);   & \) |/ Z* R; d
  32.   void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi);    3 N& y0 C! L) U( {( ?" X# ~4 @
  33.   void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi);
    0 }3 x. l6 q$ @0 p' x0 x. p2 V
  34. #endif  7 b% c+ `" R  J& e( N1 ?
  35. } SPI_HandleTypeDef;
    * c7 }: S2 L& j, D$ c8 F" K
复制代码
) R3 ~, u+ h! h

/ N$ B/ S9 a2 U  [( P注意事项:2 ^: r8 }# {$ _: K
$ a* y/ z) y9 {' d  F
条件编译USE_HAL_SPI_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:
- }  ^# L2 d, B# N
4 Q" I6 j9 O+ b& q  @( F  Q8 k6 H/ N  #define   USE_HAL_SPI_REGISTER_CALLBACKS   1
5 f. W( w8 Y0 q3 J' n% m  ?
; f. \  B% P% I. F! `  c0 }通过函数HAL_SPI_RegisterCallback注册回调,取消注册使用函数HAL_SPI_UnRegisterCallback。- C) M/ I: P' e% r' F) {
# `' }) L# B: t0 q0 H
这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。
) f' t& `7 v- m: J" v& k8 S" y! M/ b" ]4 u. O3 r
  SPI_TypeDef   *Instance
( `. l( f2 F6 K& g: |这个参数是寄存器的例化,方便操作寄存器,比如使能SPI1。, k5 s/ I- k) G$ e  C* d

5 d5 @- T! m9 B8 d% ~; pSET_BIT(SPI1 ->CR1,  SPI_CR1_SPE)。5 q/ w9 f8 t" G/ N% B
, T0 Z7 v' B: r* c8 j; W
  SPI_InitTypeDef  Init8 U- ^/ \& {1 O2 [+ T
这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。. y" f/ [/ G* q8 d2 ]& r8 r
$ ~% {0 T* _7 o8 W: H/ _% i; l
  DMA_HandleTypeDef          *hdmatx               
' @% q' e  z* D  DMA_HandleTypeDef          *hdmarx
- P* K5 c' d, R5 A7 z: E) u) J用于SPI句柄关联DMA句柄,方便操作调用。' e1 J# {( r( J
8 }1 I! ?. c9 q- x) n$ l7 b
72.4 SPI总线源文件stm32h7xx_hal_spi.c
- Q0 g. j1 p- c: s& w& u此文件涉及到的函数较多,这里把几个常用的函数做个说明:
0 t' l5 V  D1 F5 J3 {2 j" I+ F+ s( t3 |- g$ ~: r  B
  HAL_SPI_Init+ [! Y3 H2 d9 t. h, Z
  HAL_SPI_DeInit
) H0 I0 N! p7 |  HAL_SPI_TransmitReceive; r7 ?/ z5 R7 h2 W( t9 \* O* @- b
  HAL_SPI_TransmitReceive_IT: P, m1 T  F! P8 Z% S
  HAL_SPI_TransmitReceive_DMA; ~: T! \6 l% O- R+ L* [2 N: Q
72.4.1 函数HAL_SPI_Init
8 l, H7 d; e/ J' x$ s函数原型:/ ]) Z0 r  N" E

- G  ]# p6 V# F0 ~- ^/ H4 K
  1. HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)' z* d2 d! ^2 H, T
  2. {. B" P2 o2 p* Y8 }& f
  3.   uint32_t crc_length = 0UL;
    / H% D+ x' w5 U) X
  4.   uint32_t packet_length;
      V( A5 f8 Z7 X5 B6 M& i) `: C
  5. 5 s( l6 v% H* r* L) M
  6.   /* 省略未写 */9 a6 K: v0 ?- D1 ?9 }

  7. & e. Y5 [& |, z7 P$ Q
  8.   /* 如果数据位宽大于16bit,必须是SPI1,SPI2或者SPI3,而SPI4,SPI5和SPI6不支持大于16bit */4 }: S5 y2 f4 A" ]2 [) _
  9.   if ((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (hspi->Init.DataSize > SPI_DATASIZE_16BIT))
      U! z6 T% q2 G9 U. w$ L3 V" e
  10.   {$ A& \+ Y  H& }4 B( v3 F1 u* d
  11.     return HAL_ERROR;- o4 n. r* E, u$ ~* `2 {
  12.   }4 G% W: _* F- _( a! b# ]1 s
  13. $ ]  ?6 B' u, L/ `0 s! V. o
  14.   /* SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit9 u6 d+ k6 @; r$ K2 J# H  n
  15.      这里是查看设置的缓冲大小是否超出了FIFO支持的大小。
    - V. N$ a3 ^# S5 M: m2 h
  16. */
    , {+ a7 I, S# a
  17.   packet_length = SPI_GetPacketSize(hspi);
    3 I: z& d1 y/ ?* H* l5 J
  18.   if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_LOWEND_FIFO_SIZE)) ||* y. F/ Q2 d, ^/ E
  19.       ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_HIGHEND_FIFO_SIZE)))" J! i1 l1 H9 F0 J
  20.   {
    / ^" V/ y; h7 c4 h
  21.     return HAL_ERROR;
    * D' S& }. W: f% R. v9 c
  22.   }
    , Z$ }1 P7 G* h& x1 e

  23. 2 ]2 z& W& |2 h3 P6 [$ D
  24. #if (USE_SPI_CRC != 0UL)
    - w! c8 b6 A* R' U8 \5 ?7 @, V
  25.     /* 省略未写 */" |8 Q; F3 o' t  E( F: s
  26. #endif
    ' _% k9 @7 b4 R% U& X8 y% }, N
  27. " b( J* Q6 r2 {6 ]
  28.   if (hspi->State == HAL_SPI_STATE_RESET)
    * s2 g1 X# r. y! i, B
  29.   {0 j6 }) c5 |1 H" o% |
  30.     /* 解锁 */
    ' K# Z$ h  c; t8 v3 V+ c
  31.     hspi->Lock = HAL_UNLOCKED;2 K7 ~. L8 h/ F3 f( O& x7 {
  32. 5 B$ H1 I) u- M
  33.     /* 使用自定义回调 */) I( D) q. |5 B# Q
  34. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL); w. G. D- }! J' w, {7 |
  35.     /* 设置默认回调函数 */# c; _8 b; h) [# H
  36.     hspi->TxCpltCallback       = HAL_SPI_TxCpltCallback;       /* Legacy weak TxCpltCallback       */6 N8 H4 n2 L+ O2 F
  37.     hspi->RxCpltCallback       = HAL_SPI_RxCpltCallback;       /* Legacy weak RxCpltCallback       */
    3 u6 l; i: M2 u( [
  38.     hspi->TxRxCpltCallback     = HAL_SPI_TxRxCpltCallback;     /* Legacy weak TxRxCpltCallback     */
    " c' c0 f6 @+ ~- S# \/ }
  39.     hspi->TxHalfCpltCallback   = HAL_SPI_TxHalfCpltCallback;   /* Legacy weak TxHalfCpltCallback   */
      e2 F6 T! {' M$ {7 P) S
  40.     hspi->RxHalfCpltCallback   = HAL_SPI_RxHalfCpltCallback;   /* Legacy weak RxHalfCpltCallback   */8 x: ~+ ^( c) \! u" g/ f; l
  41.     hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */
    2 |' Z8 a  C4 p4 |. J' K5 r
  42.     hspi->ErrorCallback        = HAL_SPI_ErrorCallback;        /* Legacy weak ErrorCallback        */
    + Q# p5 H# Y0 R; n( s
  43.     hspi->AbortCpltCallback    = HAL_SPI_AbortCpltCallback;    /* Legacy weak AbortCpltCallback    */& t0 s  v; p9 x9 K  f( H: I1 E( Q
  44. 0 _1 B, E& _9 X7 E8 y1 @
  45.     if (hspi->MspInitCallback == NULL)$ X4 c$ ^0 N8 w/ E0 P6 [0 O! T
  46.     {
    * z* G- z2 T  c3 v9 @1 w( o
  47.       hspi->MspInitCallback = HAL_SPI_MspInit;
    / z! l, G' g$ t" \! z; o
  48.     }& f1 ]) ]  B7 y' b& D$ T

  49. ( ?$ g+ d, ]# P; d# S
  50.     /* 初始化地址硬件: GPIO, CLOCK, NVIC... */$ j9 W' F2 m4 F- J
  51.     hspi->MspInitCallback(hspi);
    1 q/ O/ C; P/ W1 Q9 y4 O* C
  52. #else- F/ m+ Y$ R$ g2 `2 C
  53.     /* 初始化底层硬件: GPIO, CLOCK, NVIC... */7 X0 _% Y2 }; p" D3 J
  54.     HAL_SPI_MspInit(hspi);
    2 O- e% r, A1 X" [2 ^( ?: q3 L% t
  55. #endif/ J/ {% D* o( z0 s& v3 p4 o* F
  56.   }* z8 `! X4 g, _: N3 O  Q

  57. , O  b. I9 Z( V' c
  58.   hspi->State = HAL_SPI_STATE_BUSY;" V1 n0 ^" L3 j% W+ |3 ?/ x+ ?

  59. 5 b! C" q, l6 _& V+ V) O) _0 q  B
  60.   /* 禁止SPI外设 */2 H# D0 R/ j; z' c5 s/ d" @  y
  61.   __HAL_SPI_DISABLE(hspi);+ v  v- C+ ~7 R& Q) ?7 l, b+ K

  62. 2 R  n  F" N+ E+ x, r" v
  63.   /*----------------------- SPIx CR1 & CR2 配置---------------------*/
    ) h+ [2 P" {. C. ^
  64.   if ((hspi->Init.NSS == SPI_NSS_SOFT) && (hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.NSSPolarity ==. B# u5 ^% A8 f8 f- H* [) s
  65. SPI_NSS_POLARITY_LOW))5 g9 o0 d+ u9 M9 t. s: {
  66.   {! j! a$ A: F0 E5 K. p# `
  67.       SET_BIT(hspi->Instance->CR1, SPI_CR1_SSI);
    1 ?: o6 X" f! W: k# h6 @
  68.   }. S& W9 K0 y1 m- A! d

  69. / x0 \. O- S' y' r2 ^
  70.   /* SPIx CFG1配置 */$ x: R8 e0 {+ m) Y* Q3 f5 \+ M
  71.   WRITE_REG(hspi->Instance->CFG1, (hspi->Init.BaudRatePrescaler | hspi->Init.CRCCalculation | crc_length |8 n4 H. x# Z. R8 u! L$ a( i
  72.                                    hspi->Init.FifoThreshold     | hspi->Init.DataSize));
    ; K$ L+ g, k2 h5 z" _/ x$ Z
  73. / o$ }: Q' ?' F5 ^1 u
  74.   /* SPIx CFG2配置 */( _4 ]! V( \) S, \4 f4 \: }6 a+ ]
  75.   WRITE_REG(hspi->Instance->CFG2, (hspi->Init.NSSPMode     | hspi->Init.TIMode           | hspi->Init.NSSPolarity  |, i! O* Z: g0 S: b8 S
  76.                                    hspi->Init.NSS          | hspi->Init.CLKPolarity      | hspi->Init.CLKPhase     |
    * m6 ]4 f& h3 r/ e
  77.                                    hspi->Init.FirstBit     | hspi->Init.Mode             | hspi->Init.MasterInterDataIdleness |
    , e$ {. l" @8 @
  78.                                    hspi->Init.Direction    | hspi->Init.MasterSSIdleness | hspi->Init.IOSwap));
    . T0 ]8 ^; J3 F# N  \' p. r7 C
  79. * J" Q4 A4 r- v  N- b' h% z0 b
  80. #if (USE_SPI_CRC != 0UL)
    , A& g6 G- u0 X8 c- i* S
  81.   /*---------------------------- SPIx CRC配置 ------------------*/8 K9 B5 u1 @6 m
  82.   /* 配置SPI CRC */  B) G( }& t# \2 {. ~) u1 t5 F
  83.   if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
    7 J9 w6 b# a( g: y. o7 [. A) q) ^
  84.   {
    * h+ J. _) d  l- V; T' ~
  85.     /* 初始化TX CRC初始值 */: h. Z# ?9 u0 o$ \7 t4 `
  86.     if (hspi->Init.TxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)
    ! ]. C( j  x7 }: l& ]
  87.     {
    $ E3 \  t3 [" u" B  I
  88.       SET_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);
    - f7 Z7 q# p) x$ {. O
  89.     }
    % O) w, v2 J5 ^+ p; ^
  90.     else' m' j' ~/ f/ Z6 L; U8 V5 Z( G
  91.     {6 I# V& Z$ Y+ A; ]5 v
  92.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);
    % ]9 j2 a: p7 b
  93.     }
    + D% j( }! N0 c5 L) c' I
  94. " Z) N; L6 H. T
  95.     /* 初始化RXCRC初始值 */
    4 H4 K9 y0 ?3 T1 {3 K/ [6 w8 _& b
  96.     if (hspi->Init.RxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)
    ( ?6 a( G" A- Y  Y3 b: f* R0 i
  97.     {/ P: H6 ~9 d. V. \9 ]
  98.       SET_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);
    ( X# ]9 z  I! b2 Q2 N" [6 J
  99.     }/ _5 a( H6 E! U7 v' U: L
  100.     else
    1 j2 G$ w; P$ C6 a$ M1 y& Q
  101.     {
    : _1 |8 A# Q2 c) S2 p' F
  102.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);; M, _( B: q$ _' g- F$ Q
  103.     }! V& c3 f/ o; \( z+ x6 {

  104. 7 k0 `) b# F8 e. z0 y5 B, _0 `
  105.     /* 使能 33/17 bit CRC计算 */$ G0 [+ _0 m1 P
  106.     if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (crc_length == SPI_CRC_LENGTH_16BIT)) ||# ^- D6 o. \# E. D* o5 k. d6 i
  107.         ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance))  && (crc_length == SPI_CRC_LENGTH_32BIT)))
    : }* P% w1 U. ^* t) @# f
  108.     {% ^+ {& ~' Y( X, N" W+ c
  109.       SET_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);( T4 B; a7 N& c: b* U" s' o
  110.     }: Z2 O  |  O) v
  111.     else
    ) J, h0 q: G% {5 t6 \% l  N
  112.     {
    * B1 o* ]+ D. |9 {- ~7 Z: A9 O% I6 |7 w- d
  113.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);9 w$ q/ s6 [: b
  114.     }
    ) g5 A0 }; u( n7 U8 F. l; I  M& M
  115. " [1 ~. ^2 D# q# p) c4 m
  116.     /* 写CRC多项式到SPI寄存器 */$ x6 A9 R( y0 y) L; F, x
  117.     WRITE_REG(hspi->Instance->CRCPOLY, hspi->Init.CRCPolynomial);
    " P, L4 W) F" _0 B9 ]2 C; ?# [
  118.   }
    5 Q8 S% o6 H6 ?4 _+ ^, Z
  119. #endif - _+ c6 ]0 @7 f0 g# t
  120. + H! Y" P# v+ `
  121.   /* SPI从模式,下溢配置 */
    / W' c; A# ^: ]) [
  122.   if (hspi->Init.Mode == SPI_MODE_SLAVE)
    % D* o/ c4 j+ x4 C  X  L6 o# P
  123.   {5 `7 c8 X4 C4 _+ r
  124.     /* 设置默认下溢配置 */
    # q7 z* X, ?! i# b' F# u
  125. #if (USE_SPI_CRC != 0UL)7 Z5 F' J; A, l
  126.     if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_DISABLE)) N5 Q1 r9 k, p
  127. #endif
    # x- B1 M# t  u( u
  128.     {
    & D4 I/ t$ G3 m6 @! L
  129.       MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRDET, SPI_CFG1_UDRDET_0);, A% O! m0 v" ]9 o, H
  130.     }$ m4 k$ w3 r; O: Z6 g
  131.     MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRCFG, SPI_CFG1_UDRCFG_1);
    0 i3 d& Y/ R# C7 U" m# Y: F" k
  132.   }
    6 {5 h$ o! ?( p. g

  133. + J# `4 ?) s6 Z3 g7 n
  134. #if defined(SPI_I2SCFGR_I2SMOD)
    2 T3 W0 F1 J8 z# N6 w. S. d
  135.   CLEAR_BIT(hspi->Instance->I2SCFGR, SPI_I2SCFGR_I2SMOD);4 g8 O* w3 H1 u! h% E' {$ U
  136. #endif & H% `' G/ S" Q# y" [/ I; G, g
  137. ; r; W- M7 H+ p$ C+ w
  138.   /* 确保AFCNTR bit由SPI主机模式管理 */
    : B$ f; {& {8 |( u7 `  J
  139.   if ((hspi->Init.Mode & SPI_MODE_MASTER) == SPI_MODE_MASTER)
    7 P/ [& S+ z  _; ~& X- D% M
  140.   {) Z9 A+ @, r' \7 t9 H$ z4 }; N4 n
  141.     /* Alternate function GPIOs control */( P5 l$ E0 q% l, s5 }
  142.     MODIFY_REG(hspi->Instance->CFG2, SPI_CFG2_AFCNTR, (hspi->Init.MasterKeepIOState));
    8 Q9 t3 Y; r( V8 G0 S  g. k
  143.   }* f: X6 H% H! b6 ?) `4 P

  144. ( n5 H) O% |1 m8 p
  145.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;) j" X1 X! a* o9 u( x3 W
  146.   hspi->State     = HAL_SPI_STATE_READY;
    , ~/ B1 a& Y) t
  147. ! J6 J/ v1 s0 _! t$ j/ }$ ?
  148.   return HAL_OK;, j3 S# e# M, r' ^: M
  149. }5 Y' h2 a- C# L+ e6 Q
复制代码

2 K% H4 K7 t, E. n9 ?1 l
# v4 E1 j) q; {9 u+ d  [$ U函数描述:- F" g) B; W3 g2 q# }( i3 y4 t4 g
+ s  q; K8 b" F8 O# i! Y
此函数用于初始化SPI。
& B& H- D$ f% i( M1 Z8 W( E; O
; ~. ?' d: V# A# I* G函数参数:0 `4 \% x0 I- M2 g

1 n8 X- v' ]& g1 P& }  第1个参数是SPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。, W7 v  e. t! i! u
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
* z" r6 z3 ?- D注意事项:/ c4 u7 r0 o5 E( a: `

& A  n4 D2 ^: G) a7 a2 t函数HAL_SPI_MspInit用于初始化SPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。, O* r  h; a! @
如果形参hspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SPI_HandleTypeDef SpiHandle。
; F. @) D1 T6 T7 c: P: p对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SPI_STATE_RESET  = 0x00U。. |8 y6 k- r: P! G" s
  V1 N7 N, @3 G3 k( n
解决办法有三7 B. \4 Z6 n' J; J4 {

$ x# R" T8 a5 Z/ a7 G. j方法1:用户自己初始化SPI和涉及到的GPIO等。
  q2 F3 g6 c/ O8 Z& P; M! }, N: H7 o2 q5 m; k. P0 B4 j) ~
方法2:定义SPI_HandleTypeDef SpiHandle为全局变量。
3 u. D* ^+ {3 n  |, }8 A
1 r- b: S# W! ^9 ?2 N8 U' o$ `! k, Q4 b! F方法3:下面的方法
/ G9 O, C( S. _' J, H( s( R
2 }3 y& e2 A2 E0 L6 \
  1. if(HAL_SPI_DeInit(&SpiHandle) != HAL_OK)
    1 k6 ~- p& `+ T
  2. {- u# b* I6 X2 {% v" ]2 y
  3.     Error_Handler();; \. t+ M+ `* k) G0 ~$ N
  4. }  . x; I7 ^  `3 }
  5. if(HAL_SPI_Init(&SpiHandle) != HAL_OK)% t, ~5 M7 M9 J6 O9 L; \7 ^
  6. {
    % l0 N% |# a! z2 B
  7.     Error_Handler();
    7 z) C' h. ], b, ~) }  O! g
  8. }
复制代码

3 O1 o* [  k2 ?8 S  T9 }使用举例:0 \' q- `$ _8 `3 E
* [4 U, N+ q1 s3 y% c9 E
  1. SPI_HandleTypeDef hspi = {0};
    ; c% L2 O- A% b2 {7 d( s' Q! j
  2.   l( u, T- {9 F/ q
  3. /* 设置SPI参数 */( z) m0 Y( o' @
  4. hspi.Instance               = SPIx;                   /* 例化SPI */3 K* F/ ?' n2 L) ?& b* K1 U
  5. hspi.Init.BaudRatePrescaler = _BaudRatePrescaler;     /* 设置波特率 */  h$ T6 C' F; D8 w5 f
  6. hspi.Init.Direction         = SPI_DIRECTION_2LINES;   /* 全双工 */
    + o$ o) s) Z+ r3 s9 b+ _
  7. hspi.Init.CLKPhase          = _CLKPhase;              /* 配置时钟相位 */
    $ j/ G+ i# c/ g2 x  R3 N7 d5 k
  8. hspi.Init.CLKPolarity       = _CLKPolarity;           /* 配置时钟极性 */
    , f9 s& N8 b( u1 _: e
  9. hspi.Init.DataSize          = SPI_DATASIZE_8BIT;      /* 设置数据宽度 */  q9 l# F& K  U1 S# a/ s# S* B
  10. hspi.Init.FirstBit          = SPI_FIRSTBIT_MSB;       /* 数据传输先传高位 */+ E# F* j' N  C" c
  11. hspi.Init.TIMode            = SPI_TIMODE_DISABLE;     /* 禁止TI模式  */$ z* G) ~$ J/ M6 }, O" R! a  N$ _
  12. hspi.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;      /* 禁止CRC */
    3 n, B8 u4 F# o* b# g
  13. hspi.Init.CRCPolynomial     = 7;                               /* 禁止CRC后,此位无效 */) G  O  Z0 h2 k* m3 K0 `" u
  14. hspi.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;             /* 禁止CRC后,此位无效 */3 U# E$ `3 L- ?1 H
  15. hspi.Init.NSS               = SPI_NSS_SOFT;                    /* 使用软件方式管理片选引脚 */
    7 \3 q* v& E7 t8 J; }
  16. hspi.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_01DATA;       /* 设置FIFO大小是一个数据项 */1 N# u# c4 B, W. H+ ~
  17. hspi.Init.NSSPMode          = SPI_NSS_PULSE_DISABLE;           /* 禁止脉冲输出 */7 m2 R) b7 X  `8 ]8 {" y2 \
  18. hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  
    . H% _$ o# P4 |4 B
  19. hspi.Init.Mode                  = SPI_MODE_MASTER;            /* SPI工作在主控模式 */
    - B7 Y# G, R: G8 O$ V

  20. 2 Z- D" m2 w& Y: `( l3 Y' h3 b
  21. if (HAL_SPI_Init(&hspi) != HAL_OK)4 R0 |5 S6 Z; n; D4 E2 |3 C
  22. {
    # e6 e, Z7 n' K5 {8 t; v
  23.     Error_Handler(__FILE__, __LINE__);* q. x! n: M5 P
  24. }
复制代码
  x' v( e; j% D

, K3 y' V0 B( Y$ q4 R2 S. {. X, n72.4.2 函数HAL_SPI_DeInit6 v9 F$ V6 u# U, n" J! J6 ~6 F, i
函数原型:$ t% Y7 U  L6 l( I1 i5 b

9 N  I( h# @; [4 p; C- k
  1. HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)$ M6 L$ Y, ?$ H5 T! J
  2. {% i1 ~: I/ s8 Z8 J
  3. /* 检测SPI句柄是否有效 */, B# ~2 c& N2 F; n& F5 f: o# S
  4.   if (hspi == NULL)
    : B/ d8 w7 s' `  Z; W- K8 S
  5.   {
    . n+ L- `5 a) M; y
  6.     return HAL_ERROR;( i# r% ?! L5 m$ U1 G. U
  7.   }( x2 D& G0 M% g& R

  8. % G) D& U6 H: `. s) o
  9. /* 检查SPI例化参数 */
    / F: X% H5 ^) Y2 l5 g2 d& }
  10.   assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));
    - o8 k6 s& c  p/ y) i

  11. 7 I" J- M* t( Y
  12.   hspi->State = HAL_SPI_STATE_BUSY;7 F9 n( n" S( Q; }% z5 M
  13. ( i% ^7 [" p! l2 Q+ u
  14.   /* 禁止SPI外设时钟 */! q( i1 g( V  {4 D0 d& H
  15.   __HAL_SPI_DISABLE(hspi);
    # o& `1 T7 E: q9 @3 O+ ]4 i/ Y

  16. 1 W' c! x5 `% R
  17. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)% F9 S  R! p; v/ [& o6 k
  18.   if (hspi->MspDeInitCallback == NULL)- r5 c/ |3 ]- P9 q) \5 o
  19.   {: J5 f2 t* P5 I+ j. _0 V% X/ z, I. j
  20.     hspi->MspDeInitCallback = HAL_SPI_MspDeInit;
    2 k% X. B2 B7 G1 N5 F0 K7 h3 d
  21.   }
    & k# D0 d5 i  b* m
  22. + P, a; |: q$ B: N$ S" }' M9 U
  23.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */9 p$ N4 Z9 L" I% }4 t! i
  24.   hspi->MspDeInitCallback(hspi);
    ( i8 w' A  l4 P  M# A2 j" ~) @! Z
  25. #else+ x. V/ S% W  k8 e, ^
  26.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */4 {' }7 E* f9 s" g% m
  27.   HAL_SPI_MspDeInit(hspi);' X8 u0 q3 p8 u) r9 Y! t
  28. #endif 6 _: ^# B  _6 m( V4 F6 y
  29. 7 I+ k) k7 z& v# u! {$ C8 G9 ?2 ~3 m  n
  30.   /* 设置无错误,复位状态标记 */  F! m& C$ `0 \) C4 F# C  }
  31.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;% d) J: h" W- Y9 E, j1 u( Z5 u+ N
  32.   hspi->State = HAL_SPI_STATE_RESET;: k/ H3 t& q* C/ {1 `: {/ `

  33. : T( w& L0 n. P" s9 h( L0 x3 R" n
  34.   /* 解锁SPI */
    ( v2 G" n' R# I7 s/ O7 @2 T
  35.   __HAL_UNLOCK(hspi);
    # H( R" ~. f  g, u2 a( D

  36. - \  U$ |' X: ~2 S$ L6 M" e/ u
  37.   return HAL_OK;# l/ a. ]* \* |8 I( F
  38. }
复制代码

: ?  r$ V7 r( z函数描述:
. ^# ~; A9 e+ |6 [3 y! ~2 R# @
用于复位SPI总线初始化。
4 u( y/ z. {7 f6 q* J, p; `& i4 q0 m# ]0 ?2 s7 d6 r
函数参数:6 y- ?4 z( D. }
7 B4 J8 x; \7 Z: H  `+ ^
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。( O7 X, l' j: z. d& }7 N; w1 ?
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中
' I$ n3 t# g/ x) ?4 @( m72.4.3 函数HAL_SPI_TransmitReceive
& \9 T% L* W. Y# P" L5 k; v函数原型:
9 _* J" p% K/ E4 Y$ |. N: L
: L% N# ~1 ]2 x/ `$ O2 u0 I- q
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)8 F) Q  Z( O% I+ t
  2. {5 o1 z  `# Z' S" U

  3. + |6 D, e+ U. C& G& I) s$ Q
  4.    /* 省略未写 */
    $ q2 Y" z' n: V9 C; @

  5. . r5 m) k- c* O
  6.   /* 大于16bit的数据收发 */
    : T( w) _; |* @; G
  7.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    2 C6 ^+ Y7 s7 V8 Y/ e
  8.   {" I9 h% c: K6 ?( s. x
  9.        /* 省略未写 */& K% l' k( P& B0 z' v) n( Q
  10.   }9 A1 k1 E  ~- x; g) |
  11.   /* 大于8bit,小于16bi的数据收发 */
    : B' V/ K4 d$ m& I* p  ?& d; m
  12.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
      @$ c+ r, R! I; M/ P# J# Y
  13.   {) F! k* C; A5 T  l4 V# r6 y# h
  14.       /* 省略未写 */
    , C' k6 m! g/ V3 O
  15.   }, q9 ?* j, f0 G5 E& N, E
  16.   /* 小于等于8bit的数据收发 */
    ; e. k5 D6 t0 _2 P
  17.   else
    0 C# R1 g4 O" V& F" f
  18.   {" p! E0 @5 @) X( {$ l8 c
  19.        /* 省略未写 */
    ( D' x+ T3 k" F2 Y4 G
  20.   }; B8 p* i$ H% U2 r* n+ p5 r
  21. " @' ~: S2 W% m- @( j0 q, a( ~
  22. }* w" B0 e' t. W' r  q% N
复制代码

( y: y- h# y8 \! J
% m: A# i5 w% V- t& t% @函数描述:5 o7 g8 |. y% ]/ a2 ]' z) `" K2 s
, ]: g) F7 ^6 Z
此函数主要用于SPI数据收发,全双工查询方式。6 Y! V  [2 ^- x( r( q
. a3 F" O" W* @! Y9 v
函数参数:& f/ x& g# h8 E7 B

" S6 m0 Y2 m4 j0 e$ E$ G  第1个参数是SPI_HandleTypeDef类型结构体指针变量。; X4 b  ]2 z8 L1 B, x. \
  第2个参数是发送数据缓冲地址。/ j2 _3 S( X$ K/ X# h
  第3个参数是接收数据缓冲地址。3 U3 V6 t" P5 L* q
  第4个参数是传输的数据大小,单位字节个数。) z( E) E8 @) T3 \- q$ a
  第5个参数是传输过程的溢出时间,单位ms。
, {0 k. i+ c( `+ j, W1 {! n8 @  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。" B; d& U/ j9 ]+ z2 l6 r
使用举例:! h( p' R9 y3 z6 l

: S% j' V7 m7 u$ `3 Y8 ?# h' O! Q& P
  1. SPI_HandleTypeDef hspi = {0};  q+ J% W. _: N: {8 O2 F5 J0 V

  2. # m% E: [, |  p! K+ [7 x3 \
  3. if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)
    & Q# `* Y8 Q/ t
  4. {9 Q6 K6 P8 z; o3 Q# c3 o
  5.     Error_Handler(__FILE__, __LINE__);6 r% t; w% g% L5 \4 k. k
  6. }
复制代码
$ A- O, n7 I( y, V. P# j! R# d4 S
72.4.4 函数HAL_SPI_TransmitReceive_IT
$ O  D; C8 e: t5 r函数原型:
$ }* z- Z6 f' }! t9 {$ q
8 b) _. y6 B/ b' P  v  ~2 [
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)$ F) C' }# P' g3 x
  2. {
    4 l! D* r( S) ^8 I( i: e
  3.    /* 省略未写 */3 O% C' X5 z' d) `
  4. 5 {2 p3 k* L9 d
  5.   /* 设置传输参数 */
    * q5 V" p: T4 M$ u4 J
  6.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
    * F$ Q) |8 Q, t, l
  7.   hspi->pTxBuffPtr  = (uint8_t *)pTxData;
    0 x" @* C) O0 N3 _
  8.   hspi->TxXferSize  = Size;/ t' u4 s0 C; Q3 p5 G3 |
  9.   hspi->TxXferCount = Size;9 n/ \  ^) R  }# d9 G7 ^+ f8 d8 t
  10.   hspi->pRxBuffPtr  = (uint8_t *)pRxData;, C+ l9 s7 ]: `& X/ X, D" F
  11.   hspi->RxXferSize  = Size;
    : _$ r" X- c4 g* F
  12.   hspi->RxXferCount = Size;5 _7 M+ g# N: E. a& K

  13. " ~0 W3 `" X4 j' b) b
  14.   /* 设置中断处理 */
    6 V) e$ F7 Y9 V& B3 h6 n
  15.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT), X) a+ l$ F& F6 Q
  16.   {
    / L9 Q$ t5 d# h# h; `" u
  17.     hspi->TxISR     = SPI_TxISR_32BIT;$ {4 R. H5 M$ p; e$ a7 b
  18.     hspi->RxISR     = SPI_RxISR_32BIT;9 s6 R9 O( G, s' w. P/ j1 X% r
  19.   }; S# K, O4 y" A# ], M7 m
  20.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
    ) G2 B% h' {+ Z
  21.   {
    ( w* y% o! u- M8 y+ d5 F$ W0 T
  22.     hspi->RxISR     = SPI_RxISR_16BIT;. K  Z0 `; R* W0 M2 m( t
  23.     hspi->TxISR     = SPI_TxISR_16BIT;
    * d, J/ H( y" F/ r
  24.   }: r- l9 c+ ?$ [- V6 L* f- S
  25.   else
      x1 \& C8 }: t8 l' d' P# b
  26.   {" M& X0 b" F4 g
  27.     hspi->RxISR     = SPI_RxISR_8BIT;2 ~$ Q! U: {) S; E4 r- y/ [+ V1 T
  28.     hspi->TxISR     = SPI_TxISR_8BIT;
    * M: p/ q( p( c% c- Y
  29.   }9 O8 Z' @, ]$ s  \

  30. - m, h( K( Y  x5 f) Y4 ]. G  B
  31.   /* 设置当前传输数据大小 */
    6 W' T5 {% E% P: y
  32.   MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);
    6 L% |) x3 F. n! B& k

  33. # N/ A$ R! Q( k' w1 {: x
  34.   /* 使能SPI外设 */% _( Z2 g' Z! S  I6 V
  35.   __HAL_SPI_ENABLE(hspi);4 K3 [, q1 K) r
  36. ) [# s' y5 I6 W! }
  37.   /* 使能各种中断标志 */
    : V8 o7 a; t2 @  ]4 Y2 Q, z
  38.   __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_EOT | SPI_IT_RXP | SPI_IT_TXP | SPI_IT_DXP | SPI_IT_UDR | SPI_IT_OVR |
    + z1 Y2 u, {, k; w
  39. SPI_IT_FRE | SPI_IT_MODF | SPI_IT_TSERF));
    ; @! P; O$ w4 X3 \8 \, s3 M
  40. 4 n0 p3 h2 s! n, l' a  M- n! G1 s
  41.   if (hspi->Init.Mode == SPI_MODE_MASTER)
    4 n# l  {! a; @
  42.   {) @, L' J6 ~2 b3 ^' f
  43.     /* 启动传输 */
    ; }. |# B' N& q8 U4 C+ ^7 [/ a6 c, j9 _
  44.     SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);
    8 s! m  A7 @1 Y
  45.   }
    ' u/ C% i: f' }, ~4 \: ~1 E6 u

  46. 9 V1 s" p- Y" k
  47.   /* 解锁 */
    " g! F8 z- Z0 U0 W4 L5 L
  48.   __HAL_UNLOCK(hspi);
    4 C+ P( ]! v% z1 t: h, {
  49.   return errorcode;
    $ Z0 Q0 a% d1 X7 Y5 \: e
  50. }
复制代码

; l5 U) o$ w$ M6 v& @* ]! z
: W* Q! n1 G3 |7 v
. u/ z7 \) |% Q: |8 [函数描述:! z' ^, e6 Q# g9 T/ [" [, W

0 S& H9 i) d: W% Q( n3 }: |此函数主要用于SPI数据收发,全双工中断方式。
7 a. O( ?" y& P1 `9 w# Z! R
" e1 l8 x- O# B# B5 w$ ~/ K- c1 h函数参数:
8 M8 C; P1 C' o7 g5 V$ u
. S% q0 O. g9 P# T, c  第1个参数是SPI_HandleTypeDef类型结构体指针变量。  y" n. H+ s/ r8 X
  第2个参数是发送数据缓冲地址。
4 Q* L' |( \5 m7 c) Y8 k  第3个参数是接收数据缓冲地址。
" E( O, s! K& j% D! a  第4个参数是传输的数据大小,单位字节个数。
0 \; O  r) C! {5 j/ ?% R" _/ R  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
  M" z6 T% F6 E' |; X. `使用举例:
" f- ~) i/ T, J; J$ N  Q8 N) E5 \" a# z7 c5 g5 ~* X
  1. SPI_HandleTypeDef hspi = {0};
    / ~) T7 J. m+ {- g) H! v3 [

  2. 4 s1 ?6 Y8 u( N- u1 n
  3. if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    6 ?  F( J* u! D7 ]
  4. {7 H% c( w8 r3 A3 m8 {  Z
  5.     Error_Handler(__FILE__, __LINE__);
    ! }- R$ P# T, J1 \- h8 L( i( f& t- E
  6. }. Y& r3 V: r4 n+ x% K
  7.   k( R8 \" y9 v+ U: {  u

  8. $ _( A: ?3 v" Z$ ^$ D* P
  9. 72.4.5 函数HAL_SPI_TransmitReceive_DMA* B6 O6 Q, a! ]) ~# e
  10. 函数原型:( @! O3 ]/ e, h7 Y8 m+ D9 a
  11. ) x7 l% ?3 @3 w7 Z
  12. HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,1 q: Q# M- [; @
  13.                                               uint16_t Size)
    ! j% _6 X# @8 T9 @
  14. {
      M/ U; S+ _- \$ h% e- P) g* x+ ]2 ?
  15.    /* 省略未写 */
    3 |/ ], y1 p8 C3 ~: a' l" |: i, j

  16. ( `* X' }" H( ~/ ~: T% c, P% q
  17. /* 注意DMA的位宽和对齐设置 */
    3 w) u# a( e: c
  18.   if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && (hspi->hdmarx->Init.MemDataAlignment !=$ Z, X0 f+ C0 d( C6 ^9 d6 x
  19. DMA_MDATAALIGN_WORD))  ||
    3 T9 z# u- k$ f9 p7 l9 C
  20.       ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) && ((hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_HALFWORD) && (hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_WORD))))
    * X) b/ l7 F: [: v
  21.   {% d/ ]. r5 K0 [8 ^
  22.   }+ U! }8 k! N$ f1 B$ @

  23. + T: B7 P# B$ u' y5 |
  24. /* 调整DMA对齐和数据大小 */1 \1 R+ l  a/ I0 f# o1 f
  25.   if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)
    . u7 q1 ]1 m5 D' r' J% L
  26.   {
    8 B8 W4 d& w9 f! y+ k0 k, }
  27.      /* 省略未写 */5 s" S% Y) t+ e7 K0 T
  28.   }/ G. |7 {/ O, D% C* H
  29.   else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)' Q/ c  P5 J4 d% G: T- w5 J
  30.   {8 ?9 Q0 m) A  b9 s& E
  31.      /* 省略未写 */$ h# G. F6 s' \3 W+ p. H$ N
  32.   }7 N# ?) V# o. {/ n. |9 t, c
  33.   else$ N% E4 Y8 D8 p. M
  34.   {& A3 Z' C7 j) g, v* X
  35.       /* 省略未写 */; u: A; V9 g6 k$ M# B( f8 z
  36.   }
    3 L4 r4 l& H& e$ b) d

  37. - x8 W; r/ g. \
  38. /*  DMA接收配置 */' b6 \7 f" h5 h5 e, y
  39.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->RXDR, (uint32_t)hspi->pRxBuffPtr,) o- E. H) a& Z, r
  40. hspi->RxXferCount))8 f% }# p! S* J
  41.   {
    ; ~' m, Z8 A' ]( W
  42. . X" N: }9 x4 K& \! m
  43.   }
    . ~/ Z/ H- z  ]' m! G% ]/ l, D3 w
  44.   I) u5 x' ?! [; \" U; L/ W
  45. /* DMA发送配置 */
    ! Y$ r) w( @" |  L  }" v/ v( R
  46.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->TXDR,
      l# E% y9 Y1 z) Z: `2 n
  47. hspi->TxXferCount))
      O& G/ O1 h' U* f1 Y; {, M: \
  48.   {
    ( M5 H( b' Q2 L) C0 D
  49.   }
    ! U- C2 Q. j3 C- o
  50. + L9 r7 @3 o6 Q0 }8 k
  51.   /* 省略未写 */
    , {: H+ H4 E  {+ p( }' O3 C
  52. }
    9 F: V0 d1 |) a- q
复制代码
8 U6 C9 i& v4 y" Y% w( G* ~) s4 C. w
) f! D7 s) a# O+ c& n
函数描述:* W: k, P* M+ k$ N2 N
) u9 E: L- ?* X
此函数主要用于SPI数据收发,全双工DMA方式。; E  v$ x7 q+ X1 j( h, V
' e9 G* p4 z- d, M: D" S' `
函数参数:
2 k/ P0 P8 \: i, L& S
% _4 B6 U: x* n4 A' `% d; f  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
  Z0 K5 q; J4 ?/ L2 L  第2个参数是发送数据缓冲地址。
$ T  v# f! o9 n% Z  g2 r' y  第3个参数是接收数据缓冲地址。
4 x2 f5 q% ?6 J( b4 q$ X' K7 |  第4个参数是传输的数据大小,单位字节个数。
3 n8 x$ o5 p; A! y5 `  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
$ y4 a2 G" b: P4 `$ D3 z使用举例:) ~! S  ?% P+ m3 l
2 p' S' C$ W! Q- h. x1 E
  1. SPI_HandleTypeDef hspi = {0};
    9 `4 K7 `/ U! c- Z
  2. $ e# @- ]5 V1 |9 Y" l
  3. if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    7 j. w* f- u; v' j
  4. {
    : [3 e' _7 B' C+ m
  5.     Error_Handler(__FILE__, __LINE__);7 a! Q# E5 U+ t, D2 @. _
  6. }
复制代码

% s2 s( X3 f/ Y; S. Q3 M. M2 J6 j2 v

8 I' x/ B4 {1 x72.5 总结
0 }$ w; T4 M9 z  C, f" w% }0 g0 d本章节就为大家讲解这么多,要熟练掌握SPI总线的查询,中断和DMA方式的实现,因为基于SPI接口的外设芯片很多,熟练后,可以方便的驱动各种SPI接口芯片,以便选择合适的驱动方式。
/ @$ }' v5 G( H' R4 u4 ^, o. s) A0 r- P  _
% V4 k! N6 n9 M5 `" l
收藏 1 评论0 发布时间:2021-11-3 10:15

举报

0个回答

所属标签

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