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

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

[复制链接]
STMCU小助手 发布时间:2021-11-3 10:15
72.1 初学者重要提示4 X8 v8 X4 J  ^; [
  STM32H7的SPI支持4到32bit数据传输,而STM32F1和F4系列仅支持8bit或者16bit。
2 ?7 ~& g$ w( \; [9 s  STM32H7的主频400MHz时,SPI1, 2, 3最高通信时钟是100MHz,而SPI4, 5, 6是50MHz。4 H$ x  C* b+ U4 R' b6 d/ _5 J
  STM32H7的MISO和MOSI引脚功能可以互换,使用比较灵活。8 J# C. ]* Z( a5 D5 x4 u
  SPI总线的片选引脚SS在单一的主从器件配置下是可选的,一般情况下可以不使用。
/ a6 g  X. h. `4 X2 B$ [& e: G) W- W' u5 `' g2 ?
72.2 SPI总线基础知识
7 Q% w& s4 B4 ?72.2.1 SPI总线的硬件框图6 Z: |' m5 z5 ?4 V+ {3 \
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SPI的基本功能,然后再看手册了解细节。
% n$ v9 }% Q8 i. E: _- @7 C- x$ T5 e3 E! L6 y. I
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

4 m" n0 n9 X. d9 C( @5 P  G0 T& w: c  N% t, D* O2 H
通过这个框图,我们可以得到如下信息:4 s8 [/ l0 C; @8 w; a7 _

9 I7 S7 Y+ k9 {5 ^  spi_wkup输出
- l8 U& K0 |# H! E, v3 t4 z4 ~5 K低功耗唤醒信号。7 u+ w6 J4 h) f5 S; z: w) f5 f9 y

2 Q1 K3 ?4 I8 e( P$ _  spi_it输出
$ ]5 Q" I' [2 s; ]! Wspi的中断请求信号。
# f) J9 i* g+ e( R( a( y. M. S6 R, T* F2 M: {
  spi_tx_dma
9 d: }$ w: _* F+ d8 kspi_rx_dma# Y$ O9 ^! F1 G/ V) E0 i
spi的DMA发送和接收请求信号。
/ o+ b4 G/ H( q
9 V0 t5 x9 Z1 h2 U# x6 F$ |& s6 E  spi_pclk
# x* ^" N4 y6 D- m5 G为寄存器提供时钟。
  a5 a! \8 N' V3 _0 `1 i& m$ e" B% I" [+ Q3 |
  spi_ker_ck8 m! r& j0 q( ], d3 w$ B- U* z
为spi内核时钟。; x/ F' X2 R' G1 K9 s

- l1 B7 Q5 z# v. m7 N  SCK(CK),Serial Clock8 k& v. \! L& \# M
此引脚在主机模式下用于时钟输出,从机模式下用于时钟输入。6 b6 M8 g0 K9 h+ @  j- }
% @' \0 ?# A& N9 Y" W
  MISO(SDI),Master In / Slave Out data6 @$ Q' Q& _- m$ o
此引脚在从机模式下用于发送数据,主机模式下接收数据。+ d3 v# Y3 Z* Q

( t  }) b0 A1 p' p% C/ w5 X  MOSI(SDO), Master Out / Slave In data
7 E3 Y: D/ {0 ~* h% S2 w8 `此引脚在从机模式下用于数据接收,主机模式下发送数据。
/ m5 C. h5 h: \2 [) K1 F0 w6 w* M
  SS(WS), Slave select pin
9 o; Q9 z  ?4 |' Y, C$ j根据SPI和SS设置,此引脚可用于:
  _" l7 U6 Q. z# {2 r6 I2 {0 d1 F& ]  A% E+ V6 S5 H
a. 选择三个从器件进行通信。. [7 f; s. u; r* R0 f

, Q2 Y! C! N- v; ~5 `b. 同步数据帧。
9 R2 l9 X0 G/ x0 V
# S2 t2 Z# `, Z* T( u; I, h( rc. 检测多个主器件之间是否存在冲突。
$ s7 ~+ F' e( v: O* s5 t" Q3 u1 }$ Z/ G% c- U9 V1 c1 i
通过这个框图还要认识到一点,SPI有三个时钟域,分别是寄存器所在的ABP总线时钟域,内核时钟发生器时钟域以及内核时钟发生器分频后的串行时钟域。+ D8 [0 G" D! s
' w' s+ ~. V* V% q- N
72.2.2 SPI接口的区别和时钟源(SPI1到SPI6)
/ `$ Z+ \# q8 [1 y2 `- ]1 x  p这个知识点在初学的时候容易忽视,所以我们这里整理下。3 f+ X3 v7 f& ]  Z8 {

2 K, v! u: }$ Q! d; W  SPI1到SPI6的区别( K  t5 M/ y/ P4 V/ f4 y& B( _
  SPI1,SPI2和SPI3支持4到32bit数据传输,SPI4,SPI5和SPI6是4到16bit数据传输。, a9 f% Y7 I2 M
  SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit。& V9 i& Y  z% [$ d8 |

4 ?. Q4 P3 l5 @
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

+ Y& ^% m" r6 Z; a
0 d3 c9 X+ y- t) E- t  SPI1到SPI6的所在的总线(对应SPI框图的SPI_CLK时钟域)
2 M, |" z6 b) a. H+ P! ASPI1,SPI4和SPI5在APB2总线,SPI2,SPI3在APB1总线,SPI6在APB4总线。注意,SPI的最高时钟不是由这些总线决定的。
* y$ {; y) J0 P8 ]  ^; l: ~, @( ^5 [9 H8 l; _9 `
  SPI1到SPI6的支持的最高时钟(对应SPI框图的SPI_KER_CK)2 L9 H& |  H- ^1 w# ]5 _, e
STM32H7主频在400MHz下,SPI1,SPI2和SPI3的最高时钟是200MHz,而SPI4,5,6是100MHz, 以SPI1为了,可以选择的时钟源如下:
5 ?7 T7 T- V& t# S( M. E
9 m2 R9 f" z; }; p% Q
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
  j* |& D# i3 t% y$ ~
4 l/ `+ M) v  q. A& d9 _
这里特别注意一点,SPI工作时最少选择二分频,也就是说SPI1,2,3实际通信时钟是100MHz,而SPI4,5,6是50MHz。
3 \! j& \: p( s4 @+ F; W# b2 |7 S0 [1 u# e) \8 l' I
72.2.3 SPI总线全双工,单工和半双工通信7 i9 J% e4 O# j4 m
片选信号SS在单一的主从器件配置下是可选的,一般情况下可以不使用。但需要同步数据流,或者用于TI模式时需要此信号。
2 M( ~9 r: A# Y& d/ N$ E: I- b# Y. F5 x
  全双工通信
! v7 I  N: Q7 n* n全双工就是主从器件之间同时互传数据,SPI总线的全双工模式接线方式如下:  h! n" X9 ^7 i. R
+ r6 z5 E2 h; V  `# z2 z
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
  u( @; ]( b0 E, h! s

( H+ k: p* T# W& O) c# z, j关于这个接线图要认识到以下几点:
9 }  N- ]$ Q2 M7 L# G% H. L
" q+ W. U/ T9 Q( ]  注意接线方式,对于主器件来说MISO引脚就是输入端,从器件的MISO是输出端,即Master In / Slave Out data。MOSI也是同样道理。
& i) [( d# l: I- g* K  每个时钟信号SCK的作用了,主器件的MISO引脚接收1个bit数据,MOSI引脚输出1个bit数据。, F: a4 R! s/ J. G3 ?& \, b  }
  这种单一的主从接线模式下,SS引脚可以不使用。7 _0 r1 Y( n# ^% W3 t% @
  半双工通信
2 _4 o; V0 j1 V; ]6 o! S3 G; T4 k半双工就是同一个时刻只能为一个方向传输数据,SPI总线的半工模式接线方式如下:* A6 f+ G# \; \6 M3 e# |1 B

  g4 y) }' L" R! A$ \+ ^
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

& `4 @* A8 o- v0 `
5 z  r, g* p1 s# B关于这个接线图要认识到以下几点:7 ^/ t! y1 C6 |8 c' x

5 t! c* o9 m" _$ p/ i  更改通信方式时,要先禁止SPI。9 E' Q9 B( ]% j
  主器件的MISO和从器件的MISO不使用,可以继续用作标准GPIO。
1 M; S0 b+ N7 e, w  1KΩ的接线电阻很有必要,因为当主器件和从器件的通信方向不是同步变化时,容易出现其中一个输出低电平,另一个输出高电平,造成短路。* p: _; Y) [* P  v. b; R
  这种单一的主从接线模式下,SS引脚可以不使用。
+ Q" Y$ q* F6 u# q! {0 a* c  单工模式' z$ H3 t, Y) i- ]- ^  V* t
单工就是只有一种通信方向,即发送或者接收,SPI总线的全双工模式接线方式如下:3 J) i+ f" @' m2 Z0 ]

" X  P2 x5 D* }0 i" @- C* m
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

. z1 z, J) `) R$ F% Q) I- L
4 m) |/ [# [  e- {关于这个接线图要认识到以下几点:
+ F1 u5 W6 v! O! J0 B
0 N4 K) P- b" z& R3 K8 q  未用到的MOSI或者MISO可以用作标准GPIO。
0 V7 J* v: W# ]2 p) d! N  这种单一的主从接线模式下,SS引脚可以不使用。, W& M  Z3 U) a/ a) {* H% m
72.2.4 SPI总线星型拓扑8 }: e$ y: C4 t: y
SPI总线星型拓扑用到的地方比较多,V7开发板就是用的星型拓扑外接多种SPI器件:) y1 I9 [' d, I; J9 g0 {( i" d( w1 ?
+ j  s) c3 n4 O& x: \9 a3 u- b0 l
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

; Z/ J8 E+ B( Q5 q! g- l' B: ^+ |1 G: i& g2 L8 ]% d3 _- Z
关于这个接线图,有以下几点需要大家了解:5 p$ E8 a; T. e$ e

  f6 u( K+ \" H. [6 d! l+ q  主器件的SS引脚不使用,使用通用GPIO控制。为每个器件配一个SS引脚,方便单独片选控制。0 C( ?7 M& c+ S' p
  从器件的MISO引脚要配置为复用开漏输出(很多外部芯片在未片选时,数据引脚是呈现高阻态)。" H* H' ~' B7 {9 k! r5 e
72.2.5 SPI总线通信格式
* I% \2 u# `) f  v* m2 sSPI总线主要有四种通信格式,由CPOL时钟极性和CPHA时钟相位控制:
. s2 ]/ V6 H! g
/ m! [+ e! L7 I! Z! J4 F6 i0 g: z
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
& Z" E2 Y% o# z

$ m* a1 Y) [, O- l3 |: g! Z四种通信格式如下:( H  H5 L: B$ G: e1 f3 J/ n
7 L+ m) p  T+ P% J
  当CPOL = 1, CPHA = 1时
, g. x' D8 ^* b3 W8 A( ASCK引脚在空闲状态处于低电平,SCK引脚的第2个边沿捕获传输的第1个数据。
5 X% E) J( m% Y( w9 H; q# X' J! p* v. T+ A( k# p- n' s
  当CPOL = 0, CPHA = 1时/ g# [0 Y  [! @  }3 n6 a
SCK引脚在空闲状态处于高电平,SCK引脚的第2个边沿捕获传输的第1个数据。; b8 y/ w1 N& m/ K( H; @/ Q

  {( t/ I- f+ W: g  当CPOL = 1, CPHA = 0时
* x( B. W0 @( k! F3 WSCK引脚在空闲状态处于低电平,SCK引脚的第1个边沿捕获传输的第1个数据。; a7 J8 V# z) F

6 S& v% F. w6 [  当CPOL = 1, CPHA = 0时" S; \$ n5 x6 S. M" q8 g' e& U
SCK引脚在空闲状态处于高电平,SCK引脚的第1个边沿捕获传输的第1个数据。
( w  M5 M& L' Q- Y( O7 u% N) q& h4 {/ ?
72.3 SPI总线的HAL库用法
7 j4 p& Y. R+ `1 t72.3.1 SPI总线结构体SPI_TypeDef
! k- v( c, R3 Q* h5 b4 C# b. qSPI总线相关的寄存器是通过HAL库中的结构体SPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
4 C0 q$ Y" u8 W% ~+ U$ j& Q
: g7 D4 a& b) @. Z
  1. typedef struct; y- H$ Z% d8 r/ I8 m
  2. {# t" @3 M4 k5 f" i( U3 V
  3.   __IO uint32_t CR1;           /*!< SPI/I2S Control register 1,                      Address offset: 0x00 */5 c8 X/ P; V" e' g! m! V2 s
  4.   __IO uint32_t CR2;           /*!< SPI Control register 2,                          Address offset: 0x04 */1 d$ M$ c3 z/ C  U. _  r
  5.   __IO uint32_t CFG1;          /*!< SPI Configuration register 1,                    Address offset: 0x08 */
    ' _" f$ M' {( I. W8 o1 W
  6.   __IO uint32_t CFG2;          /*!< SPI Configuration register 2,                    Address offset: 0x0C */% ~1 M6 F( o7 d
  7.   __IO uint32_t IER;           /*!< SPI/I2S Interrupt Enable register,               Address offset: 0x10 */8 c$ U( e" U; h: U' I* R# v% x
  8.   __IO uint32_t SR;            /*!< SPI/I2S Status register,                         Address offset: 0x14 */
    2 a% ~8 Q4 \5 ?
  9.   __IO uint32_t IFCR;          /*!< SPI/I2S Interrupt/Status flags clear register,   Address offset: 0x18 */+ x4 }5 ^& p3 L5 D
  10.   uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                        */& T. W* i! l( ?( w! w4 c; i+ l
  11.   __IO uint32_t TXDR;          /*!< SPI/I2S Transmit data register,                  Address offset: 0x20 */
    % _  q8 a. @% e: r- C
  12.   uint32_t      RESERVED1[3];  /*!< Reserved, 0x24-0x2C                                                   */
    + Z1 H# m; r0 s8 a: @
  13.   __IO uint32_t RXDR;          /*!< SPI/I2S Receive data register,                   Address offset: 0x30 */
    6 O5 F3 O1 T$ B& \2 w. o
  14.   uint32_t      RESERVED2[3];  /*!< Reserved, 0x34-0x3C                                                   */- m4 _" U, k" o3 ?
  15.   __IO uint32_t CRCPOLY;       /*!< SPI CRC Polynomial register,                     Address offset: 0x40 */( k6 o5 r6 ^0 m
  16.   __IO uint32_t TXCRC;         /*!< SPI Transmitter CRC register,                    Address offset: 0x44 */
    5 \1 U4 w0 {5 D( M' e" Q
  17.   __IO uint32_t RXCRC;         /*!< SPI Receiver CRC register,                       Address offset: 0x48 */
    8 P! U& [* T# u. y" b5 z5 g5 ~# W
  18.   __IO uint32_t UDRDR;         /*!< SPI Underrun data register,                      Address offset: 0x4C */& s# k' \) F. F4 A; z- E
  19.   __IO uint32_t I2SCFGR;       /*!< I2S Configuration register,                      Address offset: 0x50 */
    / Y0 |2 N1 g% E& I- R
  20.   h( d" t% C5 m6 `$ |9 _
  21. } SPI_TypeDef;
复制代码
" G, v. p4 D( L
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。+ s$ J1 \- b( J, _0 v, T1 I
7 u, Z4 b. {9 b( d0 S
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
, P0 B: l6 v: `" Y. n
7 Z" {, i( t+ ^" ?5 Z
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    ' x& d3 L( l% f1 v) |) }
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
6 D1 A! x, v1 ~' V$ Z: l5 w$ r
下面我们看下SPI的定义,在stm32h743xx.h文件。; W* ?$ N6 R+ R# C. v
! x) U1 i( U  o) Q3 C+ L
  1. #define PERIPH_BASE           (0x40000000UL)
    / B8 M0 |$ O6 T' e( E
  2. #define D2_APB1PERIPH_BASE     PERIPH_BASE
    9 f$ Z% J* O! F
  3. #define D2_APB2PERIPH_BASE    (PERIPH_BASE + 0x00010000UL)
    0 I! m0 Z! r7 U# x, j; m  M! n& R
  4. #define D3_APB1PERIPH_BASE    (PERIPH_BASE + 0x18000000UL)
    7 h5 `: Q0 E! a/ n2 u
  5. 8 N7 u/ q; k4 e
  6. #define SPI2_BASE             (D2_APB1PERIPH_BASE + 0x3800UL)4 |9 g- t$ ]! h( R' Z4 a6 l
  7. #define SPI3_BASE             (D2_APB1PERIPH_BASE + 0x3C00UL)
    6 G$ O+ U3 g8 G# s1 K% v
  8. #define SPI1_BASE             (D2_APB2PERIPH_BASE + 0x3000UL)
    / R0 r9 v6 e3 A6 G, E0 z9 q
  9. #define SPI4_BASE             (D2_APB2PERIPH_BASE + 0x3400UL)/ c2 a! S# S* ~, l' _7 i5 O
  10. #define SPI5_BASE             (D2_APB2PERIPH_BASE + 0x5000UL)* G- D( \! j+ {/ `: o
  11. #define SPI6_BASE             (D3_APB1PERIPH_BASE + 0x1400UL)
    - V) i+ B  Y3 C3 F$ L) T/ V

  12. : s7 L6 J( ^# e- U0 h3 R- u1 N
  13. #define SPI1                ((SPI_TypeDef *) SPI1_BASE)# Q. {' t' g( E0 O$ J2 ~
  14. #define SPI2                ((SPI_TypeDef *) SPI2_BASE)1 h: L2 R$ n0 Y: {0 V9 Y# r: {! I
  15. #define SPI3                ((SPI_TypeDef *) SPI3_BASE)) J# m/ o' f6 ^
  16. #define SPI4                ((SPI_TypeDef *) SPI4_BASE)
    0 r9 N4 M' s: L# x) o
  17. #define SPI5                ((SPI_TypeDef *) SPI5_BASE)* _- W0 u8 @) X; C
  18. #define SPI6                ((SPI_TypeDef *) SPI6_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x58001400
复制代码

" w1 }  i# [. T5 V6 Y: E我们访问SPI的CR1寄存器可以采用这种形式:SPI->CR1 = 0。
4 h. {0 {1 E& o! J; S8 }% A; j7 c6 y! p, p
72.3.2 SPI总线初始化结构体SPI_InitTypeDef
- a+ u5 A; S& O6 z) k- X下面是SPI总线的初始化结构体,用到的地方比较多:
$ j6 q( U" y: s% Z1 c) }# o3 B* T, U, T7 t# Y
  1. typedef struct
    4 x9 c( x5 O0 N6 j
  2. {
    2 o/ a' v$ m/ M
  3.   uint32_t Mode;                           
    0 K! g& S' N! y$ ]
  4.   uint32_t Direction;                     
    ) f: P3 M; x. ]3 e' f! r+ Z
  5.   uint32_t DataSize;                          
    3 o# R( T9 t! L% T0 ?
  6.   uint32_t CLKPolarity;                       
    8 m- O+ E. q% u4 F
  7.   uint32_t CLKPhase;                         + w" n' j5 Y% j8 y
  8.   uint32_t NSS;                             7 q, j8 ^$ c; c6 j$ S
  9.   uint32_t BaudRatePrescaler;               
    ( r& C" W" G! p7 _4 I: z6 B$ N
  10.   uint32_t FirstBit;                         # U/ X( q/ ^% m% p7 F1 @) k& A
  11.   uint32_t TIMode;                          
    6 a6 s$ Y# p& }& J0 V: p
  12.   uint32_t CRCCalculation;                  
    4 X- u% q( |% E: c/ j. K. \! _4 y
  13.   uint32_t CRCPolynomial;                     
    ! M2 ^- s; r6 J" v
  14.   uint32_t CRCLength;                        . Q  u4 ]- q& F, Q7 y' h
  15.   uint32_t NSSPMode;                        
    8 p/ I! ?+ f* E4 k0 s2 k3 y# ]
  16.   uint32_t NSSPolarity;                    
    2 I$ \' R- y# v2 t
  17.   uint32_t TxCRCInitializationPattern;      
    , p) b. u" G8 \. q9 s7 B' l  c8 w' R
  18.   uint32_t RxCRCInitializationPattern;      
    - ~" ^$ {9 K: U4 ]
  19.   uint32_t MasterSSIdleness;                 ( W/ Q4 w4 r3 W
  20.   uint32_t MasterInterDataIdleness;           2 N  ]% @7 ~6 N6 \0 s  g" [0 d
  21.   uint32_t MasterReceiverAutoSusp;          6 ~$ m: ]+ g6 G% |% ?9 n& L% K
  22.   uint32_t MasterKeepIOState;               
    * \+ ^1 d% `/ ]5 f" f
  23.   uint32_t IOSwap;                          * _( ]8 j$ n7 q  R! M1 R. M- G
  24. } SPI_InitTypeDef;
复制代码
5 j$ a5 e: f) S# G" r' X
下面将结构体成员逐一做个说明:
, ]0 h' ?$ u) g4 e+ `: ^4 L
. k6 [. ?3 J% o5 ^4 @5 p4 U  Mode
. m& G- B- U2 g, `用于设置工作在主机模式还是从机模式。- ?$ C: n: G8 a
! Z" c5 y3 \$ C4 p2 Q9 u
  1. #define SPI_MODE_SLAVE              (0x00000000UL)
    + {  L" Z- f& t3 F; {  g3 q$ A- ?
  2. #define SPI_MODE_MASTER             SPI_CFG2_MASTER
复制代码
: Q- r/ \, j& P0 }8 G" ?. R# S
  Direction
$ l, {3 [, m& U1 V! j用于设置SPI工作在全双工,单工,还是半双工模式。
% {! g: }( ^1 i  W
  1. #define SPI_DIRECTION_2LINES           (0x00000000UL)     /* 全双工 */
    ) B' c* B1 Q9 e# E' `5 ?- I
  2. #define SPI_DIRECTION_2LINES_TXONLY     SPI_CFG2_COMM_0   /* 单工,仅发送 */) X! X  c$ n1 n1 v+ Q
  3. #define SPI_DIRECTION_2LINES_RXONLY     SPI_CFG2_COMM_1   /* 单工,仅接收 */
    " @+ @7 R5 k/ `, k: \: O) m1 S
  4. #define SPI_DIRECTION_1LINE             SPI_CFG2_COMM     /* 半双工 */
复制代码
6 D4 d9 C: W" T: m
  DataSize
6 [5 G8 n4 n3 c2 u8 Y, K& Y用于设置SPI总线数据收发的位宽,支持4-32bit。
3 W, e# g3 e1 J, k" H; r* ~# K) U2 @+ i& p7 @* s
  1. #define SPI_DATASIZE_4BIT                             (0x00000003UL)0 ~7 o' B8 `* G5 ]
  2. #define SPI_DATASIZE_5BIT                             (0x00000004UL)
    ' g# i: y2 L% E
  3. #define SPI_DATASIZE_6BIT                             (0x00000005UL)
    " U: `1 X" k# b! w9 @
  4. #define SPI_DATASIZE_7BIT                             (0x00000006UL)
    3 k+ t" i" ~+ S& \6 q7 ]$ Z
  5. #define SPI_DATASIZE_8BIT                             (0x00000007UL)
    ! w! q" k$ a( Q- o
  6. #define SPI_DATASIZE_9BIT                             (0x00000008UL)
    % Y6 ]  r2 V( b' Y1 k- h
  7. #define SPI_DATASIZE_10BIT                            (0x00000009UL)5 b8 A; R. U. \# v% L( o+ o
  8. #define SPI_DATASIZE_11BIT                            (0x0000000AUL)
    ! v; h3 l) A' c  C; Z
  9. #define SPI_DATASIZE_12BIT                            (0x0000000BUL)9 |9 T! G  p2 ^
  10. #define SPI_DATASIZE_13BIT                            (0x0000000CUL)" w' R6 t. H, E7 P; S: b
  11. #define SPI_DATASIZE_14BIT                            (0x0000000DUL)7 P7 S& P  K/ b. |( h& s' x7 |
  12. #define SPI_DATASIZE_15BIT                            (0x0000000EUL)
    4 O  [% D* F" T% P  {$ T, i
  13. #define SPI_DATASIZE_16BIT                            (0x0000000FUL)# z1 E- o) T: P& Y( E5 T! k. g
  14. #define SPI_DATASIZE_17BIT                            (0x00000010UL)# z6 \5 z+ V) y8 d5 |0 _
  15. #define SPI_DATASIZE_18BIT                            (0x00000011UL)
    ) R/ v7 j- G' a' c1 e5 F  n/ d" e
  16. #define SPI_DATASIZE_19BIT                            (0x00000012UL)
    - b* w7 |; X; m- x( O1 o; B, L
  17. #define SPI_DATASIZE_20BIT                            (0x00000013UL)
    3 v3 F: T; b& j; Z
  18. #define SPI_DATASIZE_21BIT                            (0x00000014UL)
    3 T% }3 G& ^6 R3 x% q: ]  P8 S
  19. #define SPI_DATASIZE_22BIT                            (0x00000015UL)- p9 O. }: j# q, q( ~* P# S' U6 T
  20. #define SPI_DATASIZE_23BIT                            (0x00000016UL)
    ( d' e0 a! ~  _* i/ B& t7 I/ }  S
  21. #define SPI_DATASIZE_24BIT                            (0x00000017UL)7 b5 m" ]$ l, |
  22. #define SPI_DATASIZE_25BIT                            (0x00000018UL)
    ; b& M" W% t7 |- Q7 e
  23. #define SPI_DATASIZE_26BIT                            (0x00000019UL)
    & M7 P/ `/ x5 ?. O
  24. #define SPI_DATASIZE_27BIT                            (0x0000001AUL)6 E1 A! d3 O' d9 K' X1 O  D, r  h
  25. #define SPI_DATASIZE_28BIT                            (0x0000001BUL)8 Z$ c7 H( y5 ~
  26. #define SPI_DATASIZE_29BIT                            (0x0000001CUL)+ u  S1 ^5 ?: D; c. @
  27. #define SPI_DATASIZE_30BIT                            (0x0000001DUL)8 d' X+ U4 w$ D/ l1 D& A
  28. #define SPI_DATASIZE_31BIT                            (0x0000001EUL)- v+ _* |: Y3 H! ~) [8 b
  29. #define SPI_DATASIZE_32BIT                            (0x0000001FUL)
复制代码
2 t9 \6 V( [% P
  CLKPolarity/ Y$ g5 E' y0 n' w
用于设置空闲状态时,CLK是高电平还是低电平。
# B( `, f3 ~3 u0 k
3 s+ d3 W4 B2 {4 G
  1. #define SPI_POLARITY_LOW       (0x00000000UL)
    , R5 S/ a8 ~0 a5 y6 [
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码
( K+ i. ^2 ?2 ^7 J
  NSS2 k7 N; R% ?1 m/ S" }, X" u: N7 H
用于设置NSS信号由硬件NSS引脚管理或者软件SSI位管理。
( J/ G1 X  ^8 z! l. J5 e6 A( s1 v& A- }) L/ r
  1. #define SPI_NSS_SOFT                                  SPI_CFG2_SSM
    3 S) C* h8 {# x1 O7 @; A# T. O
  2. #define SPI_NSS_HARD_INPUT                            (0x00000000UL)# D' y( Z! g* T! f7 L! I( ]( i
  3. #define SPI_NSS_HARD_OUTPUT                           SPI_CFG2_SSOE
复制代码

) x. z4 `* [8 B( v2 W: v$ w  BaudRatePrescaler
# _! F  z0 c1 J& {6 L0 g用于设置SPI时钟分频,仅SPI工作在主控模式下起作用,对SPI从机模式不起作用。" {" A4 f) E! @* E8 q
0 A0 o0 z" s  H; u: M, N9 R5 h  e
  1. #define SPI_BAUDRATEPRESCALER_2                       (0x00000000UL)
    % A, b8 W3 k- A  Q% \! {
  2. #define SPI_BAUDRATEPRESCALER_4                       (0x10000000UL)3 u. j5 i$ `  Y: C
  3. #define SPI_BAUDRATEPRESCALER_8                       (0x20000000UL)
    ; o0 L2 j0 a7 M7 e- q
  4. #define SPI_BAUDRATEPRESCALER_16                      (0x30000000UL)! F& J( c+ H4 {$ i
  5. #define SPI_BAUDRATEPRESCALER_32                      (0x40000000UL)
    7 D% ^  Q" P' A* ~# e
  6. #define SPI_BAUDRATEPRESCALER_64                      (0x50000000UL)
    4 c* ^. [* x: k' s" J3 P
  7. #define SPI_BAUDRATEPRESCALER_128                     (0x60000000UL)
    5 a' X' |7 r( n/ ^$ N
  8. #define SPI_BAUDRATEPRESCALER_256                     (0x70000000UL)
复制代码
2 _" ^/ e$ B6 ]! C" ~4 b
  FirstBit
: Z1 @/ y, R/ f. {1 Q: N: @* Q5 d用于设置数据传输从最高bit开始还是从最低bit开始。
! K; d! X7 J8 d& T% }- P$ Y5 L- H# P" f) b
  1. #define SPI_FIRSTBIT_MSB                              (0x00000000UL)
    8 ^7 \  U# ]$ R" i: H
  2. #define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST
    5 M% z+ ^+ c" G8 v
复制代码
; d4 j1 w( Q! P8 H7 O8 d
  TIMode7 W/ s. L* R# j- P  }/ ~
用于设置是否使能SPI总线的TI模式。/ T& d6 b: H  G) e( ]. P
* l: h" ?5 n, [: M9 [
  1. #define SPI_TIMODE_DISABLE               (0x00000000UL)
    0 W6 D( e5 V8 @" @
  2. #define SPI_TIMODE_ENABLE                SPI_CFG2_SP_0
复制代码

$ x" a8 }7 F  I* w: M  CRCCalculation
* ~$ J$ l0 k7 M) L: b用于设置是否使能CRC计算。
3 c+ x+ p, ?# ?! o9 e' \7 m+ d. Y3 }0 k9 F
  1. #define SPI_CRCCALCULATION_DISABLE                    (0x00000000UL)/ T& [: e# k) ]' Z  a1 P! L1 ]% E
  2. #define SPI_CRCCALCULATION_ENABLE                     SPI_CFG1_CRCEN
复制代码
: w/ b& J: l3 V; G9 J
  CRCPolynomial/ N# A  O* n- n! w' e  S7 D5 E
用于设置CRC计算使用的多项式,必须是奇数,范围0到65535。
3 H' c2 F" m5 S- D) l  A
1 u" v& H6 e# N$ `4 X  CRCLength2 Q' u! Q3 a) H+ E" A* }
用于设置CRC计算时的CRC长度。大小要与同属此结构体的DataSize一致。或是DataSize的整数倍。; V; k; a) l% V4 H4 K' M9 ~
2 z% n; N. B7 H/ x3 |  U: m) g
  1. #define SPI_CRC_LENGTH_DATASIZE                       (0x00000000UL)
    7 o# R! [$ B) ]
  2. #define SPI_CRC_LENGTH_4BIT                           (0x00030000UL)6 g) g; C; O0 R6 t$ W
  3. #define SPI_CRC_LENGTH_5BIT                           (0x00040000UL)
    7 e( q; M2 s& w; p9 N) C
  4. #define SPI_CRC_LENGTH_6BIT                           (0x00050000UL)+ K8 n; ~1 ~% N9 |! }* ^: ], n
  5. #define SPI_CRC_LENGTH_7BIT                           (0x00060000UL)( q" R) O% m% }  c3 L0 m, ~. {. F0 K
  6. #define SPI_CRC_LENGTH_8BIT                           (0x00070000UL); t9 B8 G3 }2 g0 C
  7. #define SPI_CRC_LENGTH_9BIT                           (0x00080000UL)1 o" \7 X& c% P- R/ a5 T8 `
  8. #define SPI_CRC_LENGTH_10BIT                          (0x00090000UL)
    6 o; O+ W4 H1 W. }* s/ B1 _
  9. #define SPI_CRC_LENGTH_11BIT                          (0x000A0000UL)
    3 T+ t) O: u* q3 y9 e; M/ \
  10. #define SPI_CRC_LENGTH_12BIT                          (0x000B0000UL)5 [! a; R" g! B" O/ H7 t1 Q
  11. #define SPI_CRC_LENGTH_13BIT                          (0x000C0000UL)6 e; ~% [6 \8 E9 ?; _: W! V1 @
  12. #define SPI_CRC_LENGTH_14BIT                          (0x000D0000UL)8 f& x$ c8 v8 X6 X; `
  13. #define SPI_CRC_LENGTH_15BIT                          (0x000E0000UL)
    2 j  ^" C/ K+ l5 [# j0 X- h7 B3 g
  14. #define SPI_CRC_LENGTH_16BIT                          (0x000F0000UL)7 ]9 {7 _8 I0 v5 ?6 U; R1 F& \
  15. #define SPI_CRC_LENGTH_17BIT                          (0x00100000UL)
    . E! ^& B7 v1 a  H% X
  16. #define SPI_CRC_LENGTH_18BIT                          (0x00110000UL)2 G7 y/ q! y/ V4 p+ q
  17. #define SPI_CRC_LENGTH_19BIT                          (0x00120000UL)8 j2 I1 I* j& C& ~& [
  18. #define SPI_CRC_LENGTH_20BIT                          (0x00130000UL)
    3 O# Z5 a  R6 p. j
  19. #define SPI_CRC_LENGTH_21BIT                          (0x00140000UL)0 ~. t* n; m$ M) y- E) T3 [
  20. #define SPI_CRC_LENGTH_22BIT                          (0x00150000UL)/ @% x, c4 t5 {( h: b  F
  21. #define SPI_CRC_LENGTH_23BIT                          (0x00160000UL)" l. b4 {" ~1 V
  22. #define SPI_CRC_LENGTH_24BIT                          (0x00170000UL)
    # R8 d0 _  f* s
  23. #define SPI_CRC_LENGTH_25BIT                          (0x00180000UL); S! z5 y* c& R, p. p
  24. #define SPI_CRC_LENGTH_26BIT                          (0x00190000UL)# o2 g- w# \# l8 {0 e1 W% q
  25. #define SPI_CRC_LENGTH_27BIT                          (0x001A0000UL)
    : D) _6 \1 X' O+ d
  26. #define SPI_CRC_LENGTH_28BIT                          (0x001B0000UL)% U  Q+ \# z  J
  27. #define SPI_CRC_LENGTH_29BIT                          (0x001C0000UL); h' Z$ \6 g, l3 y- |7 P
  28. #define SPI_CRC_LENGTH_30BIT                          (0x001D0000UL)
    / |- n" ]& H! p* v0 q  O
  29. #define SPI_CRC_LENGTH_31BIT                          (0x001E0000UL)8 C: u. C; P& D$ i9 `
  30. #define SPI_CRC_LENGTH_32BIT                          (0x001F0000UL)
复制代码

' ]7 p& ?1 v; k, M! I! g0 s& J2 g. S# ~
$ A* h/ O; g, M  c
  NSSPMode( F8 V/ |# r( b! U3 @4 h7 S
用于设置是否使能NSSP信号,可以通过SPIx_CR2寄存器的SSOM位使能。注意,只有配置为摩托罗拉SPI主控模式时设置此成员才有用。
; l' O5 }3 Q9 [3 W1 A9 \/ t# ^4 j% @% x. `
  1. #define SPI_NSS_PULSE_DISABLE                         (0x00000000UL)
    1 w0 `# O0 @& @. c& W) X- O7 |
  2. #define SPI_NSS_PULSE_ENABLE                          SPI_CFG2_SSOM
复制代码
5 M& R1 k% E7 |- B% o8 V8 ~
  NSSPolarity7 G* `1 J% R6 Z" \  V. }) x' g
用于设置NSS引脚上的高电平或者低电平作为激活电平。# P, d" F) l0 e+ p
3 n. C' Q! N7 a! m- g
  1. #define SPI_NSS_POLARITY_LOW                          (0x00000000UL)
    4 {" B) N5 v" @  d
  2. #define SPI_NSS_POLARITY_HIGH                          SPI_CFG2_SSIOP
复制代码
2 O7 C8 P+ C) X0 E; _% H* v/ A9 p8 g
  FifoThreshold1 I2 H( m2 r% s* L4 R; D7 @
用于设置SPI的FIFO阀值。* O: z$ u' x4 n7 H0 e

* Z$ r" t) c6 y+ L2 p5 k1 w
  1. #define SPI_FIFO_THRESHOLD_01DATA                     (0x00000000UL)8 L1 x$ J4 Y: L7 b6 x
  2. #define SPI_FIFO_THRESHOLD_02DATA                     (0x00000020UL)  c7 N! Z% S5 L
  3. #define SPI_FIFO_THRESHOLD_03DATA                     (0x00000040UL)+ q+ K; p7 S# s1 x7 t
  4. #define SPI_FIFO_THRESHOLD_04DATA                     (0x00000060UL)$ \4 V- V" c; i8 E$ L) n
  5. #define SPI_FIFO_THRESHOLD_05DATA                     (0x00000080UL)
    # B/ |( M5 x, E/ Y
  6. #define SPI_FIFO_THRESHOLD_06DATA                     (0x000000A0UL)
    5 J* W/ v( a( A5 z3 v
  7. #define SPI_FIFO_THRESHOLD_07DATA                     (0x000000C0UL)
    1 p% |* Q5 E' A: P5 J
  8. #define SPI_FIFO_THRESHOLD_08DATA                     (0x000000E0UL). k9 y  n3 I. f1 [
  9. #define SPI_FIFO_THRESHOLD_09DATA                     (0x00000100UL)
    7 L$ r  {, j- V. }5 L
  10. #define SPI_FIFO_THRESHOLD_10DATA                     (0x00000120UL)
    0 k! G6 C; H* m/ w4 N
  11. #define SPI_FIFO_THRESHOLD_11DATA                     (0x00000140UL)
    * D. u$ o* Y" X- D) J
  12. #define SPI_FIFO_THRESHOLD_12DATA                     (0x00000160UL)
    * [0 m3 G. w. m  R# x( B5 W9 d
  13. #define SPI_FIFO_THRESHOLD_13DATA                     (0x00000180UL)
    1 G) O+ F% B" K/ ^; l* z/ o* S- K
  14. #define SPI_FIFO_THRESHOLD_14DATA                     (0x000001A0UL)
    4 m5 F7 |& T7 @6 m, a
  15. #define SPI_FIFO_THRESHOLD_15DATA                     (0x000001C0UL). Z1 P9 L( @) J
  16. #define SPI_FIFO_THRESHOLD_16DATA                     (0x000001E0UL)
    ( O2 Q8 D# F9 i. \
复制代码

$ O, r; a) ]' |' j  K0 P# K( j3 V0 j6 F! `1 }% V$ L
  TxCRCInitializationPattern& y+ d( B, h7 M7 p  o9 t9 n, w
发送CRC初始化模式。
( r1 T& q( p* Q
( ^* j. K9 r& W" A/ u
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)7 X6 A% T# ~2 j5 D1 k0 b
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)# x1 W" F3 U" O9 b1 d0 P
复制代码
$ C! f. b- Q. U# o" l" K
  RxCRCInitializationPattern9 j5 z9 Q& \5 a8 v6 z
接收CRC初始化模式
4 ], z0 U- Z* N& I. Q  K# w3 W6 P: v: }2 x2 E
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    ) C) g. G) N3 L/ Y* b6 y
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码

6 ~5 k! h5 f: T/ |& t MasterSSIdleness
( M2 R6 L) |6 e7 ?! a) n! L在主模式下插入到SS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数。
' ^1 s7 o  ]& D7 I+ O6 B
1 A) ]9 m7 j' y
  1. #define SPI_MASTER_SS_IDLENESS_00CYCLE                (0x00000000UL)$ C! R5 }' g2 D4 ~4 y! o
  2. #define SPI_MASTER_SS_IDLENESS_01CYCLE                (0x00000001UL)7 P( J; r* h6 Y# _0 O" v- }
  3. #define SPI_MASTER_SS_IDLENESS_02CYCLE                (0x00000002UL)
    2 V, U0 M2 f9 w/ _
  4. #define SPI_MASTER_SS_IDLENESS_03CYCLE                (0x00000003UL)  X9 G$ C: Z* {# y
  5. #define SPI_MASTER_SS_IDLENESS_04CYCLE                (0x00000004UL)
    # v. l& a; Y6 b+ I
  6. #define SPI_MASTER_SS_IDLENESS_05CYCLE                (0x00000005UL)" s9 q) W8 O% N3 w7 h# v" A
  7. #define SPI_MASTER_SS_IDLENESS_06CYCLE                (0x00000006UL)
    1 G! U) T" m; d0 s/ V2 d) Z
  8. #define SPI_MASTER_SS_IDLENESS_07CYCLE                (0x00000007UL)
    4 a3 d2 [( s+ U0 F2 B% N% R; v! ^. e
  9. #define SPI_MASTER_SS_IDLENESS_08CYCLE                (0x00000008UL)6 H5 B6 ?* }/ G& P- }. A
  10. #define SPI_MASTER_SS_IDLENESS_09CYCLE                (0x00000009UL). N4 l6 V. W7 c+ s
  11. #define SPI_MASTER_SS_IDLENESS_10CYCLE                (0x0000000AUL)4 b& ]9 @3 E& ?' G1 ?- G6 e
  12. #define SPI_MASTER_SS_IDLENESS_11CYCLE                (0x0000000BUL)
    ( w7 w: v) d. f1 }
  13. #define SPI_MASTER_SS_IDLENESS_12CYCLE                (0x0000000CUL)
    ; L1 n6 [: }- \) k
  14. #define SPI_MASTER_SS_IDLENESS_13CYCLE                (0x0000000DUL)
    * g* D# Z7 t$ e; [! b9 U
  15. #define SPI_MASTER_SS_IDLENESS_14CYCLE                (0x0000000EUL)
    * j( x* @% d2 h+ W7 p  z, @/ \
  16. #define SPI_MASTER_SS_IDLENESS_15CYCLE                (0x0000000FUL)9 j6 N% x, C) V! W4 w5 L
复制代码

2 w7 ^3 A9 m- o, x+ U. \$ O7 _9 s% j5 F5 ^
  MasterInterDataIdleness
9 }: H  h/ |8 v, l6 e主模式下在两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数。
" Q# [* l/ _0 b; d8 |  x' j+ H9 _& R# Y, x% D1 L
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)& O7 Z* w( q' D  _
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
复制代码
# o( |$ l( Z2 {& v
  MasterReceiverAutoSusp
) ?  W/ Q' ~5 z; Y3 d5 O9 ^用于控制主器件接收器模式下的连续 SPI 传输以及自动管理,以避免出现上溢情况。$ U; m' q$ }. F, z7 g
2 u( t- T9 e( c! F
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)
    & e* b  l: z( u2 C# g
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
    2 S4 K: X6 J  h6 o0 R6 m& }
复制代码
% D- G/ d4 B) I0 V
  MasterKeepIOState) `2 }2 F! [  G; w7 w, |' a  x
禁止SPI后,SPI相关引脚保持当前状态,以防止出现毛刺。在从模式下,该位不应该使用。: S% _/ {0 k3 ?& f1 G

+ m' N, f4 ]0 G8 h- u: o. T1 K9 V
  1. #define SPI_MASTER_KEEP_IO_STATE_DISABLE              (0x00000000UL)8 f2 v) s. {" f6 P1 g0 B
  2. #define SPI_MASTER_KEEP_IO_STATE_ENABLE               SPI_CFG2_AFCNTR
复制代码

2 {5 Z3 n7 W( N  IOSwap
* q. U5 \* G8 J4 b) l# @5 b用于交换MISO和MOSI引脚。9 f' v. p- l' Z! B) Z! W

) F2 Y1 X4 L4 i" D
  1. #define SPI_IO_SWAP_DISABLE                           (0x00000000UL)
    ' \2 k3 k7 r% r- i$ f, y
  2. #define SPI_IO_SWAP_ENABLE                            SPI_CFG2_IOSWP
复制代码

  O0 B+ v! [2 e72.3.3 SPI总线句柄结构体SPI_HandleTypeDef
* |# d5 ?; ?& G6 U7 q下面是SPI总线的初始化结构体,用到的地方比较多:
# I% v* r" u3 O5 l( O6 ~0 l4 }$ y5 v1 p* d4 j
  1. typedef struct __SPI_HandleTypeDef
    8 ?& ^2 m. y; \& C! b/ t
  2. {) k& o/ U! M7 X* Z2 y
  3.   SPI_TypeDef                *Instance;                 ; a7 K" V- K$ K# m* A
  4.   SPI_InitTypeDef            Init;                        
    ) Y# @" o+ }5 D0 J
  5.   uint8_t                    *pTxBuffPtr;                 
    ( H3 p- r! k+ s6 @+ _7 l
  6.   uint16_t                   TxXferSize;                   . ~: v: O" R7 q- S) z. [
  7.   __IO uint16_t              TxXferCount;                  ) p# F' Q; h5 e" a
  8.   uint8_t                    *pRxBuffPtr;               
    ) Y: M; H# M8 U1 c) W& m+ M
  9.   uint16_t                   RxXferSize;                  , a$ s8 p& R4 w; i# A$ Z% ^
  10.   __IO uint16_t              RxXferCount;                 
    & x3 F8 }4 U$ C( k
  11.   uint32_t                   CRCSize;                     
    9 a. m# h5 Y  R: @( W5 E8 {- |" {7 ]3 y2 k
  12.   void (*RxISR)(struct __SPI_HandleTypeDef *hspi);       2 K& @4 n! i$ o2 G  k6 X
  13.   void (*TxISR)(struct __SPI_HandleTypeDef *hspi);        
    ! n* @: J# @) P9 }
  14.   DMA_HandleTypeDef          *hdmatx;                     
    3 \  E5 |' f. H1 O# \
  15.   DMA_HandleTypeDef          *hdmarx;                     
    ; f: H) o' q+ g! X. @7 x; D
  16.   HAL_LockTypeDef            Lock;                        ' Y' j7 m2 r3 h# d1 Y( o
  17.   __IO HAL_SPI_StateTypeDef  State;                        7 C+ H3 _% L% s
  18.   __IO uint32_t              ErrorCode;                   8 Z* J  e8 u' M$ U  v8 e
  19. #if defined(USE_SPI_RELOAD_TRANSFER)
    3 p# z7 i" Y2 X% @) k0 S
  20.   SPI_ReloadTypeDef          Reload;                      , \3 ?. T( y8 K2 C8 ~. ?4 V8 \
  21. #endif - \* R0 g0 R% ^! N, ~; D5 o+ _

  22. : O3 P$ a6 ]( I1 t: b0 Y( j, @
  23. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    $ A/ _3 ]5 e3 L5 B* [
  24.   void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      
    , w: f: F, a& v) z4 a$ f7 `, S/ G
  25.   void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      ( d1 ?8 b( H7 F. F
  26.   void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    # S! q0 ?: z0 q4 t% H+ n7 `
  27.   void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  
    ' x+ d" X/ r$ p( i5 ~
  28.   void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  ; t# \7 y2 o$ Z
  29.   void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi); ! x! B, S9 L2 a8 y2 D
  30.   void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi);       ; g, {2 \* d3 U" I6 c# x1 R3 x
  31.   void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    2 y4 t2 }1 x! b( }9 v! C* N+ W* ]
  32.   void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi);    ' L" o3 V, B  L7 }
  33.   void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi); % i, j! L% l$ }( ?! M
  34. #endif    V- ^' T$ J! E. M/ F, f; G
  35. } SPI_HandleTypeDef;" B& }; x( W. L, n8 X  z
复制代码

7 D, |7 h  R" P
/ k4 J7 U( F4 ?. {% }4 u" p注意事项:
) w$ V; v  \. Q: i% Y( i& _- h( |% t
条件编译USE_HAL_SPI_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:
! C, {$ J! M( Y7 M* \! k: J9 D" k7 v
  #define   USE_HAL_SPI_REGISTER_CALLBACKS   1& h6 }4 h( T  {2 q* h

" x. t3 i0 t2 t* q& Y7 u通过函数HAL_SPI_RegisterCallback注册回调,取消注册使用函数HAL_SPI_UnRegisterCallback。0 W3 n, n* A0 U9 }! t

& b# X6 b* D3 U' Q( K: B. F这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。
' }, `: Y' @: ~4 d) Z( i- b5 y* f& q+ f# @: J7 w) \7 S+ a- w' l
  SPI_TypeDef   *Instance
4 L# i$ W0 k7 G# d这个参数是寄存器的例化,方便操作寄存器,比如使能SPI1。
) c& R. d$ k5 [6 Z0 f% z0 q  w; ]6 d! l. m
SET_BIT(SPI1 ->CR1,  SPI_CR1_SPE)。
* D5 x9 N& q+ R2 c% N8 [' U3 j
0 @& u. |, H/ ^1 @  SPI_InitTypeDef  Init" ?' G- Y8 m6 N7 y0 m7 `; c
这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。7 ?/ o6 x. F2 @* R2 r: O8 \
( o7 z3 j; l% C
  DMA_HandleTypeDef          *hdmatx               
8 k- A: H" \# y0 b# v( a  DMA_HandleTypeDef          *hdmarx
; L" t; I$ K2 Q/ p7 h" n用于SPI句柄关联DMA句柄,方便操作调用。: ]6 U7 |. [$ R( m! I) V2 K
0 M* c/ a8 X/ ^3 O2 W5 P
72.4 SPI总线源文件stm32h7xx_hal_spi.c
! f7 ~* F& R" l. e; p- v$ r此文件涉及到的函数较多,这里把几个常用的函数做个说明:; F, e8 Y% O) H6 Y9 t* [
  X( t) \/ R( Y- }; Y
  HAL_SPI_Init
& f! }' d- {. c- `  HAL_SPI_DeInit& F+ x3 x7 o" o" w) V: r' S5 ^
  HAL_SPI_TransmitReceive: w1 N' E8 l2 M$ _: x; P
  HAL_SPI_TransmitReceive_IT6 E" j4 a0 O& j; F& z( y! D1 p
  HAL_SPI_TransmitReceive_DMA
0 H% K7 G1 H! f% |72.4.1 函数HAL_SPI_Init
8 a; o& v, `: i2 I# H2 _函数原型:, z5 w% [) I8 N$ o
+ k4 ^, D: Y. R7 H9 H% P
  1. HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)
    0 V- P8 o1 r0 U: r
  2. {3 K+ k% A$ K  b, o: n
  3.   uint32_t crc_length = 0UL;3 b) g& G; y. \  D3 g  N! J
  4.   uint32_t packet_length;
    - ~( p+ d3 [3 O0 d6 }* s6 q
  5. 3 u$ f; p) n& m. ?8 R1 `
  6.   /* 省略未写 */6 R- h9 ^) d8 @& f* O9 r
  7. . c; R! g* {3 e* |, O
  8.   /* 如果数据位宽大于16bit,必须是SPI1,SPI2或者SPI3,而SPI4,SPI5和SPI6不支持大于16bit */
    ) H% C$ N' Y' U+ r
  9.   if ((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (hspi->Init.DataSize > SPI_DATASIZE_16BIT))
    " ?# a4 j- v; W" S' O; d# E( S
  10.   {+ |; Q) z0 Q9 ?" F4 P9 v
  11.     return HAL_ERROR;
    2 b7 L# g  W' Q- k5 N# r9 k5 m& n
  12.   }. N2 o! s" g5 I; x3 [
  13. ! ~) H2 k: _/ a
  14.   /* SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit/ t- I% t' I# e) s% `
  15.      这里是查看设置的缓冲大小是否超出了FIFO支持的大小。' d6 j' V8 U1 D7 V! I% @1 Y# G
  16. */# U1 w* e2 o7 Q8 ?) [
  17.   packet_length = SPI_GetPacketSize(hspi);
    8 F0 }% w% _) Z9 e9 ?
  18.   if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_LOWEND_FIFO_SIZE)) ||
    8 U% ]) G7 r. b- r: I* B9 `; N
  19.       ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_HIGHEND_FIFO_SIZE))): |4 }  _* a! s+ T& k
  20.   {
    5 n: ]: r2 c0 Q; Z7 Z" C
  21.     return HAL_ERROR;7 q* s" h: a. n" e+ c
  22.   }" b# [2 u" Q9 H* b; z
  23. 8 U3 m3 v' s/ }" @; P/ H" R
  24. #if (USE_SPI_CRC != 0UL)
    : ^3 H4 w% O4 f: C0 A1 T* g5 q  `
  25.     /* 省略未写 */7 i; t7 h0 O" Y7 d4 }
  26. #endif
    ! n+ j* O- N4 ^$ r

  27. % e! F  g+ }! _& ?: W) s
  28.   if (hspi->State == HAL_SPI_STATE_RESET)
    2 l9 s. f% z* U" z
  29.   {
    / ^& R5 _* U' u+ V: Q
  30.     /* 解锁 */
    * O% L& s" u9 G( G
  31.     hspi->Lock = HAL_UNLOCKED;
    % N/ a% I+ v  f

  32. . g$ S  r! X3 ?; h3 p; G6 {9 S
  33.     /* 使用自定义回调 */7 v! O+ @0 k4 [1 n/ g2 h- F( G- J
  34. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    2 U. R. J5 k4 n6 [# ?
  35.     /* 设置默认回调函数 */, N$ d) H3 ?. J( T8 @+ y/ Y4 B1 P. W
  36.     hspi->TxCpltCallback       = HAL_SPI_TxCpltCallback;       /* Legacy weak TxCpltCallback       */
    * ?8 b* F& Z( X; V
  37.     hspi->RxCpltCallback       = HAL_SPI_RxCpltCallback;       /* Legacy weak RxCpltCallback       */" f1 A8 T( N& e3 _1 m/ r
  38.     hspi->TxRxCpltCallback     = HAL_SPI_TxRxCpltCallback;     /* Legacy weak TxRxCpltCallback     */
    7 q8 Z& l( Z5 h- R
  39.     hspi->TxHalfCpltCallback   = HAL_SPI_TxHalfCpltCallback;   /* Legacy weak TxHalfCpltCallback   */
    0 R6 u, |) G& W6 i& J5 u+ x; E+ z0 d! N
  40.     hspi->RxHalfCpltCallback   = HAL_SPI_RxHalfCpltCallback;   /* Legacy weak RxHalfCpltCallback   */2 i$ X; o5 Y  z. c: r' ]) }' I2 K0 y
  41.     hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */% X( c( Z& [$ f( C4 [
  42.     hspi->ErrorCallback        = HAL_SPI_ErrorCallback;        /* Legacy weak ErrorCallback        */
    ; |6 d1 f0 u/ C2 F9 Q  S$ m' Q5 u
  43.     hspi->AbortCpltCallback    = HAL_SPI_AbortCpltCallback;    /* Legacy weak AbortCpltCallback    */- ~! @1 B7 F: l! @& H# N1 M/ {
  44. ' V, ?, b7 j  m0 S
  45.     if (hspi->MspInitCallback == NULL)( L$ o3 G" F$ e9 W( t) U
  46.     {
    $ z$ U. @" t# L5 ^& V+ H# T2 M: W# Q
  47.       hspi->MspInitCallback = HAL_SPI_MspInit;
      V% L) H1 B9 |9 i
  48.     }
    : \: i. _) S% F! w5 W
  49. / V4 E  A$ G. p$ }- j
  50.     /* 初始化地址硬件: GPIO, CLOCK, NVIC... */
    - }, q6 `: X1 R, R, d7 q+ ]
  51.     hspi->MspInitCallback(hspi);0 P8 C2 H2 O4 T# `
  52. #else
    2 f2 W9 R* v( K- \1 H+ E. e6 g
  53.     /* 初始化底层硬件: GPIO, CLOCK, NVIC... */
    9 L7 H  _2 q3 ^/ F( i* O
  54.     HAL_SPI_MspInit(hspi);
    , T6 ~9 Z1 W1 J3 o
  55. #endif
    1 u6 _8 E/ U3 s7 d2 o0 `
  56.   }3 Q; Z- ]$ {8 A2 z& @- u

  57. * K% q8 z: }! h1 \; l7 Z
  58.   hspi->State = HAL_SPI_STATE_BUSY;. k# M% e3 I4 s) h
  59. 6 d' J& ~' Z" V
  60.   /* 禁止SPI外设 */9 ]7 v7 z* N" L2 H
  61.   __HAL_SPI_DISABLE(hspi);
    7 P2 x. f% m4 |  j" @, R# U

  62. # p) P; ~0 T8 i. \9 O) o
  63.   /*----------------------- SPIx CR1 & CR2 配置---------------------*/6 k/ b. B0 p" M: }* L
  64.   if ((hspi->Init.NSS == SPI_NSS_SOFT) && (hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.NSSPolarity ==
    " G9 c% e8 P1 l7 A' s- S
  65. SPI_NSS_POLARITY_LOW))  N0 d6 _# r' }
  66.   {6 Y( V+ N& X- t6 R- Q3 [6 S
  67.       SET_BIT(hspi->Instance->CR1, SPI_CR1_SSI);
    2 O$ x3 z* h: B4 y" N; S* M
  68.   }5 I/ k% e  F3 z! l! H) X5 e6 [
  69. 3 w- Z8 c% z1 [) Z
  70.   /* SPIx CFG1配置 */- y, ?( `+ {" E, s$ M$ g* W- x
  71.   WRITE_REG(hspi->Instance->CFG1, (hspi->Init.BaudRatePrescaler | hspi->Init.CRCCalculation | crc_length |
    4 I/ o* Z; c  x  E0 d4 r
  72.                                    hspi->Init.FifoThreshold     | hspi->Init.DataSize));1 d! _6 v% h/ {1 ^: e! Y

  73. ! M3 c+ w) m+ `
  74.   /* SPIx CFG2配置 */
    - V% `2 H7 ^+ c0 v) n
  75.   WRITE_REG(hspi->Instance->CFG2, (hspi->Init.NSSPMode     | hspi->Init.TIMode           | hspi->Init.NSSPolarity  |1 g; {- @5 |3 w/ N% e. i
  76.                                    hspi->Init.NSS          | hspi->Init.CLKPolarity      | hspi->Init.CLKPhase     |
    7 m4 \( @- x! l( Y
  77.                                    hspi->Init.FirstBit     | hspi->Init.Mode             | hspi->Init.MasterInterDataIdleness |# d9 n  t8 ]/ t& k9 E" ]
  78.                                    hspi->Init.Direction    | hspi->Init.MasterSSIdleness | hspi->Init.IOSwap));
    - s+ s* @+ x! C" x+ m/ l
  79.   Q  R( t4 X3 e7 L/ V# u
  80. #if (USE_SPI_CRC != 0UL)$ R. G# S4 `2 m, ~8 m
  81.   /*---------------------------- SPIx CRC配置 ------------------*// E' f6 L- `! `( F8 F! U
  82.   /* 配置SPI CRC */1 \4 Q/ g" k* x* w! j
  83.   if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)" i# n+ x+ S" D3 R. L
  84.   {$ K$ ], g- V$ n& r8 S/ ]# ^6 D6 @
  85.     /* 初始化TX CRC初始值 */
    % k3 ?8 @$ d* C
  86.     if (hspi->Init.TxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)
    " o4 z. w4 f$ j
  87.     {8 \7 G. K' G- g$ q1 c3 Y
  88.       SET_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);& R3 @) Y0 A; a, N# ^* N. @
  89.     }
    3 C4 g$ G0 J% |" q9 ?7 N
  90.     else2 S/ F, U! G* H/ U1 q7 {+ U
  91.     {
    0 N+ P! S+ D* b, i" A4 l. U
  92.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);
    : x, r( y9 N) ]( G3 J: p- {
  93.     }  n/ U& z. u5 Y& }+ w0 E' e8 l

  94. 8 I/ T) ?) A5 F" y3 l$ {  X
  95.     /* 初始化RXCRC初始值 */) j: E0 W" {) X* V# w  G
  96.     if (hspi->Init.RxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)( `' G7 d( P$ E0 K
  97.     {
    / x- O! @4 m6 w- G4 n
  98.       SET_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);% [; \! s4 G( X% `$ ?' p
  99.     }
    # h9 y6 `6 ~# \% \/ S8 r( o) [( B
  100.     else
    6 g& X+ |/ y8 R! \
  101.     {$ Y/ o' ~3 i2 T4 u+ S) [
  102.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);
    / O- S/ D" I4 P7 D. V2 p- L
  103.     }
    " y7 Q6 d* U; Z; W! |- X
  104. + a  W  s1 W% j8 M, a6 k
  105.     /* 使能 33/17 bit CRC计算 */
    " q3 n) s( B! }7 }
  106.     if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (crc_length == SPI_CRC_LENGTH_16BIT)) ||
    + V' O& c! x! t5 y
  107.         ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance))  && (crc_length == SPI_CRC_LENGTH_32BIT)))
    + i- C2 r  B! Q# T
  108.     {
    1 D) Q0 f  Q; ?  U/ q
  109.       SET_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);
    6 N, u- \% H+ R" I/ Y& J1 A9 ^
  110.     }- @6 H; q4 i4 o7 v$ Z' Q
  111.     else
    % d" n9 w6 `: f. A8 p
  112.     {  m0 m+ W+ t0 z- s# `, W
  113.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);
    3 L" R0 S0 Y: P5 V8 j. z+ j
  114.     }! s/ Z3 w( n2 L5 w. C% T0 r' p

  115. ( s, U& [5 f& S( `/ B4 s* C; S
  116.     /* 写CRC多项式到SPI寄存器 */% q. J8 @- y4 K4 A
  117.     WRITE_REG(hspi->Instance->CRCPOLY, hspi->Init.CRCPolynomial);
    5 Z% j; j- j+ P3 [# D2 j5 k
  118.   }+ I" w8 N4 r9 l+ N; I
  119. #endif
    ; h9 R- |% l) {
  120. 3 s1 }# g/ p9 l  d! p7 F7 \
  121.   /* SPI从模式,下溢配置 */
    5 w4 I8 O* k! A* C
  122.   if (hspi->Init.Mode == SPI_MODE_SLAVE)
    , {- T9 \1 q* N: _2 j0 ~$ n
  123.   {
    9 W+ S5 A* e7 h! m
  124.     /* 设置默认下溢配置 */
    5 S( F# J/ I, m7 B# M( W
  125. #if (USE_SPI_CRC != 0UL)
    $ B3 t$ j1 b2 o+ {
  126.     if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_DISABLE)
    5 e' s2 L2 F' O  `8 G4 T
  127. #endif  Q! _* |9 N0 b6 c& ~
  128.     {
    ' F8 u2 A6 Q. D" K8 s
  129.       MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRDET, SPI_CFG1_UDRDET_0);
    ! |: M, G( m2 W4 N
  130.     }( E% y7 w- l2 }9 e. L
  131.     MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRCFG, SPI_CFG1_UDRCFG_1);4 a' {4 _  v, b& r
  132.   }5 k% i" o) w& D, g" }6 i5 U

  133. ( U# r! `% d5 P1 x
  134. #if defined(SPI_I2SCFGR_I2SMOD)
    ) R8 ?' J( ]  ^% l
  135.   CLEAR_BIT(hspi->Instance->I2SCFGR, SPI_I2SCFGR_I2SMOD);9 F$ Q5 _5 \* G+ \, n1 ^2 X1 d
  136. #endif & Z, Y% z( a: w9 c7 t

  137. ( V  J! Q  B7 l- W
  138.   /* 确保AFCNTR bit由SPI主机模式管理 */6 f. M/ W0 K# [% M1 |# w
  139.   if ((hspi->Init.Mode & SPI_MODE_MASTER) == SPI_MODE_MASTER)
    7 A% [. b. \$ s
  140.   {  W9 B5 m% v$ v; M  y
  141.     /* Alternate function GPIOs control */* S. y& ~& k' [) z" ~: s  Y
  142.     MODIFY_REG(hspi->Instance->CFG2, SPI_CFG2_AFCNTR, (hspi->Init.MasterKeepIOState));
    & O% t, r8 C: m' Y9 d
  143.   }6 G* @6 e. D" h, h; l* f. [! u

  144. # l7 U/ p, d9 V" v9 l$ ~& t. [# t1 {
  145.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;8 G3 A' `& g+ m. Q
  146.   hspi->State     = HAL_SPI_STATE_READY;
    * U0 N& z( I, J0 B

  147. * v4 @% Z4 m& ?# C5 F$ i- c9 Z
  148.   return HAL_OK;0 i) [6 J; p! V$ D& v" c. K
  149. }
    / q( V! g; y/ _; m. ~: V
复制代码

- X1 S5 r( i' L: @& h  G
5 ~5 N- N3 m6 z9 b函数描述:- w7 g2 u; J! f$ N
' \# f' q6 j! O
此函数用于初始化SPI。
$ j1 v/ |" d" ]' v  J
; m: Z5 M) H# P$ k$ {7 f/ p0 T2 b函数参数:' O& c, u0 R2 ]" q
) j2 h- J! C4 H0 ^" ]4 h* q
  第1个参数是SPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
  K' j& @5 p% f* v4 X2 v  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
& M$ W+ p2 m2 H2 ]注意事项:0 y, K5 r. p- O* C, s
8 p$ W+ `5 L+ k2 P% z3 ]2 v
函数HAL_SPI_MspInit用于初始化SPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
* |5 e+ j" O: u9 H如果形参hspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SPI_HandleTypeDef SpiHandle。; t( Y9 |" D6 t  ?
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SPI_STATE_RESET  = 0x00U。
1 x" ?1 g3 t8 T( m& Y  F" C
9 r) M& q3 u* Q# k解决办法有三! g! b) B" M; G$ l2 R
  I. u+ v+ |: r" J* i, A! l3 X" l
方法1:用户自己初始化SPI和涉及到的GPIO等。
. K9 c" ~9 y4 t( \, d4 o4 g. J0 ~
方法2:定义SPI_HandleTypeDef SpiHandle为全局变量。
8 A6 I( P' C1 Q) f+ W7 ~. M, G+ u
方法3:下面的方法
$ g3 C4 g3 T" {0 C: U( S
# A! Y7 T/ B, W  S' ?
  1. if(HAL_SPI_DeInit(&SpiHandle) != HAL_OK)) I# h5 [+ {5 A7 _' Y; L, ~
  2. {" F& a9 \3 F7 V
  3.     Error_Handler();) s8 X% W6 T% E8 W: \4 }7 n
  4. }  
    4 Q/ Q2 x8 ?0 q, k
  5. if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
    ( {: H1 J0 P( U( `6 s+ F
  6. {  }5 a- R0 I- s1 P
  7.     Error_Handler();
    ) G* m, f6 }0 k' b& z; @5 }; }" N5 Q
  8. }
复制代码

# @$ A" V5 ?( k! b$ y: K使用举例:
1 D* J, t2 e4 v& e& m) W! r" x  |
  1. SPI_HandleTypeDef hspi = {0};
    0 F9 ]) P9 V# p% q
  2. $ R; W* X: x, l6 I1 m& ~
  3. /* 设置SPI参数 */
    / A$ e# }* n& D2 r- Y0 S. x
  4. hspi.Instance               = SPIx;                   /* 例化SPI */
    4 H0 d+ i; d& B" |1 v0 T
  5. hspi.Init.BaudRatePrescaler = _BaudRatePrescaler;     /* 设置波特率 */
    , C( |+ c- a7 v' X  ^* p, B# Y
  6. hspi.Init.Direction         = SPI_DIRECTION_2LINES;   /* 全双工 */$ g* `7 k2 A6 e- b
  7. hspi.Init.CLKPhase          = _CLKPhase;              /* 配置时钟相位 *// x# B' ]* r# V; C* X* e  [7 X  A
  8. hspi.Init.CLKPolarity       = _CLKPolarity;           /* 配置时钟极性 */
    - a. w+ Q- z" A+ E. P
  9. hspi.Init.DataSize          = SPI_DATASIZE_8BIT;      /* 设置数据宽度 */0 C2 Q' ?/ K- ^- L
  10. hspi.Init.FirstBit          = SPI_FIRSTBIT_MSB;       /* 数据传输先传高位 */
    : m1 v! I2 _& v) D, H7 J' |1 H
  11. hspi.Init.TIMode            = SPI_TIMODE_DISABLE;     /* 禁止TI模式  */( s6 \9 o. E# @3 L' p
  12. hspi.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;      /* 禁止CRC */* o3 T2 S" [6 a( K* u
  13. hspi.Init.CRCPolynomial     = 7;                               /* 禁止CRC后,此位无效 */- I' m( }4 C* t9 J! H* [
  14. hspi.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;             /* 禁止CRC后,此位无效 */+ i7 P+ \. `/ j6 ]8 A' Q2 @1 @
  15. hspi.Init.NSS               = SPI_NSS_SOFT;                    /* 使用软件方式管理片选引脚 */
    # S9 t/ j7 Q8 o
  16. hspi.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_01DATA;       /* 设置FIFO大小是一个数据项 */1 \7 a& f: I7 b6 z% H& f
  17. hspi.Init.NSSPMode          = SPI_NSS_PULSE_DISABLE;           /* 禁止脉冲输出 */7 {+ S8 U6 P2 A2 I
  18. hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  
    / n! o. F1 i2 o. n
  19. hspi.Init.Mode                  = SPI_MODE_MASTER;            /* SPI工作在主控模式 */5 C' x- |2 D4 G4 B" y
  20. / V; D7 m  i' L) X. j* ^" F; U
  21. if (HAL_SPI_Init(&hspi) != HAL_OK)! Q2 {. v0 u% E9 W
  22. {" D4 d0 H- m' J( T& H7 g
  23.     Error_Handler(__FILE__, __LINE__);1 h" \, o/ ?! s
  24. }
复制代码
) K8 j: @" Z7 O
2 x4 @- W$ c2 k& I% ]
72.4.2 函数HAL_SPI_DeInit
0 _" n9 d& I, I, ?6 @$ n8 q函数原型:4 I5 r" i$ _3 ~1 r/ B  s9 ~
- h- }2 M1 }1 }2 \) x4 I3 J9 A& p
  1. HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)+ X7 c( }( k% F$ k1 z7 P
  2. {/ |6 w: V" w$ i8 S
  3. /* 检测SPI句柄是否有效 */
    3 G3 M, s4 {# g3 K
  4.   if (hspi == NULL)
    * Y! l( {3 d4 P* C
  5.   {/ d% Y4 P. {9 d& m+ X& Q
  6.     return HAL_ERROR;/ }7 v2 Z! `' @1 c& L- \
  7.   }8 Y4 N. G3 k3 A) z2 @
  8. . |; k$ J( [/ I  U, F
  9. /* 检查SPI例化参数 */$ f! X/ @' C. z, E+ X/ n$ y
  10.   assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));
    5 h, X; M' [! }9 `- J/ `# g

  11. 4 B1 j( b4 m$ f( g
  12.   hspi->State = HAL_SPI_STATE_BUSY;5 z3 Y6 L& Y: {  |% ~8 _# x0 U, z4 R9 g

  13. ! C  r$ [* A- V
  14.   /* 禁止SPI外设时钟 */
    % ^4 H7 q- j. c+ u2 Y, J: a6 d
  15.   __HAL_SPI_DISABLE(hspi);! k- [% x7 R3 N( K# l8 W7 z
  16. + ~$ U1 }( ]( U/ e3 a$ ~* c
  17. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    7 |9 u$ f8 P6 V* Z1 R4 v
  18.   if (hspi->MspDeInitCallback == NULL)
    ) j0 r9 c$ y' W7 \
  19.   {, i2 t" B% ]2 E9 T
  20.     hspi->MspDeInitCallback = HAL_SPI_MspDeInit;
    ) }% c/ R8 Q/ V& D9 W
  21.   }5 F2 j) D3 l4 X: J

  22. # P, P2 W$ a% w& T+ U
  23.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */
    + k9 @1 S( |+ |7 a
  24.   hspi->MspDeInitCallback(hspi);
    0 w' u7 @$ [) C% s/ a
  25. #else
    9 `+ S) S" R. j& g( @
  26.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */7 v) w, H7 q6 |7 M7 O+ X
  27.   HAL_SPI_MspDeInit(hspi);
    1 U+ L" L1 W+ H
  28. #endif . C8 {) C) A6 S6 o/ A1 Y( Y( Z

  29. 3 `" E0 B  x5 k; I  K; N2 K
  30.   /* 设置无错误,复位状态标记 */
    ; ~) s0 \; @7 M9 s. r2 R7 F
  31.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;/ ~  W  u* x; s8 `
  32.   hspi->State = HAL_SPI_STATE_RESET;  U6 X' g* b% O0 a* s; w9 w1 J3 _

  33. - }% m0 q5 B! a6 F2 N
  34.   /* 解锁SPI */
    " ^; j3 \, J* p6 k: v
  35.   __HAL_UNLOCK(hspi);8 s1 s8 a3 u0 C4 L% P/ O0 x

  36. 3 Z9 R( Z, v5 F) v4 C
  37.   return HAL_OK;, |5 S5 m+ S9 r- @! S# m
  38. }
复制代码

0 T3 Q( \$ l) |6 n7 Z: {, F# ~函数描述:
) [0 u+ k$ N8 e6 P1 v. @! |
! U& Q; w( {# ]) A- H/ I用于复位SPI总线初始化。" C: e  Q* n: U8 U6 ~
9 E) s6 t" i. G$ A# q  w" L- V  a% x4 U
函数参数:# d% q; Y, p1 O
9 x( n$ F% @& @; G2 E
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。  p* R  O" L& B* N% E
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中1 `, ~( c: P& |, M2 [* Y
72.4.3 函数HAL_SPI_TransmitReceive0 l' |, h$ V1 O5 I5 e% Q
函数原型:
6 x, Q7 b- ^+ w+ X& c
2 s; ~- ~/ q, u) F- s
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)6 I# R4 T/ u! X# N- v; m
  2. {
    ! ?/ ?) A9 y$ c. W+ H: W9 R) r

  3. : B. H& h, ?+ }. F( n7 G
  4.    /* 省略未写 */
    3 F7 l) P% d3 ^3 u/ I% S' f
  5. / h9 P; p% {6 F% ]
  6.   /* 大于16bit的数据收发 */" a! B0 w, E. }  f4 U
  7.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)0 h/ v  W1 o( ]4 V6 S8 E
  8.   {
    $ K( Y6 y# \0 @# b5 A
  9.        /* 省略未写 */
    ; p. E& T* v7 A" ^% Z
  10.   }
    . d# ]  u* X, t; S- l
  11.   /* 大于8bit,小于16bi的数据收发 */
    # D( v5 ~# ]8 m  r& i8 a1 ]
  12.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)  {0 g5 H0 L( s6 _- K9 \0 r% A+ x0 S9 j
  13.   {
    $ B* d5 `) y* D& m7 \0 P% \1 x
  14.       /* 省略未写 */
    $ F% B1 s/ Q% v" P/ V& U" x
  15.   }) K- |# {, [( t8 z. M
  16.   /* 小于等于8bit的数据收发 */  m& a9 H1 G' [% {, e( P6 \% v0 ^0 P7 k
  17.   else
    ) F5 ?" h5 n1 X5 ^1 j* E8 m9 s1 m
  18.   {
    / j5 i5 G4 {) k- ]& S: r. Q" F8 T. B6 \
  19.        /* 省略未写 */
    4 l( }, m, J4 o: T$ c
  20.   }
    ' w4 F9 |7 u" v; F$ |  X* d$ C
  21. ! g2 q, x- |: {0 k& \
  22. }0 \+ d% w& i3 A- n; E# f
复制代码

$ z3 ~. U, Z9 ]  Y5 `& O
6 l1 J; y) q. [: A函数描述:5 [8 u4 N) _. I) ]7 h& u; t/ \
4 z# A+ X9 b' Q) h- _% \1 I
此函数主要用于SPI数据收发,全双工查询方式。6 x& P4 T3 G! o: |3 t6 @5 T

( H0 m1 B' ^! @6 K; M% W" C函数参数:
$ M" ]& L6 G$ m+ ?- Q+ J$ ~2 ?% [4 w- A% ^5 H3 M
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
: _0 L! g3 D6 G. I3 j  第2个参数是发送数据缓冲地址。
, s+ Q; q! x4 S  第3个参数是接收数据缓冲地址。
& s% K( G5 S3 C" w  第4个参数是传输的数据大小,单位字节个数。
% G. L2 Z- |, i: L# G' O4 Q  第5个参数是传输过程的溢出时间,单位ms。- }6 C( n5 v3 V, z1 ^& L9 p
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。0 l. z! n0 I$ ]+ j, Y
使用举例:( ~  m& h5 U( d0 o

6 s! k  T9 Z2 `
  1. SPI_HandleTypeDef hspi = {0};7 A1 T& ]" m% W
  2. % W# u, Z% r) t( B3 d! j+ z1 ]$ H. G
  3. if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)" @2 L* u5 \1 _! \% F7 _* M
  4. {* _+ p4 h* L: ~1 Z, I+ K) w* c
  5.     Error_Handler(__FILE__, __LINE__);
    8 s/ O6 U4 I8 E" x4 M/ E
  6. }
复制代码
$ I  S) H9 g( `! H- o
72.4.4 函数HAL_SPI_TransmitReceive_IT' @1 h0 d8 n6 ?$ ]4 @. E9 G$ B7 y9 e
函数原型:
& {. {  J; Y5 g7 n) B2 i/ m: I5 i5 y; I+ J; M* Z, D
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)
    . o, {# p" F! s
  2. {
    , ~, |) A4 G3 B% `
  3.    /* 省略未写 */
    # J8 ^7 U- T* a2 T; |7 m) f0 |3 I+ S

  4. ! [# Z+ F, H0 o/ s& N! Q0 b8 B/ F
  5.   /* 设置传输参数 */+ b$ s# h% x" \
  6.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;/ p% Y& y& Q& _6 v
  7.   hspi->pTxBuffPtr  = (uint8_t *)pTxData;
    ) o. \# d; m4 l% z! a; C3 C/ g
  8.   hspi->TxXferSize  = Size;- w, R2 K: z. A
  9.   hspi->TxXferCount = Size;
    , F) G4 s. n" [- n0 Y
  10.   hspi->pRxBuffPtr  = (uint8_t *)pRxData;
    " w; s( @7 ]$ t0 J4 `
  11.   hspi->RxXferSize  = Size;
    7 E( ^% i3 \: g* g
  12.   hspi->RxXferCount = Size;/ L; [9 L+ q1 s) b: K& _
  13. : \, Q7 K$ b5 K' L7 r- ?
  14.   /* 设置中断处理 */: K/ Q8 g9 U* }8 o. {& S2 h$ ~
  15.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)  m  s% ^$ {) s& w" [4 e/ _
  16.   {
    ) A5 m9 C) o, D# @6 X$ R
  17.     hspi->TxISR     = SPI_TxISR_32BIT;
    & R) c4 ?5 L3 S" |
  18.     hspi->RxISR     = SPI_RxISR_32BIT;
    8 g9 ~% i; e0 E1 c
  19.   }
    / C+ y( i0 U* G- x: _( J" |. |
  20.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
    ) b4 ]8 y% Q/ f2 ~$ B5 t3 ]: b
  21.   {& S. k+ s6 ]$ T( C
  22.     hspi->RxISR     = SPI_RxISR_16BIT;6 A3 D: B8 L0 v& Y8 }( h
  23.     hspi->TxISR     = SPI_TxISR_16BIT;; E' K. c6 D" `4 r+ ^
  24.   }0 ]  t( Q1 I; y/ O" v) V2 X
  25.   else/ L! o, J) Q/ q
  26.   {1 `1 f# A: G; z8 o$ U) f, n9 R5 E0 T
  27.     hspi->RxISR     = SPI_RxISR_8BIT;
    & ^& m  [& l0 }
  28.     hspi->TxISR     = SPI_TxISR_8BIT;
    8 {& s5 `) k/ W6 g
  29.   }4 H# T0 g6 v; r# D" c" O: g& L! W( `
  30. 6 A3 w0 J5 E: D7 |1 H$ b) p' u' D
  31.   /* 设置当前传输数据大小 */1 e& k& P2 J7 F; t/ m1 v+ u# D
  32.   MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);
    . d& k. W6 T% ?0 o8 C

  33. 3 y+ M/ Q' }, e2 T, Q8 T
  34.   /* 使能SPI外设 */
    # E. V  o: H% v' }2 l/ I5 g" n  m
  35.   __HAL_SPI_ENABLE(hspi);
    7 p* L- C/ o- z8 J. B: L* L  q1 y

  36. $ R! F/ t6 B& w& }
  37.   /* 使能各种中断标志 */, U" m4 L/ U6 u+ s" v
  38.   __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_EOT | SPI_IT_RXP | SPI_IT_TXP | SPI_IT_DXP | SPI_IT_UDR | SPI_IT_OVR | & G; D6 ~# B3 s1 U$ t0 G
  39. SPI_IT_FRE | SPI_IT_MODF | SPI_IT_TSERF));
    0 d4 I) y# H1 N, [. x
  40. ) p$ t4 K# Y7 Q* w' `; G1 \
  41.   if (hspi->Init.Mode == SPI_MODE_MASTER)
    2 }. D' N- ]+ |, d$ j/ F# l
  42.   {
    3 D; l4 E! V6 `& o6 C7 h' s
  43.     /* 启动传输 */
    - G0 c5 i* {# b) v$ b1 d$ m8 F
  44.     SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);
    7 y7 [# z* }9 V3 X! |6 |( s6 H( T. q
  45.   }
    2 Y+ _8 L/ {% r! p; X) N
  46. : O7 L" e4 k, d% ?' c
  47.   /* 解锁 */9 \- z! C: U( k9 z3 ?
  48.   __HAL_UNLOCK(hspi);
    # s, B5 a* G+ l+ O: D! b
  49.   return errorcode;8 v  a! V+ e5 q! e2 I: x4 B
  50. }
复制代码

$ r/ W7 e( G# o4 ^6 Y, F5 x
% K4 ?: w" _5 q5 M) u
  B+ l; C! u' M' [  f' A+ J! N函数描述:
6 B. W1 V. P+ e/ T# q" y% t0 Q9 e0 X  b2 J
此函数主要用于SPI数据收发,全双工中断方式。" z5 J* l) n' v' s- T: i; P

" L: M8 J7 C# R- @" K函数参数:
, P7 z1 ~9 n$ A( w4 g1 X6 p, D2 s$ G7 J  r& {# v
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
4 |" ?4 l8 H4 `) a: C8 `, Q* Z  第2个参数是发送数据缓冲地址。
7 z. [* f9 `( i1 F! j5 H3 a  第3个参数是接收数据缓冲地址。
$ v4 z2 \2 Q# v) |: f  第4个参数是传输的数据大小,单位字节个数。* ^; j5 {, K0 G: V
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。4 |" |" _& P6 i  ?/ K* @
使用举例:
3 Q" F2 B, _  E' A
3 F! v" f9 \- Q% L
  1. SPI_HandleTypeDef hspi = {0};
    & L! l0 M; M; V6 E2 R0 v3 n: {
  2. . D: m! H; B% ~) d1 O) X: b8 l9 f# m
  3. if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    - n. g# Y/ U; R: H, F
  4. {
    3 M. z+ A1 X; T% Y
  5.     Error_Handler(__FILE__, __LINE__);6 d- G/ J2 S* \' a
  6. }
    % y5 p0 o; z, S- x( A6 r& J

  7. # _* g4 @. F$ _% \$ l( a' ^

  8. 2 O2 y) |; q, o7 t6 W) ~
  9. 72.4.5 函数HAL_SPI_TransmitReceive_DMA
    + [! `2 C" B! o
  10. 函数原型:
    & s5 a5 L+ v8 Z. y5 o1 |
  11. ( h; T2 v* V, @$ g4 y) m% u: Q. n, }
  12. HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,3 D# c0 d, y  h: |7 r
  13.                                               uint16_t Size). X" }1 {# e) @$ f8 g
  14. {6 p: Q+ d( `2 |- U" F' M/ C* l# H
  15.    /* 省略未写 */
    & g& W# G1 L+ E6 e" ]0 q1 P

  16. $ ~9 u/ k- ]7 @0 W
  17. /* 注意DMA的位宽和对齐设置 */
    1 M) y7 _' p, e$ e- \3 L
  18.   if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && (hspi->hdmarx->Init.MemDataAlignment !=& O9 }3 A. N9 o
  19. DMA_MDATAALIGN_WORD))  || 1 d- Z4 E  G6 J. H5 e- e
  20.       ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) && ((hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_HALFWORD) && (hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_WORD))))
    . B, E- f. y' [$ V% k6 ^# S3 a
  21.   {1 x4 [5 O, n* |0 L
  22.   }
    8 p$ j# I) h( e& j) o
  23. ' J/ h9 X1 L5 b2 ?: W2 I
  24. /* 调整DMA对齐和数据大小 */
    ! J, }* M" c5 [4 S  \$ f
  25.   if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)4 c, V1 F2 t8 z7 h8 g
  26.   {
    0 p8 ]7 N: Y$ k* {/ @1 p5 s; v  \
  27.      /* 省略未写 */
    . I8 A  M8 }6 b" r5 j
  28.   }
    , w4 @& _% J" M
  29.   else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)
    , S1 r: d+ J1 ?- ^+ q7 v+ H
  30.   {1 W8 g- T( n% _& J
  31.      /* 省略未写 */
    5 \5 x2 v! a9 V; d) e/ M4 r
  32.   }/ O/ Q% U) e% q
  33.   else& R9 ^$ l# x- V) N7 s# c
  34.   {5 ?+ P/ F0 e: T4 ?
  35.       /* 省略未写 */
    & m4 B# h; k' l6 M; M0 g. t; d
  36.   }
    3 ]. S: h8 ?! n9 a

  37. : ~! e0 u7 E; f; C) Z) i1 h5 L
  38. /*  DMA接收配置 */
    3 c: O/ `7 C  V; S# d5 j! i
  39.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->RXDR, (uint32_t)hspi->pRxBuffPtr,
    1 s. z% a, q: ~- C5 D! O
  40. hspi->RxXferCount))+ ?; k: q- z0 Q. X# e
  41.   {' ~# R6 w: w8 \  d: _# q
  42. & [0 J! R5 c  X: ~
  43.   }0 k% X* H, z# t! G

  44. ) a, k3 i2 Q! v0 A$ Q* m2 C5 j' O/ t
  45. /* DMA发送配置 */- R. u0 l4 e! k, V7 x5 e
  46.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->TXDR,8 P  Z9 R) u. |5 C7 R
  47. hspi->TxXferCount))5 B4 y1 z! ~8 X! C( h. g1 k$ j
  48.   {* i1 X- z4 Z: e7 r
  49.   }
    & m: t( W' e6 o( X0 N; O

  50. 2 F: E7 Y& U6 r$ F4 u) ?' S
  51.   /* 省略未写 */
    , t& G  e  ^: J0 B) q, [1 I
  52. }
    - t. g; R/ x6 d1 F0 P8 M
复制代码

1 K2 Z' q4 n. @* r" Z% T( e0 f
, K( U+ Y8 ?; I8 i& y函数描述:
7 i) |5 `" K* [8 x2 f* u
# a# ], C/ O1 R* v5 W此函数主要用于SPI数据收发,全双工DMA方式。! k6 c  W% j; F, x. ~' P
' l" c. Z8 E) s3 m
函数参数:
, B( j* c, i$ \- r/ D8 \& k! G3 E' I0 g  s# Q! y' b
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
% L* _' N( V, p4 i) b7 t  第2个参数是发送数据缓冲地址。
* A0 n3 P+ p8 v7 h  第3个参数是接收数据缓冲地址。
8 A! H) Z) d" b  第4个参数是传输的数据大小,单位字节个数。
! B' h& X& y6 N$ t  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。7 c( b2 p1 n1 [" O6 A* }
使用举例:4 b' p$ c8 @+ f

- h: z) J% X& O0 W1 I6 B; _
  1. SPI_HandleTypeDef hspi = {0};
    , g9 Y3 V' s6 i- ^$ e

  2. " \6 V6 y* z5 L4 f7 n$ f) k
  3. if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    . S: h$ L5 `  Z5 D0 o
  4. {( d& f+ u& W/ k9 u
  5.     Error_Handler(__FILE__, __LINE__);1 x* }- B& _; T3 P. q4 m4 G  ]3 M
  6. }
复制代码

' D# x2 e5 K3 s4 Y6 w' |& [4 _  l7 d9 s' `3 N2 u
' u( K  f9 T0 L, ?) m) d& m$ g
72.5 总结
/ V* b9 r- z, u3 D( [本章节就为大家讲解这么多,要熟练掌握SPI总线的查询,中断和DMA方式的实现,因为基于SPI接口的外设芯片很多,熟练后,可以方便的驱动各种SPI接口芯片,以便选择合适的驱动方式。
( L0 C1 V, e: X: D: V. N. B5 i0 y6 N, _* B4 X2 ^) j

# Q* p* q  s" Y0 Y: l
收藏 1 评论0 发布时间:2021-11-3 10:15

举报

0个回答

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版