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

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

[复制链接]
STMCU小助手 发布时间:2021-11-3 10:15
72.1 初学者重要提示
1 q! A+ @% E3 c- I+ ~# P' Q  STM32H7的SPI支持4到32bit数据传输,而STM32F1和F4系列仅支持8bit或者16bit。. `7 b* F3 Y; z& r; i& z0 @' j9 G
  STM32H7的主频400MHz时,SPI1, 2, 3最高通信时钟是100MHz,而SPI4, 5, 6是50MHz。
4 ]( X- h# q; i( h5 G2 S  STM32H7的MISO和MOSI引脚功能可以互换,使用比较灵活。- U7 t$ S2 \* P" l% O& O& R+ j
  SPI总线的片选引脚SS在单一的主从器件配置下是可选的,一般情况下可以不使用。
: D2 j, J& s# F: X( C# m- U. j
, Y; F! O. f1 a9 Z  _' ~# Q& N9 G4 o72.2 SPI总线基础知识2 N  X- V. Z' M( Y& Y+ {" {
72.2.1 SPI总线的硬件框图6 X; j0 z; N3 S! x( R: k
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SPI的基本功能,然后再看手册了解细节。9 P) ]6 q! i: w, r4 ]) n+ c8 C
( M; L% y$ o. _. f! O1 [8 k
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

1 L4 F0 l6 c; f; D* ~9 Y4 ]5 Z$ |) f; K
通过这个框图,我们可以得到如下信息:
2 D$ R* Y5 z$ A
  p: q/ _2 p( |" `7 e  spi_wkup输出
) k/ w  B$ w: v  {1 f低功耗唤醒信号。
% z4 U7 b9 V) Y+ m5 \
. {& j7 k8 d5 W; c1 v( q, Z& F  spi_it输出
% F; n* |) X' gspi的中断请求信号。
0 ?% Y; W8 }$ o: B' X' N, Q# ], r" _9 W+ O) r6 F5 h& J. b
  spi_tx_dma
% U8 E, C0 s( [& x5 ^, T; |- Vspi_rx_dma
4 [9 j( b4 G5 b0 l( \spi的DMA发送和接收请求信号。
) P0 o3 y2 d. ^
0 D. Y3 t! F$ V6 @; W  spi_pclk
6 r! v" Q8 E. C' U( ]) y为寄存器提供时钟。
! L% v+ e) D* |& K+ ]3 @* D* p1 f* H1 @8 w
  spi_ker_ck
  ~0 {! k& k" L' r为spi内核时钟。5 R; f" q; S" a# M6 g

/ A( l1 Y5 J: r, s; o  SCK(CK),Serial Clock
1 Q. Y5 u- _8 \) j此引脚在主机模式下用于时钟输出,从机模式下用于时钟输入。
3 ], I( N! @* g8 d3 E2 s  t% C: G8 t! _6 |3 o
  MISO(SDI),Master In / Slave Out data
( R. e2 p8 `5 @4 \此引脚在从机模式下用于发送数据,主机模式下接收数据。
" k6 T! x+ [( \' L: w- i1 U7 B: D+ e" W9 D# W
  MOSI(SDO), Master Out / Slave In data: w; c' m0 M( b& X& I% b/ y0 }
此引脚在从机模式下用于数据接收,主机模式下发送数据。" l4 l' N4 R1 {- @

- v5 t2 e+ R1 H  R( G; O: ?# J& b  SS(WS), Slave select pin
7 }6 q' W% x9 L: E% i( Z根据SPI和SS设置,此引脚可用于:- R& ?1 Z( v. D% M
: X+ s. o; T2 R0 k8 k5 l
a. 选择三个从器件进行通信。
9 }5 i7 M" u& p4 G  J) M
+ ?& Q4 K4 M6 Y# gb. 同步数据帧。1 Y! n+ m$ ?1 S4 ~( [  @" f" k
3 e% N. Z' F& r/ S  |6 Z
c. 检测多个主器件之间是否存在冲突。6 R% n/ M+ ^" C) Q- k) y) x0 B

- Y* ]0 i% h' V+ l: K' _/ \/ P3 _- i通过这个框图还要认识到一点,SPI有三个时钟域,分别是寄存器所在的ABP总线时钟域,内核时钟发生器时钟域以及内核时钟发生器分频后的串行时钟域。1 H( L5 ^. @: v- M  |1 S

3 s/ U) Q) u% Y; p+ V72.2.2 SPI接口的区别和时钟源(SPI1到SPI6)- l  I5 a; z0 W- X7 f
这个知识点在初学的时候容易忽视,所以我们这里整理下。
( x  t3 N8 |! a9 V8 D. Z+ B( b% c) n/ t) P" Y, J; J
  SPI1到SPI6的区别
4 J8 u1 i5 o+ I0 E4 p. z  SPI1,SPI2和SPI3支持4到32bit数据传输,SPI4,SPI5和SPI6是4到16bit数据传输。
2 h% }! }% k) E# G( o8 T4 |- E  SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit。
' I! q, U1 H7 k; `% z  h  |) X+ _% w: M; s3 o
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

* ^. Z9 ?7 X# T- t' K! |& G5 Z: a; M  E' ~! e( C" i
  SPI1到SPI6的所在的总线(对应SPI框图的SPI_CLK时钟域)6 J7 @! X8 Q5 X( [) u# a
SPI1,SPI4和SPI5在APB2总线,SPI2,SPI3在APB1总线,SPI6在APB4总线。注意,SPI的最高时钟不是由这些总线决定的。
7 h3 L/ o5 u0 d& o; p
1 C! {  S$ D3 u0 w6 m1 M  SPI1到SPI6的支持的最高时钟(对应SPI框图的SPI_KER_CK)
" o3 A6 q: R+ F# X( G( ?STM32H7主频在400MHz下,SPI1,SPI2和SPI3的最高时钟是200MHz,而SPI4,5,6是100MHz, 以SPI1为了,可以选择的时钟源如下:
6 A* v$ C2 G0 a# D9 F# j, N2 z" L3 B; p  {( Q; F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

$ s# x/ y, R- R1 F% m: V+ i1 P
' z- M- a0 {! e% {) W这里特别注意一点,SPI工作时最少选择二分频,也就是说SPI1,2,3实际通信时钟是100MHz,而SPI4,5,6是50MHz。. O, R7 q. |0 k- Z! e9 @

6 r: Z2 f: D2 }' H/ X+ Z& |72.2.3 SPI总线全双工,单工和半双工通信5 q% j$ V6 W4 @# E1 A/ Y
片选信号SS在单一的主从器件配置下是可选的,一般情况下可以不使用。但需要同步数据流,或者用于TI模式时需要此信号。: n5 z9 `' p% B7 e& u

* ^: r* ?3 g8 @. I  全双工通信* @* v6 e2 {) w# l; e
全双工就是主从器件之间同时互传数据,SPI总线的全双工模式接线方式如下:
, p+ O, p$ i3 ~' ]* V8 s% U
4 |. G. W, v; e6 D) S+ h7 z' F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

3 U$ J- d( L9 V/ o) d
' P: @$ _8 `) u9 W: e/ ]/ Y关于这个接线图要认识到以下几点:
8 Y! D& G. T7 n* _& T1 ^; }; v. Y! O8 }% E  c: _
  注意接线方式,对于主器件来说MISO引脚就是输入端,从器件的MISO是输出端,即Master In / Slave Out data。MOSI也是同样道理。' C, a# [0 G" H) _. [/ h) r, S
  每个时钟信号SCK的作用了,主器件的MISO引脚接收1个bit数据,MOSI引脚输出1个bit数据。2 I5 ]5 K% }6 T9 r: H+ b* g0 r* i
  这种单一的主从接线模式下,SS引脚可以不使用。
; `# k1 C1 j6 G( c: l4 R  半双工通信
2 S: v  J' ~/ I: f8 A* y( H半双工就是同一个时刻只能为一个方向传输数据,SPI总线的半工模式接线方式如下:
6 q. r/ o9 d# b( t  @1 o) N, V
% D4 G! W% M" _! [2 n
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
4 {2 u7 \- `" W9 b! w
- Z6 h! D% y* q3 e. M& N) F6 d
关于这个接线图要认识到以下几点:  L+ d0 E! x" k% u- |

, r, g* Y. U9 u/ l, A  更改通信方式时,要先禁止SPI。) y) X# s/ q+ Z% l7 ?/ H0 }
  主器件的MISO和从器件的MISO不使用,可以继续用作标准GPIO。* B9 {6 A+ ?# W; u6 c' N/ r7 W$ |$ K% J
  1KΩ的接线电阻很有必要,因为当主器件和从器件的通信方向不是同步变化时,容易出现其中一个输出低电平,另一个输出高电平,造成短路。: ?- F0 ^5 D) d4 `& b% C7 H( n
  这种单一的主从接线模式下,SS引脚可以不使用。* S% P* J4 a. V3 H
  单工模式$ q/ N5 o9 q3 M. ^7 @; R
单工就是只有一种通信方向,即发送或者接收,SPI总线的全双工模式接线方式如下:
% z8 a7 z) C4 @2 X5 a( j' {
1 |2 h) z4 @0 t9 e
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
* ^  @; X$ q$ K! g1 @# `

. g9 \# O9 Z- h5 D4 i关于这个接线图要认识到以下几点:
4 q6 G/ T) j# @) @
1 w- C3 v1 f- K' W# V  未用到的MOSI或者MISO可以用作标准GPIO。
+ g7 C/ c! y6 J! e5 b; v  这种单一的主从接线模式下,SS引脚可以不使用。
' D+ f1 g+ Y$ i. L& m1 @& x6 y' [2 U72.2.4 SPI总线星型拓扑6 _+ ^) J; r( A2 ~5 }3 r" t0 |1 o
SPI总线星型拓扑用到的地方比较多,V7开发板就是用的星型拓扑外接多种SPI器件:* t' ]* F/ |- u5 `% b+ {
( p" r' t1 P% y' A8 F
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

* }$ Y) p8 z( h' e* I- J* ]5 S! s. r( j5 D2 j- Y3 U
关于这个接线图,有以下几点需要大家了解:8 t2 T- a2 D- w/ k
" U9 P' t; O# F, |4 `
  主器件的SS引脚不使用,使用通用GPIO控制。为每个器件配一个SS引脚,方便单独片选控制。  Z) I+ i' L5 y/ g) s5 {2 m
  从器件的MISO引脚要配置为复用开漏输出(很多外部芯片在未片选时,数据引脚是呈现高阻态)。( _: M+ w9 Q5 s% w
72.2.5 SPI总线通信格式
9 k+ S' f/ e0 F  b7 P3 f" xSPI总线主要有四种通信格式,由CPOL时钟极性和CPHA时钟相位控制:: m0 |$ h$ \; [+ K3 a& m

6 s, {4 L4 ^, U4 r2 y! l/ j
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

- h! o; Z- @6 u# w" g# H- A7 B7 |% V5 g* o) y4 ~: G+ E# @
四种通信格式如下:
7 _; O. B. R' [9 D- d5 V& A
$ G+ O& K; L+ r  I: x  当CPOL = 1, CPHA = 1时! s4 R" C6 r9 P7 F' k
SCK引脚在空闲状态处于低电平,SCK引脚的第2个边沿捕获传输的第1个数据。
, ^1 ~$ g  Q( A$ f- F9 A8 V" N/ |- {5 v7 r% X  M
  当CPOL = 0, CPHA = 1时6 N# k/ w9 c; c& p
SCK引脚在空闲状态处于高电平,SCK引脚的第2个边沿捕获传输的第1个数据。
" S' ?* a' K, b: s1 n4 A$ c
  `9 N7 j: ?  I& w$ S8 m  当CPOL = 1, CPHA = 0时
' [. ?1 G* D  J$ T- B( gSCK引脚在空闲状态处于低电平,SCK引脚的第1个边沿捕获传输的第1个数据。0 i- ]# Z; y+ P5 E% k  ?
& b. u2 W6 X, l
  当CPOL = 1, CPHA = 0时0 D- C8 B) J% v" Z0 ^
SCK引脚在空闲状态处于高电平,SCK引脚的第1个边沿捕获传输的第1个数据。
1 h) x! ]# b; M
& c0 j5 o* A4 e& ?/ T% ?, i7 f72.3 SPI总线的HAL库用法% r& @2 g" W1 V7 H
72.3.1 SPI总线结构体SPI_TypeDef! p) ~# m: O0 t0 r# k5 ~
SPI总线相关的寄存器是通过HAL库中的结构体SPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:" I1 C% y. j% Q5 Y
8 t' J" n" I! ^2 }1 }2 t
  1. typedef struct
    # @7 ~6 f; e( c) ]* r/ \4 a
  2. {
    9 N( B, I; r) R1 F! E& }
  3.   __IO uint32_t CR1;           /*!< SPI/I2S Control register 1,                      Address offset: 0x00 */6 p6 E8 B5 [  B: i/ f* P% G
  4.   __IO uint32_t CR2;           /*!< SPI Control register 2,                          Address offset: 0x04 */
    2 T  j$ T9 e( U2 ^& C
  5.   __IO uint32_t CFG1;          /*!< SPI Configuration register 1,                    Address offset: 0x08 */0 B4 s# w8 R, v* v8 P
  6.   __IO uint32_t CFG2;          /*!< SPI Configuration register 2,                    Address offset: 0x0C */5 ^( E7 m6 r0 b( {% o/ E/ W
  7.   __IO uint32_t IER;           /*!< SPI/I2S Interrupt Enable register,               Address offset: 0x10 */7 Q* Y) Y% @. v2 |
  8.   __IO uint32_t SR;            /*!< SPI/I2S Status register,                         Address offset: 0x14 */
    2 u1 {2 W/ \3 h7 z2 v% E
  9.   __IO uint32_t IFCR;          /*!< SPI/I2S Interrupt/Status flags clear register,   Address offset: 0x18 */
    4 P( S+ ?1 i% N; E& }2 T. U3 {
  10.   uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                        */, J6 K: b. t$ O9 ~3 y2 ?
  11.   __IO uint32_t TXDR;          /*!< SPI/I2S Transmit data register,                  Address offset: 0x20 */: T0 ^3 V$ ~/ p" O
  12.   uint32_t      RESERVED1[3];  /*!< Reserved, 0x24-0x2C                                                   */
      P) a6 d5 T% U
  13.   __IO uint32_t RXDR;          /*!< SPI/I2S Receive data register,                   Address offset: 0x30 */
    . Y/ m( f/ O, c+ J$ j; t
  14.   uint32_t      RESERVED2[3];  /*!< Reserved, 0x34-0x3C                                                   */2 `8 [+ k: V2 ]& I
  15.   __IO uint32_t CRCPOLY;       /*!< SPI CRC Polynomial register,                     Address offset: 0x40 */
    4 [: a& ^; ?! d! i
  16.   __IO uint32_t TXCRC;         /*!< SPI Transmitter CRC register,                    Address offset: 0x44 */
    3 R+ |8 i9 D* R2 G+ G
  17.   __IO uint32_t RXCRC;         /*!< SPI Receiver CRC register,                       Address offset: 0x48 */- i) I, O9 V6 ]2 F
  18.   __IO uint32_t UDRDR;         /*!< SPI Underrun data register,                      Address offset: 0x4C */0 x: c+ p& q2 }2 V; L
  19.   __IO uint32_t I2SCFGR;       /*!< I2S Configuration register,                      Address offset: 0x50 */
    . O( ^' L6 P/ \" r

  20. 2 X- }1 ^2 d, \' \; n; L
  21. } SPI_TypeDef;
复制代码

2 n4 k9 P" ~- b' f# Y- h这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。+ Z- Y. T" G' V
9 d3 \* G" o1 `# F+ }
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
& A7 w- e! R& P+ D8 _4 O* I1 m5 F- @' R
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    ; r6 d" E  _, C
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

. A. o# Q8 I5 ~下面我们看下SPI的定义,在stm32h743xx.h文件。2 Y% {" B& H: A* [

! u4 w# J$ s# U" _
  1. #define PERIPH_BASE           (0x40000000UL)
    ) u9 n8 G9 Y# z$ k' c0 \( B0 y: _
  2. #define D2_APB1PERIPH_BASE     PERIPH_BASE; D, s+ l/ m& `$ @2 I. K. [' o
  3. #define D2_APB2PERIPH_BASE    (PERIPH_BASE + 0x00010000UL), A8 T: d5 Z+ ]6 q; o
  4. #define D3_APB1PERIPH_BASE    (PERIPH_BASE + 0x18000000UL); c; m- c: g& m! w

  5. ( t" ]( Y$ S; E$ n; S5 [
  6. #define SPI2_BASE             (D2_APB1PERIPH_BASE + 0x3800UL)$ V* o  s. p, u' ~
  7. #define SPI3_BASE             (D2_APB1PERIPH_BASE + 0x3C00UL)6 f2 p9 j0 v2 R) Y: L8 A
  8. #define SPI1_BASE             (D2_APB2PERIPH_BASE + 0x3000UL)& w" k7 _/ Y0 A$ o  U
  9. #define SPI4_BASE             (D2_APB2PERIPH_BASE + 0x3400UL)8 q) u) S0 u! ~, a% D: R6 ~" B" [4 T5 s
  10. #define SPI5_BASE             (D2_APB2PERIPH_BASE + 0x5000UL)# U8 ~+ V5 ^# ^' m' i
  11. #define SPI6_BASE             (D3_APB1PERIPH_BASE + 0x1400UL)
    5 }( [6 G8 L! R. |6 C4 ~

  12. + O) X2 n+ O7 _% n; e) G9 ]5 X
  13. #define SPI1                ((SPI_TypeDef *) SPI1_BASE)
    ! [. o* Z  [5 F2 T- ^
  14. #define SPI2                ((SPI_TypeDef *) SPI2_BASE)% U3 d( M% Y* \# ^' e3 {& ~
  15. #define SPI3                ((SPI_TypeDef *) SPI3_BASE)! F1 X' _# e% R4 ^# S% U
  16. #define SPI4                ((SPI_TypeDef *) SPI4_BASE)
    : Y; n5 d' g# v9 ?
  17. #define SPI5                ((SPI_TypeDef *) SPI5_BASE)  D* `: e0 k' ^# D8 E
  18. #define SPI6                ((SPI_TypeDef *) SPI6_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x58001400
复制代码

5 M6 o4 z2 {6 ]7 C我们访问SPI的CR1寄存器可以采用这种形式:SPI->CR1 = 0。
7 O0 E% O7 v' k% L0 @: E2 o
9 p: |# x1 V  N" i72.3.2 SPI总线初始化结构体SPI_InitTypeDef
/ `4 `+ F5 S' F7 E( C下面是SPI总线的初始化结构体,用到的地方比较多:( W0 l( o2 m9 a  Z7 g5 a5 [* R6 ^9 P
* H% w& u: R8 p. m4 E) s2 T
  1. typedef struct
    - U/ _& M- ?+ t) u+ m7 _8 d9 g* |% J
  2. {
    * N0 \& t3 k: T
  3.   uint32_t Mode;                           
    - l1 K2 @1 O* M& N
  4.   uint32_t Direction;                      ; [* C- p$ A& h" h$ G
  5.   uint32_t DataSize;                          
    2 v2 |- I6 W. D$ Z- @  d' Y
  6.   uint32_t CLKPolarity;                       
    ; Z" n) a5 `. h6 F2 o
  7.   uint32_t CLKPhase;                        
    / l6 F# K! S% a! n% N
  8.   uint32_t NSS;                             7 C' A% U! Z7 f. \. _9 {) j
  9.   uint32_t BaudRatePrescaler;               
    : K  [4 A4 z6 c$ e
  10.   uint32_t FirstBit;                         1 c9 I/ q# z7 V/ t! ]) K. o
  11.   uint32_t TIMode;                          7 q, R' ~: R% n7 V4 x
  12.   uint32_t CRCCalculation;                   : c$ H3 a; s6 u, h  d- O, J
  13.   uint32_t CRCPolynomial;                     
    1 z) f' m! v9 o
  14.   uint32_t CRCLength;                        4 t2 }' I" I1 R# K* ?- z
  15.   uint32_t NSSPMode;                        
    ) q. D: F5 T* J$ k
  16.   uint32_t NSSPolarity;                    4 s% B. D) l! ?- d. r- o
  17.   uint32_t TxCRCInitializationPattern;      
    ) v4 W. X9 h. e1 f- z& b4 G; e1 ^
  18.   uint32_t RxCRCInitializationPattern;       ( P9 J& ~, f; c& r3 c& X
  19.   uint32_t MasterSSIdleness;                 
    3 f: T8 R- G/ y, V
  20.   uint32_t MasterInterDataIdleness;           ' O* E) D5 }! c
  21.   uint32_t MasterReceiverAutoSusp;          7 \$ |' B) P0 f, F' {
  22.   uint32_t MasterKeepIOState;               
    + T" K0 a( l" ?# c
  23.   uint32_t IOSwap;                          
      p7 |" p7 r% E" g& p0 l
  24. } SPI_InitTypeDef;
复制代码
& u; c8 ~- `2 V
下面将结构体成员逐一做个说明:8 S5 r* n! M. H

! T2 Z, ?, j  k: s: {  Mode/ i2 ~- h; T: P; _; A4 _* I7 I- X; M
用于设置工作在主机模式还是从机模式。0 p% y1 \" ]* \5 ^' G3 S9 O
1 X' C; O1 }. [! z) _$ x
  1. #define SPI_MODE_SLAVE              (0x00000000UL)6 E) [, @, z$ Y) @2 T5 S% \6 [
  2. #define SPI_MODE_MASTER             SPI_CFG2_MASTER
复制代码
. h+ k+ [* [5 p: p9 g% p
  Direction7 b: ^, ?) o, e; P, i
用于设置SPI工作在全双工,单工,还是半双工模式。. R% a3 ^7 @9 A; r4 r# P# e
  1. #define SPI_DIRECTION_2LINES           (0x00000000UL)     /* 全双工 */9 D3 ?6 U4 C, b/ Q! U: @
  2. #define SPI_DIRECTION_2LINES_TXONLY     SPI_CFG2_COMM_0   /* 单工,仅发送 */
    # L5 X/ c- A1 k. ^) w" J
  3. #define SPI_DIRECTION_2LINES_RXONLY     SPI_CFG2_COMM_1   /* 单工,仅接收 */
    " e" i1 g4 o) T+ d; r
  4. #define SPI_DIRECTION_1LINE             SPI_CFG2_COMM     /* 半双工 */
复制代码
+ Y* o. d  `: R  A/ X
  DataSize
: ]0 W8 @; B) {4 a用于设置SPI总线数据收发的位宽,支持4-32bit。
6 M. c  \' R& f6 D1 {; ?
: |5 i8 P; z* c+ q# `
  1. #define SPI_DATASIZE_4BIT                             (0x00000003UL)) I- k0 l6 D6 K0 e- s
  2. #define SPI_DATASIZE_5BIT                             (0x00000004UL)$ j/ S' S! |: Y' L9 A7 J
  3. #define SPI_DATASIZE_6BIT                             (0x00000005UL)' Z$ ^  `# Y* F1 G3 Z  F
  4. #define SPI_DATASIZE_7BIT                             (0x00000006UL), _: v, W' l8 K9 `$ @* a
  5. #define SPI_DATASIZE_8BIT                             (0x00000007UL)
    2 \& ~5 f7 _  Z) s+ e$ z$ b
  6. #define SPI_DATASIZE_9BIT                             (0x00000008UL)
    - e; ^' V5 M8 u
  7. #define SPI_DATASIZE_10BIT                            (0x00000009UL)4 M  v# T9 W' P4 Z2 H$ u* T% ?/ F
  8. #define SPI_DATASIZE_11BIT                            (0x0000000AUL)! [& w+ I) f" Z
  9. #define SPI_DATASIZE_12BIT                            (0x0000000BUL)! |# R6 n* l; I9 \/ d0 _; g% L
  10. #define SPI_DATASIZE_13BIT                            (0x0000000CUL)6 x- y2 @% s4 I- I
  11. #define SPI_DATASIZE_14BIT                            (0x0000000DUL)% o! y4 J/ y6 `1 ^
  12. #define SPI_DATASIZE_15BIT                            (0x0000000EUL)9 f. h9 R8 n$ z: R' W% `
  13. #define SPI_DATASIZE_16BIT                            (0x0000000FUL)
    ; m9 T5 c2 F& D  M% F3 O3 O# q$ M; m
  14. #define SPI_DATASIZE_17BIT                            (0x00000010UL)8 f' x7 x6 ^( ~+ S
  15. #define SPI_DATASIZE_18BIT                            (0x00000011UL)& h# Z1 J  Z0 Q* u( q% T) B$ F
  16. #define SPI_DATASIZE_19BIT                            (0x00000012UL)
    : \+ P6 O+ p1 J0 Y
  17. #define SPI_DATASIZE_20BIT                            (0x00000013UL)
    / x0 a. t3 p: d7 ]
  18. #define SPI_DATASIZE_21BIT                            (0x00000014UL)
    ( K8 S5 C* M+ R0 s
  19. #define SPI_DATASIZE_22BIT                            (0x00000015UL)3 M1 S; T1 f3 P) w+ ^1 x
  20. #define SPI_DATASIZE_23BIT                            (0x00000016UL)
    0 S  O6 T4 W6 n# D: B, m% g( y( X$ p  v
  21. #define SPI_DATASIZE_24BIT                            (0x00000017UL)
    # Z7 P# I* z9 H( d
  22. #define SPI_DATASIZE_25BIT                            (0x00000018UL)
    9 s9 S6 S+ d3 C- ~: O
  23. #define SPI_DATASIZE_26BIT                            (0x00000019UL)
    6 @( @1 ^3 r- `/ f) r4 o8 M/ X
  24. #define SPI_DATASIZE_27BIT                            (0x0000001AUL)
    ' \4 @) Z9 t( F+ `8 K
  25. #define SPI_DATASIZE_28BIT                            (0x0000001BUL)% D  M) N) h1 S) J% D9 ?+ S8 f$ B
  26. #define SPI_DATASIZE_29BIT                            (0x0000001CUL)
    / [& v, ?- O" l) `! u
  27. #define SPI_DATASIZE_30BIT                            (0x0000001DUL)5 k6 ~5 u% X) s1 Z  m2 ?! R" w& I; G
  28. #define SPI_DATASIZE_31BIT                            (0x0000001EUL)6 b: a( n5 G" o
  29. #define SPI_DATASIZE_32BIT                            (0x0000001FUL)
复制代码

& z. o- J" G1 ?. o% V  CLKPolarity: J" q8 O. \" f( f6 U
用于设置空闲状态时,CLK是高电平还是低电平。
- f% N8 a/ q0 ]( \
( y! \5 A( b3 y2 L
  1. #define SPI_POLARITY_LOW       (0x00000000UL)
      {- A9 J, \- @. H2 V! ^% e: A
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码
9 X& K. ~, [( I) F( q/ M! h
  NSS% U" _9 K' {, b
用于设置NSS信号由硬件NSS引脚管理或者软件SSI位管理。) x+ ?& Q0 z3 l7 Q/ F3 t2 C6 {

, v! \5 S; h+ P4 [% ^7 M
  1. #define SPI_NSS_SOFT                                  SPI_CFG2_SSM
    4 x& {) ]; j" ^/ U& u+ c4 `
  2. #define SPI_NSS_HARD_INPUT                            (0x00000000UL): d" H9 \, \% \4 Q9 D6 k
  3. #define SPI_NSS_HARD_OUTPUT                           SPI_CFG2_SSOE
复制代码
5 y7 _' l" n1 d4 b% R/ S% S
  BaudRatePrescaler3 x0 g% ]8 T" b' f1 [
用于设置SPI时钟分频,仅SPI工作在主控模式下起作用,对SPI从机模式不起作用。
) q2 h7 q3 j" r
9 k& d* `+ y9 f4 _
  1. #define SPI_BAUDRATEPRESCALER_2                       (0x00000000UL)* L5 G, n" J% c7 x3 Q: w7 {
  2. #define SPI_BAUDRATEPRESCALER_4                       (0x10000000UL)6 _4 T4 P3 ]" t+ \7 J2 i2 L
  3. #define SPI_BAUDRATEPRESCALER_8                       (0x20000000UL)
    $ g4 \9 G" u/ F* a  C7 R
  4. #define SPI_BAUDRATEPRESCALER_16                      (0x30000000UL)/ X' V0 _/ L- ]) d: E8 D, c9 {
  5. #define SPI_BAUDRATEPRESCALER_32                      (0x40000000UL), s  q3 y; [) f9 @; D9 u# q
  6. #define SPI_BAUDRATEPRESCALER_64                      (0x50000000UL)0 Q( R$ g. D1 j) ~/ `
  7. #define SPI_BAUDRATEPRESCALER_128                     (0x60000000UL)
    , O9 J% r: h& b" T
  8. #define SPI_BAUDRATEPRESCALER_256                     (0x70000000UL)
复制代码
+ r; s) l% g& r; F% G6 Q$ d
  FirstBit3 r# a# W# `% Q2 O
用于设置数据传输从最高bit开始还是从最低bit开始。
" T9 {0 F$ h/ Q6 H) I3 i% x0 D$ K0 D* e
  1. #define SPI_FIRSTBIT_MSB                              (0x00000000UL)
    0 d, b8 g5 r- R+ d* v
  2. #define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST1 Z2 k* ]  x# j  \3 V3 w
复制代码

4 t" d6 R" N% ~$ V, D% n  TIMode
2 c" @  `# D4 R用于设置是否使能SPI总线的TI模式。
& Y1 h$ W! O1 n. s$ J3 J) n, C
+ }6 y+ E; E! r/ \- p- E
  1. #define SPI_TIMODE_DISABLE               (0x00000000UL)
    ( g, M4 z/ I) d: N# s/ s" a7 T
  2. #define SPI_TIMODE_ENABLE                SPI_CFG2_SP_0
复制代码

) a! c3 r  D9 `0 K& |8 E  CRCCalculation
2 s# J+ u) Q% j3 q+ @# K用于设置是否使能CRC计算。
. m1 @7 |& h% M  y' }( O4 U) |( Y2 }3 K& j  m9 t
  1. #define SPI_CRCCALCULATION_DISABLE                    (0x00000000UL); G/ n$ L! e% C5 D0 l) P( i6 L& P
  2. #define SPI_CRCCALCULATION_ENABLE                     SPI_CFG1_CRCEN
复制代码
9 b3 {# o$ o( z2 q
  CRCPolynomial! G, J! m0 j- ^( _. l5 p
用于设置CRC计算使用的多项式,必须是奇数,范围0到65535。6 Y7 {" }& L- f1 F% [, o" G
) V: X) D# E) e6 w1 N
  CRCLength
$ q* ?1 M, a/ A* ~0 e2 h! c用于设置CRC计算时的CRC长度。大小要与同属此结构体的DataSize一致。或是DataSize的整数倍。% d. b* ]% C  g+ C& w
! i- R) s; K: I- I  T  j3 O! p4 ~
  1. #define SPI_CRC_LENGTH_DATASIZE                       (0x00000000UL)
    3 _* J; R" s# X% T3 s2 T8 z
  2. #define SPI_CRC_LENGTH_4BIT                           (0x00030000UL)1 B7 S4 w; w3 L! K
  3. #define SPI_CRC_LENGTH_5BIT                           (0x00040000UL)
    9 z2 H; r& ~* E* v1 r1 k# z
  4. #define SPI_CRC_LENGTH_6BIT                           (0x00050000UL)
    4 X+ E$ y5 I+ [, H, C6 a
  5. #define SPI_CRC_LENGTH_7BIT                           (0x00060000UL)6 [3 |; J- `! k1 P3 h
  6. #define SPI_CRC_LENGTH_8BIT                           (0x00070000UL)4 \8 T2 t9 a3 v' Q* b- Y8 E
  7. #define SPI_CRC_LENGTH_9BIT                           (0x00080000UL), }4 Q7 E5 T) ^
  8. #define SPI_CRC_LENGTH_10BIT                          (0x00090000UL)9 |  X# N) B! d+ v" q1 \
  9. #define SPI_CRC_LENGTH_11BIT                          (0x000A0000UL)
    " x6 J. O5 c% Z( z
  10. #define SPI_CRC_LENGTH_12BIT                          (0x000B0000UL)
    5 e! F$ `: K! W5 f( P( S
  11. #define SPI_CRC_LENGTH_13BIT                          (0x000C0000UL)% [' R% K- ?' I* `
  12. #define SPI_CRC_LENGTH_14BIT                          (0x000D0000UL)' |* d5 G/ p+ ^$ s, r; ], j
  13. #define SPI_CRC_LENGTH_15BIT                          (0x000E0000UL)+ ~. Y% J; w  H/ t- t1 a
  14. #define SPI_CRC_LENGTH_16BIT                          (0x000F0000UL)
    2 u6 p8 C8 S5 X3 H" A: m
  15. #define SPI_CRC_LENGTH_17BIT                          (0x00100000UL)
    9 I7 r# V  f+ V: c
  16. #define SPI_CRC_LENGTH_18BIT                          (0x00110000UL)
    + i6 i. K! Y: B/ G' e; M7 c
  17. #define SPI_CRC_LENGTH_19BIT                          (0x00120000UL)
    / Q% N, Z  c5 \$ V2 H# d
  18. #define SPI_CRC_LENGTH_20BIT                          (0x00130000UL)
    5 K& O/ F8 a8 R* h& ?. e6 b! r
  19. #define SPI_CRC_LENGTH_21BIT                          (0x00140000UL)
    # Q, U1 ?7 Q) j4 U
  20. #define SPI_CRC_LENGTH_22BIT                          (0x00150000UL)
    1 Y7 k; f# p9 W; ]# n/ u
  21. #define SPI_CRC_LENGTH_23BIT                          (0x00160000UL)
    0 L  p" n% p4 ^
  22. #define SPI_CRC_LENGTH_24BIT                          (0x00170000UL)
    $ I) Y2 k3 @: G; K! V: h( R
  23. #define SPI_CRC_LENGTH_25BIT                          (0x00180000UL)/ E8 G4 `4 J2 I8 U. i
  24. #define SPI_CRC_LENGTH_26BIT                          (0x00190000UL)
    # C) I  [$ t  b; A
  25. #define SPI_CRC_LENGTH_27BIT                          (0x001A0000UL)9 b$ P$ o" G* ^- J8 X; _: R, T
  26. #define SPI_CRC_LENGTH_28BIT                          (0x001B0000UL)3 b& R' W0 p; X
  27. #define SPI_CRC_LENGTH_29BIT                          (0x001C0000UL)0 ?8 O4 E' X2 R0 k
  28. #define SPI_CRC_LENGTH_30BIT                          (0x001D0000UL)
    , O+ K1 C  O  \
  29. #define SPI_CRC_LENGTH_31BIT                          (0x001E0000UL)2 {$ |# |' _7 M0 g
  30. #define SPI_CRC_LENGTH_32BIT                          (0x001F0000UL)
复制代码

1 m  f9 B2 d  n/ F. f4 X, ?1 t6 l1 a1 m4 a
; E5 E, M0 j5 [& T1 ?
  NSSPMode, ?* ^; |& b! V: I, g$ e
用于设置是否使能NSSP信号,可以通过SPIx_CR2寄存器的SSOM位使能。注意,只有配置为摩托罗拉SPI主控模式时设置此成员才有用。
1 k$ p$ `! x4 M  h$ w3 V8 ~* a# Q: W) J; ?. [
  1. #define SPI_NSS_PULSE_DISABLE                         (0x00000000UL)  k+ l) d' ~5 N0 {4 ^7 c8 l
  2. #define SPI_NSS_PULSE_ENABLE                          SPI_CFG2_SSOM
复制代码
3 b, q' q2 v4 ?2 r7 m
  NSSPolarity! i3 _7 v5 C' Q# P
用于设置NSS引脚上的高电平或者低电平作为激活电平。
) }) W- s/ S. J% \$ f3 f
3 e7 y+ j% j+ \# Q/ V
  1. #define SPI_NSS_POLARITY_LOW                          (0x00000000UL)! K% I: ?8 M$ e3 L& d' f/ I3 C
  2. #define SPI_NSS_POLARITY_HIGH                          SPI_CFG2_SSIOP
复制代码

6 Z9 y5 |: t* m) D& c/ r! p  FifoThreshold
2 l2 `- s) h  t用于设置SPI的FIFO阀值。
) T  p$ H7 k' X$ G( |4 z2 F1 F: e+ H& g* S: P
  1. #define SPI_FIFO_THRESHOLD_01DATA                     (0x00000000UL); P2 n' B% ]8 n
  2. #define SPI_FIFO_THRESHOLD_02DATA                     (0x00000020UL)5 r" C3 w; z, y
  3. #define SPI_FIFO_THRESHOLD_03DATA                     (0x00000040UL)
    $ ^: u  W1 {7 W
  4. #define SPI_FIFO_THRESHOLD_04DATA                     (0x00000060UL)- ~6 f- `+ b6 F7 v; Y( @
  5. #define SPI_FIFO_THRESHOLD_05DATA                     (0x00000080UL)9 `3 Z$ n9 w, M% P/ z; t" f8 w
  6. #define SPI_FIFO_THRESHOLD_06DATA                     (0x000000A0UL)( x% N) @: _& Z3 s0 d
  7. #define SPI_FIFO_THRESHOLD_07DATA                     (0x000000C0UL)
    ( J# c! X) R. @2 R
  8. #define SPI_FIFO_THRESHOLD_08DATA                     (0x000000E0UL)7 J- X  U! n  v( K! c4 f( W
  9. #define SPI_FIFO_THRESHOLD_09DATA                     (0x00000100UL)
    2 p6 o9 C5 h% d. {8 Y
  10. #define SPI_FIFO_THRESHOLD_10DATA                     (0x00000120UL)6 b' v5 I  m( |
  11. #define SPI_FIFO_THRESHOLD_11DATA                     (0x00000140UL)
    + ^3 ]5 J- n9 i- t' O) P
  12. #define SPI_FIFO_THRESHOLD_12DATA                     (0x00000160UL)0 q( h  a$ ^0 Y, @' {, J
  13. #define SPI_FIFO_THRESHOLD_13DATA                     (0x00000180UL)
    $ m+ q- o/ ^; Y! L/ C; M
  14. #define SPI_FIFO_THRESHOLD_14DATA                     (0x000001A0UL)0 I6 x; C1 U7 ^1 s7 E% \
  15. #define SPI_FIFO_THRESHOLD_15DATA                     (0x000001C0UL)
      Y4 C- l6 E: c+ j$ _% y( {
  16. #define SPI_FIFO_THRESHOLD_16DATA                     (0x000001E0UL)6 h3 t& j' }# I8 g1 L' n% f
复制代码
( Z# S& f' Q8 Y: Q
& g- J( k( X' G5 S2 M8 ]
  TxCRCInitializationPattern
3 T  V1 X2 P8 P% j9 }* Q发送CRC初始化模式。: y& i5 u& S( R5 |

2 J8 M7 g6 b$ c/ r( Q3 g8 {
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)" h1 j- _1 N5 N$ G+ ]0 Y* e+ G
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
    " ~6 I1 e1 X  i" ?
复制代码
" c2 |0 H, t( e* a2 o* K
  RxCRCInitializationPattern% j2 `# r  p1 o
接收CRC初始化模式5 ?1 C: H- p' A8 k% X
8 i1 M8 M3 e7 Z0 o( X6 n
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)! P; R% u  x4 x/ g5 _# w+ `# `
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码

) F- S# D2 J4 }) N3 q) n6 Y0 z MasterSSIdleness: v9 g" E, y" @0 q
在主模式下插入到SS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数。
8 E4 S6 P" I0 Q* `9 p, d5 G# A
+ F8 x4 C0 |2 S7 U
  1. #define SPI_MASTER_SS_IDLENESS_00CYCLE                (0x00000000UL)
    4 k% I; m& g1 X: S( D5 g, w% o
  2. #define SPI_MASTER_SS_IDLENESS_01CYCLE                (0x00000001UL)
    ) d; S! I1 ?5 }* H
  3. #define SPI_MASTER_SS_IDLENESS_02CYCLE                (0x00000002UL)
    3 X% x8 M" p  j9 {, S
  4. #define SPI_MASTER_SS_IDLENESS_03CYCLE                (0x00000003UL)5 d  J& |& H! Q. D, Q' A
  5. #define SPI_MASTER_SS_IDLENESS_04CYCLE                (0x00000004UL)3 [2 J7 Q3 `4 `* g# m
  6. #define SPI_MASTER_SS_IDLENESS_05CYCLE                (0x00000005UL)$ y. ]+ P/ Z( {: i2 Q' E. h
  7. #define SPI_MASTER_SS_IDLENESS_06CYCLE                (0x00000006UL)8 \- A- D' E; e& b" Y1 F6 `1 t
  8. #define SPI_MASTER_SS_IDLENESS_07CYCLE                (0x00000007UL)9 e! ~/ ^  M4 s- ~, y
  9. #define SPI_MASTER_SS_IDLENESS_08CYCLE                (0x00000008UL)
    . ]0 H2 P, c4 n0 t6 @# z" o' {) H4 B
  10. #define SPI_MASTER_SS_IDLENESS_09CYCLE                (0x00000009UL)
    9 s6 \. I+ `. n2 J7 O
  11. #define SPI_MASTER_SS_IDLENESS_10CYCLE                (0x0000000AUL)
    " B) `/ D7 c! C. H3 _
  12. #define SPI_MASTER_SS_IDLENESS_11CYCLE                (0x0000000BUL)
    ! U9 i$ H" p4 t1 F7 [2 h) k4 A4 L
  13. #define SPI_MASTER_SS_IDLENESS_12CYCLE                (0x0000000CUL)# o) [/ Q9 z. h0 Z
  14. #define SPI_MASTER_SS_IDLENESS_13CYCLE                (0x0000000DUL)
    1 ?9 S8 I) o  k( _) q5 q! S
  15. #define SPI_MASTER_SS_IDLENESS_14CYCLE                (0x0000000EUL)$ D7 l; c5 }$ Y
  16. #define SPI_MASTER_SS_IDLENESS_15CYCLE                (0x0000000FUL)9 Y% H6 W' v0 ?4 [6 ~" t
复制代码

8 g5 K) B: j9 P, v! |5 D+ a  `$ {) G, t: u9 k8 }6 m. ^
  MasterInterDataIdleness- Y/ g+ B5 i2 J% t9 U; e: Y. l
主模式下在两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数。, m' n' ~; E, H7 ?% a

6 Q6 [. J8 o$ |- d) w
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)' \$ Z+ [2 P, |& e% h& m
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
复制代码
3 Y; N0 U9 ?& |. i
  MasterReceiverAutoSusp
9 V- j# e7 K& K/ e; ~用于控制主器件接收器模式下的连续 SPI 传输以及自动管理,以避免出现上溢情况。" p! _5 `- L: v

% W4 X  ?/ J5 U( v4 n8 @
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)3 J% A$ F: z7 s
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX* E1 S) @( C+ n  o1 I
复制代码

0 P% Y/ T( |& O1 }  MasterKeepIOState
" K% ?8 A" k! f' e& W禁止SPI后,SPI相关引脚保持当前状态,以防止出现毛刺。在从模式下,该位不应该使用。
& j7 U0 t- C9 V6 p/ O' _8 s/ h, }  P, Q
  1. #define SPI_MASTER_KEEP_IO_STATE_DISABLE              (0x00000000UL)
    $ X* F: r/ V$ F1 }- w/ L
  2. #define SPI_MASTER_KEEP_IO_STATE_ENABLE               SPI_CFG2_AFCNTR
复制代码

, ]2 V; L8 K' n# Y  IOSwap1 u7 p8 n! o" o/ Q' r0 C
用于交换MISO和MOSI引脚。7 L6 |  l  N( O$ B

7 b- u* W: v" `4 r
  1. #define SPI_IO_SWAP_DISABLE                           (0x00000000UL)2 |  ^& c) X: }9 N
  2. #define SPI_IO_SWAP_ENABLE                            SPI_CFG2_IOSWP
复制代码

6 ~+ i4 X! @; f+ M/ `; `72.3.3 SPI总线句柄结构体SPI_HandleTypeDef
: C7 y( ~6 b6 i下面是SPI总线的初始化结构体,用到的地方比较多:
# b) ]) K7 i: x" D
- _4 V: v1 Q/ d) Q% C
  1. typedef struct __SPI_HandleTypeDef; C* O2 F, J# {: [( R/ l; E" v
  2. {
    # l( |$ W, Z6 J" Z( r
  3.   SPI_TypeDef                *Instance;                 ' O& r5 w' d, X5 J4 L7 g" K) v; b
  4.   SPI_InitTypeDef            Init;                        
    ; Q: H; ~, T) L) N8 k+ H5 y- N
  5.   uint8_t                    *pTxBuffPtr;                 
    5 E3 ], R( t: g8 Q8 Z4 t; q& i
  6.   uint16_t                   TxXferSize;                   3 ~% [6 K1 u7 L: v. Y8 E
  7.   __IO uint16_t              TxXferCount;                  0 T( P, m8 u8 R& `+ R6 a2 n
  8.   uint8_t                    *pRxBuffPtr;               
    + [- q0 B2 o4 ?- x+ }2 R% b! i2 X
  9.   uint16_t                   RxXferSize;                  
    ; z+ a) g8 K5 v( Y
  10.   __IO uint16_t              RxXferCount;                 
    3 p0 p7 ]) q. H
  11.   uint32_t                   CRCSize;                     4 f) c/ E' n0 H( P, ^4 _; S. @6 Z
  12.   void (*RxISR)(struct __SPI_HandleTypeDef *hspi);       7 Q& ]9 ]1 t- H% [# k1 N6 g  |
  13.   void (*TxISR)(struct __SPI_HandleTypeDef *hspi);        # B4 i" B8 w# _
  14.   DMA_HandleTypeDef          *hdmatx;                     
    & H5 p, G1 Q7 Y1 ?  |
  15.   DMA_HandleTypeDef          *hdmarx;                     8 G& P6 J# @; S( j" [
  16.   HAL_LockTypeDef            Lock;                        ! ^7 t- Q8 s6 Y& ]5 k: ^5 ?
  17.   __IO HAL_SPI_StateTypeDef  State;                        - g5 g2 \% I* `6 M8 `2 i
  18.   __IO uint32_t              ErrorCode;                  
    1 y2 O1 |* A+ f
  19. #if defined(USE_SPI_RELOAD_TRANSFER)5 g7 Z9 l6 R& s6 [: l
  20.   SPI_ReloadTypeDef          Reload;                     
    5 Q' `( ^4 V$ h& o
  21. #endif
    4 M. D0 Q3 U8 a, P7 W
  22. ) g- Q2 x& |1 E6 ^
  23. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)! O  u. q" p/ j9 _
  24.   void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      
    - o, S! @! \( S4 M- a& B4 N! G
  25.   void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      
    2 j$ E' x% o; z  {1 M8 c& S
  26.   void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi);    . R/ Z9 }! J6 h/ G/ j; M5 |4 |  y  Q5 y
  27.   void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  . E* m. e+ I" k0 L
  28.   void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  
    0 z5 @1 z! V. o- }! p. h+ b" ~4 \
  29.   void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi); 5 \' Q. e- E5 I5 }
  30.   void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi);      
    4 E& _; E8 ~: J. z& ]. r$ t0 o# a" A
  31.   void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi);   - n+ H) U* @' e! B3 u) v! p) c
  32.   void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi);   
    : F( @3 G4 u# T5 O( D9 h
  33.   void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi);
    % f4 q# C9 U4 U7 w
  34. #endif  
    ( I( w; L6 `& c9 c
  35. } SPI_HandleTypeDef;
    + E% V$ |* h% U; T
复制代码

9 O6 |5 @2 J. \0 `7 m9 T! X+ A
( `+ J- n* h1 g. V* l( V注意事项:4 }% S  V8 u& m' E- L

' {" s$ m1 d( f3 k- n条件编译USE_HAL_SPI_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:: k0 N8 r; m/ x" R# r! c' t

) C3 Q% d; f7 m( X  #define   USE_HAL_SPI_REGISTER_CALLBACKS   1. _& S8 n8 v) b' r7 j9 C" X6 Y1 S' w

$ m2 G/ v5 [! v* o# S; O通过函数HAL_SPI_RegisterCallback注册回调,取消注册使用函数HAL_SPI_UnRegisterCallback。% h$ ?! X! L: e

( S5 `$ J/ t- H0 n8 g这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。0 c# x+ T! |; e& C* g
9 z+ O4 c  o- n. C
  SPI_TypeDef   *Instance
) e( d1 r6 \+ j! e: Y1 E0 C这个参数是寄存器的例化,方便操作寄存器,比如使能SPI1。6 h' P" }/ `0 A2 Y+ i

6 X4 }) G9 I8 c" d# ~) H8 C8 BSET_BIT(SPI1 ->CR1,  SPI_CR1_SPE)。) T6 e8 W8 N: q! k& L& Q
+ Y7 R' a9 m4 ?# V
  SPI_InitTypeDef  Init, _% A* t. G; A+ r2 U% }5 \  D
这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。+ H4 e1 G7 |3 i% Y: j
1 y9 y/ q/ N" _# J1 q& d
  DMA_HandleTypeDef          *hdmatx               
0 e- D* R1 m# G, G. A  DMA_HandleTypeDef          *hdmarx) K/ {* s% r% H7 ]$ U' k
用于SPI句柄关联DMA句柄,方便操作调用。
8 I: B9 h# U0 Y+ g, c& i
4 J7 X- y6 o% b, m- s72.4 SPI总线源文件stm32h7xx_hal_spi.c
. A1 ?6 A. g, b) C此文件涉及到的函数较多,这里把几个常用的函数做个说明:; K$ ?5 p7 i; a- I2 F' G

4 ?% p! O" w4 Q$ X3 H; j4 z  HAL_SPI_Init; M' G0 G% L6 r; B0 J+ Q
  HAL_SPI_DeInit9 V* }* q4 u5 V' U1 a8 S
  HAL_SPI_TransmitReceive
) ]* w4 c8 U/ D- S  HAL_SPI_TransmitReceive_IT
% S0 k% V& {) Q' V, W' d  HAL_SPI_TransmitReceive_DMA( C2 G1 n% T, F+ L6 k$ V2 Y( J" ]
72.4.1 函数HAL_SPI_Init' r$ I/ p8 u+ ^6 [
函数原型:/ i- u4 p( h& r4 z- r

4 c0 M8 m" x/ K5 y# k7 N3 f% m
  1. HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)4 F+ @) l  r. y' ^0 u5 J. m
  2. {
    8 ^! k. g( G  ~+ F
  3.   uint32_t crc_length = 0UL;5 a+ t$ _" d9 @1 O9 ?) s8 t
  4.   uint32_t packet_length;$ @; s5 A" H) x8 ]0 t- X7 ^
  5. 3 k1 |0 z2 j' `4 L
  6.   /* 省略未写 */
    ; Z, Z* A3 B! R0 y

  7. % }- s. C) h. o$ a
  8.   /* 如果数据位宽大于16bit,必须是SPI1,SPI2或者SPI3,而SPI4,SPI5和SPI6不支持大于16bit */
    3 A. B. j: M; @* `- R: e8 J
  9.   if ((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (hspi->Init.DataSize > SPI_DATASIZE_16BIT))& a" A$ p% h: D3 V* F
  10.   {
    3 n: y8 }" D! S  `. J% N' H
  11.     return HAL_ERROR;
    " p. x5 t+ |& I: R0 Z" F& D/ M
  12.   }
    & f- v( ^3 R) H% j

  13. & D9 E) l0 Y3 g# w
  14.   /* SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit1 t' J) D/ v7 ?. ~! K
  15.      这里是查看设置的缓冲大小是否超出了FIFO支持的大小。
    7 m2 q8 }0 U; j( f. n
  16. */
    2 v) k' m4 n9 d: ~& L1 N1 Q
  17.   packet_length = SPI_GetPacketSize(hspi);3 ?) L7 w, f( G* G
  18.   if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_LOWEND_FIFO_SIZE)) ||
    0 F6 U3 d9 s4 G# Q
  19.       ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_HIGHEND_FIFO_SIZE)))$ W5 m# K* N" u9 E
  20.   {
    7 ~% z: A5 W) E; @( l% B$ e
  21.     return HAL_ERROR;
    ; ?, Y& \  A( C' J4 ^5 r0 Y2 B: J/ e
  22.   }! N+ g$ q# P* G5 g/ f6 m: t/ P
  23. " q) b' C7 m' o& A; L3 t
  24. #if (USE_SPI_CRC != 0UL)
    ) ]8 b" m- _; g5 P$ }1 w
  25.     /* 省略未写 */2 q) h5 B- l( B( q4 `5 U% b
  26. #endif
    6 {( J% L( e. I6 |/ A: \9 Y
  27. & O2 x  A+ w4 m0 ~7 ]; r% K$ f, G% Q8 R
  28.   if (hspi->State == HAL_SPI_STATE_RESET)
    ) A5 Q5 h9 Z. _0 `9 \# F5 V
  29.   {. y: e! [3 x  c5 c3 @  d
  30.     /* 解锁 */
    3 j3 u5 c( s+ O. Y" I  P
  31.     hspi->Lock = HAL_UNLOCKED;
    % Y7 e! p$ N* o- Q% u4 n5 i
  32. ; e. A" w6 U* P$ A& d
  33.     /* 使用自定义回调 */
    ! E% ^# G/ E7 X6 Z
  34. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    9 \  Z/ B9 z: k( e
  35.     /* 设置默认回调函数 */* s: q) n% n* P4 t" r8 F) |
  36.     hspi->TxCpltCallback       = HAL_SPI_TxCpltCallback;       /* Legacy weak TxCpltCallback       */" N% a! g6 T( G: D. Y1 B9 U
  37.     hspi->RxCpltCallback       = HAL_SPI_RxCpltCallback;       /* Legacy weak RxCpltCallback       */
    , [& o# p' y+ |5 J0 U
  38.     hspi->TxRxCpltCallback     = HAL_SPI_TxRxCpltCallback;     /* Legacy weak TxRxCpltCallback     */( M: M6 n4 x8 l; j2 x2 ]. l
  39.     hspi->TxHalfCpltCallback   = HAL_SPI_TxHalfCpltCallback;   /* Legacy weak TxHalfCpltCallback   */
    & k; H8 Y2 m. z8 c9 E! q
  40.     hspi->RxHalfCpltCallback   = HAL_SPI_RxHalfCpltCallback;   /* Legacy weak RxHalfCpltCallback   */
    + Z/ j: @, K" p" y# O, B9 Z% x
  41.     hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */; K, g5 t- ~3 r' a9 f
  42.     hspi->ErrorCallback        = HAL_SPI_ErrorCallback;        /* Legacy weak ErrorCallback        */
    : d9 a3 s* q" V) ]- x
  43.     hspi->AbortCpltCallback    = HAL_SPI_AbortCpltCallback;    /* Legacy weak AbortCpltCallback    */( ^. {" \# M: Q$ ~9 b1 D* Z0 }3 ?

  44. 8 s" [4 x1 e; L2 t. N
  45.     if (hspi->MspInitCallback == NULL)" B9 E3 C; Z. I+ x, d' r
  46.     {
    . v1 v2 G1 L/ I: h) `. `# Q) [3 n8 P
  47.       hspi->MspInitCallback = HAL_SPI_MspInit;
    ) o% m( n8 q5 v3 S
  48.     }0 c- z" Y: f/ ^) Q

  49. ! h/ V4 _5 X. }& b! C8 U
  50.     /* 初始化地址硬件: GPIO, CLOCK, NVIC... */2 ~2 m5 g' u- X6 i' i4 L9 K
  51.     hspi->MspInitCallback(hspi);% i; m/ G7 p$ N6 i3 \  R
  52. #else1 H( }2 c/ e# ~; V0 y" |
  53.     /* 初始化底层硬件: GPIO, CLOCK, NVIC... */
    4 o2 O$ M+ r% F' C) K: o" x2 O
  54.     HAL_SPI_MspInit(hspi);
    ) s% N# F, [5 A& F
  55. #endif9 Z# a% j, i* d# @9 K
  56.   }4 g. }' f3 a6 o$ p# a9 e

  57. + M; G5 ?. F8 S# R
  58.   hspi->State = HAL_SPI_STATE_BUSY;
    5 W7 v' y0 q9 Y  t- e

  59. 2 g9 g3 h- r1 O/ W
  60.   /* 禁止SPI外设 */
    9 G* w; {) H% Q) u" Y) C
  61.   __HAL_SPI_DISABLE(hspi);
    ! @( ^; R# |4 z8 d
  62. 2 F) e) H) |. |7 Y* V/ S
  63.   /*----------------------- SPIx CR1 & CR2 配置---------------------*/, e6 B5 A8 n5 P
  64.   if ((hspi->Init.NSS == SPI_NSS_SOFT) && (hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.NSSPolarity ==
    / b% h$ k1 K5 p( F4 e
  65. SPI_NSS_POLARITY_LOW))
    . ~. Z6 a- U" M' S. m
  66.   {
    & Y# L2 C# R# ]( ~
  67.       SET_BIT(hspi->Instance->CR1, SPI_CR1_SSI);
    ) E  Z8 p. {  N' F
  68.   }& k, U7 y7 ?  c, t# G1 M7 @

  69. 0 O" _! @. O6 J7 T0 @
  70.   /* SPIx CFG1配置 */  {/ H  ~3 K% q/ y
  71.   WRITE_REG(hspi->Instance->CFG1, (hspi->Init.BaudRatePrescaler | hspi->Init.CRCCalculation | crc_length |
    ' k% H; u$ @# K1 Y% x- [
  72.                                    hspi->Init.FifoThreshold     | hspi->Init.DataSize));* Q8 Y6 N( H$ L1 |$ {: n7 W
  73. . p6 c! w* l; b4 `) p
  74.   /* SPIx CFG2配置 */
    $ O- d. l6 y! q' a
  75.   WRITE_REG(hspi->Instance->CFG2, (hspi->Init.NSSPMode     | hspi->Init.TIMode           | hspi->Init.NSSPolarity  |
    1 w2 c6 X: S' |& ~
  76.                                    hspi->Init.NSS          | hspi->Init.CLKPolarity      | hspi->Init.CLKPhase     |
    - Q! R3 I8 J  b! h! G
  77.                                    hspi->Init.FirstBit     | hspi->Init.Mode             | hspi->Init.MasterInterDataIdleness |# M" `* W5 V) X/ ^* d' U
  78.                                    hspi->Init.Direction    | hspi->Init.MasterSSIdleness | hspi->Init.IOSwap));
    ' q- k% C/ r. C+ Y# U. }( y
  79. / _* K0 z% l. `1 F9 a5 [8 F7 c7 g
  80. #if (USE_SPI_CRC != 0UL)$ w- j1 J/ p' k6 M
  81.   /*---------------------------- SPIx CRC配置 ------------------*/) p6 u! ~; N% z  H, c! x: E* g
  82.   /* 配置SPI CRC */* E% m8 F& l  d/ J
  83.   if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
    + d: H* ^2 e1 l
  84.   {+ C. ~3 l( H# x+ R( ?
  85.     /* 初始化TX CRC初始值 */
    9 U  I, n7 {3 @
  86.     if (hspi->Init.TxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)4 M! \) M! G$ D( }2 U7 \
  87.     {
    1 N$ V! P9 Q7 \$ _( [% Y! \. G' E; {
  88.       SET_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);+ W2 m0 t( ]- l* U; L
  89.     }
    " R* j$ e3 t# {- z4 l2 d+ w( a1 o0 S3 Z
  90.     else+ `5 b* `: @" Q4 X8 E# g" E# G% ?
  91.     {" Y) x1 G5 t7 p6 R9 W. o  q
  92.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);
    $ s, L6 Q: c5 e, `" t9 [* l2 Q
  93.     }
    . N9 u, ]/ E. ]! A7 f) L+ v# s
  94. 4 m/ g- v6 B: [3 I5 l  _( L. O
  95.     /* 初始化RXCRC初始值 */4 T& Y+ c0 i$ W
  96.     if (hspi->Init.RxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)6 V: H8 A* C0 B: R& i% u6 F9 G
  97.     {
    - s5 x. }. W- L
  98.       SET_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);; U$ w- d' U, {  p7 }
  99.     }
    2 L7 m, a; A3 W6 F% N
  100.     else
    & {5 H0 O5 g2 Q/ W/ m( n' I
  101.     {
    ) O  {9 X! [# v- U. Z$ P  U
  102.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);; {# ?5 _' H& ~) B/ ?( A! z* L
  103.     }. C6 ?; A0 g6 J3 D- g& m
  104. . o! g3 r" l5 e2 v
  105.     /* 使能 33/17 bit CRC计算 */6 J1 B3 G2 ^) Q( N& M' z3 k
  106.     if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (crc_length == SPI_CRC_LENGTH_16BIT)) ||
    5 ^( _9 y/ e+ N3 k
  107.         ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance))  && (crc_length == SPI_CRC_LENGTH_32BIT))): g6 y5 ]9 ^% K% H* z# `: r
  108.     {
    # \! \2 [$ |5 Y* ~! t. x( Y5 C1 ~
  109.       SET_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);( x* M, ?$ C* r6 F" [
  110.     }
    , Z/ e) a5 _8 z. V5 l! r% L
  111.     else
    - E' [: b, E3 V1 g4 L
  112.     {
    2 ~% ~9 ^1 R3 ?6 }8 A
  113.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);) c* V0 Y4 W, M( W3 N* X& m
  114.     }6 g' b# F. T1 V9 C0 Z0 L

  115. $ i) @# x8 `, F7 L
  116.     /* 写CRC多项式到SPI寄存器 */! w, Z( F" P) g
  117.     WRITE_REG(hspi->Instance->CRCPOLY, hspi->Init.CRCPolynomial);; @1 v( b# b3 \; m8 W0 g9 t5 T
  118.   }
    ; N8 B$ w( I; `  F2 N5 T: l7 H7 }
  119. #endif
    4 X* G2 r/ P4 U/ Z7 A- q+ u+ ^/ h% _
  120. # m. S& |9 C& U
  121.   /* SPI从模式,下溢配置 */
    $ w0 F$ I+ b6 ~5 f% g5 E  t# l
  122.   if (hspi->Init.Mode == SPI_MODE_SLAVE)
    % K4 m/ q' r/ x* r4 F0 C
  123.   {
    % ?, A& C" J1 s/ f' _
  124.     /* 设置默认下溢配置 */
    ' m: {3 _, F. w8 b3 R
  125. #if (USE_SPI_CRC != 0UL)
    6 u* j& {, G+ k1 ^
  126.     if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_DISABLE)) ?3 h7 G- J$ W+ K
  127. #endif
    ( k. W$ d) D* X
  128.     {
    ; `8 t) x; c3 x% H" w6 a" O
  129.       MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRDET, SPI_CFG1_UDRDET_0);
    " }. c1 Q" y  B' C) w
  130.     }
    * _: C( y. f$ ~# ?
  131.     MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRCFG, SPI_CFG1_UDRCFG_1);: g2 N: P1 o1 a* ?& o2 t
  132.   }/ a7 i8 [" z/ T# s% r4 B* I
  133. 2 x+ ^4 _2 @0 Z# v6 }, y- x
  134. #if defined(SPI_I2SCFGR_I2SMOD)& E2 w9 o# S0 ~5 t, D* o2 p/ E
  135.   CLEAR_BIT(hspi->Instance->I2SCFGR, SPI_I2SCFGR_I2SMOD);
    ; W5 W5 Z& K; ~+ l
  136. #endif ( k% ?! _3 G- o! S8 r3 ^

  137. 6 L# _. \' d! F8 g* P) ?
  138.   /* 确保AFCNTR bit由SPI主机模式管理 */6 J% l& _, x" A, _& H1 o
  139.   if ((hspi->Init.Mode & SPI_MODE_MASTER) == SPI_MODE_MASTER)
    4 I6 Y% ?, H) h" E7 D" v, G
  140.   {2 B; I. o6 U1 y6 w  u- z; `' h/ ]
  141.     /* Alternate function GPIOs control */- j# [" p, z9 x! F; f7 d
  142.     MODIFY_REG(hspi->Instance->CFG2, SPI_CFG2_AFCNTR, (hspi->Init.MasterKeepIOState));
    $ I# n; n( w0 o
  143.   }5 A: H9 V4 R# A% b
  144. ( p9 v3 _" I: l4 J% F$ Z
  145.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;/ J8 g) u1 _& T( M, S- @3 `  B
  146.   hspi->State     = HAL_SPI_STATE_READY;, t5 C3 ]% i! P, m' g

  147. % m" u. B, O$ B2 Q  m0 i: A
  148.   return HAL_OK;5 d; @6 n. B0 N& k
  149. }
    3 H2 ]" _6 x* i" }3 b/ J. k
复制代码
) p, B4 Z; ^( o* `% C/ H- N4 T. y$ N
! s8 E/ E6 \. P) V0 a% m2 {
函数描述:. h' C- `" l* ?$ p( K4 ]& R' J

! Y" J; a  v8 k+ I此函数用于初始化SPI。
6 }2 j) q; y& b2 M! Y% O, a( f2 D2 q. q$ ^8 j# G# o4 ]
函数参数:- R  z6 U/ ]+ [2 n" ?. Z9 s- r
- q" e; X7 r9 g6 n. M/ m# X
  第1个参数是SPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。3 f. h: e0 F$ @, ~) Y* @: x
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
) n% g# h4 J: }! ]注意事项:/ Y. o. O3 j/ j& c( M; G! m

% n. i7 |" L9 I2 Y0 s* G7 t, L函数HAL_SPI_MspInit用于初始化SPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。1 e  g9 G/ |2 v# c: [- q1 F
如果形参hspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SPI_HandleTypeDef SpiHandle。
0 l. k( g9 j; J# Q. a对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SPI_STATE_RESET  = 0x00U。0 X, s0 @: e. W" F2 O- z2 V
+ }2 Q- X; |4 ?- _' g
解决办法有三& B2 i9 p+ ?6 v2 `- o  u
% d7 K" \. Q, m4 I/ ?4 p& a
方法1:用户自己初始化SPI和涉及到的GPIO等。
+ p, D, W9 F7 {' U
" _; w. q, h4 U4 m4 w方法2:定义SPI_HandleTypeDef SpiHandle为全局变量。5 y: D2 |; y1 d
( Y' e" m* r- P5 X5 k% d
方法3:下面的方法
. J" A0 Q% u: y( w5 B8 M% P. X' x! |) f6 W
  1. if(HAL_SPI_DeInit(&SpiHandle) != HAL_OK)
    ; L$ E( c1 @" I
  2. {
      ~5 T, [$ x( w# u4 w$ O
  3.     Error_Handler();; U5 S% L. y, k# ^! e
  4. }  5 F& \* U7 P7 a; U0 l( S( x
  5. if(HAL_SPI_Init(&SpiHandle) != HAL_OK)0 Q, I2 g7 N7 H$ l; |
  6. {
    ( {. L8 r: R; B/ X( p  Y
  7.     Error_Handler();9 h2 |6 Z  ~: p& x
  8. }
复制代码
8 C& Y* z5 G5 X
使用举例:  z1 ?$ H# U- ^( e" L; T

- q+ A0 U; F, Z" h, h$ h
  1. SPI_HandleTypeDef hspi = {0};) o* D! }) Y6 i5 q* c  U% X

  2. % @- @: Z) k) j3 u
  3. /* 设置SPI参数 */
    # `' P% E3 D2 ^$ _# j3 H* u
  4. hspi.Instance               = SPIx;                   /* 例化SPI */
    4 B/ k# W5 S- a# s: m/ n
  5. hspi.Init.BaudRatePrescaler = _BaudRatePrescaler;     /* 设置波特率 */. l, g- N' p* e" e: g
  6. hspi.Init.Direction         = SPI_DIRECTION_2LINES;   /* 全双工 */* t2 d* |" @( j- a8 \
  7. hspi.Init.CLKPhase          = _CLKPhase;              /* 配置时钟相位 */+ j# J& E# T  y- N
  8. hspi.Init.CLKPolarity       = _CLKPolarity;           /* 配置时钟极性 */
    , z* l" O4 H7 u! o; ^
  9. hspi.Init.DataSize          = SPI_DATASIZE_8BIT;      /* 设置数据宽度 */
    ' [# n' b, G( O
  10. hspi.Init.FirstBit          = SPI_FIRSTBIT_MSB;       /* 数据传输先传高位 */1 R( ]8 u4 A0 z% }: Z/ D+ U
  11. hspi.Init.TIMode            = SPI_TIMODE_DISABLE;     /* 禁止TI模式  */7 D& M" D4 U+ }
  12. hspi.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;      /* 禁止CRC */
    1 O. y0 Q/ ]) w# N4 t
  13. hspi.Init.CRCPolynomial     = 7;                               /* 禁止CRC后,此位无效 */
    , U7 k; n$ D7 N7 f8 M5 X
  14. hspi.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;             /* 禁止CRC后,此位无效 */& e8 @7 ^/ R' l4 N. [
  15. hspi.Init.NSS               = SPI_NSS_SOFT;                    /* 使用软件方式管理片选引脚 */
    ' |  h; {4 j+ m6 ]6 U8 z, [: g$ R0 X
  16. hspi.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_01DATA;       /* 设置FIFO大小是一个数据项 */
    % Y# _* n, c7 v( C! D, ^8 e
  17. hspi.Init.NSSPMode          = SPI_NSS_PULSE_DISABLE;           /* 禁止脉冲输出 */
    5 r. t" B, @& [) q$ _
  18. hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  
    % l7 r5 v% c/ o4 n6 |1 l" s$ _2 T
  19. hspi.Init.Mode                  = SPI_MODE_MASTER;            /* SPI工作在主控模式 */9 q4 z2 b) Z: T$ D0 p* |, _" I+ P& ~1 C

  20.   v9 S& p  F/ [5 Y9 `5 x5 {
  21. if (HAL_SPI_Init(&hspi) != HAL_OK)/ H0 @  J4 @8 s6 u  M, C, P
  22. {& @4 F! `  z+ @4 ~" e
  23.     Error_Handler(__FILE__, __LINE__);" i+ J" f: ~4 ^& E3 H1 e
  24. }
复制代码
7 Q/ O3 A+ _5 w; `% |2 J% a

' T. B) @9 \" C8 b5 f72.4.2 函数HAL_SPI_DeInit% N2 a* r5 n+ ], h
函数原型:. E" _$ `0 y/ O5 i! v% q% {
3 ^+ V- K, @" Z* i
  1. HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)
    . z" Z! x! Q2 a+ J; j4 |7 o
  2. {
    2 ~* f/ j2 H& A* |1 c3 s
  3. /* 检测SPI句柄是否有效 */- i4 `, C9 t, t+ E1 j7 V
  4.   if (hspi == NULL)) X8 ^3 s, D. j3 R. H) `
  5.   {  s& g0 {, G% ^5 t
  6.     return HAL_ERROR;8 C1 o3 \& [9 R0 m+ l
  7.   }2 u, g" C. A5 }4 |, M3 t0 a/ B
  8. 0 {! d9 D: r, k3 b/ q, X0 r3 Q1 U
  9. /* 检查SPI例化参数 */
    - A) A% s8 ]- X+ G# n5 o8 c) B
  10.   assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));
    # |+ F6 V% e, F: g& f2 o- J5 A& @

  11. 7 t4 G$ e* G" j
  12.   hspi->State = HAL_SPI_STATE_BUSY;
    6 ^  b) x! }. r% \3 \0 S

  13. # w8 U- Q9 J3 [$ {
  14.   /* 禁止SPI外设时钟 */
    4 O' }9 A: U+ {, ~
  15.   __HAL_SPI_DISABLE(hspi);# g/ m) v. B4 c$ x& B# i, V* [8 g
  16. 8 d$ K6 Q, D) B6 _: p
  17. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    " R4 z! W( j6 M' Y2 V  b0 O5 Q% j
  18.   if (hspi->MspDeInitCallback == NULL)
    , A5 c( M4 r" b4 q
  19.   {& g4 j/ p' e0 j
  20.     hspi->MspDeInitCallback = HAL_SPI_MspDeInit;
    ) B' Z; x/ H6 ^6 H$ i! L7 W4 D
  21.   }
    5 ^( ~* l) r. t6 M7 A4 l, w
  22. + i. w8 p0 j- I
  23.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */
    7 A9 G; }/ o$ h4 z' |+ _
  24.   hspi->MspDeInitCallback(hspi);2 K( s9 X! t0 C
  25. #else# p2 Q! |+ H, t. ~( B- J, S
  26.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */$ {- v' o+ {% q0 q/ Y
  27.   HAL_SPI_MspDeInit(hspi);6 \. `1 N- Q8 J+ Q+ v
  28. #endif
    4 D; z. M0 A) i
  29. / J; S8 s" x4 [* W, s( h- G# R
  30.   /* 设置无错误,复位状态标记 */
    5 H' l& }# s0 ?
  31.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;$ v, {" m' x1 n
  32.   hspi->State = HAL_SPI_STATE_RESET;& t" S9 W0 S; Z' R+ |' G
  33. 4 x" }: }6 s1 z
  34.   /* 解锁SPI */6 J3 Y( o# r' i$ X8 N" v. @
  35.   __HAL_UNLOCK(hspi);
    & V1 ?7 i# G9 U3 X/ d: z
  36. ) J3 P4 t( d2 q) @9 ^
  37.   return HAL_OK;+ F6 a* Y3 v8 C
  38. }
复制代码
0 R  p; z- p* P6 n# f
函数描述:; a. a0 L( f: }1 S: R
# I2 Q& M5 a$ k( V: Z
用于复位SPI总线初始化。
, ?) p, Y1 {7 o5 ^7 F+ F& g+ q+ I$ R" o0 J( a: j( W9 E
函数参数:  Z9 Z' O6 @! ~# F+ J# Z! R* z  F
' O3 n% {9 m5 l# N! T5 _) F$ H
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。, M1 q8 w2 W! N9 @5 o$ s* ]/ z- D! i
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中
3 k: M- l# b6 J72.4.3 函数HAL_SPI_TransmitReceive9 z& R. P6 t! J0 H
函数原型:
. d" Q! F" |! L1 b( R+ p5 R& w+ [/ q# ~" f
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
    : \9 p) H9 @( A6 z: x
  2. {# F8 F# u4 B* {3 m4 c& }

  3. * p5 B" ?. b  v# i
  4.    /* 省略未写 */
    & V" P' K9 W: r/ [4 {5 u* Y4 w

  5. 3 W. @: q. `7 e4 `" L2 s
  6.   /* 大于16bit的数据收发 */
    ' G8 M6 d# K5 M3 i8 C) D
  7.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    ! w! d8 S5 W' Q( v+ f
  8.   {
    " W; p' A7 _( o7 r& m% B
  9.        /* 省略未写 */" H, H, W& w% Y) E, D
  10.   }
    % K/ M4 r2 K$ d* ?6 S
  11.   /* 大于8bit,小于16bi的数据收发 */5 S  _6 R  a' E, c  T+ z7 M1 y: l
  12.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
    ( f8 I# R) z8 z% L3 K
  13.   {
      ^$ H6 [+ g. \7 F& D0 M: x! K
  14.       /* 省略未写 */
    ) T: }' _( j% q( g6 t  `( v' y* `
  15.   }
    3 V( I% r6 Q! r% c
  16.   /* 小于等于8bit的数据收发 */+ ]$ M4 A; M. y8 b- V& k- v
  17.   else0 V# F$ T8 p  E% P% r1 L. E5 N$ _
  18.   {
    ) ?$ A+ X* o  u6 f
  19.        /* 省略未写 */5 l, Y0 d5 \4 Z( G% M1 |
  20.   }
    ( ^' h5 s9 w2 k
  21. 3 E- q8 u0 M% x
  22. }& B( w( y$ a* D( B+ Q# w8 s$ J  w
复制代码
- r9 T1 c5 M  k- @8 e6 h* R0 W
+ s) n( l# r$ S2 S( {  F9 N3 g+ b
函数描述:0 p# `1 M; K8 o1 J! D- Q
6 \0 K  e' {9 i# l
此函数主要用于SPI数据收发,全双工查询方式。
$ t: {  M- S, L5 X4 Z  }* @2 F! N+ D- c
函数参数:# a# k: A8 e' S: r4 S

, l6 }1 V- Z) r1 F  第1个参数是SPI_HandleTypeDef类型结构体指针变量。$ d3 w. x0 F0 Y
  第2个参数是发送数据缓冲地址。
5 h) u% s" Y6 ~  第3个参数是接收数据缓冲地址。+ F2 z9 T+ u% F
  第4个参数是传输的数据大小,单位字节个数。* ?$ m  G3 F  v* O! _2 Q, R
  第5个参数是传输过程的溢出时间,单位ms。# E/ k* N" D% n
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
% l2 V" D8 c) `, W使用举例:+ E8 H( E; Q4 x& O" V6 S) U0 e

$ y# A3 o! N7 k  z+ a
  1. SPI_HandleTypeDef hspi = {0};
    ' C2 c! A' F$ ?, s
  2. 2 |5 n/ g/ W/ U* n
  3. if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)) |1 p/ X3 I$ o
  4. {
    0 A$ a$ r( D$ V; }/ A/ ~
  5.     Error_Handler(__FILE__, __LINE__);; F3 C7 p: I  K7 W  z; L
  6. }
复制代码

6 j" n6 W0 Y9 y" S$ f2 y72.4.4 函数HAL_SPI_TransmitReceive_IT9 H4 Z/ g/ Z4 Q# h$ O6 r
函数原型:# e# `1 [" Q; O  L/ v; s

) [- }2 [+ Y9 G# t. Z) F- d
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)
    6 b: q! W: D/ k9 `* d
  2. {
    ) Y% ~: d) M" R
  3.    /* 省略未写 */
    - X  x& Y: _% F+ `$ f* ^2 k

  4. # R  I) [7 J9 a5 B
  5.   /* 设置传输参数 */
    1 k6 I9 c! q! V8 r/ z
  6.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
    4 F9 h! s( Q- ]8 {
  7.   hspi->pTxBuffPtr  = (uint8_t *)pTxData;
      N4 z" ~( i+ b! ?8 U) p
  8.   hspi->TxXferSize  = Size;+ }5 F* T* d, d$ M  S; J0 U
  9.   hspi->TxXferCount = Size;
      Z5 A( f# e7 \  I2 S0 V
  10.   hspi->pRxBuffPtr  = (uint8_t *)pRxData;
      E2 K7 ?+ l' n! T+ t
  11.   hspi->RxXferSize  = Size;
    & U% y( w- o: I: @( X* q0 y
  12.   hspi->RxXferCount = Size;
    " r% \" @) ?8 z7 s. ?2 H8 S$ O
  13. % Q& F# S& r# Z4 D$ A4 `
  14.   /* 设置中断处理 */
    ; m% N% k, K1 v" X4 @
  15.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    % K. R4 X3 S: b8 U4 M
  16.   {) @, w' Y6 x8 j# }
  17.     hspi->TxISR     = SPI_TxISR_32BIT;
    + o* n& W5 H/ z0 ]; t
  18.     hspi->RxISR     = SPI_RxISR_32BIT;9 a# x  o/ i# m" a; r6 n5 }
  19.   }7 x3 z7 `1 {$ G
  20.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)* Q6 d- t; ^- U  W0 t4 j
  21.   {
    7 h6 }- Z, U: T1 h8 ~$ y
  22.     hspi->RxISR     = SPI_RxISR_16BIT;/ W) h( b: T: V. T" C; q: M
  23.     hspi->TxISR     = SPI_TxISR_16BIT;" I8 ^2 _9 t. P+ D% K' K
  24.   }
    9 y. D1 W& b! X$ A0 g! j
  25.   else$ w) j. A$ d/ i
  26.   {; [5 o* r5 Z7 U5 i
  27.     hspi->RxISR     = SPI_RxISR_8BIT;* m. z  ^( N1 D# M3 m# d
  28.     hspi->TxISR     = SPI_TxISR_8BIT;- _% m& l: q3 V$ \
  29.   }% N& j+ m9 @2 X/ g3 Y* l# T
  30. ' x( K7 b* q% b' o$ [
  31.   /* 设置当前传输数据大小 */
    ) R8 r1 J& Z/ w% t1 J2 U
  32.   MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);
    1 m& p6 B; I2 Y" l6 R0 K% n
  33. ) G( H: B1 G& x8 c
  34.   /* 使能SPI外设 */
    7 u5 K9 B. b5 R8 m; s8 t
  35.   __HAL_SPI_ENABLE(hspi);& Y1 A# Q( `% k+ |' c& S

  36. ' V) {3 M- n8 |% p5 y) m2 [7 S4 P- {
  37.   /* 使能各种中断标志 */2 q4 D2 |' W3 R! g5 o' 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 | - L& i/ F1 `/ s. _% o
  39. SPI_IT_FRE | SPI_IT_MODF | SPI_IT_TSERF));. L& c+ L+ {' Y. O1 o1 Z
  40. ) x/ S% _; E, D5 ?" W) a
  41.   if (hspi->Init.Mode == SPI_MODE_MASTER)
    & Z+ V2 u6 N& E8 r
  42.   {$ z& p* D6 K5 s% O9 j
  43.     /* 启动传输 */
    3 o8 M0 R2 |" R! Y# K; K! g" y
  44.     SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);+ c6 {/ l  j7 `4 a$ S1 f
  45.   }+ _0 e  o; I% g/ Q. j5 h# Y

  46. 2 ?( F% [0 h% u; {) v  v  S; J
  47.   /* 解锁 */
    - t7 s1 H" z4 o4 Y; T2 x. n
  48.   __HAL_UNLOCK(hspi);: e: [6 ?8 K* R" g/ r# [2 y
  49.   return errorcode;
    ( Z7 a/ e+ f* X: g0 k, y, @/ a; U
  50. }
复制代码
( P0 w% v# v7 s& B
0 h: R* ?, S2 N" M

  }3 m. f. ~2 G, b+ ~函数描述:- O+ }$ \, ^$ Y& u
' W' I. \( z. `* |) l
此函数主要用于SPI数据收发,全双工中断方式。2 M$ @/ U% d9 X0 g% [  }

8 m, {6 ~( U  p9 y7 O" h8 N# H函数参数:
1 \2 Q& M) H3 v! T( ]( d9 M( T- @5 C3 H+ z/ ~, Q/ C8 {$ k
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
1 |- w8 C0 k! o) @; |9 P( ^9 G8 k  第2个参数是发送数据缓冲地址。
4 z- u& n3 j8 O, u9 @- r  第3个参数是接收数据缓冲地址。
) y( T, |7 i: p. }# g! p  第4个参数是传输的数据大小,单位字节个数。8 k, a$ M# J! E: u# @1 \
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
  p$ l6 y, g+ N, r" n使用举例:
9 N5 Y" y5 i+ o0 A' Y) _
' T! I' h( F& ~$ o* f, K& ]
  1. SPI_HandleTypeDef hspi = {0};/ q% o% k: d+ W4 q

  2. % K$ U2 b$ A% ~& G  B# ?) t& B
  3. if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)   
    " v' T$ y2 V! h% Y& S4 ?
  4. {
    - e# ]( V3 o) ~$ M! J
  5.     Error_Handler(__FILE__, __LINE__);: |/ K( f; n( P" K4 `4 t8 l1 e
  6. }# r" ~* d+ j5 a( s5 [. M( q

  7. 5 T, f2 |+ p( a$ _

  8. + M5 l7 |' Z7 ^& {  ]) F
  9. 72.4.5 函数HAL_SPI_TransmitReceive_DMA. _1 J$ f4 ^& Z% d; F
  10. 函数原型:2 p5 i. u( N: l$ ~7 i( y1 u) M

  11. * ]1 O: |9 ]( N9 U, A* D: {
  12. HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,; ^- r) y3 x6 W8 k  R6 @
  13.                                               uint16_t Size)
    0 @  C# S" j" f3 \/ \: T+ X
  14. {4 H* k$ {- ~: f9 Z% g& I; G
  15.    /* 省略未写 */4 D  j! K/ ?9 a

  16. $ e. u  M( i5 g; m7 }
  17. /* 注意DMA的位宽和对齐设置 */; U! J. x+ v2 ]8 z6 x, d
  18.   if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && (hspi->hdmarx->Init.MemDataAlignment !=5 F  Q8 l# U. M$ L
  19. DMA_MDATAALIGN_WORD))  || 1 p4 @. ^* a. l' u' N* |
  20.       ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) && ((hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_HALFWORD) && (hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_WORD))))+ B4 u/ M# ]- [! t! A* L0 H) W
  21.   {
    + D- a# w! ~; y/ Z% ^1 S% ?+ T
  22.   }8 l8 d. O: S! _% v. [

  23. # u. A4 n9 d4 s0 ?0 R6 e, c+ x
  24. /* 调整DMA对齐和数据大小 */# S7 p! ]$ {( Y$ y
  25.   if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)6 y3 X, B1 D  f5 H# A7 U$ B
  26.   {: ]2 q7 K! ^4 n/ T) z& H
  27.      /* 省略未写 */
    ' K0 ]5 {1 s( T1 K: _
  28.   }
    9 Z" g" X6 e0 f: U" ?
  29.   else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)( B% Y+ F9 x0 B- C! C% N  ~6 u
  30.   {+ @$ g5 h. j4 _9 P( D/ J- S5 q; q6 ~
  31.      /* 省略未写 */6 {7 k# y( ^  r) p# G
  32.   }! w- e# e2 _2 p2 f# z2 S) m
  33.   else; ], P$ D; Q: J2 p0 k- Z" [4 Q8 _
  34.   {  e3 i6 c1 p# X$ D2 M( `7 f$ v
  35.       /* 省略未写 */' w( J0 U6 E' u* o3 }' w
  36.   }
    2 \6 Z, y2 }5 x, @! `
  37. ; i4 A7 z0 s+ {. _0 u! J
  38. /*  DMA接收配置 */1 L3 x; I% h) K: G: d
  39.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->RXDR, (uint32_t)hspi->pRxBuffPtr,% q$ ~) Q5 ?- h% _8 L! S) W% a
  40. hspi->RxXferCount))# {* W) A4 a1 z8 A
  41.   {% ~- G' y6 b% |0 q0 V4 u
  42. : n6 ~) y! ^. {$ k: D* K
  43.   }) v. g2 ~0 _9 ]* ?0 _
  44. , A8 ~4 R" I5 H4 c7 C# b( }
  45. /* DMA发送配置 */
    / R' U" H- ?+ Z( a8 Z
  46.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->TXDR,
    + m: B; ]3 z5 e; n& Y( h
  47. hspi->TxXferCount))
    * s, m7 }4 {4 w
  48.   {
    & Q/ J. w7 G; o
  49.   }  H! D5 B1 U8 W+ L7 n
  50. 5 o1 u5 A2 q) ]1 T: ]$ D
  51.   /* 省略未写 */
      G3 Z- p# Q, T5 \: B! F
  52. }. U0 h( X- D: [, _" w' ?2 R* o
复制代码
4 f# W5 o8 A- A5 h6 ]; D

* p5 T' J; O/ @% _- ^3 B函数描述:
, Z% p/ ?/ n1 [% T: a1 s. ~9 g+ r: ^9 ]0 V" J" U
此函数主要用于SPI数据收发,全双工DMA方式。
2 P$ S) [% y0 j' m( }  q$ U% [' @
2 U2 |( R. C: @函数参数:
8 ^) E/ L1 P+ x0 Z' X" K
9 l- B7 A: |- s# t- ]$ y  第1个参数是SPI_HandleTypeDef类型结构体指针变量。7 G9 S% A( [8 u" y
  第2个参数是发送数据缓冲地址。# i9 J- r$ j- H8 n' l9 P4 ]
  第3个参数是接收数据缓冲地址。
  f' i5 L6 m/ z2 E  第4个参数是传输的数据大小,单位字节个数。
: q/ B% w8 y. `* q  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
( w& [0 g2 m6 D- {4 Z5 U0 T使用举例:
- x2 }3 O/ U9 R7 X# \/ \" G$ o! ?7 K" A! b  K" R) e
  1. SPI_HandleTypeDef hspi = {0};
    2 O8 i- w  @5 G6 k2 \$ a9 B

  2. 7 n4 A7 @. [, F, }- y& i
  3. if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    : k7 w, {$ f; N2 N7 y
  4. {) q" m0 u; N; k2 W0 z' S
  5.     Error_Handler(__FILE__, __LINE__);
    " D# I# @- v& x) v
  6. }
复制代码
: ~: }/ ?  Q  N. @, A6 X* f

6 {  n- y0 ]0 A1 e& D1 G4 H, L' s% F/ ]7 ~1 G( Q( ?
72.5 总结0 X; _/ W6 D1 P. w
本章节就为大家讲解这么多,要熟练掌握SPI总线的查询,中断和DMA方式的实现,因为基于SPI接口的外设芯片很多,熟练后,可以方便的驱动各种SPI接口芯片,以便选择合适的驱动方式。
6 b* b2 Z) J1 i- F1 Z3 a
2 M# |/ z+ b0 O8 ^( y  N- B% O# D& e0 q; o$ C- S( ?
收藏 1 评论0 发布时间:2021-11-3 10:15

举报

0个回答

所属标签

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