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

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

[复制链接]
STMCU小助手 发布时间:2021-11-3 10:15
72.1 初学者重要提示
- L7 C* p( H( e4 E9 W# k' J5 ?% Y  STM32H7的SPI支持4到32bit数据传输,而STM32F1和F4系列仅支持8bit或者16bit。# ~9 e& ^6 ^) h) ^$ M" {3 Z
  STM32H7的主频400MHz时,SPI1, 2, 3最高通信时钟是100MHz,而SPI4, 5, 6是50MHz。% }' r' g/ ]4 p/ C# E
  STM32H7的MISO和MOSI引脚功能可以互换,使用比较灵活。6 Z- u  x6 P* C3 m4 V% z- S
  SPI总线的片选引脚SS在单一的主从器件配置下是可选的,一般情况下可以不使用。1 f6 M3 j" I0 r! B: U
2 y  Z' g5 E! S- x' u. ^
72.2 SPI总线基础知识
0 _" s' b; z+ m! I" g5 h$ ?4 X72.2.1 SPI总线的硬件框图
; {1 y% Q# C' H# r& f1 p; q8 D/ t  U4 T认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SPI的基本功能,然后再看手册了解细节。- o4 p. x5 V/ x/ v0 q

& Q% {& X( e- {) P  o
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
( M! ^( P2 K# ]/ [
7 b) ^1 {# V2 _
通过这个框图,我们可以得到如下信息:
" C" T$ G6 d, D! h9 S/ @7 T- y+ L) h- A) s% E! f5 s
  spi_wkup输出* O+ l& }- u8 U8 |8 L8 }
低功耗唤醒信号。
& i7 g1 b. \+ {1 y7 c8 T7 s/ f! ?) d/ T- q
  spi_it输出% o& l6 g. P1 ^
spi的中断请求信号。9 N" E- w9 m, a

2 ^/ m6 p# y. D5 N8 c) _  spi_tx_dma. m2 a4 D8 Q1 i& L" h( ~
spi_rx_dma" h5 N2 e0 B4 k3 r' p  l2 c; M2 T
spi的DMA发送和接收请求信号。# Z+ |5 r$ N  {! s) u  E& i# A  }4 X

, ^2 ]9 ]: R- [  spi_pclk- P  X4 Z& R2 n% [, Z
为寄存器提供时钟。( H, v9 h. Z6 o

9 \! W3 ?  Y9 G* `  spi_ker_ck
  J' g  q9 k" j: J" F* M为spi内核时钟。! \0 `3 _- k. }3 q0 c
2 z3 D9 {  f( ?# g# t1 u) q' Z
  SCK(CK),Serial Clock
; e0 N1 M0 B# j( N: P- z此引脚在主机模式下用于时钟输出,从机模式下用于时钟输入。) C7 p5 T. p2 i# C) R8 x9 X3 c

6 ]8 g7 y3 y* a7 O" H  MISO(SDI),Master In / Slave Out data
& u  ^) w+ U" I/ Y此引脚在从机模式下用于发送数据,主机模式下接收数据。
6 r" e  p5 J& ?# Q6 O
/ z. h8 k( c+ x) O) P; R  MOSI(SDO), Master Out / Slave In data
, L5 v0 u1 e5 l$ W1 }此引脚在从机模式下用于数据接收,主机模式下发送数据。
; G0 q& w) Y( Z  C4 v5 b6 t% ^
- l" e& t( K5 n1 k4 C$ q  SS(WS), Slave select pin6 Q: Z3 j" r5 f: H6 ?) G
根据SPI和SS设置,此引脚可用于:6 ?( {: M( V. O( ]
# N( P2 b6 F, q' L, H4 |$ f
a. 选择三个从器件进行通信。0 A7 e( J) n4 d" Q" O8 V( D+ O0 I
1 D! p8 K5 Z  z9 ^  q$ n
b. 同步数据帧。0 l0 g* O% z6 m! V: f: l6 P
5 x1 T5 C4 |: p- H+ A; i
c. 检测多个主器件之间是否存在冲突。
# u0 P) {) L7 W- I
1 u/ v. R6 u" {: V9 d; c* Q" `- _通过这个框图还要认识到一点,SPI有三个时钟域,分别是寄存器所在的ABP总线时钟域,内核时钟发生器时钟域以及内核时钟发生器分频后的串行时钟域。3 G- ~) q0 [0 x4 ~4 n6 i

$ u1 u4 i: x! x3 K/ c  K7 `72.2.2 SPI接口的区别和时钟源(SPI1到SPI6)
) K* k- e" b. m4 H1 c" b1 |这个知识点在初学的时候容易忽视,所以我们这里整理下。* K  S6 O% t- E* a+ l
2 o6 G! y  w* G3 o1 q( h, B8 a
  SPI1到SPI6的区别
# Z, A& J: S0 Q/ m) T  SPI1,SPI2和SPI3支持4到32bit数据传输,SPI4,SPI5和SPI6是4到16bit数据传输。
* E& X' ?$ t& {6 j( a. c  SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit。
8 i; z, ~: ^* |# f$ y
6 y. k8 l7 w* I, w, A+ P8 o( Q
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
. g" `- g% C) q  ?
/ T0 k4 P7 t  y: L! ~8 u% R' K
  SPI1到SPI6的所在的总线(对应SPI框图的SPI_CLK时钟域)
1 Z. b2 F  @$ W8 vSPI1,SPI4和SPI5在APB2总线,SPI2,SPI3在APB1总线,SPI6在APB4总线。注意,SPI的最高时钟不是由这些总线决定的。9 T4 o& D. ]0 l4 a) y7 K+ E
8 J! d! K$ u# R; O3 r
  SPI1到SPI6的支持的最高时钟(对应SPI框图的SPI_KER_CK)$ D2 Y+ _# t- ?" B9 a  x0 L/ c
STM32H7主频在400MHz下,SPI1,SPI2和SPI3的最高时钟是200MHz,而SPI4,5,6是100MHz, 以SPI1为了,可以选择的时钟源如下:( E) u" Q0 L3 C# N. E- y& s+ i

5 `1 Y! d2 H, u, r. `; x
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
" c! R" ?  d( n+ f8 g

; P0 `" Y* A7 }  H6 z+ a, c这里特别注意一点,SPI工作时最少选择二分频,也就是说SPI1,2,3实际通信时钟是100MHz,而SPI4,5,6是50MHz。
* y8 w8 P$ [& a
) R& C" y, e* t. Y# {$ o8 N72.2.3 SPI总线全双工,单工和半双工通信5 O$ t" L  Z! E
片选信号SS在单一的主从器件配置下是可选的,一般情况下可以不使用。但需要同步数据流,或者用于TI模式时需要此信号。
% J: X+ O$ T# i0 b) H
+ y1 q/ I5 L% k7 R  全双工通信3 Y! w' m5 ~+ ^  P0 K% K( v
全双工就是主从器件之间同时互传数据,SPI总线的全双工模式接线方式如下:
9 i$ d$ z" K' l  S3 V7 P- M/ n7 ~+ e* Y) |/ W+ U. [
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
  \5 n5 V. s7 s* e

! M, Y$ a+ t5 ^# s; O3 I关于这个接线图要认识到以下几点:
( `, s5 _5 q4 n
3 N# p& Y, J7 \& e! l5 y  注意接线方式,对于主器件来说MISO引脚就是输入端,从器件的MISO是输出端,即Master In / Slave Out data。MOSI也是同样道理。
1 j7 N" i1 `; O0 o" W8 J) ]+ e  每个时钟信号SCK的作用了,主器件的MISO引脚接收1个bit数据,MOSI引脚输出1个bit数据。4 \& y4 [+ ^6 p" |3 r% r
  这种单一的主从接线模式下,SS引脚可以不使用。1 R* [, G, g4 Q7 D2 i- t) |+ f
  半双工通信8 ]. v+ \8 {1 c5 m7 p, f4 c' Z
半双工就是同一个时刻只能为一个方向传输数据,SPI总线的半工模式接线方式如下:& f8 i; `& g' t* I
* B5 `8 P& i8 u1 @$ G* r) t
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

+ `6 v# ~- e* a* t* q! b$ u, Z/ Q6 l! Z0 g# A2 a% d. `: @
关于这个接线图要认识到以下几点:
1 x2 I5 t, U1 `! \$ K* f
( }) O; n0 M% c  更改通信方式时,要先禁止SPI。9 M6 W: Y  M; b5 f/ T' \& X
  主器件的MISO和从器件的MISO不使用,可以继续用作标准GPIO。
" m# _  U3 B7 W0 ~8 O  1KΩ的接线电阻很有必要,因为当主器件和从器件的通信方向不是同步变化时,容易出现其中一个输出低电平,另一个输出高电平,造成短路。
* o& B0 \2 n" S8 P2 Q( J0 d  这种单一的主从接线模式下,SS引脚可以不使用。5 j/ D2 v+ `7 e# |
  单工模式# k% v  M$ A9 f0 L$ a
单工就是只有一种通信方向,即发送或者接收,SPI总线的全双工模式接线方式如下:
$ Z3 Q1 `" ^4 ^$ z) t8 u7 U8 y3 p
5 \% Y. _) Q" k! t& k0 k
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

7 p  D7 W+ K, k1 z1 l7 |! q3 B  D$ k! L" S/ R# ~
关于这个接线图要认识到以下几点:
" D+ i# o7 H8 J! m
( g6 @1 u$ L) ]4 Q  未用到的MOSI或者MISO可以用作标准GPIO。, k( Z3 C6 |# ^" }7 I
  这种单一的主从接线模式下,SS引脚可以不使用。2 D, h6 e1 z3 a
72.2.4 SPI总线星型拓扑
' h& w9 H1 A: B6 _/ F: Q# WSPI总线星型拓扑用到的地方比较多,V7开发板就是用的星型拓扑外接多种SPI器件:
! T! |6 `1 U) G5 l
/ r% y% S# V" h. q, e' g( X$ i
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
4 C: K% g: ^. V3 I' @' c

+ d* \7 x, y! w8 ?! p7 V4 }/ Y- A; g( Z关于这个接线图,有以下几点需要大家了解:
8 i& F2 [# P' c5 r# ?! E6 e. k6 ]! j/ }1 M& R
  主器件的SS引脚不使用,使用通用GPIO控制。为每个器件配一个SS引脚,方便单独片选控制。* z$ T' S1 L. x( l4 Z7 t, `5 x- b
  从器件的MISO引脚要配置为复用开漏输出(很多外部芯片在未片选时,数据引脚是呈现高阻态)。
9 B) I; [- U& k/ t; l" _72.2.5 SPI总线通信格式
& X$ u+ C5 X: A  g$ i5 lSPI总线主要有四种通信格式,由CPOL时钟极性和CPHA时钟相位控制:% _" G! C+ X- M3 m5 ]& }. C
1 J* m: n6 ^9 c' Q$ T  N
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
5 d; e5 m+ @- i, ^# k

: `; X2 X: t; l! D" u/ K2 h四种通信格式如下:
  t  n" w4 `  d5 R& a' A. m+ z  b2 q; x
  当CPOL = 1, CPHA = 1时/ _, `$ h' t( O
SCK引脚在空闲状态处于低电平,SCK引脚的第2个边沿捕获传输的第1个数据。8 J" L3 c! h2 a5 t: i: Y" |
) U( L3 h1 x" o2 k
  当CPOL = 0, CPHA = 1时/ c; _7 o, Z; r4 i8 ]$ P
SCK引脚在空闲状态处于高电平,SCK引脚的第2个边沿捕获传输的第1个数据。1 @/ a4 v7 H0 A) u9 u- x

8 N) J7 R7 s; @1 t2 z  当CPOL = 1, CPHA = 0时
: z7 N+ y; V8 T' s3 L9 x! eSCK引脚在空闲状态处于低电平,SCK引脚的第1个边沿捕获传输的第1个数据。1 H$ a/ L, ~* b* J" H" z, _
5 O( Y. N2 p, C
  当CPOL = 1, CPHA = 0时. ?0 N8 _$ u6 F
SCK引脚在空闲状态处于高电平,SCK引脚的第1个边沿捕获传输的第1个数据。. h7 a8 q& m$ |" _, [+ p+ U5 |
) v- n9 A+ i$ X1 v
72.3 SPI总线的HAL库用法6 G! T2 |" U/ I3 I1 C3 d* s) c
72.3.1 SPI总线结构体SPI_TypeDef
0 ~3 k- L* c0 j; }% F: A! CSPI总线相关的寄存器是通过HAL库中的结构体SPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:+ O/ |/ m/ T2 E( ]. R- o) V

1 x3 _4 G* s. ?) c$ y- O& |/ }0 l
  1. typedef struct
    3 A* @8 h3 I2 E& r  b
  2. {+ k: p8 d* @( Q3 Z
  3.   __IO uint32_t CR1;           /*!< SPI/I2S Control register 1,                      Address offset: 0x00 */  }+ B8 l4 J7 n. P9 r- a6 `: u
  4.   __IO uint32_t CR2;           /*!< SPI Control register 2,                          Address offset: 0x04 */, e2 ~( _' e# N; B& W: w/ v
  5.   __IO uint32_t CFG1;          /*!< SPI Configuration register 1,                    Address offset: 0x08 */
    & _* v3 S# O9 @2 D  I
  6.   __IO uint32_t CFG2;          /*!< SPI Configuration register 2,                    Address offset: 0x0C */$ M" {0 I0 O, B. q
  7.   __IO uint32_t IER;           /*!< SPI/I2S Interrupt Enable register,               Address offset: 0x10 */) k) G4 m$ Y( T8 O4 M' q
  8.   __IO uint32_t SR;            /*!< SPI/I2S Status register,                         Address offset: 0x14 */. ?+ Y1 W9 ], k
  9.   __IO uint32_t IFCR;          /*!< SPI/I2S Interrupt/Status flags clear register,   Address offset: 0x18 */$ e' J- u$ z: I# Q) Q7 f9 |: |
  10.   uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                        */3 N7 |9 b8 X5 ?$ I8 f/ a$ f# }
  11.   __IO uint32_t TXDR;          /*!< SPI/I2S Transmit data register,                  Address offset: 0x20 */7 U- }& Y( k) \$ }+ L
  12.   uint32_t      RESERVED1[3];  /*!< Reserved, 0x24-0x2C                                                   */
    0 \# }: R: \6 o( q* N
  13.   __IO uint32_t RXDR;          /*!< SPI/I2S Receive data register,                   Address offset: 0x30 */
    - J* j* \0 v  l5 Z9 m- A
  14.   uint32_t      RESERVED2[3];  /*!< Reserved, 0x34-0x3C                                                   */
    7 y" L- }) f! {6 a3 @7 v. V
  15.   __IO uint32_t CRCPOLY;       /*!< SPI CRC Polynomial register,                     Address offset: 0x40 */4 X9 l3 A3 v. |, S* ^& q1 X: H
  16.   __IO uint32_t TXCRC;         /*!< SPI Transmitter CRC register,                    Address offset: 0x44 */
    / o* ^( s! o$ u$ t% m" b
  17.   __IO uint32_t RXCRC;         /*!< SPI Receiver CRC register,                       Address offset: 0x48 */
    7 f2 _7 t5 E. }+ d; G
  18.   __IO uint32_t UDRDR;         /*!< SPI Underrun data register,                      Address offset: 0x4C *// r, m! f; b' i% g  z- L  t
  19.   __IO uint32_t I2SCFGR;       /*!< I2S Configuration register,                      Address offset: 0x50 */
    , l4 {8 k1 e) U/ P, z
  20. - e* S. I$ f' G6 n# Z6 {. w
  21. } SPI_TypeDef;
复制代码
( e! }& n- }& U* e. X' V6 [
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
! p6 M8 f+ y0 V& Q. b' C5 z' P# K& h; a, g! [
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
+ O; m4 i5 @% e( X( x% C* B
! A0 @  E8 @* r
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */& A2 z# ?0 Q/ \! k3 M9 }! d
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

' X. w' N8 _, G" A下面我们看下SPI的定义,在stm32h743xx.h文件。: ?7 r% z0 J, k4 S7 _
% Y. h; T# i; l/ \
  1. #define PERIPH_BASE           (0x40000000UL)
    4 R6 B  m$ v2 l: o
  2. #define D2_APB1PERIPH_BASE     PERIPH_BASE" d  L# W8 C$ h. }/ [
  3. #define D2_APB2PERIPH_BASE    (PERIPH_BASE + 0x00010000UL)
    ' Y, e+ o/ ]3 v5 T" c. p6 |3 `
  4. #define D3_APB1PERIPH_BASE    (PERIPH_BASE + 0x18000000UL)/ X, ^" t8 y  a3 k4 t% c! F) {! c

  5. $ S$ h4 X7 B, Q+ n
  6. #define SPI2_BASE             (D2_APB1PERIPH_BASE + 0x3800UL)
    6 ~& A/ Y" G5 i+ v/ o% h$ u4 [
  7. #define SPI3_BASE             (D2_APB1PERIPH_BASE + 0x3C00UL)
    + F% U/ S+ V1 o0 ]6 Z2 O; g
  8. #define SPI1_BASE             (D2_APB2PERIPH_BASE + 0x3000UL)6 |) z8 t6 q6 q& E2 R
  9. #define SPI4_BASE             (D2_APB2PERIPH_BASE + 0x3400UL)
    ! Q2 `: h7 H# N# X
  10. #define SPI5_BASE             (D2_APB2PERIPH_BASE + 0x5000UL)
    / D- N5 x* ~/ j3 H1 `
  11. #define SPI6_BASE             (D3_APB1PERIPH_BASE + 0x1400UL)1 |1 N$ g" ~/ n; f. |3 o$ V3 P
  12. - u1 v# |8 M4 T: w
  13. #define SPI1                ((SPI_TypeDef *) SPI1_BASE)% h8 h& ~% ^4 w6 {% b$ x3 B
  14. #define SPI2                ((SPI_TypeDef *) SPI2_BASE)- ~- \5 l3 Y1 ^0 L' C
  15. #define SPI3                ((SPI_TypeDef *) SPI3_BASE)
    - {3 h  G3 R6 l  l
  16. #define SPI4                ((SPI_TypeDef *) SPI4_BASE)6 q- O6 R, `: N/ l0 V! x. T
  17. #define SPI5                ((SPI_TypeDef *) SPI5_BASE)
    ' H3 K+ v6 R" D  `. w, v$ L( P
  18. #define SPI6                ((SPI_TypeDef *) SPI6_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x58001400
复制代码
2 ]- ~( E; j  x# V7 w, {8 l' F
我们访问SPI的CR1寄存器可以采用这种形式:SPI->CR1 = 0。" J0 W* t4 I! g4 x. Z
3 O8 l# n! x/ t6 _' h  Z- E
72.3.2 SPI总线初始化结构体SPI_InitTypeDef
! X, Y3 q5 \' v# _- a% t" m  c& n9 C下面是SPI总线的初始化结构体,用到的地方比较多:5 K2 T! y( J+ Y2 v4 g' L
  `2 G3 S, I- z" p1 M
  1. typedef struct# ^+ K" A) e% b& O6 Y8 J" k/ a
  2. {
    ( @& A; G$ j# Z) k4 V3 b
  3.   uint32_t Mode;                            4 C6 }# b; j: s% R' B7 O
  4.   uint32_t Direction;                     
    + N" X. D$ j0 v- V# a
  5.   uint32_t DataSize;                          
    ( N3 G9 C% }7 d; B
  6.   uint32_t CLKPolarity;                       6 p0 w0 A; R; P5 {8 K, `/ W7 v
  7.   uint32_t CLKPhase;                        
    : @& a* C( ~$ b5 a- i+ J
  8.   uint32_t NSS;                             
    # o2 y. ^8 m! o' N' \
  9.   uint32_t BaudRatePrescaler;                7 u( x* B, O6 d6 S
  10.   uint32_t FirstBit;                        
    8 ]1 g- z& f- M9 j1 X
  11.   uint32_t TIMode;                          ; B7 Y3 c; U" O4 I5 }3 S  h
  12.   uint32_t CRCCalculation;                  
    * v- l2 g2 m( f3 s- |* P- h$ k
  13.   uint32_t CRCPolynomial;                     3 p3 X+ o' E4 K: d
  14.   uint32_t CRCLength;                        & _. `) d, n& O3 K% I
  15.   uint32_t NSSPMode;                        
    : F& _1 L: l' l
  16.   uint32_t NSSPolarity;                    ; G7 E! P4 l2 m* Q+ x
  17.   uint32_t TxCRCInitializationPattern;       , \+ ]3 F- Z- Y9 R
  18.   uint32_t RxCRCInitializationPattern;       ! ^8 B9 ~% ?2 H
  19.   uint32_t MasterSSIdleness;                 
    ( H" }) n+ W% Y( T7 v
  20.   uint32_t MasterInterDataIdleness;           ; J6 l5 J0 {* Q
  21.   uint32_t MasterReceiverAutoSusp;         
    ; d3 T" c# A# V/ D& g* S9 F. E
  22.   uint32_t MasterKeepIOState;               
    4 {3 G0 R$ V) N- j% `6 ?- ]
  23.   uint32_t IOSwap;                          
    1 z1 A* K( A9 z( K9 t. S. q
  24. } SPI_InitTypeDef;
复制代码

7 V" g0 B2 p) n下面将结构体成员逐一做个说明:
2 E" H. r2 y+ Q& z
2 l  U3 \9 L$ O  Mode" K3 e9 Q8 y) J5 b! V; h3 n
用于设置工作在主机模式还是从机模式。
; A5 d/ A4 O+ O; D# M9 t5 W! ]) E: v) I$ G9 i; X
  1. #define SPI_MODE_SLAVE              (0x00000000UL)
    + @, W% k; a0 e1 V6 s
  2. #define SPI_MODE_MASTER             SPI_CFG2_MASTER
复制代码

" |$ q9 M  L1 V; K0 x  Direction1 n$ o4 L) J2 I' G9 B' K
用于设置SPI工作在全双工,单工,还是半双工模式。  _- ?2 u, a4 Z3 B  R$ |
  1. #define SPI_DIRECTION_2LINES           (0x00000000UL)     /* 全双工 */
    : a1 _2 c* c. L  o' x1 t
  2. #define SPI_DIRECTION_2LINES_TXONLY     SPI_CFG2_COMM_0   /* 单工,仅发送 */. g8 Q( I( j& @2 L2 F+ M9 y) N
  3. #define SPI_DIRECTION_2LINES_RXONLY     SPI_CFG2_COMM_1   /* 单工,仅接收 */( F/ b) f3 z9 c* u4 A
  4. #define SPI_DIRECTION_1LINE             SPI_CFG2_COMM     /* 半双工 */
复制代码
0 P! x. G# o$ M& n' R
  DataSize  A9 k2 w7 M: F5 M
用于设置SPI总线数据收发的位宽,支持4-32bit。4 [  Q; s$ o' n9 Z

7 z& n: e+ o, _' \
  1. #define SPI_DATASIZE_4BIT                             (0x00000003UL)' Z9 t9 T6 R" l8 y9 T) B
  2. #define SPI_DATASIZE_5BIT                             (0x00000004UL)  Y5 i# p& J+ a* D) v7 k
  3. #define SPI_DATASIZE_6BIT                             (0x00000005UL)4 W& w- g, P% L, n2 {
  4. #define SPI_DATASIZE_7BIT                             (0x00000006UL)
    6 u7 v8 R. q& @! _! w
  5. #define SPI_DATASIZE_8BIT                             (0x00000007UL)
    . S2 u9 ]/ O1 R' x2 `; l
  6. #define SPI_DATASIZE_9BIT                             (0x00000008UL)" a  \4 b( F# B6 \$ @: `6 t' B7 {
  7. #define SPI_DATASIZE_10BIT                            (0x00000009UL)
    # A7 C* c- P% ?$ y9 v9 a6 l
  8. #define SPI_DATASIZE_11BIT                            (0x0000000AUL): Y; k& u/ l; T; E
  9. #define SPI_DATASIZE_12BIT                            (0x0000000BUL)
    , L" Z) [* G& ^5 c
  10. #define SPI_DATASIZE_13BIT                            (0x0000000CUL)
    ; I: [3 z* T- u- W% q
  11. #define SPI_DATASIZE_14BIT                            (0x0000000DUL)% ]$ w: D5 \# C$ H! W! {4 P7 s, e
  12. #define SPI_DATASIZE_15BIT                            (0x0000000EUL); v. l( w3 X, j& M) G
  13. #define SPI_DATASIZE_16BIT                            (0x0000000FUL)5 E9 _" c* y/ t
  14. #define SPI_DATASIZE_17BIT                            (0x00000010UL)0 U4 F: v% T- c7 `7 h* w
  15. #define SPI_DATASIZE_18BIT                            (0x00000011UL)
    8 l5 X  [: V, T' f% r; P4 A4 c9 W
  16. #define SPI_DATASIZE_19BIT                            (0x00000012UL)
    . {. `- u2 ], d3 ~0 w% R! P
  17. #define SPI_DATASIZE_20BIT                            (0x00000013UL)5 |- X! H2 j9 n
  18. #define SPI_DATASIZE_21BIT                            (0x00000014UL)6 T: ~+ e0 m: W6 ~
  19. #define SPI_DATASIZE_22BIT                            (0x00000015UL); P1 C8 K, P8 Z9 v- T/ h0 L1 l  J
  20. #define SPI_DATASIZE_23BIT                            (0x00000016UL)
    8 L3 r' X- D% E: ?6 h' M
  21. #define SPI_DATASIZE_24BIT                            (0x00000017UL)2 V+ ^6 f1 r6 Q( `8 U3 }( R+ r
  22. #define SPI_DATASIZE_25BIT                            (0x00000018UL)# G2 F  u) T6 @2 n7 C1 W
  23. #define SPI_DATASIZE_26BIT                            (0x00000019UL)) \$ I, J5 \3 `; C, W7 B9 b
  24. #define SPI_DATASIZE_27BIT                            (0x0000001AUL)  i8 c4 Q7 b7 ^, S& Z
  25. #define SPI_DATASIZE_28BIT                            (0x0000001BUL)
    ( L& s2 f1 R+ T+ a
  26. #define SPI_DATASIZE_29BIT                            (0x0000001CUL)
    * [; j! ~2 n- Q- g; w& j" ^7 |% m& O
  27. #define SPI_DATASIZE_30BIT                            (0x0000001DUL)
    ( A1 U( L- J- s, t
  28. #define SPI_DATASIZE_31BIT                            (0x0000001EUL)
    1 x: X& @" h* R; c* v8 Q5 k- C
  29. #define SPI_DATASIZE_32BIT                            (0x0000001FUL)
复制代码

: H8 c7 T) J' v% p( U" p& D, D: o  CLKPolarity  h. S/ @: u% T6 ]
用于设置空闲状态时,CLK是高电平还是低电平。
/ G  |/ z- S& E3 N9 h
0 m! |" ]# [7 @- r1 _1 v
  1. #define SPI_POLARITY_LOW       (0x00000000UL)5 q) N4 a# ~* m" }2 P
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码
# ~4 Y2 h8 [7 M2 C% g
  NSS
* q; P. f* F+ Q6 x# n, E用于设置NSS信号由硬件NSS引脚管理或者软件SSI位管理。) x1 _7 H9 H" e! C$ x; U: p6 O
7 C! l3 {1 z/ p6 T
  1. #define SPI_NSS_SOFT                                  SPI_CFG2_SSM, ?$ ~' D/ W$ g6 c+ H! r& M
  2. #define SPI_NSS_HARD_INPUT                            (0x00000000UL)
    9 v, R8 W2 i6 f6 r% x3 ~# x
  3. #define SPI_NSS_HARD_OUTPUT                           SPI_CFG2_SSOE
复制代码
; d: u4 _3 `0 J$ v; \
  BaudRatePrescaler/ p' |3 {2 l. _1 \) {
用于设置SPI时钟分频,仅SPI工作在主控模式下起作用,对SPI从机模式不起作用。: s* J$ F- H" y; |, ^: q- ]$ Y
- ?3 H" [9 T9 K- N
  1. #define SPI_BAUDRATEPRESCALER_2                       (0x00000000UL); O/ u+ `. \  w+ E  q: e% E
  2. #define SPI_BAUDRATEPRESCALER_4                       (0x10000000UL)
    & k. L/ Q, u  o1 \( N; j8 |* L
  3. #define SPI_BAUDRATEPRESCALER_8                       (0x20000000UL)
    0 d; ^- ?( r$ R
  4. #define SPI_BAUDRATEPRESCALER_16                      (0x30000000UL)# c7 A- U8 _5 e" V  K% m9 }
  5. #define SPI_BAUDRATEPRESCALER_32                      (0x40000000UL)- f8 q$ {. O/ |8 W: l
  6. #define SPI_BAUDRATEPRESCALER_64                      (0x50000000UL): G( p; h7 d" l; I6 i, b
  7. #define SPI_BAUDRATEPRESCALER_128                     (0x60000000UL)2 Q$ K' L$ Q# M& d" r/ ~
  8. #define SPI_BAUDRATEPRESCALER_256                     (0x70000000UL)
复制代码

$ f1 @& i1 y( w* z  FirstBit# K2 r# k/ a* c# y* D/ ^
用于设置数据传输从最高bit开始还是从最低bit开始。
" g/ T1 d4 r6 U6 b0 j; b5 x% f* c: D
  1. #define SPI_FIRSTBIT_MSB                              (0x00000000UL)5 p  l7 n5 ~2 _' o. h! ~
  2. #define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST
    ) X8 S' D" m- `8 V1 h$ l
复制代码

# y  E6 W6 }3 T+ z4 I  TIMode
  P; L' k3 o! b用于设置是否使能SPI总线的TI模式。
$ E# }* s% ?5 ?5 f0 e) [$ g
) ^0 o/ T9 ]$ L. m$ N/ n5 j$ k
  1. #define SPI_TIMODE_DISABLE               (0x00000000UL)
    2 Y; C- p- c( Z9 D
  2. #define SPI_TIMODE_ENABLE                SPI_CFG2_SP_0
复制代码

1 p3 p3 l4 @5 Z5 F5 F  CRCCalculation
% ~0 s' X* ?4 ~$ s用于设置是否使能CRC计算。, e$ S+ P# p8 ~
( k, U( y0 Z: |% |8 l( Z
  1. #define SPI_CRCCALCULATION_DISABLE                    (0x00000000UL)
    0 p* x7 K' M/ Q6 r; T9 y% f% ~
  2. #define SPI_CRCCALCULATION_ENABLE                     SPI_CFG1_CRCEN
复制代码
; L+ S8 z" b# z7 Z8 C; F' D  R
  CRCPolynomial. S9 k( N6 g' d7 v7 I
用于设置CRC计算使用的多项式,必须是奇数,范围0到65535。2 {, N' d8 F* k3 d. c6 v
5 j4 E8 s$ I. M+ C  k) G; N
  CRCLength
2 Z: }; a3 y! ?! [& W用于设置CRC计算时的CRC长度。大小要与同属此结构体的DataSize一致。或是DataSize的整数倍。3 H# I# x* R8 `8 L9 Q
* p: A2 v( ~/ R- ^' E. @0 {
  1. #define SPI_CRC_LENGTH_DATASIZE                       (0x00000000UL)' N( j9 L3 {; |  s2 s/ b
  2. #define SPI_CRC_LENGTH_4BIT                           (0x00030000UL)
    8 v* s8 c+ d. F
  3. #define SPI_CRC_LENGTH_5BIT                           (0x00040000UL)1 N0 G9 `7 P5 S& R
  4. #define SPI_CRC_LENGTH_6BIT                           (0x00050000UL)
    ! b( H7 [7 S4 |# m
  5. #define SPI_CRC_LENGTH_7BIT                           (0x00060000UL); s7 i6 d+ M3 o5 n
  6. #define SPI_CRC_LENGTH_8BIT                           (0x00070000UL)
    # m7 A; `1 U  S- W; }1 j
  7. #define SPI_CRC_LENGTH_9BIT                           (0x00080000UL)) E# Z. A9 \  k: w
  8. #define SPI_CRC_LENGTH_10BIT                          (0x00090000UL)
    1 N5 d+ i! c( t. k
  9. #define SPI_CRC_LENGTH_11BIT                          (0x000A0000UL)/ ~8 @! R& n2 p6 }8 C$ x
  10. #define SPI_CRC_LENGTH_12BIT                          (0x000B0000UL)
    $ n9 l0 a5 P; w; _7 D3 T$ [
  11. #define SPI_CRC_LENGTH_13BIT                          (0x000C0000UL)
    5 U, E3 G* y$ i; v2 l
  12. #define SPI_CRC_LENGTH_14BIT                          (0x000D0000UL)$ `' a6 i5 W' J, ?
  13. #define SPI_CRC_LENGTH_15BIT                          (0x000E0000UL)# c8 o; N2 o+ b% K6 h- I7 i: }
  14. #define SPI_CRC_LENGTH_16BIT                          (0x000F0000UL)0 Y$ W6 V7 F& w
  15. #define SPI_CRC_LENGTH_17BIT                          (0x00100000UL)
    ) f' b+ N) k/ R
  16. #define SPI_CRC_LENGTH_18BIT                          (0x00110000UL)% A4 m$ S1 X+ P: R5 T. ^$ V0 ]
  17. #define SPI_CRC_LENGTH_19BIT                          (0x00120000UL)6 f+ p- \4 A4 f* w" Q
  18. #define SPI_CRC_LENGTH_20BIT                          (0x00130000UL)+ @6 R. q# \( j" F% B* t
  19. #define SPI_CRC_LENGTH_21BIT                          (0x00140000UL)1 f4 j+ D3 W& k  d1 O$ Z
  20. #define SPI_CRC_LENGTH_22BIT                          (0x00150000UL)
    4 N, |1 Y, u$ T9 U( p+ F2 F
  21. #define SPI_CRC_LENGTH_23BIT                          (0x00160000UL)' |$ H) E# v5 M. U4 X
  22. #define SPI_CRC_LENGTH_24BIT                          (0x00170000UL)+ ]* p; G+ K+ T2 m2 N  ?
  23. #define SPI_CRC_LENGTH_25BIT                          (0x00180000UL)9 I- ~1 e' P* \' D: O. \% @1 o
  24. #define SPI_CRC_LENGTH_26BIT                          (0x00190000UL)/ n* s6 E  {# Q$ l
  25. #define SPI_CRC_LENGTH_27BIT                          (0x001A0000UL)+ \1 [: @/ o6 n3 G3 i1 i& n" J4 e
  26. #define SPI_CRC_LENGTH_28BIT                          (0x001B0000UL)4 M; j* Z+ E( n7 j
  27. #define SPI_CRC_LENGTH_29BIT                          (0x001C0000UL)
    0 ]7 B" A( l/ e0 A9 @
  28. #define SPI_CRC_LENGTH_30BIT                          (0x001D0000UL)! y5 }: r! D- a8 E$ M' G9 R3 W
  29. #define SPI_CRC_LENGTH_31BIT                          (0x001E0000UL)6 X! T) e- S! J. ]6 o, }" m2 U
  30. #define SPI_CRC_LENGTH_32BIT                          (0x001F0000UL)
复制代码
$ j, D8 U' t' k3 e+ o# n( J  _) E

5 T; S1 S3 Y$ K& E! g
# u: v1 G% j& f/ l$ I/ ~" ]2 I  NSSPMode
$ x9 i0 J' G+ M! R* z0 f用于设置是否使能NSSP信号,可以通过SPIx_CR2寄存器的SSOM位使能。注意,只有配置为摩托罗拉SPI主控模式时设置此成员才有用。+ D& G& {4 t0 y# e
3 |9 ~$ P* h& Y7 J0 E+ l# _/ w
  1. #define SPI_NSS_PULSE_DISABLE                         (0x00000000UL)
    , o/ l' V( n( A, x  L) o
  2. #define SPI_NSS_PULSE_ENABLE                          SPI_CFG2_SSOM
复制代码
/ X. V* @; n* O3 @5 `
  NSSPolarity) n6 r( e3 o3 l, ^1 _5 k% r/ t2 h( Z
用于设置NSS引脚上的高电平或者低电平作为激活电平。" |' \8 L) }( f3 k. {  W/ {
, u  N) u6 \+ D7 F( _
  1. #define SPI_NSS_POLARITY_LOW                          (0x00000000UL)
    ! K- W9 n+ d" O% N' N% u$ ?
  2. #define SPI_NSS_POLARITY_HIGH                          SPI_CFG2_SSIOP
复制代码

$ ?. P% @7 t- d) u) m  FifoThreshold; j& L: O2 N) U+ j" H9 T6 f
用于设置SPI的FIFO阀值。
: l% c9 q1 p) l+ j& W2 d: t" \- r) K2 _- H. K: e
  1. #define SPI_FIFO_THRESHOLD_01DATA                     (0x00000000UL)) b0 ?9 Q: Y9 @
  2. #define SPI_FIFO_THRESHOLD_02DATA                     (0x00000020UL)6 Y2 z1 m5 {- n% I
  3. #define SPI_FIFO_THRESHOLD_03DATA                     (0x00000040UL). e5 A$ P" Y& F2 X1 e4 u9 m2 K
  4. #define SPI_FIFO_THRESHOLD_04DATA                     (0x00000060UL)
    ) |. k2 u5 V0 M, I6 M. y
  5. #define SPI_FIFO_THRESHOLD_05DATA                     (0x00000080UL)
    1 ~/ V, Q+ W4 n$ m2 W) |5 _- W
  6. #define SPI_FIFO_THRESHOLD_06DATA                     (0x000000A0UL)9 S$ ?; O3 B: p1 d& }2 s
  7. #define SPI_FIFO_THRESHOLD_07DATA                     (0x000000C0UL)- i% {& ^$ B) n' f* w
  8. #define SPI_FIFO_THRESHOLD_08DATA                     (0x000000E0UL)7 `% A5 B3 `# a) |# Z1 Q! y
  9. #define SPI_FIFO_THRESHOLD_09DATA                     (0x00000100UL)5 g$ F' `) _5 I; ?2 }- Q
  10. #define SPI_FIFO_THRESHOLD_10DATA                     (0x00000120UL)  }& a8 u, C6 W4 Z; X7 v3 b  z, m
  11. #define SPI_FIFO_THRESHOLD_11DATA                     (0x00000140UL)3 a9 U# E- ^/ F2 i6 f
  12. #define SPI_FIFO_THRESHOLD_12DATA                     (0x00000160UL)) L5 r: m. E: |9 O5 a* t3 I# w/ U
  13. #define SPI_FIFO_THRESHOLD_13DATA                     (0x00000180UL). i/ |3 C$ e" N9 a' @
  14. #define SPI_FIFO_THRESHOLD_14DATA                     (0x000001A0UL)
    . e; a0 R, `2 C' x5 l% I& O  W$ ]1 r
  15. #define SPI_FIFO_THRESHOLD_15DATA                     (0x000001C0UL)
    . ]6 G1 {' ^$ i  Z  w
  16. #define SPI_FIFO_THRESHOLD_16DATA                     (0x000001E0UL)) {2 a9 u% ]( w6 ^
复制代码

' S. E' H3 U1 Y( Z" K1 ?* Q* h7 l
  TxCRCInitializationPattern1 a* `$ Q3 n6 b5 t  M* v2 d) l, i
发送CRC初始化模式。+ h$ G" g+ _% D7 U" D6 c) t  v
) `" B0 n% H7 J7 y* M: H6 b4 h
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    : k+ Y/ k, S* \) N: m' j7 v
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)6 N& P1 u3 b* l+ s9 E, C
复制代码
; J, f7 Q" g9 `/ e; Z- A
  RxCRCInitializationPattern8 C* Q) u- C. K% M2 F
接收CRC初始化模式/ l% V  [, p  M4 B

+ Z' u# }; {9 r$ T1 D' ^
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    . T" }. f# a! c3 J1 A
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码
) W; e+ p7 d, i: L, X. U( t3 J
MasterSSIdleness$ r* T1 Y: ^9 k; L& P7 W
在主模式下插入到SS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数。
1 c: d- O; t' Y$ n  U) u  g/ \+ m+ \% h! @3 R3 P
  1. #define SPI_MASTER_SS_IDLENESS_00CYCLE                (0x00000000UL)8 i$ {+ @; a6 i/ U* F% R) [( d
  2. #define SPI_MASTER_SS_IDLENESS_01CYCLE                (0x00000001UL)" z# b' ^8 l9 }  X2 Q- n* [8 F/ ?  O
  3. #define SPI_MASTER_SS_IDLENESS_02CYCLE                (0x00000002UL)/ b/ p7 b0 O+ L
  4. #define SPI_MASTER_SS_IDLENESS_03CYCLE                (0x00000003UL)" B& q" I7 j1 A3 X
  5. #define SPI_MASTER_SS_IDLENESS_04CYCLE                (0x00000004UL)
    ! w- \' ~, L9 C& |; s
  6. #define SPI_MASTER_SS_IDLENESS_05CYCLE                (0x00000005UL)( x- r2 H$ k) E# ~
  7. #define SPI_MASTER_SS_IDLENESS_06CYCLE                (0x00000006UL)$ w$ X  @% B: x1 o: I
  8. #define SPI_MASTER_SS_IDLENESS_07CYCLE                (0x00000007UL)0 D( y" `2 U3 z, v6 k
  9. #define SPI_MASTER_SS_IDLENESS_08CYCLE                (0x00000008UL)
    - Y- s) {% U0 J8 o
  10. #define SPI_MASTER_SS_IDLENESS_09CYCLE                (0x00000009UL)
    $ i6 d* V. o2 ?3 I) }& [  R9 O
  11. #define SPI_MASTER_SS_IDLENESS_10CYCLE                (0x0000000AUL)
    , }3 \. b* O5 M
  12. #define SPI_MASTER_SS_IDLENESS_11CYCLE                (0x0000000BUL)
    1 S) W" Q$ {+ E1 g
  13. #define SPI_MASTER_SS_IDLENESS_12CYCLE                (0x0000000CUL)3 q7 L, V1 w: _- E4 x: m. j
  14. #define SPI_MASTER_SS_IDLENESS_13CYCLE                (0x0000000DUL)
    # n  y3 q% u+ t" N* }+ ?
  15. #define SPI_MASTER_SS_IDLENESS_14CYCLE                (0x0000000EUL)& A% y6 {$ d0 E5 V- H
  16. #define SPI_MASTER_SS_IDLENESS_15CYCLE                (0x0000000FUL)
    : R. y+ M: k3 b# P
复制代码
  V& l6 f8 {$ B$ i
4 z; Y( W. O" G. Z
  MasterInterDataIdleness. N' Q9 q$ `. D4 N( t, g: {* }
主模式下在两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数。: l$ i9 O( H$ [
! V( Y  m  I/ w$ a+ @
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)& |6 d' k: S7 d3 m7 M7 x& f" m! X9 m  U
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
复制代码
+ D) ^; x" I- k# P* r7 C; O- f( m
  MasterReceiverAutoSusp3 s$ P3 ~% j/ v* Z# b& C
用于控制主器件接收器模式下的连续 SPI 传输以及自动管理,以避免出现上溢情况。
7 X$ P! k* ?' ]1 t5 d
9 H6 n& Y6 K  V6 ?. ^$ Z: g  A
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)
    : z1 d3 i  ]% L" I* G) v" C0 f
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX0 \" g+ D* L1 v/ C0 o! E
复制代码

( c& N7 Y/ q: }4 M  MasterKeepIOState
( X( ]* P; [# o6 z禁止SPI后,SPI相关引脚保持当前状态,以防止出现毛刺。在从模式下,该位不应该使用。5 F0 ^: s  b/ D
( a+ x$ u9 {& x/ D: A3 H. O
  1. #define SPI_MASTER_KEEP_IO_STATE_DISABLE              (0x00000000UL)
    # |6 f% ]+ y0 @7 ~0 L" |
  2. #define SPI_MASTER_KEEP_IO_STATE_ENABLE               SPI_CFG2_AFCNTR
复制代码

7 I  d3 K' x9 X7 {  IOSwap
8 d1 @+ v! \/ t5 E用于交换MISO和MOSI引脚。
4 T, {/ E( P# ^0 A! {# {
0 o: N, ?  F' {8 `# z
  1. #define SPI_IO_SWAP_DISABLE                           (0x00000000UL)
      j; f% C5 K3 w2 g0 r0 a8 B
  2. #define SPI_IO_SWAP_ENABLE                            SPI_CFG2_IOSWP
复制代码

* h- l- I4 a% A72.3.3 SPI总线句柄结构体SPI_HandleTypeDef6 k- ?0 M" P" U5 k
下面是SPI总线的初始化结构体,用到的地方比较多:, d3 F: r4 N1 ~4 b3 x
  |% Q9 y* t- |  o! r
  1. typedef struct __SPI_HandleTypeDef
    0 l5 W# u' n1 o; Q) j' y
  2. {
    1 J- T% \) T/ }) O+ F) H
  3.   SPI_TypeDef                *Instance;                 % Y; k/ ]) v5 G" n. f' h
  4.   SPI_InitTypeDef            Init;                        
    & o3 v( L3 q6 s, Y7 h4 G
  5.   uint8_t                    *pTxBuffPtr;                 
    , t+ [8 Y% i: W  H. O
  6.   uint16_t                   TxXferSize;                  
    & X3 T$ X. \$ G. }- L
  7.   __IO uint16_t              TxXferCount;                  
    / |# U/ U5 b# J
  8.   uint8_t                    *pRxBuffPtr;               
    - E. v3 {9 }" M  U) |- \
  9.   uint16_t                   RxXferSize;                  2 G7 u# W0 ^7 F# M4 ?1 o
  10.   __IO uint16_t              RxXferCount;                 
    # H4 x: t; [! \! z
  11.   uint32_t                   CRCSize;                     9 @" e7 d9 K7 G
  12.   void (*RxISR)(struct __SPI_HandleTypeDef *hspi);       4 L8 M; Z* d* r1 h
  13.   void (*TxISR)(struct __SPI_HandleTypeDef *hspi);          C' P% r$ n0 x
  14.   DMA_HandleTypeDef          *hdmatx;                      2 y6 ^+ |8 \. O
  15.   DMA_HandleTypeDef          *hdmarx;                     ( i& @8 z) w% E* x9 G
  16.   HAL_LockTypeDef            Lock;                        
    9 l8 H5 |; }: Z  \
  17.   __IO HAL_SPI_StateTypeDef  State;                        0 [7 x. C( m& A- U# h: U/ C% y
  18.   __IO uint32_t              ErrorCode;                  
    + `2 A$ O* R% y6 I5 `
  19. #if defined(USE_SPI_RELOAD_TRANSFER)
    5 w; |& p- Y. e( Z# T0 X
  20.   SPI_ReloadTypeDef          Reload;                      # `) f: I- i- V% C6 Q" {
  21. #endif
    8 ~4 x' f0 H  c) J) r0 @" k

  22. 6 x: k7 x: X# v$ s) U
  23. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)( p+ m; w5 C# ^. e* i$ o9 ~5 p2 T
  24.   void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      
    2 b& K1 m" n1 k  g" Q; P
  25.   void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      
    5 E: j: A5 J/ K3 x- T6 p! h) H
  26.   void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    " [7 I# r/ @: m$ P
  27.   void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  " z2 f$ v( [+ A' g
  28.   void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  9 B- N5 ]& U9 w
  29.   void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);
    0 J  I% t9 L& t/ C) G
  30.   void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi);      
    / j8 v/ C" p; Q9 _
  31.   void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    + T" o: e2 R/ z4 A# T: ]
  32.   void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi);   
    9 t' T% q4 w$ @* j' V# s1 r3 Q
  33.   void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi);
    ; c6 N- P, C0 x+ \
  34. #endif  5 N1 Z) d% q0 s. I5 t6 R* U2 ]/ ~* g! x, H
  35. } SPI_HandleTypeDef;8 A9 J2 F7 a6 w
复制代码

! ]+ I6 ^, I7 A( N0 o9 z
& }* }! H9 v; L! @  k注意事项:1 j& z# v" \! [9 l0 v
& A+ B' |! p4 o6 Z5 T
条件编译USE_HAL_SPI_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:
, ]$ t" J# h$ E5 ]" q4 H# P* ~8 h# s& ]
  #define   USE_HAL_SPI_REGISTER_CALLBACKS   1
7 O$ O! a- w4 d5 R& S  N# R( |' w( t9 l( r* I+ x9 O) I: u
通过函数HAL_SPI_RegisterCallback注册回调,取消注册使用函数HAL_SPI_UnRegisterCallback。; s1 E- h) q" |

% o0 m" G. O$ L  v! k这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。; p! ^6 C- ^. t, A

7 d: R9 a: S/ z' \: D; O0 @$ a8 x  SPI_TypeDef   *Instance  D$ j4 S+ N( Y& a" G% a; f/ Y
这个参数是寄存器的例化,方便操作寄存器,比如使能SPI1。( k- ]; j4 c3 g! o

& t2 H) T0 Z& w- {SET_BIT(SPI1 ->CR1,  SPI_CR1_SPE)。
" Q1 s. X3 E- U5 x' B4 T4 w
' t& z4 _, E( b0 c  F5 f6 X  SPI_InitTypeDef  Init9 E% X' Y% b; \7 @& E
这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。9 U; |9 D9 X, ^/ J2 y7 u& ~
5 X  K. t& n. E) O
  DMA_HandleTypeDef          *hdmatx               + M8 h! H! h8 g
  DMA_HandleTypeDef          *hdmarx
/ s2 }) H* a' a" H1 Q4 [' N4 E用于SPI句柄关联DMA句柄,方便操作调用。
+ b% [8 s' X  x- r, S$ c8 V( _# t# F$ M9 a% }: B! @9 d
72.4 SPI总线源文件stm32h7xx_hal_spi.c
5 E4 Y' I" F6 G5 Q此文件涉及到的函数较多,这里把几个常用的函数做个说明:3 g6 v; X9 C) [" F
: L# E& g; P5 D, S+ R6 V. c
  HAL_SPI_Init3 l# R) t/ \5 @( s
  HAL_SPI_DeInit: A8 J7 y% c2 W, `7 m, c' W
  HAL_SPI_TransmitReceive
+ O1 _. n9 y: n; @$ J$ u  HAL_SPI_TransmitReceive_IT, d3 L6 Z& M; ^. s
  HAL_SPI_TransmitReceive_DMA
4 {' F$ o9 G1 o) p- a72.4.1 函数HAL_SPI_Init
$ C9 \# v" t8 \* L函数原型:
! u; ]0 m0 `$ i3 P# g* F
- {( y; Y, Z3 D
  1. HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)" e1 H9 W1 ~# @: F2 W! _: k
  2. {
    & A$ B, S1 n7 \% |% q4 u
  3.   uint32_t crc_length = 0UL;7 u0 E8 Y" u7 c) j1 q
  4.   uint32_t packet_length;* l' T% D5 \# w1 p8 {! |, i

  5. 3 u/ a9 o/ [" s9 M3 E  c4 r( C
  6.   /* 省略未写 */
    2 J& B4 e( ~3 j$ W, \* t2 J! ?0 G9 ^

  7. ' ]" _- M& S: W: X
  8.   /* 如果数据位宽大于16bit,必须是SPI1,SPI2或者SPI3,而SPI4,SPI5和SPI6不支持大于16bit */
      W7 I3 k; w5 _  c9 K1 j$ v
  9.   if ((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (hspi->Init.DataSize > SPI_DATASIZE_16BIT))
    / \6 B4 W& ]1 Y% {; `# B
  10.   {
    . o8 j+ h# v# {8 n* a; }
  11.     return HAL_ERROR;
    4 S* i( M% u. U/ D
  12.   }2 w) l# r% z% G# ~5 ]
  13. 9 [8 }; w: J+ `# C/ h
  14.   /* SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit' |) b4 k3 B0 I, j
  15.      这里是查看设置的缓冲大小是否超出了FIFO支持的大小。
    " h% o4 a6 I. f& @# q
  16. */
    + M$ K4 X. w. ?0 V- e, h* d
  17.   packet_length = SPI_GetPacketSize(hspi);
    ( i$ i" u9 n2 f
  18.   if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_LOWEND_FIFO_SIZE)) ||3 Y+ y7 O7 o1 q0 b. Z* [1 c% v
  19.       ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_HIGHEND_FIFO_SIZE)))# T* G& M0 k7 l2 Z. F7 C" M# Z( R( [
  20.   {
    : \  u% h' r# M7 }
  21.     return HAL_ERROR;
    9 G9 `. l9 F% q5 Q) y# g. r; {
  22.   }
    & E1 k+ E$ J8 O
  23. & `% Q) X, I4 W% H
  24. #if (USE_SPI_CRC != 0UL)7 D* [9 p! x. s; c6 U
  25.     /* 省略未写 */
    3 S: W5 S) T9 Q* [/ R
  26. #endif 9 R) b5 H! R6 ^/ {, s  M. s+ [

  27.   ?, G3 L  R' g  t' Z: G
  28.   if (hspi->State == HAL_SPI_STATE_RESET)
    / x+ j# z7 }( _! J7 z
  29.   {' K  c) [: a5 M6 K1 S6 ^
  30.     /* 解锁 */, e' z8 N: i" ~; ~4 i1 f
  31.     hspi->Lock = HAL_UNLOCKED;
    1 Q' ]8 u: S$ |# z1 |& m% U
  32. 4 u3 Q2 ?& f1 b; p9 Q6 X
  33.     /* 使用自定义回调 */
    : a# Z# M* r5 J! G8 P: y  F+ U
  34. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL); s+ Z6 _; P% ]  Y; o- B
  35.     /* 设置默认回调函数 */4 G5 s2 V4 N- h7 h3 g
  36.     hspi->TxCpltCallback       = HAL_SPI_TxCpltCallback;       /* Legacy weak TxCpltCallback       */
    2 U- R$ A/ j# ]) \3 f3 R
  37.     hspi->RxCpltCallback       = HAL_SPI_RxCpltCallback;       /* Legacy weak RxCpltCallback       */! N+ g0 J% f) P! v/ b6 f% ^- S
  38.     hspi->TxRxCpltCallback     = HAL_SPI_TxRxCpltCallback;     /* Legacy weak TxRxCpltCallback     */
    : y0 Y  m+ U6 y2 Z4 \3 z
  39.     hspi->TxHalfCpltCallback   = HAL_SPI_TxHalfCpltCallback;   /* Legacy weak TxHalfCpltCallback   */
    3 B1 [1 @) w+ _' e9 G% Z
  40.     hspi->RxHalfCpltCallback   = HAL_SPI_RxHalfCpltCallback;   /* Legacy weak RxHalfCpltCallback   */
    % v; c: v9 G  L- y8 X, j6 @! c
  41.     hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */
    1 [% u7 f  n1 g
  42.     hspi->ErrorCallback        = HAL_SPI_ErrorCallback;        /* Legacy weak ErrorCallback        */% W2 {8 Q8 e% w+ [: l
  43.     hspi->AbortCpltCallback    = HAL_SPI_AbortCpltCallback;    /* Legacy weak AbortCpltCallback    */
    3 A& O* ~' _+ A: p

  44. 9 G6 N: T# u* X
  45.     if (hspi->MspInitCallback == NULL)
    + o6 B7 w, L3 m
  46.     {
    4 k! ?1 G* S+ z* h+ d- n
  47.       hspi->MspInitCallback = HAL_SPI_MspInit; * o! w% o6 Y& f7 ~; b* W* T0 c
  48.     }4 `' l- y( z$ |2 Y( h2 {
  49. % y; Y. w7 R9 _3 Z' H# H, k5 G
  50.     /* 初始化地址硬件: GPIO, CLOCK, NVIC... */
    & ~3 L# Z- x0 s
  51.     hspi->MspInitCallback(hspi);8 q$ J7 j( p% D6 k
  52. #else
    5 v; J8 a1 `& p! M+ S& {) s! g
  53.     /* 初始化底层硬件: GPIO, CLOCK, NVIC... */
    , |$ R, s' {6 h) P
  54.     HAL_SPI_MspInit(hspi);7 _  H$ _5 ]2 U+ E& o
  55. #endif( ~) J- f1 Y  F' x* ~
  56.   }
    6 N" {% `- ^1 n
  57. % H' s/ j7 I9 ~4 q$ `0 i
  58.   hspi->State = HAL_SPI_STATE_BUSY;" n/ Z) Q% ?/ U+ n7 c

  59. 1 A% T  }1 n) k+ z) R+ o( p
  60.   /* 禁止SPI外设 */
    6 Z3 P0 J& f6 E/ t
  61.   __HAL_SPI_DISABLE(hspi);3 m5 I* M  X: C- K

  62. 5 @  y  W4 k) N7 b: f5 h
  63.   /*----------------------- SPIx CR1 & CR2 配置---------------------*/
    / l( K* x9 ^- o
  64.   if ((hspi->Init.NSS == SPI_NSS_SOFT) && (hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.NSSPolarity ==3 ]& J3 K+ R$ W, D) |( j' O6 t
  65. SPI_NSS_POLARITY_LOW))
    3 c/ P8 g& j) j+ l& W/ Y
  66.   {4 J0 W" P+ I# }2 u
  67.       SET_BIT(hspi->Instance->CR1, SPI_CR1_SSI);
    * ~3 j" A& Y% F( C
  68.   }
    * m( N  O. B8 k
  69. " m6 Z3 z. M0 b8 o7 h; f" w
  70.   /* SPIx CFG1配置 */
    3 [: p5 z9 T# {9 E. a" J8 _; _
  71.   WRITE_REG(hspi->Instance->CFG1, (hspi->Init.BaudRatePrescaler | hspi->Init.CRCCalculation | crc_length |
    ( H  ]- C& \3 G7 X$ C! o& w
  72.                                    hspi->Init.FifoThreshold     | hspi->Init.DataSize));
    . }" A: B- L$ R6 o2 z2 F$ U
  73. 9 W4 R# R5 E7 W: x
  74.   /* SPIx CFG2配置 */
    ' p9 T6 _  q( |- N. ^
  75.   WRITE_REG(hspi->Instance->CFG2, (hspi->Init.NSSPMode     | hspi->Init.TIMode           | hspi->Init.NSSPolarity  |  s  y- l* c1 Z6 n/ K! E1 Q
  76.                                    hspi->Init.NSS          | hspi->Init.CLKPolarity      | hspi->Init.CLKPhase     |
    ) B% J" b. _& w. S8 [
  77.                                    hspi->Init.FirstBit     | hspi->Init.Mode             | hspi->Init.MasterInterDataIdleness |
    0 _1 x4 [# O. j' s; a, i
  78.                                    hspi->Init.Direction    | hspi->Init.MasterSSIdleness | hspi->Init.IOSwap));* d. |6 F: D$ |0 _
  79. # R) |( {9 L* i- y- J* |0 r( j
  80. #if (USE_SPI_CRC != 0UL)
    1 X3 A0 K9 T  y0 }3 [9 {" i, g
  81.   /*---------------------------- SPIx CRC配置 ------------------*/
    * w  |* T' Q- S: b  z
  82.   /* 配置SPI CRC */- |1 W5 S2 \- l' ~+ c) j' ]
  83.   if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)  Z% R# ?: w9 A$ W( Q8 ]8 D
  84.   {
    ! S, s1 {  Q2 x  R' ?' p
  85.     /* 初始化TX CRC初始值 */8 B# o2 G/ ~1 U; p  y' q: k
  86.     if (hspi->Init.TxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)5 U9 i) Y6 Y2 m& f
  87.     {
    ; Q: B, M& G: ?3 Z7 E% ~
  88.       SET_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);4 l0 i1 v& ?6 _8 O( s3 q
  89.     }
    ) X: C6 ?& d" I7 C# Y
  90.     else/ V5 Q3 B+ N; i, P1 |3 n
  91.     {5 @0 T. n9 h0 c' b
  92.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);
    " ^; X" R6 [7 d$ \4 V3 y
  93.     }/ k  l0 d2 n! Q1 ~) K
  94. ( t' x& c- Z* K% A
  95.     /* 初始化RXCRC初始值 */4 v$ f3 }! c5 Q3 C8 e1 b
  96.     if (hspi->Init.RxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN); [) g- I0 [. D$ L/ ^
  97.     {2 ?$ S# Q) b. G8 K
  98.       SET_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);
    2 v! f, f) ?! g. s3 R
  99.     }
    ( A( L  C& A* t
  100.     else
    ' W5 X5 o2 A9 I& \- C
  101.     {
    8 \3 q* A' }; p4 B8 _+ Q
  102.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);
    4 `4 M/ T: h) K9 j9 V
  103.     }/ h' n) a) j5 s: U- [9 R
  104. 8 M: c/ l, M. S: x5 n! E- }9 K+ c# t
  105.     /* 使能 33/17 bit CRC计算 */
    ' _! o( G4 w2 F; w9 v  h
  106.     if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (crc_length == SPI_CRC_LENGTH_16BIT)) ||
    - C% I1 B% i, |& p0 Y* Y- c# D6 ~. F
  107.         ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance))  && (crc_length == SPI_CRC_LENGTH_32BIT)))9 o: [* P# R$ Z* x
  108.     {
    ( _3 p: O8 [9 g$ v$ e! K
  109.       SET_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);
    8 |. h, V# _. p2 v# j/ O* g. i1 h! W
  110.     }
    ( `4 ]$ F1 p2 b1 ]
  111.     else
    5 o6 [* Y( L* r7 ]& o) J
  112.     {3 G: l1 F7 h% q- h$ f6 h" G( V8 K
  113.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);
    : H9 _- p$ t* V: q# Z
  114.     }9 d: g: A( K2 l1 K: y6 n# S4 l

  115. 9 H) V5 A* H8 u- j6 R
  116.     /* 写CRC多项式到SPI寄存器 */3 p" U* o) \9 f7 W
  117.     WRITE_REG(hspi->Instance->CRCPOLY, hspi->Init.CRCPolynomial);* c$ [- k: w- S& W; P
  118.   }5 A$ o4 n) ]( }' a# `4 d/ Q8 G+ P. K
  119. #endif
    # D6 W6 t: O5 c  r3 W
  120. 7 T9 i( v' k  G% X+ ]6 T4 ?3 U- [! d
  121.   /* SPI从模式,下溢配置 */
    $ T( i; R1 ^& P+ }8 I2 _  b+ e" C
  122.   if (hspi->Init.Mode == SPI_MODE_SLAVE)
    , E" r* v. H, A: [8 b
  123.   {
    2 H$ V* g3 P( L% K/ V
  124.     /* 设置默认下溢配置 */7 F3 {1 g) N- Y% o" k+ z1 i3 f
  125. #if (USE_SPI_CRC != 0UL)8 V! _+ k% U8 r) i6 u1 r5 l
  126.     if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_DISABLE)+ a. _0 h0 ]1 ?0 ~; f+ N# ~
  127. #endif! v; M( \2 d' C- a, y
  128.     {1 ^2 [2 `+ z% N  n/ m' G
  129.       MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRDET, SPI_CFG1_UDRDET_0);: a' {$ u8 i! U! W
  130.     }" V/ M+ @& ^3 x0 r$ o- v- U9 r
  131.     MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRCFG, SPI_CFG1_UDRCFG_1);
    & N2 `: T2 b- n; W  Q: O
  132.   }$ {9 K2 C" ?0 c! {8 d, ?
  133. $ ?1 w7 Q% O% `, D
  134. #if defined(SPI_I2SCFGR_I2SMOD), |& J# g: C8 K, \" Z
  135.   CLEAR_BIT(hspi->Instance->I2SCFGR, SPI_I2SCFGR_I2SMOD);$ N5 c  q8 }& }5 X  g: O
  136. #endif " _% l9 Q! O/ ^( g3 C
  137. ' _: H; j6 }* s* i- ?& x
  138.   /* 确保AFCNTR bit由SPI主机模式管理 */
    ; E7 K& k# Q1 n$ P* P% U
  139.   if ((hspi->Init.Mode & SPI_MODE_MASTER) == SPI_MODE_MASTER)
    ! z* |. l( _1 P! Q3 G9 p
  140.   {8 |2 q) y7 U- u1 G& O# H* U3 O
  141.     /* Alternate function GPIOs control */3 E  v, `9 O5 R  q3 l# d3 h
  142.     MODIFY_REG(hspi->Instance->CFG2, SPI_CFG2_AFCNTR, (hspi->Init.MasterKeepIOState));
    ' X0 Z: d* Q8 z) n6 _4 b1 G7 Z
  143.   }! |% C5 a# B' y( L* u

  144. 9 K; g9 R6 `6 Y, p( h/ }
  145.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;$ u' _2 o9 k, j& L
  146.   hspi->State     = HAL_SPI_STATE_READY;
    5 l$ j% t7 c, d  Y: N
  147. 5 q' n6 ^$ R& Y$ c* a* J  r
  148.   return HAL_OK;
    7 q1 p; L; \( ~$ E' R7 R
  149. }
    3 @" V+ {" m8 q+ |& l! f! M/ C
复制代码

; h6 O. L& _% o9 d1 W2 R' ]7 B6 O4 n8 r, [' P+ P
函数描述:
( k6 m8 e$ T7 b$ }2 T9 l0 p2 K5 v1 u! J+ M& z! [1 p; }( A
此函数用于初始化SPI。
" F, d9 m+ X5 C& e7 d' b5 E* F, C# I" @6 w7 |. R8 k" g* h
函数参数:; R+ U5 i9 J0 ?* G4 X3 p

& j0 U/ O$ l  Q5 K' q6 e# y  第1个参数是SPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。* }4 m4 o/ f' x) e/ Z0 i6 N0 k+ C! R5 m
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
4 f9 b& A) O9 s. U5 d注意事项:
; Q  B/ t& M% s* e2 Q. X! }
/ w. t* D) X# Z, m函数HAL_SPI_MspInit用于初始化SPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。/ i9 v- c$ D8 L, I  o; q
如果形参hspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SPI_HandleTypeDef SpiHandle。& @" {  [/ E( [9 ~) a0 e. {
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SPI_STATE_RESET  = 0x00U。
4 Z& m2 B! h5 I7 y; x. g: D& B/ g
& S7 m8 ^/ m9 k* u解决办法有三# d7 D8 m3 d+ q$ l9 D# O- z

4 u4 f1 c' u- B+ p/ ^方法1:用户自己初始化SPI和涉及到的GPIO等。
  ]* ]- J, O/ e! k! Z+ m7 G
2 L' X9 w1 ^5 v方法2:定义SPI_HandleTypeDef SpiHandle为全局变量。
! q3 o% W# {5 W. K) e2 Y/ U0 {: F. P# j" O9 F, d' f, I% k
方法3:下面的方法9 U7 z( @. Y. l4 |, _; s
/ \& v9 i4 q1 O0 `: A" M
  1. if(HAL_SPI_DeInit(&SpiHandle) != HAL_OK)
    0 `9 ]9 I/ f7 X8 o+ \
  2. {) F9 q! t# Y+ s: [1 m
  3.     Error_Handler();
    0 C2 G% j* ~3 j" C, Q- I
  4. }  
    - d( X+ p0 |' `2 P4 Q1 z
  5. if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
    , [& Z. j$ x5 U# N$ t+ {
  6. {
    , q; S4 v8 U, p/ A4 b! e
  7.     Error_Handler();
    2 c$ G0 \  x! ?& K
  8. }
复制代码
  b4 ~2 v  Y0 y" H% o
使用举例:. T+ r% t4 ^; a9 Q" O) X
$ R4 @6 i6 C- `4 Y4 |6 \& L
  1. SPI_HandleTypeDef hspi = {0};
    3 E+ @( ?3 [$ K! ^" a# P

  2. ' E; }. ?: q& r6 m
  3. /* 设置SPI参数 */
    4 b# x1 P9 z( c+ ]4 n3 i
  4. hspi.Instance               = SPIx;                   /* 例化SPI */
    8 p/ e/ f" I5 `& u9 p' g8 P  p
  5. hspi.Init.BaudRatePrescaler = _BaudRatePrescaler;     /* 设置波特率 */8 e7 }3 \: E4 o- C
  6. hspi.Init.Direction         = SPI_DIRECTION_2LINES;   /* 全双工 */
      q$ z' E1 T  y4 x& K
  7. hspi.Init.CLKPhase          = _CLKPhase;              /* 配置时钟相位 */
    " B+ ]% S/ n- e! k: L8 s4 o* E' O
  8. hspi.Init.CLKPolarity       = _CLKPolarity;           /* 配置时钟极性 */$ ^4 T1 c/ i- ^$ N  S9 S3 Q2 m
  9. hspi.Init.DataSize          = SPI_DATASIZE_8BIT;      /* 设置数据宽度 */; Z( _) Z% d6 r/ y  }
  10. hspi.Init.FirstBit          = SPI_FIRSTBIT_MSB;       /* 数据传输先传高位 */: p  o" ]3 T* w
  11. hspi.Init.TIMode            = SPI_TIMODE_DISABLE;     /* 禁止TI模式  */
    0 o: s& I: C% n
  12. hspi.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;      /* 禁止CRC */
    ; D5 n7 K% _" G) o2 \" H9 p' |
  13. hspi.Init.CRCPolynomial     = 7;                               /* 禁止CRC后,此位无效 */
    ; z2 n: e4 ]5 ^. K8 V" C: C
  14. hspi.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;             /* 禁止CRC后,此位无效 *// R  ]5 _) y& G1 k2 k; ?
  15. hspi.Init.NSS               = SPI_NSS_SOFT;                    /* 使用软件方式管理片选引脚 */
    5 D( F" w& c6 s
  16. hspi.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_01DATA;       /* 设置FIFO大小是一个数据项 */" I) J* _- Y, b% X) P) i
  17. hspi.Init.NSSPMode          = SPI_NSS_PULSE_DISABLE;           /* 禁止脉冲输出 */
      h' X1 I) N/ s
  18. hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  9 B4 \9 s: F% E# L2 X9 u3 @, T
  19. hspi.Init.Mode                  = SPI_MODE_MASTER;            /* SPI工作在主控模式 */' |$ B4 k% U( B( D, f

  20. 1 G% ]% s' n/ A
  21. if (HAL_SPI_Init(&hspi) != HAL_OK)+ `+ y7 p( o4 {* ^, e: ]% H
  22. {
    ! D5 A/ n9 O! p1 T" s7 m0 _3 l
  23.     Error_Handler(__FILE__, __LINE__);
    $ ]( W9 b! v! `: W7 S
  24. }
复制代码

/ G* w1 m. i" k' w8 T$ O+ l. T6 j5 ^! A0 E9 {
72.4.2 函数HAL_SPI_DeInit
! w. w3 {7 E9 d# z; E1 B函数原型:
6 a% F( X8 c0 Q2 W
5 C6 H& A5 Y1 w9 a& C8 A
  1. HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)
    * g3 _; \# {, b& X
  2. {
    4 R2 m  H  G( N/ W
  3. /* 检测SPI句柄是否有效 */+ |: P' ?: K/ l2 g+ X. H% p; K
  4.   if (hspi == NULL)
    - M5 a; a5 a, @/ N2 t& E  u* e
  5.   {
    ; f0 M2 n7 |. n" Y
  6.     return HAL_ERROR;
    ( o9 p4 u3 W7 z8 H/ i
  7.   }) ~& @1 k& i' X! {. J9 ?# n$ y) e' N
  8. $ D- |$ s( I7 u) z7 x: Y
  9. /* 检查SPI例化参数 */5 X4 E5 s) V- h# a% t
  10.   assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));
    " _5 M- y9 |7 x8 ~$ P

  11. 6 z# p* J4 `5 N
  12.   hspi->State = HAL_SPI_STATE_BUSY;
    : ~/ }, J0 Y( C3 n' S: B- R

  13. ( E; a9 l  h  g5 Q- p7 N8 _
  14.   /* 禁止SPI外设时钟 */
    + W* X$ z1 b2 J+ V# t2 v9 \' j* S
  15.   __HAL_SPI_DISABLE(hspi);
    6 Q, k4 z9 a: o& O# n+ \, s. f

  16. : f; x' f' U. L3 I4 ~
  17. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)6 s& \  u/ i, p& E! t5 X
  18.   if (hspi->MspDeInitCallback == NULL)$ b( ?. _: x- U% {
  19.   {
    ) n9 C/ M: x+ Q. [# F) Z
  20.     hspi->MspDeInitCallback = HAL_SPI_MspDeInit; ' S$ G% y& j6 _3 N$ p+ u4 `% R: [
  21.   }5 E3 d% X0 [  S1 i, T" x  \8 K
  22. # u( s9 Y6 Y1 }/ @7 @$ o9 x" [. G8 t
  23.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */4 i6 q8 r. ^2 Q5 R  k
  24.   hspi->MspDeInitCallback(hspi);9 ^2 U6 X7 w, m3 K, Z% V
  25. #else
    # Y% D  \. E: x" R
  26.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */
    6 s. y& f" H  O9 D# ^
  27.   HAL_SPI_MspDeInit(hspi);' W, E7 ~! e0 [
  28. #endif ) k' c2 n! \  y, d# h5 W% @

  29. ; j4 s. y# ]0 ]1 R$ I- o( h' A
  30.   /* 设置无错误,复位状态标记 */: `5 u2 M1 Z/ B% N) v5 x0 |" p
  31.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;
    5 C- O* i0 c' P- ^9 }" _/ F5 u
  32.   hspi->State = HAL_SPI_STATE_RESET;
    " ^! E* y. K" K) T8 N3 [

  33. 3 L# v4 x; R  v, c3 d/ n$ H+ S
  34.   /* 解锁SPI */( f( G0 W, }# a2 c/ n7 V
  35.   __HAL_UNLOCK(hspi);
    , E) |; Y# M& u

  36. 6 B5 O) L8 A* c. T( m  V2 P8 @1 ]/ G
  37.   return HAL_OK;
    8 l, T- c+ s7 H0 x
  38. }
复制代码
; O5 g) X' ]! Z
函数描述:! Q; k, U- |5 K4 E) U0 [

& `0 P  u& C% l+ z0 r: G用于复位SPI总线初始化。
' }! Y# I' L* D6 U. L. Y) E, Z( j! p9 i! r
函数参数:
4 J) u9 d! w% Q  y* l( B
2 ]+ s: i* ?2 ?( a& i) k9 U# }$ p4 \  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
/ @7 [  K, N8 W. j' w  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中7 J, f% S( q0 h+ ]. }5 T  x! v
72.4.3 函数HAL_SPI_TransmitReceive' }4 m! x: g8 i8 t7 p1 m
函数原型:
2 N4 J& b# d) E; [. r: K6 w8 i1 p2 E3 n* L6 V
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
    1 `8 R; |( E/ H. b
  2. {- G$ Z' M$ Q; D/ f0 {

  3. 1 M: J4 G8 _* i2 S6 q* A
  4.    /* 省略未写 */% X5 a% Q4 O. g( c

  5. * W5 L% |" P; R2 g7 U, I
  6.   /* 大于16bit的数据收发 */4 W6 p7 H  {3 m8 |- [% V
  7.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    + H6 d8 R/ ^, N
  8.   {
    0 I0 @- j# D& w  q
  9.        /* 省略未写 */5 B- \2 y$ ~) h5 r. J8 q' \; d' T; ~
  10.   }
    5 C# a+ H3 Y$ D3 M. ]: e
  11.   /* 大于8bit,小于16bi的数据收发 */: p' @2 ^$ F1 ?% I% U
  12.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)! w+ ?. A/ w- R6 D# z
  13.   {
    3 K1 n3 T: ^" t+ f6 b) i
  14.       /* 省略未写 */
    5 O* W9 f! C4 A4 p
  15.   }& L# I/ O# F/ g* K0 v
  16.   /* 小于等于8bit的数据收发 */
    - `, Z: ~; b5 i9 ]6 |4 C( ^5 y: u
  17.   else
    3 @% h/ K) O3 _% E1 X! S$ ~
  18.   {, M* t( v! K6 l) |  g+ C
  19.        /* 省略未写 */
    / P6 T9 e; x8 M- A* C% r
  20.   }
    . P6 p/ v3 L- g
  21. / p9 |. |, Y4 a# V7 [
  22. }( p$ A! @0 Y# d5 e! D4 @. g
复制代码

2 y: B7 |/ \. g0 A8 d
$ s- c! `$ x9 r/ o函数描述:
* _5 `5 g( A- \% b: V7 G% \5 x
此函数主要用于SPI数据收发,全双工查询方式。
1 e* G! `9 J3 t) \) |  B0 j' \9 I* F1 w1 e% x( |4 G0 y6 x4 J9 k
函数参数:1 L/ @" M+ C4 B) o; m
- W% [9 x, j) `2 ~/ y
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
4 m# I* t6 n2 I1 j9 f  R+ E  第2个参数是发送数据缓冲地址。0 O! q# R0 v/ i
  第3个参数是接收数据缓冲地址。* S: o- z* X5 q$ l- u- }9 c4 X
  第4个参数是传输的数据大小,单位字节个数。
! y7 [2 o4 W/ w! M# b% l4 L6 H  第5个参数是传输过程的溢出时间,单位ms。5 J/ s0 ]/ G1 }7 N. g/ w
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。% b8 h5 I2 R7 }3 i$ k" k
使用举例:# ?$ A* M) O" X
+ [+ X' r' q; y
  1. SPI_HandleTypeDef hspi = {0};
    ' `' x% X, P/ [$ i9 @
  2. . X! b. n$ D8 d' ?" I# s6 x' r
  3. if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)6 M) m( t/ x$ j$ r- _- _- {( m/ j
  4. {
    $ i/ a+ s2 Z+ b3 m! e1 _8 v( i
  5.     Error_Handler(__FILE__, __LINE__);5 t/ z4 L: D6 i* Q; ^1 O
  6. }
复制代码

9 e6 g5 G1 {& l" R3 B72.4.4 函数HAL_SPI_TransmitReceive_IT' \% c# r# J% a- v
函数原型:
6 P7 l* c/ X& h/ _: D( V) W! Y- }6 M# B9 v
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)
    : r9 x$ n1 M( g) a  R5 o
  2. {$ @) p1 v0 W3 k" p. a
  3.    /* 省略未写 */
    ; h' r0 g, ]/ H/ v7 Q" W, q

  4. # p2 o0 Q- R3 J9 Z
  5.   /* 设置传输参数 */+ v( I/ f- _6 T2 {7 A5 L
  6.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;0 y, g5 n8 Z3 ^* g$ P6 B
  7.   hspi->pTxBuffPtr  = (uint8_t *)pTxData;0 V& ?$ x9 P/ ~) i1 ~( }
  8.   hspi->TxXferSize  = Size;5 p# U% P5 M0 n5 Y
  9.   hspi->TxXferCount = Size;
    ) j2 Z$ [: p8 S4 d
  10.   hspi->pRxBuffPtr  = (uint8_t *)pRxData;
    / R- I2 I6 d$ \( Q
  11.   hspi->RxXferSize  = Size;
    * q) ]% p- v! C9 }
  12.   hspi->RxXferCount = Size;
    * F: x" l6 S$ w) O) z, \' _

  13. 8 v. `! w7 j* w
  14.   /* 设置中断处理 */+ @, d$ t" X1 h- A
  15.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    1 f0 T6 \- b7 E0 a6 Z
  16.   {: X% H" k6 E- f. D
  17.     hspi->TxISR     = SPI_TxISR_32BIT;
    % }* A; p" }) V9 t* M
  18.     hspi->RxISR     = SPI_RxISR_32BIT;
    2 [; d* [4 G% J& X" v7 G
  19.   }: j' T/ Q/ x& M& Z$ E( f  I
  20.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)& ~* O9 k" D* O) h( G- n/ M
  21.   {
    ' [+ Z- j4 P1 x' c
  22.     hspi->RxISR     = SPI_RxISR_16BIT;7 x! x+ K4 Q: R8 U3 D! H
  23.     hspi->TxISR     = SPI_TxISR_16BIT;
    - S9 |# i$ E/ r$ C% i5 P9 _
  24.   }+ B0 j+ P' M1 _( i6 ^& b1 v' u
  25.   else! q) k5 O( P. J' ~) j; z
  26.   {
    ) ^/ R% B$ N) o8 z. k7 p+ f' u
  27.     hspi->RxISR     = SPI_RxISR_8BIT;7 h( h) G' _$ l2 S/ c
  28.     hspi->TxISR     = SPI_TxISR_8BIT;
    + V8 l6 Z9 E' J5 ]6 a
  29.   }
    3 s- p' n4 l: U8 p. G# `
  30. / x6 Z- Z# ]6 o+ m3 @, W4 b& t& D3 h% m
  31.   /* 设置当前传输数据大小 */
    , V: X, _  `9 k
  32.   MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);% t/ ^' l% f6 Z, U8 J
  33. : k: X- m! s* Q5 u) B7 Z. }
  34.   /* 使能SPI外设 */
    % I5 ?( @$ }' _7 {) T
  35.   __HAL_SPI_ENABLE(hspi);
    # Y6 t) t) k2 ]* f

  36.   u2 N7 b) S" N) |/ M7 V& U
  37.   /* 使能各种中断标志 */
    & D! r2 ^8 A* W" ^/ `
  38.   __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_EOT | SPI_IT_RXP | SPI_IT_TXP | SPI_IT_DXP | SPI_IT_UDR | SPI_IT_OVR | 3 f6 L+ Q" Y( i4 e* t; }$ \
  39. SPI_IT_FRE | SPI_IT_MODF | SPI_IT_TSERF));
    , f+ w1 B/ q5 S
  40. / @6 R8 s2 H/ }: f* Q
  41.   if (hspi->Init.Mode == SPI_MODE_MASTER)
    7 q( i. _5 n2 h, B
  42.   {
    7 @5 S) S4 l( d; E1 E1 R
  43.     /* 启动传输 */
    + \. v( M5 V  ~( N: i
  44.     SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);, q% ~0 A- g6 B7 F& T
  45.   }6 c# f, l, @8 M! y1 ]6 d, b, I* N+ W

  46. 7 }" O6 y; v8 }8 f: C
  47.   /* 解锁 */
    & y+ J- _6 [& Z0 ~/ w8 W
  48.   __HAL_UNLOCK(hspi);
    - Z4 m/ T. G/ g
  49.   return errorcode;$ P/ Y, [9 B! @% S
  50. }
复制代码
( x) P( d; @* {" m+ V; O

9 D3 L1 }9 P4 u0 A. k7 M3 X  b  \0 c8 d: x
函数描述:
, W: j4 N# p) o, [- Q) k6 s& o& A& r7 F+ W# l
此函数主要用于SPI数据收发,全双工中断方式。
/ g- \" k3 ?& T1 ~7 D7 H# T" J3 ?9 g( q
函数参数:1 i; ?; W' d9 g6 n
- B( S( n- \! |! Y& d) ]/ n4 P
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
0 ]3 X1 N* a( H$ s$ W  第2个参数是发送数据缓冲地址。
5 [( G) }7 h2 s5 {  第3个参数是接收数据缓冲地址。1 u/ r# K, g. p2 K
  第4个参数是传输的数据大小,单位字节个数。$ U, N+ Y, t1 c, n1 ]
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。# F+ |1 H2 r6 j6 m& N6 W
使用举例:5 E4 R8 ]  m/ g" x( s

/ m9 p# W7 ]: T
  1. SPI_HandleTypeDef hspi = {0};
    8 ~+ L9 g2 G9 ~- ~' O' M
  2. 0 A6 J. E) b4 V+ f1 X
  3. if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)   
    , l5 }" l/ l, v/ P
  4. {) E4 {" j+ g# f  B, G
  5.     Error_Handler(__FILE__, __LINE__);! N$ ^  C2 ~: ?* d& P
  6. }1 Q, ^! j- C/ J9 |( a

  7. 7 _3 s$ |- l6 v; y5 E

  8. ( I# g' L( e$ K2 N& _
  9. 72.4.5 函数HAL_SPI_TransmitReceive_DMA
    . ]3 N% }. o% c( y
  10. 函数原型:
    1 P# U, g. a7 \' L: R8 _

  11. ' J7 {% {1 d$ F' L
  12. HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,# ~! [4 E: m* ?3 k3 P6 Z% i
  13.                                               uint16_t Size): F/ [9 y0 J( o6 @: q3 f# y
  14. {
    1 x* a8 O/ I, [+ p
  15.    /* 省略未写 */
    5 {$ v' K; C; c5 C7 a  p' G$ c8 l

  16. & y6 X0 h% G5 ]
  17. /* 注意DMA的位宽和对齐设置 */1 J' g' R+ s3 G. h9 j' z
  18.   if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && (hspi->hdmarx->Init.MemDataAlignment !=: I1 f, x4 u* g+ a
  19. DMA_MDATAALIGN_WORD))  ||
    ) q- h% ~/ U7 {4 v+ }$ J
  20.       ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) && ((hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_HALFWORD) && (hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_WORD))))" A8 W3 Y- f% _! [# U5 v
  21.   {
    ' K' c* D) m7 _( w: @8 ?8 T
  22.   }
    , b0 W7 x4 _* b8 E9 w, d+ f

  23. ! x% ~* E. P  ^4 z/ F0 J/ w! h
  24. /* 调整DMA对齐和数据大小 */
    ! n7 P9 D! Y& l% }2 n6 b, g6 J5 o
  25.   if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)
    3 N4 l5 [- \) a* h4 \
  26.   {
    ' g% \; h* L+ q* m: N
  27.      /* 省略未写 */4 C8 |1 w$ w  K2 T
  28.   }- ^4 J+ Y* I4 Y9 ~8 Y+ @
  29.   else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)
    + \) |7 Q0 y0 W+ {& v1 y, [
  30.   {+ d) u, ~, a/ ?, S" z- k0 D
  31.      /* 省略未写 */0 b7 F) z8 h6 t8 x6 d: Q# W
  32.   }1 v  i5 z+ F9 H; p0 ?. f; V1 j
  33.   else* s6 p3 L  v) h5 U
  34.   {2 n5 q$ y* [$ g/ {* Z% e2 ]
  35.       /* 省略未写 */
    + }7 k) `- [5 `! E& S& _
  36.   }6 ?1 ~% N; q7 F. w* C+ F0 v

  37. & a( N4 ^& U& F0 U; z. f6 F+ }
  38. /*  DMA接收配置 */, G4 Z5 S2 N- \  @' q% D
  39.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->RXDR, (uint32_t)hspi->pRxBuffPtr," z3 [9 R8 o, }( Z2 j' s
  40. hspi->RxXferCount))7 X7 L6 k4 ?9 x9 M9 @
  41.   {
    2 \; s% ^2 A$ g3 f

  42. ; G  E+ v4 @& X- U4 q5 H: ^( I/ J
  43.   }
    ( {5 N, @  B  D( o
  44. 8 G+ j3 s; @0 I2 a9 U" [
  45. /* DMA发送配置 */# x$ S' Y" O+ O. y# c
  46.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->TXDR,$ i- i) [3 R% Z5 i' `
  47. hspi->TxXferCount))
    + D" ^0 n3 B: O! C4 i: `
  48.   {
    * ]+ V; _! }+ J6 w/ v% ]& |
  49.   }
    - v  J; e3 L; p% ^8 c/ G

  50. ; v4 ^7 b$ U6 }! ?' m, q$ e! f
  51.   /* 省略未写 */8 C1 u+ @, z/ ^9 L1 b1 l
  52. }# e( F2 e1 e) t+ W
复制代码
1 x# G" A3 ~$ f% F  p$ M# k
! x# k! |2 u! K1 q- I- W" u; l- u
函数描述:3 `# i$ h2 |" q4 N
0 r6 G  g" f; X6 }/ T
此函数主要用于SPI数据收发,全双工DMA方式。
) o, e6 D3 c' M# R, A. a1 \; P- ]) h
0 u' j6 i7 Z: B; A' }( L% _5 ^; j函数参数:
4 ^& c  V0 N& b/ c1 b9 l5 i- s6 n4 A6 l+ t
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。" K; {2 R* n( {/ f: ]
  第2个参数是发送数据缓冲地址。; T2 r6 J/ g$ ~$ l7 N- F& C
  第3个参数是接收数据缓冲地址。8 x0 J4 a+ m) G$ N7 V; Z( X, x
  第4个参数是传输的数据大小,单位字节个数。* ]$ \3 K3 y/ D) b+ ~  g
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
0 n  E! o9 t& l使用举例:$ u+ {* |3 h! S' [6 {

2 ?' O' ]( _7 N; N
  1. SPI_HandleTypeDef hspi = {0};* m1 W1 f! L& U

  2. 9 o) ?" {8 ^6 C2 T4 b
  3. if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)   
    - i# R% ]. s9 g4 [8 K- W, g, n
  4. {( Z( Z* i' @7 [9 @, O
  5.     Error_Handler(__FILE__, __LINE__);
    : y# H: j  ^5 T: T3 r5 X% _: o
  6. }
复制代码
/ p! [) W/ k" n! O' f
6 R. _1 I- Z1 r) L* L

2 I+ b- \- c6 h8 O; u- X72.5 总结  {0 S1 L6 w) s! F
本章节就为大家讲解这么多,要熟练掌握SPI总线的查询,中断和DMA方式的实现,因为基于SPI接口的外设芯片很多,熟练后,可以方便的驱动各种SPI接口芯片,以便选择合适的驱动方式。
9 B( L9 p  [; H1 X& Z
+ l# J0 @* t8 v8 S6 k
1 j8 `, w* d4 s. v1 \. u7 O& d
收藏 1 评论0 发布时间:2021-11-3 10:15

举报

0个回答

所属标签

相似分享

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