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

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

[复制链接]
STMCU小助手 发布时间:2021-11-3 10:15
72.1 初学者重要提示0 b9 J5 F% ^6 N; z) m
  STM32H7的SPI支持4到32bit数据传输,而STM32F1和F4系列仅支持8bit或者16bit。; w, v7 M" U' z0 s: n1 n# V% D
  STM32H7的主频400MHz时,SPI1, 2, 3最高通信时钟是100MHz,而SPI4, 5, 6是50MHz。
" u0 }/ N+ _/ g* J$ E) C* u# o. T1 j  STM32H7的MISO和MOSI引脚功能可以互换,使用比较灵活。1 W/ @/ d2 ~/ W( k( F- M0 L
  SPI总线的片选引脚SS在单一的主从器件配置下是可选的,一般情况下可以不使用。/ C' }* i; v4 ~- ~4 N% R
: a: _6 y1 V$ D+ e& ?( }
72.2 SPI总线基础知识/ t  ^0 E0 @0 k  D
72.2.1 SPI总线的硬件框图6 i) t: r, |2 ?5 S* w% R
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SPI的基本功能,然后再看手册了解细节。
' F8 l$ V  B# O0 }1 @# \
/ @/ c) K" [* {1 [$ A
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

% i0 k( W. x3 q+ z; E; v: i4 b$ }* f. ?3 R5 b
通过这个框图,我们可以得到如下信息:( X) I+ s& y4 T8 w/ p. E4 s
: o. }$ @  w6 n& U2 h4 [: d# W& Z
  spi_wkup输出
5 }0 B  @3 m; O4 ^低功耗唤醒信号。+ Z+ q' L3 F. U6 N

" O8 p! R8 e! H  spi_it输出
0 D, `2 E/ n- v6 V0 q7 H8 Wspi的中断请求信号。9 m7 a0 ]: `3 \, v1 B
9 W6 {$ p; G; w% ^" ?2 F2 U
  spi_tx_dma# n$ ]1 G4 Z# J2 O7 _( o
spi_rx_dma
1 l% M% ?' r) xspi的DMA发送和接收请求信号。
$ V1 b& J7 Z. b7 `6 l- C- n$ ^
  t8 N* E- `) S& a6 d" X) _  spi_pclk
& Q) @6 ?0 A# f9 g7 C& V% v为寄存器提供时钟。
4 F/ }6 d0 L5 @$ j9 \# H. s( o/ X. m' W
  spi_ker_ck0 W* q1 J2 Q# i4 d$ V: O# Y
为spi内核时钟。, V- Q* m: e3 X

- d# T" v' ]7 h7 I  SCK(CK),Serial Clock
# c! z2 w! H3 ~* `此引脚在主机模式下用于时钟输出,从机模式下用于时钟输入。
# Z' s3 i6 O( s' n/ h( E
" _7 ~. p9 g7 F' F) E3 x  MISO(SDI),Master In / Slave Out data- e1 I6 u5 R; Z! U( Z  a; l+ j
此引脚在从机模式下用于发送数据,主机模式下接收数据。
( A4 N4 ?/ L- M5 d/ r9 t
7 j- p# U- P1 U/ C9 k7 E0 I% B  MOSI(SDO), Master Out / Slave In data
* L/ m1 _& ^# S; Y' w6 o$ X此引脚在从机模式下用于数据接收,主机模式下发送数据。1 |& s4 O8 Q$ H0 j: z

- ]! E1 Z3 A2 ~* q( d  SS(WS), Slave select pin
2 e  T' V- r" q+ m3 D7 a/ a% P根据SPI和SS设置,此引脚可用于:
! A) U+ m* S$ r  Q6 H4 p; v, C* W$ {8 B
a. 选择三个从器件进行通信。" }% d& t0 c% Y  Q( k6 S9 x

" {& M6 m$ L; f/ ob. 同步数据帧。8 V0 n( r1 D% g+ G8 _5 s
- R4 J  J3 \* V/ I" ^
c. 检测多个主器件之间是否存在冲突。6 `' u" S% U$ e; J1 S
- w+ z1 K5 z, I4 C! J* E+ u
通过这个框图还要认识到一点,SPI有三个时钟域,分别是寄存器所在的ABP总线时钟域,内核时钟发生器时钟域以及内核时钟发生器分频后的串行时钟域。
+ N5 D$ P9 A- m1 B3 n' a# B* Y2 v% S  @. a
72.2.2 SPI接口的区别和时钟源(SPI1到SPI6)' Y6 q7 x, |* A4 [
这个知识点在初学的时候容易忽视,所以我们这里整理下。
, }& {1 i7 V; p: W  I( S* g: c% H$ Y& W6 e: e6 p$ n& u2 _# m
  SPI1到SPI6的区别
: ~/ f4 M7 N! }* S! `1 a  SPI1,SPI2和SPI3支持4到32bit数据传输,SPI4,SPI5和SPI6是4到16bit数据传输。& E: |% R! S9 u2 |! Y
  SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit。
6 T0 [: j3 K$ Y. n# v' t9 x4 a. L! B4 g) M
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
* L6 g: f: D" g. u

/ n5 n7 `# B( a- [# M: P& h" \; x  SPI1到SPI6的所在的总线(对应SPI框图的SPI_CLK时钟域)' ^1 g$ Z5 {/ u) _- F/ N
SPI1,SPI4和SPI5在APB2总线,SPI2,SPI3在APB1总线,SPI6在APB4总线。注意,SPI的最高时钟不是由这些总线决定的。9 X: K  E$ a* n) f$ ^, }

; M/ N- ^& X1 Q1 c. T  {  SPI1到SPI6的支持的最高时钟(对应SPI框图的SPI_KER_CK)
- s4 L6 J- S1 E1 ], Q2 QSTM32H7主频在400MHz下,SPI1,SPI2和SPI3的最高时钟是200MHz,而SPI4,5,6是100MHz, 以SPI1为了,可以选择的时钟源如下:
! t& M* s2 V8 ]7 o4 ?5 m" `- z
2 S2 d" n$ z5 k
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
# t) ^: f. @6 E7 |

) g5 O3 I6 a* ?. g7 d+ y% J6 V8 e这里特别注意一点,SPI工作时最少选择二分频,也就是说SPI1,2,3实际通信时钟是100MHz,而SPI4,5,6是50MHz。
5 g6 K' s6 d& @& y6 h6 B# g) t
72.2.3 SPI总线全双工,单工和半双工通信8 `: n# T2 A' i& z2 u
片选信号SS在单一的主从器件配置下是可选的,一般情况下可以不使用。但需要同步数据流,或者用于TI模式时需要此信号。
4 y; l# M- x) F8 `3 \' n1 A+ u" e2 Z
  全双工通信
2 m7 N  g- ^8 J  l! s全双工就是主从器件之间同时互传数据,SPI总线的全双工模式接线方式如下:  ?4 c3 c7 H) o

( I/ {2 H  j+ g  e5 S8 `, W
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
3 W5 a$ n2 f! L% s* p

5 t: B) s9 `1 e6 |: G* D关于这个接线图要认识到以下几点:
: _) G2 h6 G7 m6 R5 l
: b5 m/ f/ n, n& R  注意接线方式,对于主器件来说MISO引脚就是输入端,从器件的MISO是输出端,即Master In / Slave Out data。MOSI也是同样道理。$ s' w: [7 Q. `$ T2 |  W8 s; n5 q
  每个时钟信号SCK的作用了,主器件的MISO引脚接收1个bit数据,MOSI引脚输出1个bit数据。
$ J2 Y2 O8 y  Y/ r; c; {$ U  这种单一的主从接线模式下,SS引脚可以不使用。) R6 P; d- r0 S! z4 [: I1 ?( _
  半双工通信
+ ^- t0 j) N, d; i) d) T半双工就是同一个时刻只能为一个方向传输数据,SPI总线的半工模式接线方式如下:+ j& }5 x! G& r( k2 ?
2 K$ l" f- A  `9 D! n/ V: M0 A
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

  z, G3 V* H9 Y" V4 r  `+ D: o
% x. l* A; _8 \3 r关于这个接线图要认识到以下几点:
4 b1 ^3 \' t! v  f, @
" Q5 a; ^: a" z/ K  更改通信方式时,要先禁止SPI。
, X9 w; E* r; z2 o0 n- o  主器件的MISO和从器件的MISO不使用,可以继续用作标准GPIO。3 I0 z) j6 d' C! [
  1KΩ的接线电阻很有必要,因为当主器件和从器件的通信方向不是同步变化时,容易出现其中一个输出低电平,另一个输出高电平,造成短路。
5 q& g! i* T1 t  i5 E  F  这种单一的主从接线模式下,SS引脚可以不使用。; S9 c7 R- g" _& k: n/ l
  单工模式
) W' `* P+ P" i" s+ w单工就是只有一种通信方向,即发送或者接收,SPI总线的全双工模式接线方式如下:
5 i# w) Y" J! g# }0 j3 U" x
4 J3 M% U  ^* [
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

7 Y; p* L3 s7 ^
- Y$ ^! i6 j* W5 X* t0 }$ [* h关于这个接线图要认识到以下几点:* s- M$ h5 I, W1 v1 j* p

& O  ^* q( ?4 w( |7 N8 h  未用到的MOSI或者MISO可以用作标准GPIO。
) k8 \! i5 @) }. n- {! ~  这种单一的主从接线模式下,SS引脚可以不使用。  \$ _! ~. P& O
72.2.4 SPI总线星型拓扑& x; v8 C3 [3 `8 W) f4 g
SPI总线星型拓扑用到的地方比较多,V7开发板就是用的星型拓扑外接多种SPI器件:; n* M* j' M! h$ ]* J+ F9 ^6 d
' h/ \2 m3 i% A1 Q. p7 Z
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
1 O' Z. [' K3 z7 u1 z& J# P! z
4 Y8 Q# ]' \4 h( b
关于这个接线图,有以下几点需要大家了解:8 d, [% `( g4 j8 U0 z/ K# @0 s

7 ?+ J- x+ O  Z' d4 c- U  主器件的SS引脚不使用,使用通用GPIO控制。为每个器件配一个SS引脚,方便单独片选控制。1 `& L  U( Z7 J. |; e
  从器件的MISO引脚要配置为复用开漏输出(很多外部芯片在未片选时,数据引脚是呈现高阻态)。' k5 W* i! L9 `' ?$ c9 K
72.2.5 SPI总线通信格式+ K  }9 T) D4 f5 z
SPI总线主要有四种通信格式,由CPOL时钟极性和CPHA时钟相位控制:
, [( P* t' @" W3 _  J& b) x9 l0 z; N7 [# I, C, a0 a) y
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

" t- r- H; F. i( \4 O1 Q" i4 p3 ~. K) I( V$ h/ \- `6 n; y; Y/ u3 n
四种通信格式如下:0 x, g5 O# f) l
5 }$ O: N6 v5 ~& T6 p4 N% X
  当CPOL = 1, CPHA = 1时
4 C& d" U' y  i1 X( E2 ^SCK引脚在空闲状态处于低电平,SCK引脚的第2个边沿捕获传输的第1个数据。
. X0 |# ~8 D+ p; E
! Z5 _1 Y/ V- d8 c# E  当CPOL = 0, CPHA = 1时
3 ^' T8 }9 N# P" H5 \; XSCK引脚在空闲状态处于高电平,SCK引脚的第2个边沿捕获传输的第1个数据。8 K: o; ^& e/ @/ Y+ X5 Y8 }

) }! p# L4 g1 p' @# z  当CPOL = 1, CPHA = 0时4 d3 u3 m: X8 r% e
SCK引脚在空闲状态处于低电平,SCK引脚的第1个边沿捕获传输的第1个数据。- g) n  F$ u: a# {7 f: ^3 @
# ~3 y* J  o2 [+ v$ n
  当CPOL = 1, CPHA = 0时
, [9 ^* x0 R0 j- H, ~/ R& gSCK引脚在空闲状态处于高电平,SCK引脚的第1个边沿捕获传输的第1个数据。
0 L- M: h1 i' R* A6 g. Y4 Y% o4 V) U1 t% a! ]* D% G
72.3 SPI总线的HAL库用法
% o% A! k' I# A& M72.3.1 SPI总线结构体SPI_TypeDef* B" d# Y7 b1 i3 i2 [6 X1 {/ s
SPI总线相关的寄存器是通过HAL库中的结构体SPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:  n4 I- [" s/ ]

- z2 v9 |2 A, ~; x/ y" b& e
  1. typedef struct
    * V1 a. X; s( W) n+ L. K
  2. {, ^6 L& B' M- l( S
  3.   __IO uint32_t CR1;           /*!< SPI/I2S Control register 1,                      Address offset: 0x00 */1 ~3 U' f- k; y9 |$ o, s
  4.   __IO uint32_t CR2;           /*!< SPI Control register 2,                          Address offset: 0x04 */
    6 N  h8 O% v% f2 S' r
  5.   __IO uint32_t CFG1;          /*!< SPI Configuration register 1,                    Address offset: 0x08 */9 B/ }" d; H. x4 q
  6.   __IO uint32_t CFG2;          /*!< SPI Configuration register 2,                    Address offset: 0x0C */
    & K' h/ [+ g, v# U- l
  7.   __IO uint32_t IER;           /*!< SPI/I2S Interrupt Enable register,               Address offset: 0x10 */
    5 _7 X  e% m" ?, v9 k
  8.   __IO uint32_t SR;            /*!< SPI/I2S Status register,                         Address offset: 0x14 */
    ) E' a3 @& I7 h4 \% R
  9.   __IO uint32_t IFCR;          /*!< SPI/I2S Interrupt/Status flags clear register,   Address offset: 0x18 */3 O4 G" ?. S% e: X8 O
  10.   uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                        */8 M6 Q8 p; `/ d$ \- z5 M
  11.   __IO uint32_t TXDR;          /*!< SPI/I2S Transmit data register,                  Address offset: 0x20 */
    / ]% y7 {' y6 K( P# |9 \$ h
  12.   uint32_t      RESERVED1[3];  /*!< Reserved, 0x24-0x2C                                                   */
    " ~/ ~' E* J% v# z
  13.   __IO uint32_t RXDR;          /*!< SPI/I2S Receive data register,                   Address offset: 0x30 */
    1 M- u) ]. Z2 U+ t
  14.   uint32_t      RESERVED2[3];  /*!< Reserved, 0x34-0x3C                                                   */
    / M  @+ T& E( h, ^" f5 N' t$ {
  15.   __IO uint32_t CRCPOLY;       /*!< SPI CRC Polynomial register,                     Address offset: 0x40 */0 l% G( |# h' K$ H9 d
  16.   __IO uint32_t TXCRC;         /*!< SPI Transmitter CRC register,                    Address offset: 0x44 */
    ) q/ x( p5 _& N
  17.   __IO uint32_t RXCRC;         /*!< SPI Receiver CRC register,                       Address offset: 0x48 */
    3 O! i6 `2 s4 w( _  z
  18.   __IO uint32_t UDRDR;         /*!< SPI Underrun data register,                      Address offset: 0x4C */7 A' L" v: a+ O5 i9 L
  19.   __IO uint32_t I2SCFGR;       /*!< I2S Configuration register,                      Address offset: 0x50 */
    ) z. B7 W3 W: H8 e+ F3 Q4 k
  20. % B- R5 q$ M: x! ~
  21. } SPI_TypeDef;
复制代码

% h5 A8 T! V) B, l$ I这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。( T. ~' v: M# a

& L$ i) V# s4 P% l! `- Q6 j7 P; b__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
* v! H! h+ p) ]8 B9 M- ^0 [0 D2 z9 N/ t+ m$ S) s1 }
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
      R  j+ D7 D2 R/ M5 u: X
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

5 X7 j; o) |$ M1 k下面我们看下SPI的定义,在stm32h743xx.h文件。
' D; ?& p: }& V! [2 }# L6 R
; ~, e5 }2 }0 l1 |
  1. #define PERIPH_BASE           (0x40000000UL)
      P- x' \: k" ~6 o
  2. #define D2_APB1PERIPH_BASE     PERIPH_BASE
    # n0 e- B- U; U/ r: O
  3. #define D2_APB2PERIPH_BASE    (PERIPH_BASE + 0x00010000UL)7 a% ^  U3 r) {# l0 J% T/ |; H
  4. #define D3_APB1PERIPH_BASE    (PERIPH_BASE + 0x18000000UL)4 C" O8 b5 t9 F
  5. 8 S1 n1 d& o: g# e1 U  \$ h7 k9 _
  6. #define SPI2_BASE             (D2_APB1PERIPH_BASE + 0x3800UL)
    8 l6 p0 u& n) z# }; A
  7. #define SPI3_BASE             (D2_APB1PERIPH_BASE + 0x3C00UL)
    4 ~  n$ @0 P8 g6 J% z  E
  8. #define SPI1_BASE             (D2_APB2PERIPH_BASE + 0x3000UL)
    ; Y" m, B! d/ s1 ~
  9. #define SPI4_BASE             (D2_APB2PERIPH_BASE + 0x3400UL)/ y0 D0 M; P! t
  10. #define SPI5_BASE             (D2_APB2PERIPH_BASE + 0x5000UL)( L+ F% {! g1 x! _, z+ L
  11. #define SPI6_BASE             (D3_APB1PERIPH_BASE + 0x1400UL), v: ?/ a  S( p2 D9 Y9 T9 [6 h: f

  12. 5 N1 D3 @; D1 c* ]* L# w% W+ b
  13. #define SPI1                ((SPI_TypeDef *) SPI1_BASE)
    5 g' w6 r' {% w& i/ D/ G
  14. #define SPI2                ((SPI_TypeDef *) SPI2_BASE)
    / f9 _) K  f8 r
  15. #define SPI3                ((SPI_TypeDef *) SPI3_BASE)/ N2 D+ I( ?2 y! _. h
  16. #define SPI4                ((SPI_TypeDef *) SPI4_BASE)3 f# }" h) R# T( M
  17. #define SPI5                ((SPI_TypeDef *) SPI5_BASE)
    4 _! p' P3 C$ n; L
  18. #define SPI6                ((SPI_TypeDef *) SPI6_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x58001400
复制代码

9 K' G# W$ n1 B8 K6 S8 a4 f我们访问SPI的CR1寄存器可以采用这种形式:SPI->CR1 = 0。
% F3 O4 Z! @5 l5 }! t# @) e* W3 W" `  g' K. E) d/ I- B
72.3.2 SPI总线初始化结构体SPI_InitTypeDef8 w5 g, T7 p; q6 D% S, m
下面是SPI总线的初始化结构体,用到的地方比较多:4 j# ~' E1 {+ L. i! V
; f  T  \7 Z, F0 g3 `, o1 v: n4 S
  1. typedef struct
    6 W3 j9 `2 T" ^0 Y: B6 w7 F
  2. {5 |& \3 c( [+ W' k
  3.   uint32_t Mode;                           
    4 Y' u/ v. x& P9 w
  4.   uint32_t Direction;                     
    * y/ c- v& _' L4 y" S
  5.   uint32_t DataSize;                          / f7 [: @7 u% [: N
  6.   uint32_t CLKPolarity;                       . p, L: @- ]& p8 I( K
  7.   uint32_t CLKPhase;                         / t4 A2 v" ?1 j* Z. Q
  8.   uint32_t NSS;                             
    * a% a- l+ M. D- d) ^
  9.   uint32_t BaudRatePrescaler;                & E& j) {& y/ U9 ]$ q1 r0 }
  10.   uint32_t FirstBit;                        
    + B: j* e5 A* t5 Z$ V
  11.   uint32_t TIMode;                          ( s  Z6 i% N. Z, V
  12.   uint32_t CRCCalculation;                  
    * y. A6 q  s) d) ]& |3 [
  13.   uint32_t CRCPolynomial;                     / f2 O" o! {4 h& h
  14.   uint32_t CRCLength;                        
    7 k9 |7 {2 a3 B5 E' Y  L8 R. _
  15.   uint32_t NSSPMode;                        
    % {0 f: I, I& F) A7 b
  16.   uint32_t NSSPolarity;                    
    2 @4 i+ m) m8 q4 J: S5 u
  17.   uint32_t TxCRCInitializationPattern;       ; ~) L- R# J, [7 i# x# e
  18.   uint32_t RxCRCInitializationPattern;      
    4 j# A* e/ K+ V2 T7 Z4 W6 e
  19.   uint32_t MasterSSIdleness;                 
    1 {+ r- y6 v7 c0 W* G
  20.   uint32_t MasterInterDataIdleness;           
    2 k; n& b9 E( T7 C+ L$ ]
  21.   uint32_t MasterReceiverAutoSusp;         
    6 e' ^4 P9 y9 Z$ b  Z
  22.   uint32_t MasterKeepIOState;               
    2 z& v9 l! a; J) s5 i4 {2 a/ i
  23.   uint32_t IOSwap;                          ( X  |3 H* Z, V# I. }) U0 {
  24. } SPI_InitTypeDef;
复制代码

+ x/ c4 ^: G, Z: m' B& P下面将结构体成员逐一做个说明:
% m! G! h( M1 P/ C+ ^# p. [) M
) m5 n5 v7 u. A6 n# F  Mode
* b3 S3 [! F1 T& m* J用于设置工作在主机模式还是从机模式。2 W8 N+ D, \4 D% o% t1 B

' R4 U- F& I& g# O6 ?: a. p
  1. #define SPI_MODE_SLAVE              (0x00000000UL): b: g* x/ ?% r5 I" g
  2. #define SPI_MODE_MASTER             SPI_CFG2_MASTER
复制代码

& t- \! T& I5 B- H* W6 o8 @+ g; R  Direction
% m  K" ~# q) t0 c3 q用于设置SPI工作在全双工,单工,还是半双工模式。; A7 u. X8 C$ Q& X; K; R+ s& |4 ?1 Z
  1. #define SPI_DIRECTION_2LINES           (0x00000000UL)     /* 全双工 */
    2 z- D0 j4 X1 V, J2 e& }, S" x$ ]
  2. #define SPI_DIRECTION_2LINES_TXONLY     SPI_CFG2_COMM_0   /* 单工,仅发送 */2 Z) h2 r) ?/ n' i/ h8 a
  3. #define SPI_DIRECTION_2LINES_RXONLY     SPI_CFG2_COMM_1   /* 单工,仅接收 */
    0 X. ^5 `7 F- F6 }( o% R+ x
  4. #define SPI_DIRECTION_1LINE             SPI_CFG2_COMM     /* 半双工 */
复制代码

7 S& v7 G1 S. {& `  DataSize- P6 q# v! }9 X+ W  |
用于设置SPI总线数据收发的位宽,支持4-32bit。2 V7 a* T3 x: J) X$ m' {
! I* b0 I7 ]% i6 F( ]) w" r/ W, J
  1. #define SPI_DATASIZE_4BIT                             (0x00000003UL)' N% g- A5 \0 T5 ?* \* X+ R
  2. #define SPI_DATASIZE_5BIT                             (0x00000004UL)
    8 L" Z1 A% ?* G% u. |
  3. #define SPI_DATASIZE_6BIT                             (0x00000005UL)6 g8 l9 S; I0 l4 z
  4. #define SPI_DATASIZE_7BIT                             (0x00000006UL)$ i6 P9 R2 h& w1 r" l7 u
  5. #define SPI_DATASIZE_8BIT                             (0x00000007UL)& D8 j* l  J0 v8 P0 T
  6. #define SPI_DATASIZE_9BIT                             (0x00000008UL)
    * H' Y# r6 Q9 j6 T4 d
  7. #define SPI_DATASIZE_10BIT                            (0x00000009UL), c2 @% z( Z" l  S' G; Y' R/ A: t+ ^* \
  8. #define SPI_DATASIZE_11BIT                            (0x0000000AUL)2 h9 I% v5 N0 K% X
  9. #define SPI_DATASIZE_12BIT                            (0x0000000BUL)
    3 g, z" s4 Y3 l1 }; N6 g% q) p
  10. #define SPI_DATASIZE_13BIT                            (0x0000000CUL)
    " S9 F2 y% G& Q9 m; X0 G, @
  11. #define SPI_DATASIZE_14BIT                            (0x0000000DUL)
    5 ~( _' ~# ^8 U$ u) u
  12. #define SPI_DATASIZE_15BIT                            (0x0000000EUL)
      |; @- ]' P: |6 }6 H
  13. #define SPI_DATASIZE_16BIT                            (0x0000000FUL)
    3 R0 R+ E% ]7 x8 y3 V: m' l
  14. #define SPI_DATASIZE_17BIT                            (0x00000010UL)
    # c% Z2 @" B2 c0 m' m/ c4 K) ?
  15. #define SPI_DATASIZE_18BIT                            (0x00000011UL)- [' T- |! ]2 k. u3 H- c
  16. #define SPI_DATASIZE_19BIT                            (0x00000012UL)8 Y- G! I1 o3 W/ c  H# a% c
  17. #define SPI_DATASIZE_20BIT                            (0x00000013UL)# Q2 T+ s' C. {$ e7 D
  18. #define SPI_DATASIZE_21BIT                            (0x00000014UL)0 R$ N; z8 i" m) p2 K# s
  19. #define SPI_DATASIZE_22BIT                            (0x00000015UL): u: P# L' X3 L. [7 s
  20. #define SPI_DATASIZE_23BIT                            (0x00000016UL)
    % ^, B+ v! h, P1 X4 z* d& s# |2 i
  21. #define SPI_DATASIZE_24BIT                            (0x00000017UL)8 P/ A  X1 ?5 i4 Z  p
  22. #define SPI_DATASIZE_25BIT                            (0x00000018UL)
    ; M# r! ~3 S3 t! [2 g, e: d; B4 ?" \% \
  23. #define SPI_DATASIZE_26BIT                            (0x00000019UL), d1 y- i+ g' N" Z2 I: g
  24. #define SPI_DATASIZE_27BIT                            (0x0000001AUL)
    - S8 l1 q/ n7 J9 H* ?+ W
  25. #define SPI_DATASIZE_28BIT                            (0x0000001BUL)# t& r" M8 L. ~& _* {
  26. #define SPI_DATASIZE_29BIT                            (0x0000001CUL)6 a9 X7 J2 C" o$ l
  27. #define SPI_DATASIZE_30BIT                            (0x0000001DUL)8 c, e( M0 q# P, z1 R
  28. #define SPI_DATASIZE_31BIT                            (0x0000001EUL)! U, t$ l1 v2 f/ I) A/ S
  29. #define SPI_DATASIZE_32BIT                            (0x0000001FUL)
复制代码

8 B$ J( w& L' k. Q  CLKPolarity/ G9 G4 z2 X5 o; T9 r/ E+ W5 l" j
用于设置空闲状态时,CLK是高电平还是低电平。' r( w, i3 w' z
& v* c. T% I8 s
  1. #define SPI_POLARITY_LOW       (0x00000000UL)  u8 ]; `+ _. c9 c
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码
0 u& o- [" ~( N6 p. J
  NSS
1 S9 }: k7 ~" b2 i8 @' c. f用于设置NSS信号由硬件NSS引脚管理或者软件SSI位管理。
+ f7 N7 \$ D# B9 e4 m, y1 \# R
6 z4 @. i1 h1 W$ {( d% h& E
  1. #define SPI_NSS_SOFT                                  SPI_CFG2_SSM( B$ V3 L, P$ r
  2. #define SPI_NSS_HARD_INPUT                            (0x00000000UL)1 o$ Y% J6 m. m! [" g1 q/ K7 T6 ]$ R
  3. #define SPI_NSS_HARD_OUTPUT                           SPI_CFG2_SSOE
复制代码

1 j; f, v4 u1 d  J1 e  BaudRatePrescaler- J* K7 z$ Z: Q; q) K, @
用于设置SPI时钟分频,仅SPI工作在主控模式下起作用,对SPI从机模式不起作用。
: b; I* N4 o6 \) Y7 x/ Y# H
+ _. N% e# ~- q3 r$ I8 E' q6 q
  1. #define SPI_BAUDRATEPRESCALER_2                       (0x00000000UL)
    7 k/ o, J3 t; w  D& Q9 `
  2. #define SPI_BAUDRATEPRESCALER_4                       (0x10000000UL)
    1 l- c0 L9 o! `- w
  3. #define SPI_BAUDRATEPRESCALER_8                       (0x20000000UL)3 U, t4 n; K4 j6 H; e
  4. #define SPI_BAUDRATEPRESCALER_16                      (0x30000000UL)% {* y( h, L, U$ ~
  5. #define SPI_BAUDRATEPRESCALER_32                      (0x40000000UL)2 I2 N. U" H4 Y: A! g4 W4 `& }
  6. #define SPI_BAUDRATEPRESCALER_64                      (0x50000000UL)
    + r7 A$ t0 \, _" H9 M" B
  7. #define SPI_BAUDRATEPRESCALER_128                     (0x60000000UL)
    : S+ s% c/ l  l* |$ t
  8. #define SPI_BAUDRATEPRESCALER_256                     (0x70000000UL)
复制代码

& e  {- I, g$ ]  FirstBit! c+ S4 }0 I6 m+ |4 O0 V; I
用于设置数据传输从最高bit开始还是从最低bit开始。
  M; t: V; T* r* S/ b( {9 C6 b% `9 M# t  e
  1. #define SPI_FIRSTBIT_MSB                              (0x00000000UL)
    3 F9 L$ K. P0 J
  2. #define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST
    3 c; C" @& _* V
复制代码
% |0 M4 {! s& {- I: F" ~
  TIMode' M! ?( m0 H' m( H
用于设置是否使能SPI总线的TI模式。
0 P, i! y& y- {3 [3 E+ r* I2 v3 `: I; q1 S3 f
  1. #define SPI_TIMODE_DISABLE               (0x00000000UL)
    9 P% u/ ?$ J; G& I: W) I2 w
  2. #define SPI_TIMODE_ENABLE                SPI_CFG2_SP_0
复制代码

* Y. O, S4 s; i# B  CRCCalculation& c; W3 U2 a* ~0 V: U- \
用于设置是否使能CRC计算。
* a$ v- W* i4 O  q2 E7 I7 @" S4 G, q7 M) F
  1. #define SPI_CRCCALCULATION_DISABLE                    (0x00000000UL)
    : v- b2 K1 a' o1 h
  2. #define SPI_CRCCALCULATION_ENABLE                     SPI_CFG1_CRCEN
复制代码
. S" i- q  V" z& z0 f* a* X5 b( p
  CRCPolynomial
1 w; B! x& o" k5 t* Q用于设置CRC计算使用的多项式,必须是奇数,范围0到65535。, u2 B& C- H+ r& V! p

: w, Y* N( A- |* w0 W: r  p$ }  CRCLength
, a' b7 n1 t1 Y$ w2 Y用于设置CRC计算时的CRC长度。大小要与同属此结构体的DataSize一致。或是DataSize的整数倍。
) ^3 }8 w0 d- Z% k
6 i- r: U( }' e/ f
  1. #define SPI_CRC_LENGTH_DATASIZE                       (0x00000000UL)) M2 C8 H( L! P- j% E+ i
  2. #define SPI_CRC_LENGTH_4BIT                           (0x00030000UL)5 b$ }/ O4 d; m
  3. #define SPI_CRC_LENGTH_5BIT                           (0x00040000UL)# @$ R; W/ H+ r( y5 ^5 C1 a  G& v
  4. #define SPI_CRC_LENGTH_6BIT                           (0x00050000UL)' T- B4 o! n8 X  a+ C2 J/ X
  5. #define SPI_CRC_LENGTH_7BIT                           (0x00060000UL)* ^1 Q! u' D- C# ?
  6. #define SPI_CRC_LENGTH_8BIT                           (0x00070000UL)( T9 M$ f+ y. D$ D
  7. #define SPI_CRC_LENGTH_9BIT                           (0x00080000UL)
    6 [* I4 g* x$ u. q
  8. #define SPI_CRC_LENGTH_10BIT                          (0x00090000UL)0 r+ {: d, q6 n6 a( w$ M4 H% a
  9. #define SPI_CRC_LENGTH_11BIT                          (0x000A0000UL)
    : a3 w; [1 n. ^2 \: D
  10. #define SPI_CRC_LENGTH_12BIT                          (0x000B0000UL)
    ' [9 A! G( ^# v0 F8 F  C
  11. #define SPI_CRC_LENGTH_13BIT                          (0x000C0000UL)
    ! m5 t  O' Q! E' z4 |4 S: v
  12. #define SPI_CRC_LENGTH_14BIT                          (0x000D0000UL)
    3 K1 b* o9 e4 c1 U4 O, J2 M8 q
  13. #define SPI_CRC_LENGTH_15BIT                          (0x000E0000UL)4 W5 K2 y( d( ]. G1 @( w7 I5 v" \" f8 u
  14. #define SPI_CRC_LENGTH_16BIT                          (0x000F0000UL)+ }) R& g% B0 L
  15. #define SPI_CRC_LENGTH_17BIT                          (0x00100000UL)& K6 r% i# U2 Y# I8 n; u
  16. #define SPI_CRC_LENGTH_18BIT                          (0x00110000UL)
    . _) w" I- H& Q: W3 L
  17. #define SPI_CRC_LENGTH_19BIT                          (0x00120000UL)
    & w( M9 Y2 H9 z2 U9 Y2 C( n
  18. #define SPI_CRC_LENGTH_20BIT                          (0x00130000UL)
    9 N. |$ W) k2 y$ R4 L5 w8 C/ _6 P
  19. #define SPI_CRC_LENGTH_21BIT                          (0x00140000UL)
    ! ~/ v/ s: P; g' j% M7 k
  20. #define SPI_CRC_LENGTH_22BIT                          (0x00150000UL)
    / x( |+ U! ]; Y9 z+ k* u- c
  21. #define SPI_CRC_LENGTH_23BIT                          (0x00160000UL)
    % ~, z. Z9 g( S. P/ f
  22. #define SPI_CRC_LENGTH_24BIT                          (0x00170000UL)
    9 Q: R, e7 y& E9 _* M
  23. #define SPI_CRC_LENGTH_25BIT                          (0x00180000UL)1 u3 G# B+ {& X. q
  24. #define SPI_CRC_LENGTH_26BIT                          (0x00190000UL)
    # p. R; y3 S* Y' |9 ^0 T
  25. #define SPI_CRC_LENGTH_27BIT                          (0x001A0000UL)
    . z' h( m/ |, T& s# r, w! B
  26. #define SPI_CRC_LENGTH_28BIT                          (0x001B0000UL)
    * g5 Q% D7 j4 e) A" _
  27. #define SPI_CRC_LENGTH_29BIT                          (0x001C0000UL)
    - p( ^0 ?  L! |9 p# E/ b
  28. #define SPI_CRC_LENGTH_30BIT                          (0x001D0000UL)* C' }* \0 w8 P) A  {, j
  29. #define SPI_CRC_LENGTH_31BIT                          (0x001E0000UL)' v3 Q2 t! h9 Q% a# d
  30. #define SPI_CRC_LENGTH_32BIT                          (0x001F0000UL)
复制代码

; v+ y; B! Z9 [2 s3 z+ E* p" g; g" A- {" _0 g

& u2 G/ a* |" L$ J8 o, W& l  NSSPMode0 l' n. h2 H, e: _) U* Y/ Z
用于设置是否使能NSSP信号,可以通过SPIx_CR2寄存器的SSOM位使能。注意,只有配置为摩托罗拉SPI主控模式时设置此成员才有用。6 u; L, z. Y( L4 ^5 {, h' w8 u( y
2 S4 R' k1 A* {
  1. #define SPI_NSS_PULSE_DISABLE                         (0x00000000UL)
    8 B/ I8 l  t) d/ r  B6 S
  2. #define SPI_NSS_PULSE_ENABLE                          SPI_CFG2_SSOM
复制代码

0 c- D6 }" w0 d! I( v  NSSPolarity: P1 n+ k0 s7 k) q
用于设置NSS引脚上的高电平或者低电平作为激活电平。
1 s+ `" H/ h) b, y4 \8 X: Y" o+ g0 o3 @5 W
  1. #define SPI_NSS_POLARITY_LOW                          (0x00000000UL)2 g& ]' \% `' h; U3 D
  2. #define SPI_NSS_POLARITY_HIGH                          SPI_CFG2_SSIOP
复制代码

; R0 J) O0 C3 m1 _3 e4 r2 g) X  FifoThreshold
+ y8 m9 u4 p* Y9 A$ ~用于设置SPI的FIFO阀值。
' U( `6 {# v. d. p7 a2 r/ v) _  A" ]* R" R
  1. #define SPI_FIFO_THRESHOLD_01DATA                     (0x00000000UL)3 y- k) S: l8 y8 O7 L3 {0 ~) [
  2. #define SPI_FIFO_THRESHOLD_02DATA                     (0x00000020UL)
    9 G1 s2 {$ R/ D8 W# d2 B5 l' z
  3. #define SPI_FIFO_THRESHOLD_03DATA                     (0x00000040UL)$ ]% e8 n8 f( I# c" p8 L; G: c! k4 `
  4. #define SPI_FIFO_THRESHOLD_04DATA                     (0x00000060UL)- S) k- ^. ~& W
  5. #define SPI_FIFO_THRESHOLD_05DATA                     (0x00000080UL)' Y) m! e" ~' y) Z, i7 C
  6. #define SPI_FIFO_THRESHOLD_06DATA                     (0x000000A0UL)6 O  B1 u' V/ R0 c5 R2 Y( L4 K
  7. #define SPI_FIFO_THRESHOLD_07DATA                     (0x000000C0UL)
    ) I% o# J8 D) n7 u2 b
  8. #define SPI_FIFO_THRESHOLD_08DATA                     (0x000000E0UL)
    9 z9 \: e& B- r: G- i8 I
  9. #define SPI_FIFO_THRESHOLD_09DATA                     (0x00000100UL)5 \2 ?8 M8 B! S% T  B: M
  10. #define SPI_FIFO_THRESHOLD_10DATA                     (0x00000120UL)6 r& P$ n# V* j, o7 [4 c! O
  11. #define SPI_FIFO_THRESHOLD_11DATA                     (0x00000140UL)
    * V5 @7 A3 ^- G
  12. #define SPI_FIFO_THRESHOLD_12DATA                     (0x00000160UL)
    ( U! }" R* ]1 F1 j( V( ^2 a8 a0 @
  13. #define SPI_FIFO_THRESHOLD_13DATA                     (0x00000180UL)
    5 _" q& Q0 _' o' P/ H
  14. #define SPI_FIFO_THRESHOLD_14DATA                     (0x000001A0UL)6 U6 {3 R' X! [
  15. #define SPI_FIFO_THRESHOLD_15DATA                     (0x000001C0UL)4 S' Z1 X9 P" U
  16. #define SPI_FIFO_THRESHOLD_16DATA                     (0x000001E0UL)
    & f3 n8 ]( f- x# d' B3 U
复制代码
6 H$ @4 k) b) y0 t5 K* A7 S! F

5 t( i7 x- `9 K8 s0 Y" Q  TxCRCInitializationPattern
; S/ H, ~1 B- L  c; a  @5 \发送CRC初始化模式。: X. w: [% E' S. G, z4 g

5 i: M7 O/ ?. K3 C. z
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    7 s- f" [$ i% X* p6 V
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)! k9 r; S: i: Q5 j$ X5 `
复制代码
8 E! `8 V1 t0 |, s$ j% R+ c
  RxCRCInitializationPattern
: N7 d- M$ Z* W% c接收CRC初始化模式
9 f: b& G. U6 L+ U5 ~( D" t
5 H- K; y  f6 D3 b
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL); a9 u2 @6 z, k1 f7 o
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码

5 A$ [1 ]8 o+ e$ ` MasterSSIdleness; S' Y1 T# s) L2 Q* U
在主模式下插入到SS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数。
& \' ~, {  ^( A, r" D! J8 X, }/ `4 _- P8 k6 I9 y) }: _* v. f; T
  1. #define SPI_MASTER_SS_IDLENESS_00CYCLE                (0x00000000UL)3 E: `& Z8 B& U' C  q& N
  2. #define SPI_MASTER_SS_IDLENESS_01CYCLE                (0x00000001UL)
    - R3 g$ _4 m7 V
  3. #define SPI_MASTER_SS_IDLENESS_02CYCLE                (0x00000002UL)
    " M. m+ `( Z* j9 Y
  4. #define SPI_MASTER_SS_IDLENESS_03CYCLE                (0x00000003UL)
    ; p4 ~' {' [6 C' d0 `+ `
  5. #define SPI_MASTER_SS_IDLENESS_04CYCLE                (0x00000004UL)
    " |" Z, n7 q! }1 y4 K- v; O
  6. #define SPI_MASTER_SS_IDLENESS_05CYCLE                (0x00000005UL)
    % T# x& Y% v3 K/ W
  7. #define SPI_MASTER_SS_IDLENESS_06CYCLE                (0x00000006UL)
    " p# f4 k+ U8 e; E1 ?
  8. #define SPI_MASTER_SS_IDLENESS_07CYCLE                (0x00000007UL)
    , U) P1 f  h* S, ~
  9. #define SPI_MASTER_SS_IDLENESS_08CYCLE                (0x00000008UL)3 y4 o( Z/ @# b1 F$ e
  10. #define SPI_MASTER_SS_IDLENESS_09CYCLE                (0x00000009UL); M5 \- R2 l4 N% r3 @
  11. #define SPI_MASTER_SS_IDLENESS_10CYCLE                (0x0000000AUL)
    3 `" R' n7 `+ b2 X9 e7 A( n$ D
  12. #define SPI_MASTER_SS_IDLENESS_11CYCLE                (0x0000000BUL)
    0 G/ X# h. ?+ W9 r8 V1 U; z" ]
  13. #define SPI_MASTER_SS_IDLENESS_12CYCLE                (0x0000000CUL)7 F; ~) i' W" p+ w1 V
  14. #define SPI_MASTER_SS_IDLENESS_13CYCLE                (0x0000000DUL)
    ) Y5 r+ Q! k  a7 `6 o% [7 }
  15. #define SPI_MASTER_SS_IDLENESS_14CYCLE                (0x0000000EUL)' r  {+ x5 T& R8 ^
  16. #define SPI_MASTER_SS_IDLENESS_15CYCLE                (0x0000000FUL)
    . q% L% x) r) f! J) s) _- I
复制代码
0 ^  O: G/ C. x& ?( L
, C0 @" j5 z; v+ T
  MasterInterDataIdleness0 x- r, E8 I+ k& U$ e
主模式下在两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数。
& _  z! k; @' ]- H6 }( w  t" u! R
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)
    : q7 g6 q/ b% P5 B
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
复制代码

3 P8 ?6 r" M- J! D* J  \  ~) t$ `) t: e  MasterReceiverAutoSusp1 R9 P: {  V+ L) F
用于控制主器件接收器模式下的连续 SPI 传输以及自动管理,以避免出现上溢情况。
' Z+ Z4 ~; K7 l4 k2 j; u( G5 S& _7 V, P
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)
    % u9 F$ l+ t% h$ l1 l7 U
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX: X$ D2 S! z- W4 M- D$ n
复制代码

- @. A( c* c$ ^0 B+ ~/ x. l  MasterKeepIOState
' B6 g: @# ?+ Q) O. R禁止SPI后,SPI相关引脚保持当前状态,以防止出现毛刺。在从模式下,该位不应该使用。2 y9 n( s' E8 o1 y: V
, e  T) b! a/ x1 e$ e
  1. #define SPI_MASTER_KEEP_IO_STATE_DISABLE              (0x00000000UL)0 D; L, y" H! e) F
  2. #define SPI_MASTER_KEEP_IO_STATE_ENABLE               SPI_CFG2_AFCNTR
复制代码

' a+ c& e% l7 c# g7 |4 M) j  IOSwap* Y0 i! W, {3 |$ E4 @: [
用于交换MISO和MOSI引脚。6 ^; Z$ G1 F% M7 S3 m

4 s; _. ~, Q2 R; ^0 ]
  1. #define SPI_IO_SWAP_DISABLE                           (0x00000000UL)
    2 l+ b* v0 Q. V
  2. #define SPI_IO_SWAP_ENABLE                            SPI_CFG2_IOSWP
复制代码
! M3 {$ O" ~! {2 M8 G& c  H, w, F% K
72.3.3 SPI总线句柄结构体SPI_HandleTypeDef( Y9 r1 I( G7 B/ J
下面是SPI总线的初始化结构体,用到的地方比较多:
* K9 T5 B  s: q; o
3 e$ \2 v/ o' {% M, Z1 m
  1. typedef struct __SPI_HandleTypeDef
    ) r  A5 \  c! y
  2. {
    ( s! @# j4 E  y; O( w" n: C$ \
  3.   SPI_TypeDef                *Instance;                 $ j1 H; n% b' g
  4.   SPI_InitTypeDef            Init;                        
    6 p+ N6 t& E+ q( q, T7 H7 n& W
  5.   uint8_t                    *pTxBuffPtr;                 
    / Q* w/ E" M& q$ N' C# O( v* `' L
  6.   uint16_t                   TxXferSize;                  
    2 o! @- B9 N/ b# e' E" S8 F9 k$ p
  7.   __IO uint16_t              TxXferCount;                  % S7 j: U5 S6 @2 ~
  8.   uint8_t                    *pRxBuffPtr;               
    & T  ]  ]4 L  G
  9.   uint16_t                   RxXferSize;                  : Z+ V4 }% q; [+ J
  10.   __IO uint16_t              RxXferCount;                 $ M) P" X. ]0 P& c
  11.   uint32_t                   CRCSize;                     
    ) I. N& I% E  ]  i: H
  12.   void (*RxISR)(struct __SPI_HandleTypeDef *hspi);      
    6 q8 |. F5 u/ L: ?: H1 i' V
  13.   void (*TxISR)(struct __SPI_HandleTypeDef *hspi);        
    & s$ s! n( ^/ \
  14.   DMA_HandleTypeDef          *hdmatx;                     
    ; L: v# C1 j% M( j* ?6 n! t2 e
  15.   DMA_HandleTypeDef          *hdmarx;                     $ [& l0 \+ G  Q3 {: c  D8 S/ A5 y
  16.   HAL_LockTypeDef            Lock;                        * R9 m) X8 c% {  [
  17.   __IO HAL_SPI_StateTypeDef  State;                        ' q( Y( k8 H8 S: S: k2 r2 s
  18.   __IO uint32_t              ErrorCode;                   5 z  `2 m3 D/ A! M
  19. #if defined(USE_SPI_RELOAD_TRANSFER)/ H6 [1 S* t- |, d; r1 {
  20.   SPI_ReloadTypeDef          Reload;                     
    # v" l% l$ `8 \1 _) n+ r
  21. #endif 9 p3 y2 E1 P7 ^9 h* @
  22. / m' q# z; Y* E! S& w2 V
  23. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    & v+ h8 T# S# o! a, l
  24.   void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      , @, n# l. t. e2 }+ g, h) u# I' d
  25.   void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      5 \2 G! z7 f3 Z: Z+ e
  26.   void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    " Q% ~2 J: ~7 O' E( ~! t( ?
  27.   void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  * I; _& ]; C0 |! x8 u+ R1 V: I
  28.   void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  
    , g, s! q+ f$ `. Q3 Q9 o
  29.   void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);
    1 P! S3 o* s; X! d- y
  30.   void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi);      
    5 @  t* ~1 J- ^7 \7 j8 i
  31.   void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi);   ) ]4 O4 b4 g3 t$ Z
  32.   void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi);   
    ; e" A3 s0 w/ _* D5 K
  33.   void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi); $ D3 u4 q0 _! r" A/ v+ }  a9 z+ D
  34. #endif  . Z5 G0 b* }0 E' J2 N) z8 p# ]
  35. } SPI_HandleTypeDef;+ Q0 a! ^7 A7 n" T8 h% c) {' f
复制代码

  `! d8 ~, B9 v1 N
# Q2 o% Z, m9 N7 X注意事项:
3 f* _% P+ w7 ~. e/ ^) M' d7 }8 h3 _/ d& [% R$ {+ V& y5 Y+ C  U1 r
条件编译USE_HAL_SPI_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:& K. w; J- K7 M7 o

) L) T: k( Q. t; U; H" z8 c  #define   USE_HAL_SPI_REGISTER_CALLBACKS   11 k  G& V6 ?/ z; g2 ?* M* \& l

5 c. ~( D6 U$ u% z) Y通过函数HAL_SPI_RegisterCallback注册回调,取消注册使用函数HAL_SPI_UnRegisterCallback。
; l, P1 K- X% }
: I+ T9 a3 V1 d! T: ]- v这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。
( v) J8 b9 W* ]* K% I) O, M
: b+ ]& `& \- X; v3 i  SPI_TypeDef   *Instance9 R, [: L, v5 `
这个参数是寄存器的例化,方便操作寄存器,比如使能SPI1。6 a$ j: x: }) o

4 W/ V! j: a6 WSET_BIT(SPI1 ->CR1,  SPI_CR1_SPE)。
3 A$ e/ C& X$ \: l( w+ ?: E5 ^' o# z/ }/ Q1 i/ |
  SPI_InitTypeDef  Init) a5 g$ r- D; R
这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。& C# A0 \  r- g8 t- n
1 }" K! s' f2 M8 T! h
  DMA_HandleTypeDef          *hdmatx               & f  S* e4 A0 k: y
  DMA_HandleTypeDef          *hdmarx
$ u3 M& m; b, q1 h用于SPI句柄关联DMA句柄,方便操作调用。
/ F( @( A: ]. {2 N( `$ y! G- Q9 x0 D
72.4 SPI总线源文件stm32h7xx_hal_spi.c9 |0 S! z& R9 k: K8 w( {9 L
此文件涉及到的函数较多,这里把几个常用的函数做个说明:# O, G% j4 z* b" ?" X$ |3 W

1 \( F) Z  C6 V( p/ e  HAL_SPI_Init
: u; L* M3 |( W- u% W- m  HAL_SPI_DeInit7 k% i$ l2 I5 W" B" s' k, o& ^
  HAL_SPI_TransmitReceive4 ]# s& p+ O; [7 q- h6 n. l
  HAL_SPI_TransmitReceive_IT/ f6 k: `  W6 Y4 r/ N/ C! c0 Q; K5 s0 W& A
  HAL_SPI_TransmitReceive_DMA
  t3 ]% ]1 o& C72.4.1 函数HAL_SPI_Init- m' R+ L* b  R  n: `7 g
函数原型:
4 r9 x0 W7 \8 ^8 S) w* u" z! j6 a
  1. HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)
    % _. a- l$ H. V3 w3 e0 m2 j6 K! O
  2. {
    ( g3 T3 V3 V3 }8 ^1 j+ a0 s
  3.   uint32_t crc_length = 0UL;
    : V' o. n4 u% \0 A1 l
  4.   uint32_t packet_length;
    2 c4 L/ r6 h" C3 F; _7 D' t7 h
  5. 6 E' u6 G  G$ Q/ `
  6.   /* 省略未写 */
    + ]9 q1 F3 X/ k, [& [" J

  7. 6 P* |+ N. Y- V! s- w$ e
  8.   /* 如果数据位宽大于16bit,必须是SPI1,SPI2或者SPI3,而SPI4,SPI5和SPI6不支持大于16bit */
    . S/ d* H4 @' S" Q- W. h7 B# E
  9.   if ((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (hspi->Init.DataSize > SPI_DATASIZE_16BIT))4 |2 ?& |/ r9 ]. w' v( [
  10.   {
    0 j& K* ~6 e, M& r# x
  11.     return HAL_ERROR;
    $ Y2 _6 o( l' N
  12.   }2 y" w) N# H$ x: [& v) M
  13. ) {. S) N- v4 N* S
  14.   /* SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit
    8 i8 l( b# h; M& j4 `
  15.      这里是查看设置的缓冲大小是否超出了FIFO支持的大小。
    ! G) z* T- o- Q1 _
  16. */
    4 Y4 m7 c6 `4 A
  17.   packet_length = SPI_GetPacketSize(hspi);4 E9 h" q$ K6 ^
  18.   if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_LOWEND_FIFO_SIZE)) ||
    * [4 r  F: m$ P
  19.       ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_HIGHEND_FIFO_SIZE)))
    ( ]% d: [2 c% C: K
  20.   {, V1 d+ Z1 L0 t
  21.     return HAL_ERROR;0 q. B. @) ^3 i6 l
  22.   }% S- R+ o7 P* |8 Z

  23. : G0 ]' b! e! f5 y
  24. #if (USE_SPI_CRC != 0UL)
    2 J3 z& N/ J6 Z4 m  a) A
  25.     /* 省略未写 */
    6 s7 T  W2 D/ A9 D
  26. #endif 6 [$ B: D8 K; }7 {
  27. , Z6 _, B+ E* h" S) Z& P
  28.   if (hspi->State == HAL_SPI_STATE_RESET)
    : G! I! ^+ o9 R+ p
  29.   {% e/ a* L; y3 V+ ~4 _  b5 T
  30.     /* 解锁 */0 y# Q! [2 I& \! G) ^# v
  31.     hspi->Lock = HAL_UNLOCKED;1 x  D; X. l2 s* P) g, F
  32. 8 B4 l% C. u2 i3 B0 h. X
  33.     /* 使用自定义回调 */
      J5 s! }, o  B: ]* H5 e9 R4 [4 W
  34. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)% P" @, h4 `5 z
  35.     /* 设置默认回调函数 */
      L' G' m. _) t
  36.     hspi->TxCpltCallback       = HAL_SPI_TxCpltCallback;       /* Legacy weak TxCpltCallback       */# j. O) C9 C* H) e3 H& L0 ~0 F
  37.     hspi->RxCpltCallback       = HAL_SPI_RxCpltCallback;       /* Legacy weak RxCpltCallback       */
    # T+ `/ v/ T$ U3 B; D
  38.     hspi->TxRxCpltCallback     = HAL_SPI_TxRxCpltCallback;     /* Legacy weak TxRxCpltCallback     */
    - d3 V: H7 K2 @( {
  39.     hspi->TxHalfCpltCallback   = HAL_SPI_TxHalfCpltCallback;   /* Legacy weak TxHalfCpltCallback   *// X+ J) U, F% k. y* O1 p
  40.     hspi->RxHalfCpltCallback   = HAL_SPI_RxHalfCpltCallback;   /* Legacy weak RxHalfCpltCallback   */! n/ E. ~3 A( s/ G& M( M
  41.     hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */
    7 F$ Z  w+ F. Z
  42.     hspi->ErrorCallback        = HAL_SPI_ErrorCallback;        /* Legacy weak ErrorCallback        */
    1 n% m  m3 }% c8 I4 u7 q
  43.     hspi->AbortCpltCallback    = HAL_SPI_AbortCpltCallback;    /* Legacy weak AbortCpltCallback    */8 ?: E, P1 k! ]3 O* V- z# @

  44. ' B/ v& o7 t8 a! y$ g0 M) t5 v# G# d
  45.     if (hspi->MspInitCallback == NULL)
    1 B* h7 X5 X# v8 ~8 c
  46.     {
    : C! L/ m" j3 ?; h
  47.       hspi->MspInitCallback = HAL_SPI_MspInit;
    - K; ?8 B" j2 g- f0 i2 u
  48.     }4 q) {% k- L  f6 Q$ D
  49. 5 D  r4 t0 E( z7 e  ^
  50.     /* 初始化地址硬件: GPIO, CLOCK, NVIC... */5 Y2 O5 s; O2 T5 C
  51.     hspi->MspInitCallback(hspi);5 _% u+ F0 r# T* g6 d4 }* I- I
  52. #else
    * {- y% n$ V. ^9 L7 C* L
  53.     /* 初始化底层硬件: GPIO, CLOCK, NVIC... */
    + t& u  [, u! C. Y$ Z7 p* g& G1 P
  54.     HAL_SPI_MspInit(hspi);- q; y2 O* g, j$ c8 I/ r
  55. #endif! v% C. E  y! w6 J3 p2 W5 K
  56.   }
    9 Y0 I! E2 {0 U" S1 @

  57. # M& V1 X+ q1 p
  58.   hspi->State = HAL_SPI_STATE_BUSY;8 u* H/ K5 s& P
  59. 5 D/ X1 N* x! Y; H* v& I, h/ O
  60.   /* 禁止SPI外设 */
    3 J+ G! i( h8 W& i8 a
  61.   __HAL_SPI_DISABLE(hspi);
    7 x6 W7 M6 ]. g) d: H! r
  62. 4 W7 g( t& Z" f# z2 A& C. I8 Q
  63.   /*----------------------- SPIx CR1 & CR2 配置---------------------*/, f0 d7 l  n% O4 M% T! W3 V
  64.   if ((hspi->Init.NSS == SPI_NSS_SOFT) && (hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.NSSPolarity ==
    $ \6 ~  J3 N, s( L! @3 X. x" t
  65. SPI_NSS_POLARITY_LOW))
    " h' b. e7 {, k) v% [& g
  66.   {% h( r' T8 c7 H6 Y
  67.       SET_BIT(hspi->Instance->CR1, SPI_CR1_SSI);# q; @# a2 }$ z' e9 E3 d* ?- r
  68.   }; |& K5 r' A4 O0 n' k4 M, o
  69. ' C, k8 C: U1 U' z; ]$ a# T
  70.   /* SPIx CFG1配置 */* f0 X4 e' M. M, C, H- T" m% X
  71.   WRITE_REG(hspi->Instance->CFG1, (hspi->Init.BaudRatePrescaler | hspi->Init.CRCCalculation | crc_length |
    ( f+ `5 U( K8 V! V
  72.                                    hspi->Init.FifoThreshold     | hspi->Init.DataSize));& V' c, c; g' j4 t) O+ g; e
  73. - d9 A* D% C' L# J( Y* x/ N# ?
  74.   /* SPIx CFG2配置 */  R' C  a' @2 K7 q) k
  75.   WRITE_REG(hspi->Instance->CFG2, (hspi->Init.NSSPMode     | hspi->Init.TIMode           | hspi->Init.NSSPolarity  |
    ; q" m9 F$ ], c" ~& l
  76.                                    hspi->Init.NSS          | hspi->Init.CLKPolarity      | hspi->Init.CLKPhase     |
    8 p/ J- e7 [* Z! S# @" ]% G
  77.                                    hspi->Init.FirstBit     | hspi->Init.Mode             | hspi->Init.MasterInterDataIdleness |
    1 G. o) p9 M+ L$ c
  78.                                    hspi->Init.Direction    | hspi->Init.MasterSSIdleness | hspi->Init.IOSwap));
    . Y/ U0 O) w- ?# e

  79. , Y2 H5 x- r! I
  80. #if (USE_SPI_CRC != 0UL)8 K  p. }' v  {! t$ _! _% y
  81.   /*---------------------------- SPIx CRC配置 ------------------*/
    6 V  H  I  v( u. {& M. h" k; l
  82.   /* 配置SPI CRC */
    1 F* L& t& E* Z7 l3 W- u1 m- f& u8 D
  83.   if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
    9 i7 G: a) D5 F3 q( y: Z3 F
  84.   {
    ) ]! s  M2 ?/ x/ D; L% J
  85.     /* 初始化TX CRC初始值 */, j% U- f* \7 B2 d8 M( x, d
  86.     if (hspi->Init.TxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)9 J% `6 R; T' B- k! f# _* Q5 Y
  87.     {/ R6 i) B$ G& C  P$ b3 ~
  88.       SET_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);; F! \! S0 W1 P# r! a, w% k4 B5 [
  89.     }
    1 ?% V4 U. W0 w' [% U- D$ f+ S# [4 y' g
  90.     else
    3 }0 @4 J* G2 x0 r; O3 L/ }
  91.     {6 ~7 b0 {8 f  e$ v. Y
  92.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);
    * n0 g' B& E/ y8 h
  93.     }* T) y. t+ E5 R+ g- N
  94. ) S! [$ G* c7 E# H5 I2 O
  95.     /* 初始化RXCRC初始值 */* z; q6 N7 A+ x$ J8 J, |
  96.     if (hspi->Init.RxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)9 b: [& A+ q# ]9 u3 i/ x
  97.     {4 B+ S/ Y3 N9 F+ m5 O
  98.       SET_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);
    6 b0 W1 A$ l, m, q
  99.     }
    2 [& M$ e, U4 z; L6 t3 P
  100.     else
    / j- w$ ]6 ^, x1 Z
  101.     {
    % F5 |: @5 }( y
  102.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);
    % h& I6 o' X- `) ?  N
  103.     }/ c. g- p& d4 Z

  104. 7 U+ H7 h* Q8 _. Z. ]! D
  105.     /* 使能 33/17 bit CRC计算 */
    9 |; }8 O9 |% a8 K% m9 ^$ P
  106.     if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (crc_length == SPI_CRC_LENGTH_16BIT)) ||9 e. H  B! [" V
  107.         ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance))  && (crc_length == SPI_CRC_LENGTH_32BIT)))
    6 t# a' I! G6 R. [
  108.     {
    8 K- e7 C. f: g$ T( X2 O1 S% E
  109.       SET_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);" G8 f6 p2 p; @" F
  110.     }
    : b2 b, H, \* h
  111.     else1 M+ k" L  n3 E0 V% }& f% C  l
  112.     {
    0 [  B: U& b0 O5 q! r
  113.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);
    9 l: z9 ]  m, _4 X% B' R( C0 P
  114.     }! F& p, ^" J. Z5 Z1 ~+ F" {

  115. ( k0 J4 C3 }( H9 E( E
  116.     /* 写CRC多项式到SPI寄存器 */
    5 O7 o* g( p3 d! ^
  117.     WRITE_REG(hspi->Instance->CRCPOLY, hspi->Init.CRCPolynomial);
    9 y, z  z+ F$ B) S3 G
  118.   }
    & Q* q0 E  @. R" Q
  119. #endif
    . P6 V! r+ o( y; x7 p

  120. & p% l" E: o' P/ }
  121.   /* SPI从模式,下溢配置 */; X0 V. u0 |" @2 l1 V0 v6 M
  122.   if (hspi->Init.Mode == SPI_MODE_SLAVE)
    . e" M8 H4 C/ A9 b+ X
  123.   {: Q7 h7 ^% S# X8 f& c! N8 ]: V
  124.     /* 设置默认下溢配置 */
    # z* V2 C/ l0 O! V
  125. #if (USE_SPI_CRC != 0UL)0 G& b" M7 ~/ U9 E% `
  126.     if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_DISABLE)% ^1 v( A4 R" a& K
  127. #endif" ]8 C6 }1 \* p
  128.     {
    + z# G7 r% Y2 B) Z' e2 G
  129.       MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRDET, SPI_CFG1_UDRDET_0);
    % t  s+ N0 m! ~/ b
  130.     }
    - L* p+ Z+ I+ |) m
  131.     MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRCFG, SPI_CFG1_UDRCFG_1);
      Y" A  W3 u7 A4 u# ]4 K0 K! ^
  132.   }
    ( T. n  P  o/ U1 d, h7 t# `

  133. # X$ p) y2 w9 y* F. p
  134. #if defined(SPI_I2SCFGR_I2SMOD)$ j& o. l# Y$ b0 J+ s+ j
  135.   CLEAR_BIT(hspi->Instance->I2SCFGR, SPI_I2SCFGR_I2SMOD);
    9 j9 Q( o# q. Q1 ~; J
  136. #endif 8 E+ d0 t5 I$ m. E) F7 [
  137. 3 J+ d( j9 ?% E# }
  138.   /* 确保AFCNTR bit由SPI主机模式管理 */0 u7 T; b6 b6 U& J( Z, A) I, {. U9 O
  139.   if ((hspi->Init.Mode & SPI_MODE_MASTER) == SPI_MODE_MASTER); v; H; `1 X, X# ^0 u7 X
  140.   {: g; `$ c' O$ ~9 r
  141.     /* Alternate function GPIOs control */
    % W2 x0 _, L. {7 L* m
  142.     MODIFY_REG(hspi->Instance->CFG2, SPI_CFG2_AFCNTR, (hspi->Init.MasterKeepIOState));
    # K* s2 C  x& ?+ F1 X9 y
  143.   }- x) r% M7 W: ~, S3 e. m

  144. # E+ k. y- m" {$ c% N1 |
  145.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;
    8 F3 P2 ], o  n7 L8 T$ c
  146.   hspi->State     = HAL_SPI_STATE_READY;
    ; J; `$ \( `& M' |

  147. 2 d( o, L( E  T
  148.   return HAL_OK;% |+ a. q  m0 D' d$ J9 ]  V9 @
  149. }
    # x" d9 K- b; e' P
复制代码
6 w. j. \. k2 O7 ]: V: L

, e: d! r2 S' U1 ^' a9 ^函数描述:
' M2 c% J  v6 x& `- O* m% r3 k& \9 [2 x1 F0 u& X9 D3 a
此函数用于初始化SPI。: J8 J- E9 G, D5 Z- y; }. i# z

: \+ H2 C# W$ L8 }( I( P& t函数参数:
1 m& C  V" J+ P* P; y7 a# J* Z" f' S3 g8 ?# U
  第1个参数是SPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
: O& J. ]- {6 {4 x" U  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。( Z4 h1 [% K5 i4 ?
注意事项:
, H' k3 m& o4 e6 a2 u8 [6 ?4 J2 B/ B$ u
函数HAL_SPI_MspInit用于初始化SPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
& z$ N$ S( y" p如果形参hspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SPI_HandleTypeDef SpiHandle。
( d) r: C, H" H: n) @4 p* l对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SPI_STATE_RESET  = 0x00U。
# P* I# }2 \% p  h
! Y; P# l2 Z6 z/ B9 @解决办法有三5 }4 b/ E$ Q6 _8 a& S- l% x8 g

5 o7 M/ A4 [1 D方法1:用户自己初始化SPI和涉及到的GPIO等。
4 E7 u2 \# K$ d. g' ~# o6 d% @) ?$ C; p: f
方法2:定义SPI_HandleTypeDef SpiHandle为全局变量。/ q$ Q; y$ f; {; ^$ v: N
2 T- }0 u  K" l* t; ~. F) l& r( Y
方法3:下面的方法
9 q4 I( Q4 f' h0 v$ w7 P( n) q& s* ^9 Q0 H, _
  1. if(HAL_SPI_DeInit(&SpiHandle) != HAL_OK)
    0 S% S" o0 w+ T! L: p2 `! d2 D
  2. {
    ! W; h3 \1 u5 s- y+ v
  3.     Error_Handler();
    * Q, M) T. m1 Y4 x
  4. }  0 z$ [8 c. f) C' i% a: d3 H
  5. if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
    & _: v3 [3 ~; r" M) G& `% I5 ?
  6. {# m8 d. E" ~& y$ x6 g: U# |- S
  7.     Error_Handler();0 Y# Q% W2 {. N! T: v
  8. }
复制代码

7 t* Y0 a7 a# A& H# D9 {使用举例:
" r9 ^7 B; O  w9 H
7 ]5 |4 G( J$ |# {  Q& g
  1. SPI_HandleTypeDef hspi = {0};
    * }. l+ ]) B0 h2 A
  2. : s' D+ J. A6 V- i
  3. /* 设置SPI参数 */1 ?" o" A9 Q" E# \
  4. hspi.Instance               = SPIx;                   /* 例化SPI */) T6 r5 F; K' g* E- h, L
  5. hspi.Init.BaudRatePrescaler = _BaudRatePrescaler;     /* 设置波特率 */# \6 d5 P# E# U; e. s( r) h9 c
  6. hspi.Init.Direction         = SPI_DIRECTION_2LINES;   /* 全双工 */
    - Q# ]5 t% G" Z, X8 }7 z% F9 w$ @
  7. hspi.Init.CLKPhase          = _CLKPhase;              /* 配置时钟相位 */
    , m: M% c. |$ g; W
  8. hspi.Init.CLKPolarity       = _CLKPolarity;           /* 配置时钟极性 */! u5 I7 y' |0 |
  9. hspi.Init.DataSize          = SPI_DATASIZE_8BIT;      /* 设置数据宽度 */
    ; |% ]7 u+ O, @& A! f. e% B5 v$ C# m
  10. hspi.Init.FirstBit          = SPI_FIRSTBIT_MSB;       /* 数据传输先传高位 */
    ( l! Z- ?$ C( q  f  X1 F+ Q" \7 O. R
  11. hspi.Init.TIMode            = SPI_TIMODE_DISABLE;     /* 禁止TI模式  */
      F% ?! _5 U$ r+ c# @
  12. hspi.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;      /* 禁止CRC */! @( e( X, _  e' J1 Z) h" _& h
  13. hspi.Init.CRCPolynomial     = 7;                               /* 禁止CRC后,此位无效 */" |  ^& T8 |+ t; y+ u
  14. hspi.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;             /* 禁止CRC后,此位无效 */
    7 Z" _; b' b, s8 d  C+ n2 l5 \% ]
  15. hspi.Init.NSS               = SPI_NSS_SOFT;                    /* 使用软件方式管理片选引脚 */
    6 N0 J2 z% K2 L2 d7 K
  16. hspi.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_01DATA;       /* 设置FIFO大小是一个数据项 */
    ; j+ @) T' J* Y3 A$ \) _/ D& U" Y
  17. hspi.Init.NSSPMode          = SPI_NSS_PULSE_DISABLE;           /* 禁止脉冲输出 */
    % o. F; j8 K# _- O& g* Q: x2 A
  18. hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  
    + L9 f& c% b+ Z8 _6 ^  r
  19. hspi.Init.Mode                  = SPI_MODE_MASTER;            /* SPI工作在主控模式 */9 P8 f% s* [- v; r3 b: N0 u
  20. . x* V* T7 M: c2 t3 F3 _9 E
  21. if (HAL_SPI_Init(&hspi) != HAL_OK)
    $ Q  d& x9 N* I% a0 e5 m* w
  22. {
    3 ]7 S1 {- u  n: V  r3 u3 L
  23.     Error_Handler(__FILE__, __LINE__);
    * |7 h. {, ^( w) q5 O
  24. }
复制代码
1 m( t6 g* |  c8 r
1 V7 W3 M5 Q2 Y& p0 n6 a  j
72.4.2 函数HAL_SPI_DeInit
2 s4 V# x+ L4 R7 Z# q0 E函数原型:
! J  F8 x! P! O' t8 S' k( M8 g+ D0 B7 q, G7 f# O
  1. HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)" M) o' c- K' i8 e. D: }7 G: l
  2. {7 {9 p2 X9 z& b3 h; |) ]- A! m
  3. /* 检测SPI句柄是否有效 */3 T7 G6 L9 k/ N3 m8 D* Q, d3 O0 W. U
  4.   if (hspi == NULL)+ g, U' v) T. V0 k9 e' u
  5.   {
    ) C) V& h9 o& R3 m: `$ U, t( x& G5 H
  6.     return HAL_ERROR;3 D( O1 O8 \6 r; y; l
  7.   }1 \! p$ ~6 D8 w5 L! g6 v- o
  8. ) v7 f2 L  @+ l7 ?
  9. /* 检查SPI例化参数 */
    2 o1 x! _* N$ t
  10.   assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));
    / x/ J' R, F( p% r- Z' g7 E* ?
  11. ! C# r: q. D+ S% X
  12.   hspi->State = HAL_SPI_STATE_BUSY;; Y. r  o5 b8 x& e# G' I
  13. * ]2 W6 {! Z! M! I4 A5 C
  14.   /* 禁止SPI外设时钟 */: _7 _* l) H1 W6 k3 u% ~
  15.   __HAL_SPI_DISABLE(hspi);
    & D' C3 V% u0 K, q0 I; z
  16. ; D- ^3 O; W9 ?5 g0 v. u7 a) L
  17. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)9 v6 j0 P) ^! m# M' l& w
  18.   if (hspi->MspDeInitCallback == NULL)
    : i. P+ j) K- p7 F: r& t! Y2 k  x
  19.   {
    , y) K* V$ i3 I
  20.     hspi->MspDeInitCallback = HAL_SPI_MspDeInit; 3 S3 k) h+ }  Y6 m% I
  21.   }
    ' l6 Z  V# i2 r2 s, \+ k0 J' i* h
  22. 5 O* j% t  {  l" K3 n
  23.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */
    / V' b9 e" }2 m& ]: D
  24.   hspi->MspDeInitCallback(hspi);, F: m! `; q, B  _4 V
  25. #else, I/ r4 x" Q& M  M4 y5 G* ^
  26.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */7 w9 h  @; J) y( \) U9 a2 ]
  27.   HAL_SPI_MspDeInit(hspi);
    0 X; r& y4 n% M; \
  28. #endif
    6 N& Q5 t; t& v5 Z, M
  29. ( m" P$ c& ~: J# J$ d+ q
  30.   /* 设置无错误,复位状态标记 */
    $ T  T3 H6 N3 m& J/ E9 N6 r
  31.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;
    * e5 y' a& A9 Z1 {* l: V
  32.   hspi->State = HAL_SPI_STATE_RESET;) d3 n. c$ ?- O# Z

  33. # [4 u+ ?/ O6 H
  34.   /* 解锁SPI */8 d' S+ _/ h  ~( x
  35.   __HAL_UNLOCK(hspi);( K& I) E* M$ m  C' c

  36. " _, o1 T' u! e; \! L
  37.   return HAL_OK;
    ( \% g8 ?* r/ O, M" d
  38. }
复制代码
7 q( X6 i1 h! Y6 T$ q
函数描述:* D. l/ }/ o& x" a9 l0 F( k% ^

/ o. _! ]7 h: ~- J2 C4 ?, U用于复位SPI总线初始化。
* b9 |* w& _: j: h8 ]0 S. ]: ~) V  i3 w6 o# K! g3 v8 }
函数参数:
: v! O1 |3 K/ J0 M6 Y0 S' ?  I/ d. q# z0 Q4 E
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
) @( \3 r9 V! ~) J' U2 w  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中, k; p1 z0 B+ g: W' a; K
72.4.3 函数HAL_SPI_TransmitReceive" Z9 d$ D4 Q8 @+ F! d- |
函数原型:2 E' R0 z5 [3 E( K% R8 b
3 r4 |( i: N" L1 q2 U; K
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout): s% u+ I4 t) F0 g, p) x" G% C
  2. {! `" z' ^) c/ X* _

  3. 1 [7 p0 @& J$ E  `, r
  4.    /* 省略未写 */
    8 p( h  n- k7 L$ `7 o7 s1 N
  5. 5 s7 f& n* ?) M) h' \0 g- g  G
  6.   /* 大于16bit的数据收发 */
    ! L! G" @' e. ]# a. Z( e$ q
  7.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)( I( X. }, l0 Q7 \' d) d2 t$ F- N
  8.   {
    - D' O2 z1 Z  T; i% N0 e2 I
  9.        /* 省略未写 */
    # P7 M! U8 ]- J+ z7 D& s9 [6 g
  10.   }; x& B0 }  Q( K2 j
  11.   /* 大于8bit,小于16bi的数据收发 */9 L3 _! K7 `7 {" @. P3 U/ F! C, G
  12.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
    / a4 b, d6 `' G/ B5 Q6 j8 q1 \  V" e6 @
  13.   {
    ' d% ~5 I$ o6 O) K8 X
  14.       /* 省略未写 */2 `) n( J6 ~6 Q& I) ~
  15.   }
    0 U6 Y- u& b3 B7 u
  16.   /* 小于等于8bit的数据收发 */
    : {1 w8 y  l' Y# o& e8 j6 m+ L
  17.   else& H$ G1 q/ Q  B& o- n
  18.   {& ~0 |2 L+ @( S
  19.        /* 省略未写 */
    3 m0 t! v4 t5 U: Q) ?
  20.   }
    9 ]# A5 v% p1 Y/ w2 Y/ e

  21. . h, w. @+ R1 ?0 \0 b
  22. }; ^- q  a6 |. ~1 r9 l
复制代码
% v/ I; ~6 |( |
4 x$ f( j5 ]' y
函数描述:6 I% S! a2 Q% O

/ n% w4 r2 e# d  Y$ p+ w1 {此函数主要用于SPI数据收发,全双工查询方式。) ]6 P  z+ L: u" v0 K1 _0 o
  E" L4 C- o' Q" S: ~) s
函数参数:
. h" i+ D0 b+ ^7 M- L6 {9 @7 [+ `
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。; {4 v( T* |0 D
  第2个参数是发送数据缓冲地址。
5 f/ \+ q$ R. f, c6 O- I  A  第3个参数是接收数据缓冲地址。# N: {- p6 ~# {
  第4个参数是传输的数据大小,单位字节个数。
, h3 }6 n4 M, X' u! |2 Q  第5个参数是传输过程的溢出时间,单位ms。5 x8 R6 V/ t+ v# L. d1 x
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
2 ?5 z4 b/ f* j# F1 D! i% @使用举例:
+ z# K! m( M; ?" i& [0 t' y: ^: v& I. I: F: H( e
  1. SPI_HandleTypeDef hspi = {0};& w, z8 A8 T: ^0 B0 t

  2. 1 T9 N! {# @0 W3 L: m2 _
  3. if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)
    8 h3 K* Q% h  W" P. W
  4. {
    $ p; P. v! \! I9 Z
  5.     Error_Handler(__FILE__, __LINE__);- n/ r7 N7 D* g8 z% g9 w; D7 a
  6. }
复制代码
. m% h) y% K6 k! M3 u: _
72.4.4 函数HAL_SPI_TransmitReceive_IT( ~3 p) C: q6 z% ^( Z7 o' ~" ^
函数原型:
/ M& Q* [2 n$ @: {, Y( M1 k
& ]9 S7 F& d" X1 S/ p
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)* [6 A. C7 h5 U( h0 Z8 T
  2. {  b" P" f) v& n' x) s, ?
  3.    /* 省略未写 */
    4 Y$ |4 X5 _" o* G
  4. ( [- R+ z7 C$ r7 \5 m; P, c
  5.   /* 设置传输参数 */* B! ]( C, E0 P! f7 I
  6.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
      q1 O; t5 T" l5 g! q5 ~' {& M
  7.   hspi->pTxBuffPtr  = (uint8_t *)pTxData;2 Q$ ~  O( H1 j0 [& }
  8.   hspi->TxXferSize  = Size;2 k. f& _5 p: v3 j0 H1 z
  9.   hspi->TxXferCount = Size;: Q: v5 N* e( J! d
  10.   hspi->pRxBuffPtr  = (uint8_t *)pRxData;( K/ T; j. [* f  j$ D
  11.   hspi->RxXferSize  = Size;
    0 }$ L* U, }) g& e) R8 t# l
  12.   hspi->RxXferCount = Size;
    4 z8 T0 t: c5 H( s  u/ c8 N
  13. : n1 L3 y- B( f1 A: E- c
  14.   /* 设置中断处理 */
    ! v' D: q2 B; M( m. i0 F
  15.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    ( P4 \0 X& z* c; A; B  D" h' Q
  16.   {+ ^( L% ?' ~; X$ [1 K
  17.     hspi->TxISR     = SPI_TxISR_32BIT;
    ' m- v: L" {' ^7 |5 |1 q
  18.     hspi->RxISR     = SPI_RxISR_32BIT;
    # v; D' V. V4 K- O/ B3 G; w
  19.   }
    8 }6 c: W* O4 s1 ?* W
  20.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)3 u9 G; `6 D3 v( F5 c
  21.   {
    $ Y# {- D, [' i( n; E9 {1 Y
  22.     hspi->RxISR     = SPI_RxISR_16BIT;
    , ?9 t* o! G+ [
  23.     hspi->TxISR     = SPI_TxISR_16BIT;" y" b. v. t" H/ j& K* ~
  24.   }
    9 \/ P9 e; _( W/ T
  25.   else1 J3 e' U  \2 q
  26.   {
    ' X4 Z0 }/ @2 C5 w. ^% C9 S& P/ r* J
  27.     hspi->RxISR     = SPI_RxISR_8BIT;
    + S& Z% h+ i2 G- C( N6 d8 \
  28.     hspi->TxISR     = SPI_TxISR_8BIT;
    * q5 ~& z/ A7 q, X3 I) B
  29.   }
    % R2 X" n% R  w) r$ v( D/ u

  30. " o7 ?2 p+ o$ o- F3 i7 ?; w
  31.   /* 设置当前传输数据大小 */- }8 ~1 m# y0 f! t3 i, U
  32.   MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);' G% P7 U. w& U: l4 y+ _5 `

  33. 5 o- w* j5 P! m
  34.   /* 使能SPI外设 */; p! n2 P" ~1 ?1 }$ ^6 _! T% b# h
  35.   __HAL_SPI_ENABLE(hspi);
    2 s# t  F+ M1 ^4 \, N3 ^
  36. % p9 J4 p+ s* D; @# q  g& H# }
  37.   /* 使能各种中断标志 */
    + D" U9 }8 U, `9 v# f! @& G# T
  38.   __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_EOT | SPI_IT_RXP | SPI_IT_TXP | SPI_IT_DXP | SPI_IT_UDR | SPI_IT_OVR | $ u8 X- K$ Q% Z' {; F
  39. SPI_IT_FRE | SPI_IT_MODF | SPI_IT_TSERF));
    , v( A7 y2 C  `+ f
  40. 8 o1 u: B+ H5 o
  41.   if (hspi->Init.Mode == SPI_MODE_MASTER)1 o) F4 q  R* n) y& o
  42.   {& x/ k5 |7 F" P. N3 }9 Y7 D: |
  43.     /* 启动传输 */
    . o' X) [: h$ B5 ^7 D; J
  44.     SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);
      Y$ @' Z5 {$ Z9 J+ `
  45.   }
    # {) F1 y4 V  u+ D! T) a+ Q
  46. : T1 Y& c2 w+ A! j: ?
  47.   /* 解锁 */6 X; t& @. k7 t! f% V+ P
  48.   __HAL_UNLOCK(hspi);
    & W, ]6 `* v  e
  49.   return errorcode;( J( }, A3 u8 d3 B& c( X
  50. }
复制代码
+ V! `; n8 x( \2 d/ B, u5 J
# @0 S  l) _: M8 l: x& Z& I, w
1 d* K. ^$ r7 q
函数描述:
  z& b  b5 ~+ D0 W& p4 \  H6 Y/ I4 k
此函数主要用于SPI数据收发,全双工中断方式。, p' n, b* ^- t  }; h" P% f
0 q1 ?, x/ U% ~# g( ?6 W+ P) G2 T
函数参数:
% r0 R& k* p$ v% F: `; o  J
9 w) W. f$ M" i  |# s" \7 _  第1个参数是SPI_HandleTypeDef类型结构体指针变量。. D9 ^( `3 e/ l- F  H$ [
  第2个参数是发送数据缓冲地址。
. a# f8 D& t6 t  `  第3个参数是接收数据缓冲地址。
. A, x" H3 N9 c$ u: l' Q  第4个参数是传输的数据大小,单位字节个数。0 s$ t( g+ f) e& ?+ M. T
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。4 O+ J5 R! [( e' k
使用举例:/ {1 u* d( N5 H* Q  _8 h  f% R
, Z3 Q2 L! w8 W" ?
  1. SPI_HandleTypeDef hspi = {0};
    $ K$ C1 N7 `0 v! z, i7 U/ d

  2. ! k& Z- S! U/ m# b
  3. if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    7 f4 V+ x1 B9 H1 n. }- P3 C
  4. {  G- ^& X3 m8 ?; O% K1 `( m
  5.     Error_Handler(__FILE__, __LINE__);
    ( L0 A, a3 G7 B5 ~' c0 X6 t) r
  6. }
    : X' _7 M7 B) i4 `
  7. 5 g0 ]0 t5 T- J. \3 m" g' k
  8. ! F) ^% C# {4 o: a3 X, z" Q- ~. ?
  9. 72.4.5 函数HAL_SPI_TransmitReceive_DMA' V8 d4 X4 T) X3 A* x- P, y
  10. 函数原型:- ]  m2 H& h3 K" U  G
  11. : a+ X6 t6 P7 O1 V6 z
  12. HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,# o$ E' s( K$ w. o* T- F0 F4 T
  13.                                               uint16_t Size)
    " a; {- D$ P" B
  14. {
    ( c! I: `/ k% v+ n  B
  15.    /* 省略未写 */
    0 T0 C6 H& w" A6 K3 G) C! l5 O, ]

  16. , f4 k- s. h& m+ L4 @
  17. /* 注意DMA的位宽和对齐设置 */
    # {5 F+ r7 Z3 r; I! z1 J( S1 m" g( r
  18.   if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && (hspi->hdmarx->Init.MemDataAlignment !=
    6 U  \  }# b0 {/ t/ E9 b, y5 @
  19. DMA_MDATAALIGN_WORD))  || ; u6 m- h" Z. \
  20.       ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) && ((hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_HALFWORD) && (hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_WORD))))
    ' s; p$ I* J3 D2 ^7 R2 e
  21.   {* j. e5 W$ n$ G
  22.   }, R& ^# _" C4 Q
  23. # B* T+ T" @0 W* I8 w
  24. /* 调整DMA对齐和数据大小 */& `- M; c. s" A% a9 \9 y
  25.   if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)
    2 V* n1 W2 w, O* m. g
  26.   {7 `2 ]' [  P: s% u/ X
  27.      /* 省略未写 */
    4 V" {2 a4 t7 D, A3 o
  28.   }
    3 q( B! D" p7 m( L4 H8 g9 F" o7 M
  29.   else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)/ h0 c( s" S% K
  30.   {/ p7 W0 d, G/ j9 @8 G+ ~
  31.      /* 省略未写 */2 N' _8 L! @" I
  32.   }
    / P% O2 X4 C% g& ]% D
  33.   else  b' U. W5 m1 x6 j! i
  34.   {
    # @) a; R# d  d  m  r- @  C
  35.       /* 省略未写 */
    " e& ]2 V: y- A9 p
  36.   }
    . }9 ]! ]6 c: v! W6 k8 T
  37. * p% o$ j; R9 S) X: \  N3 p! K
  38. /*  DMA接收配置 */
    ! {3 p; Y, @- V- {% r$ C- [, {
  39.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->RXDR, (uint32_t)hspi->pRxBuffPtr,% \# `' p0 g0 ~6 n2 T4 p
  40. hspi->RxXferCount))' L, }9 H. k7 P6 Y6 a' n/ e
  41.   {- M/ f. ]& ?* T* G
  42. ; Q/ }8 l* R5 \9 e
  43.   }
    2 Q, [4 n, ^: f4 C. S. z
  44. / ?5 Z& a9 b. c/ X0 D; W; h
  45. /* DMA发送配置 */
    4 D. W0 [9 ]- U  z4 v" Q
  46.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->TXDR,
    ( j: }( K7 m6 a6 F# s: M
  47. hspi->TxXferCount))6 J# t' I# i6 d8 s5 q4 O
  48.   {
    ' {( U- J; J$ [- x
  49.   }
    9 l6 }4 }1 e( x1 [7 J% f( e  e: b. P

  50. 9 O# j$ Q  _. b+ n2 |) n/ f
  51.   /* 省略未写 */3 Y( h" b8 b9 w
  52. }' o9 u$ q0 s/ v8 @
复制代码
! l- T, P4 ~# w8 d8 E8 x4 {
( {5 M# q. J1 ^" d# N. D! k! m
函数描述:
- n: W& A3 [5 Q  V9 D+ t2 u
. K6 l. F: `4 {  N- x# L3 S$ _此函数主要用于SPI数据收发,全双工DMA方式。0 d* R, h# i4 o& v) {: T* ]/ A4 n

$ c, ?8 |+ b: E/ r  }函数参数:
- F5 c+ S3 T# m6 P3 a8 s9 M1 j. M* X" g5 R7 z4 X+ O& j8 O
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
' R' i6 t( f# K7 I( F  第2个参数是发送数据缓冲地址。9 ?9 i7 S+ L0 N$ O
  第3个参数是接收数据缓冲地址。; R# `, S! W7 a# y: B7 u
  第4个参数是传输的数据大小,单位字节个数。: A) W/ T& T, }% U! N7 K
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
- D% T. h8 ]3 N: K! i9 z使用举例:  x% L% o0 E, t# E& m  C% H, \

! {5 {1 G# \, N0 H7 f# @9 j& C
  1. SPI_HandleTypeDef hspi = {0};
    ) Q* H, d' p9 e% ]" H. m
  2. ( h* q1 x1 v6 M: n
  3. if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)   
    # h9 \' Q+ X# @, \
  4. {
    4 o) P* K7 a4 Z+ r, e  p$ V5 |1 Z
  5.     Error_Handler(__FILE__, __LINE__);
    ( N( C& h" _/ n" j
  6. }
复制代码
( W. m9 T6 p/ \
  C4 Y2 l  d8 _" _' `
4 ~+ B& R: Y0 w+ @
72.5 总结7 `9 w- @: i" U8 b
本章节就为大家讲解这么多,要熟练掌握SPI总线的查询,中断和DMA方式的实现,因为基于SPI接口的外设芯片很多,熟练后,可以方便的驱动各种SPI接口芯片,以便选择合适的驱动方式。& a1 t% o. q+ S# p4 B5 K

9 v" |/ @+ @. \" B+ L4 R2 Y1 S0 r0 f) E& g9 f. z
收藏 1 评论0 发布时间:2021-11-3 10:15

举报

0个回答

所属标签

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