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

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

[复制链接]
STMCU小助手 发布时间:2021-12-20 19:00
72.1 初学者重要提示
5 V2 J4 s- r) ^6 H6 ?/ R2 j  STM32H7的SPI支持4到32bit数据传输,而STM32F1和F4系列仅支持8bit或者16bit。2 I; p& E' J6 R* F
  STM32H7的主频400MHz时,SPI1, 2, 3最高通信时钟是100MHz,而SPI4, 5, 6是50MHz。
2 `5 _/ Y1 O: t' B7 ~  STM32H7的MISO和MOSI引脚功能可以互换,使用比较灵活。) T: ]% z; i: F1 o
  SPI总线的片选引脚SS在单一的主从器件配置下是可选的,一般情况下可以不使用。
: H3 M7 R( ?( [9 [- l, g6 X; ]3 ?/ b2 D. A  f/ N
72.2 SPI总线基础知识  T( F% J( ]  K  A" S3 h
72.2.1 SPI总线的硬件框图

/ \* ~2 m, m) `4 s+ ]认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SPI的基本功能,然后再看手册了解细节。
: T; e% y* }6 |) U# u9 y& J0 m& M4 A0 Y
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
# _% `- g6 s: A2 B% H
' v; S9 X- T8 O. H4 L9 r, ^
通过这个框图,我们可以得到如下信息:
; z5 `: }, {1 N" c  spi_wkup输出
! l2 @1 w& V7 `- z% z7 D
( q( g6 D- R- J8 U0 M: h低功耗唤醒信号。" R4 V. W9 m: t3 R2 a' ]
  spi_it输出
1 e1 D2 \8 m5 m/ w8 A. R- X$ B( O: Z

5 m% ^# @4 S7 Z( Cspi的中断请求信号。
1 d1 [2 j$ r, {% J  spi_tx_dma
0 A/ T. Y7 x# a" @/ D0 X% }  spi_rx_dma& ?, I+ A4 R, F& d
) [4 q3 y4 {# h# l2 i! M; P3 R
+ w  N/ n9 R( |6 g" I
spi的DMA发送和接收请求信号。
* e; U- ?9 j3 u4 @  spi_pclk
1 B8 q! {" D, F$ q
: Z% h8 l" D# R5 _0 v$ |# t2 U+ [2 |4 S( y1 z" E$ D; X2 U
为寄存器提供时钟。" g: S4 O+ }  i. A+ i& R. U7 Y
  spi_ker_ck& a8 W, G" U; X) \8 x3 S% |
- N& h* s- v( D
/ @+ U* U( ?1 b9 f: H3 Q1 U0 b
为spi内核时钟。+ W0 y$ K+ i# L" o2 v- Y1 E
  SCK(CK),Serial Clock: \+ l# Y: V( |5 N( S) B" H

7 T+ G4 I3 N5 f( i6 o. v( U2 X+ p% Z9 j2 _' C
此引脚在主机模式下用于时钟输出,从机模式下用于时钟输入。
, b9 z/ u; E# K' b) Z- K# ~  MISO(SDI),Master In / Slave Out data+ s  j+ k3 D$ {9 e: {
5 B$ q3 U6 ^, J
  Y. o% I: C6 j, Q
此引脚在从机模式下用于发送数据,主机模式下接收数据。9 s# b6 H2 k( E0 i: \% ?
  MOSI(SDO), Master Out / Slave In data3 a" a5 ^7 ~( N
. E0 U/ }8 g) B& S

" s: b1 b+ x+ {: E+ y2 f) y此引脚在从机模式下用于数据接收,主机模式下发送数据。0 H4 _) s2 g" ~& }
  SS(WS), Slave select pin# J; A( p3 `! [: Y

, D1 T8 \+ J. Y1 b6 [  G$ P2 W% M9 t, I5 y
根据SPI和SS设置,此引脚可用于:+ ^6 ^3 v# G1 \; ]( n* b3 \1 f
a. 选择三个从器件进行通信。% k' E1 j( a# O6 p) \0 F% u6 j

6 U  {$ c8 o" U3 O6 {b. 同步数据帧。5 W7 v% _! n! n( e7 h7 x3 e

+ S# ^. l* w& r: N/ E, mc. 检测多个主器件之间是否存在冲突。
0 H; X0 \8 Y8 O8 f
7 B! [5 o. S$ h. \1 I- N通过这个框图还要认识到一点,SPI有三个时钟域,分别是寄存器所在的ABP总线时钟域,内核时钟发生器时钟域以及内核时钟发生器分频后的串行时钟域。
4 P6 S' j! d* c8 P8 x2 V9 F3 ~% Q! I/ |  Y
72.2.2 SPI接口的区别和时钟源(SPI1到SPI6)

8 t; m& w+ U( K% D6 Y% x( f这个知识点在初学的时候容易忽视,所以我们这里整理下。" L6 ]! U1 J* f, }" n
SPI1到SPI6的区别
5 m7 r. p& S; T' p. T: c; a  SPI1,SPI2和SPI3支持4到32bit数据传输,SPI4,SPI5和SPI6是4到16bit数据传输。6 ^1 k* U# i7 w; M" B& l5 u
  SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit。* q$ o2 _, p& Q2 |# n, ^
# V% E# B9 G/ k0 L
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
! _1 U# N' t( R! m* g, k* T

: x% ~- ]8 o9 c  SPI1到SPI6的所在的总线(对应SPI框图的SPI_CLK时钟域)
" x' C& g' I0 l' b8 Y
; m2 x2 U9 e8 q+ r
$ v/ D! v) C+ y  |  l2 TSPI1,SPI4和SPI5在APB2总线,SPI2,SPI3在APB1总线,SPI6在APB4总线。注意,SPI的最高时钟不是由这些总线决定的。
/ K) t  Y. @( T- @8 {4 Z
) l. r, y3 ?  W3 m% U/ B" B; N2 ~; ]  SPI1到SPI6的支持的最高时钟(对应SPI框图的SPI_KER_CK)
+ Y) ^/ J; l, k: l. X/ ~5 F4 ^% r$ M
2 {6 v8 i' `3 \0 k
STM32H7主频在400MHz下,SPI1,SPI2和SPI3的最高时钟是200MHz,而SPI4,5,6是100MHz, 以SPI1为了,可以选择的时钟源如下:
* `; x/ s& `- c+ Z1 k7 Z- W3 w8 z& T) g2 I: X
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

% ]" Y( t* T% d3 W; ~0 V; }/ H
5 K4 {  y5 k) p, l* T: l4 F8 i这里特别注意一点,SPI工作时最少选择二分频,也就是说SPI1,2,3实际通信时钟是100MHz,而SPI4,5,6是50MHz。
8 Z3 c/ H' k4 n$ A$ ?5 H5 e2 O: X+ w2 V6 R+ L* k
72.2.3 SPI总线全双工,单工和半双工通信
6 ^( P5 r$ o0 z# K" A( w片选信号SS在单一的主从器件配置下是可选的,一般情况下可以不使用。但需要同步数据流,或者用于TI模式时需要此信号。: h0 }! V; I7 `/ ^! y/ T2 a

$ w+ z$ t5 W9 [8 U' u; h6 k  全双工通信8 s$ Y" I0 q% Y9 p2 J. a
全双工就是主从器件之间同时互传数据,SPI总线的全双工模式接线方式如下:$ l$ F  j2 ^6 X# K
- W+ c3 j" p9 J2 [# }
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

; m$ `! A- ]# R/ l# |  _9 L( Q  P  d$ J- Q
关于这个接线图要认识到以下几点:
: M) o2 n8 L' u1 s: @7 E% {  注意接线方式,对于主器件来说MISO引脚就是输入端,从器件的MISO是输出端,即Master In / Slave Out data。MOSI也是同样道理。& C$ X8 L0 W* D  F! f6 N" [
  每个时钟信号SCK的作用了,主器件的MISO引脚接收1个bit数据,MOSI引脚输出1个bit数据。
+ M' M5 k3 ~# Z, D; I9 k# R- @+ p# ~  这种单一的主从接线模式下,SS引脚可以不使用。
. C8 k( o! j6 F3 j
7 e7 J  V# \. ^; D* y: N半双工通信) o- I' _0 p. ?( Q
半双工就是同一个时刻只能为一个方向传输数据,SPI总线的半工模式接线方式如下:
8 a* M( M) [% M: m4 U' k! M- a
, n5 T. c0 A/ d$ w7 i1 s, m
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

4 h/ E# ?" T/ M# y3 n& k' L
/ c3 q4 Z! C4 F* o$ W+ v& W$ X$ G关于这个接线图要认识到以下几点:: U) W! |7 `' Y& Z

- B! n+ ]1 U- c* W  更改通信方式时,要先禁止SPI。
5 T4 P) E- z+ r- e( ~7 l  主器件的MISO和从器件的MISO不使用,可以继续用作标准GPIO。* E1 n4 J& {9 N# {% U/ y
  1KΩ的接线电阻很有必要,因为当主器件和从器件的通信方向不是同步变化时,容易出现其中一个输出低电平,另一个输出高电平,造成短路。: f! V3 z" i8 X6 B. M% W, R( x. g
  这种单一的主从接线模式下,SS引脚可以不使用。
7 _) |! }1 q; @- O1 ^4 g2 p( _  6 ?7 g: k% M& R2 Y1 m9 c8 j
单工模式
4 T' c: v4 F, s$ j+ g1 D单工就是只有一种通信方向,即发送或者接收,SPI总线的全双工模式接线方式如下:
: E: Q7 a4 u4 T; w
' s) ?# h5 W4 _5 Q. d3 g. D% q
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

; b; u2 p0 R% I. ?3 E& q) d- L$ X4 M- C4 O0 e5 U3 \
关于这个接线图要认识到以下几点:3 j" D. x$ X. Q7 k8 f- E- ~
) I+ |( m; W4 H
  未用到的MOSI或者MISO可以用作标准GPIO。  K( p, l7 h  U0 Q0 B8 F
  这种单一的主从接线模式下,SS引脚可以不使用。
/ y$ L& p; u/ c- c4 K
0 y! j5 @9 t. Z  T+ \* E+ {; Q72.2.4 SPI总线星型拓扑
% i' [9 [7 X# M1 F/ ASPI总线星型拓扑用到的地方比较多,V7开发板就是用的星型拓扑外接多种SPI器件:2 b! {4 [* z6 T3 d8 _$ T+ E
  O4 A6 Q" g! g& p
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png

0 u/ [1 J. v4 h
& ^5 d- |; F- e: W4 t$ M3 X4 B关于这个接线图,有以下几点需要大家了解:
3 P8 z% \# f# \" n: x9 S# Y( D8 M% e3 A3 n  Y
  主器件的SS引脚不使用,使用通用GPIO控制。为每个器件配一个SS引脚,方便单独片选控制。
8 u0 J6 x' N- X2 ?  从器件的MISO引脚要配置为复用开漏输出(很多外部芯片在未片选时,数据引脚是呈现高阻态)。- f9 m0 L5 X+ @7 U9 J5 ^
3 B4 c6 l& V( O5 L: Z; I0 {

; N1 `* w# {% e' v# ~72.2.5 SPI总线通信格式
, n1 ]  e2 n$ @6 mSPI总线主要有四种通信格式,由CPOL时钟极性和CPHA时钟相位控制:
, T1 a: c! c9 p# g" B- t( r. M
" y: j! J: g$ @2 V* m
aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDMvMTM3OTEwNy0yMDIw.png
; H. Y. U& h/ }, I) f$ |

2 s% v; x' H  u7 s四种通信格式如下:
6 ^1 R6 ^! T! z: ?$ D, F  当CPOL = 1, CPHA = 1时4 k( W/ P* S: K9 `

. d- M, `1 s( }+ B% U5 u- q! q) y4 Z& m2 _' o3 C, F# B" x. [1 ]
SCK引脚在空闲状态处于低电平,SCK引脚的第2个边沿捕获传输的第1个数据。
3 T( t2 y& O0 \  当CPOL = 0, CPHA = 1时
+ F4 \% M6 |3 G# x& T7 @0 g1 O4 ]
* L3 D0 R" n5 T! a- {8 \) Q. h6 \; S7 H1 r: y' ?, C6 p+ W
SCK引脚在空闲状态处于高电平,SCK引脚的第2个边沿捕获传输的第1个数据。
( O, w$ j2 f/ n2 d6 f  当CPOL = 1, CPHA = 0时
  F1 t7 j/ t/ N% O# m
+ Q2 Q) B2 f/ }+ T% u8 J. D/ L: n4 L) Z& Y' z6 o
SCK引脚在空闲状态处于低电平,SCK引脚的第1个边沿捕获传输的第1个数据。8 v- t. k6 o4 J1 W- U$ h/ H: ?1 p
  当CPOL = 1, CPHA = 0时5 O3 i1 V0 `% k* T7 W9 G2 k
" |8 Y$ r* X4 N1 p( F( W$ o1 J
: u- i" t" M# v# l7 O/ F* {( u6 d
SCK引脚在空闲状态处于高电平,SCK引脚的第1个边沿捕获传输的第1个数据。
. a0 R( @7 g) f$ [4 @1 a3 ~$ F; K8 I# m
72.3 SPI总线的HAL库用法
+ H6 a$ c  K# P
72.3.1 SPI总线结构体SPI_TypeDef
( B9 p$ l" q2 i. T$ H( l0 J( DSPI总线相关的寄存器是通过HAL库中的结构体SPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:1 C: k9 y) F4 o) U  Z

9 |3 \$ \$ Y$ E  A2 ]
  1. typedef struct% ^4 v6 l1 g  z5 q; V4 n
  2. {* N) [% x* M( ^/ A" d* ]" E
  3.   __IO uint32_t CR1;           /*!< SPI/I2S Control register 1,                      Address offset: 0x00 */5 b& @1 U" i* j
  4.   __IO uint32_t CR2;           /*!< SPI Control register 2,                          Address offset: 0x04 */
    % Y/ q4 u7 Z( @8 r" I  u
  5.   __IO uint32_t CFG1;          /*!< SPI Configuration register 1,                    Address offset: 0x08 */
    ; W0 H7 q5 A" G* W5 O8 u& I
  6.   __IO uint32_t CFG2;          /*!< SPI Configuration register 2,                    Address offset: 0x0C */- P% C- D% T( u9 Y, o! w
  7.   __IO uint32_t IER;           /*!< SPI/I2S Interrupt Enable register,               Address offset: 0x10 */6 s: V( }' B3 p$ Y4 A0 j4 P0 D
  8.   __IO uint32_t SR;            /*!< SPI/I2S Status register,                         Address offset: 0x14 */
    . g" n( x0 O: z; p
  9.   __IO uint32_t IFCR;          /*!< SPI/I2S Interrupt/Status flags clear register,   Address offset: 0x18 */: q$ @7 b8 U! S# D* m7 v7 w
  10.   uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                        */
    0 z. K( n1 O( e
  11.   __IO uint32_t TXDR;          /*!< SPI/I2S Transmit data register,                  Address offset: 0x20 */- x6 h8 v( w* x. M4 Q! z
  12.   uint32_t      RESERVED1[3];  /*!< Reserved, 0x24-0x2C                                                   */# U- e5 z3 g6 Y7 t) V" L
  13.   __IO uint32_t RXDR;          /*!< SPI/I2S Receive data register,                   Address offset: 0x30 */+ U* v1 ?7 k+ c/ M$ E8 ^7 ~5 U
  14.   uint32_t      RESERVED2[3];  /*!< Reserved, 0x34-0x3C                                                   */' Y" i8 w! m" m7 q+ t( f; M4 ^+ {
  15.   __IO uint32_t CRCPOLY;       /*!< SPI CRC Polynomial register,                     Address offset: 0x40 */
    ! d  O1 P" Z9 U9 M. L. ^
  16.   __IO uint32_t TXCRC;         /*!< SPI Transmitter CRC register,                    Address offset: 0x44 */6 V$ t: `; o$ _5 }; N
  17.   __IO uint32_t RXCRC;         /*!< SPI Receiver CRC register,                       Address offset: 0x48 */( ^' R4 y* D5 z# z: [
  18.   __IO uint32_t UDRDR;         /*!< SPI Underrun data register,                      Address offset: 0x4C */: E3 _* X% V7 |
  19.   __IO uint32_t I2SCFGR;       /*!< I2S Configuration register,                      Address offset: 0x50 */
    9 H8 j1 u! Z$ y' C: U- N6 S- M
  20. 2 f; g/ h9 D) p$ R
  21. } SPI_TypeDef;
复制代码
# X+ a+ y+ A+ z( U, R, r4 r
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。, u$ \& n; L" d% J# y2 p

# K8 S; D$ y  E% F* d__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:) W2 B8 N0 c! I7 h6 H& ~2 \, m

. d6 a# l5 p0 V2 N. f) J9 x
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */7 b, a* x7 @" d$ S
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
" N$ k8 E3 L* j/ ~6 A9 ^
下面我们看下SPI的定义,在stm32h743xx.h文件。
& e* J/ |& ]! `+ ?
" p/ ?7 X$ I1 `/ t  n& c8 [
  1. #define PERIPH_BASE           (0x40000000UL)
    , H6 }( k( ]- i- k8 P
  2. #define D2_APB1PERIPH_BASE     PERIPH_BASE9 j; f4 Q: m/ u% g( N$ i, h
  3. #define D2_APB2PERIPH_BASE    (PERIPH_BASE + 0x00010000UL)
    ( a) t7 ?* Z- J" u* ~
  4. #define D3_APB1PERIPH_BASE    (PERIPH_BASE + 0x18000000UL)
    5 Q# F' X  A4 N- r* F
  5. % [7 B- m: ]5 c
  6. #define SPI2_BASE             (D2_APB1PERIPH_BASE + 0x3800UL)
    ! c6 U. R7 K' M
  7. #define SPI3_BASE             (D2_APB1PERIPH_BASE + 0x3C00UL)
    % U/ E/ }* ?( j+ Y
  8. #define SPI1_BASE             (D2_APB2PERIPH_BASE + 0x3000UL)4 `: V& W+ C9 @* Q+ o+ x8 F0 `
  9. #define SPI4_BASE             (D2_APB2PERIPH_BASE + 0x3400UL)+ l3 ~  x4 _4 S+ b. z  n, {' a
  10. #define SPI5_BASE             (D2_APB2PERIPH_BASE + 0x5000UL)
      a/ L. ^$ b* p& M! ^
  11. #define SPI6_BASE             (D3_APB1PERIPH_BASE + 0x1400UL)
    $ B& i- m3 w) {& B0 a% ~2 }
  12. 2 A4 l- ]% ~4 I. l2 [
  13. #define SPI1                ((SPI_TypeDef *) SPI1_BASE)
    8 k/ U7 h. R1 a! X  N* r
  14. #define SPI2                ((SPI_TypeDef *) SPI2_BASE)- p* o- ?' I0 R0 A, l2 ^
  15. #define SPI3                ((SPI_TypeDef *) SPI3_BASE)( C, M" k0 n$ y
  16. #define SPI4                ((SPI_TypeDef *) SPI4_BASE)( `5 k0 u5 F* p( G5 r
  17. #define SPI5                ((SPI_TypeDef *) SPI5_BASE)
    $ p! k5 |& I3 H4 M% s' [* v8 `
  18. #define SPI6                ((SPI_TypeDef *) SPI6_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x58001400
复制代码

2 N2 p6 I* J; @: f( T& l* p8 d我们访问SPI的CR1寄存器可以采用这种形式:SPI->CR1 = 0。
; h# J6 |: a7 n7 F* A+ F3 p; _/ x- G3 H
72.3.2 SPI总线初始化结构体SPI_InitTypeDef
/ F- u8 E- H) Z/ C# |9 r
下面是SPI总线的初始化结构体,用到的地方比较多:; U8 t6 `% U9 ]/ @7 [

4 K% Y; Q+ u5 p' S8 k
  1. typedef struct
    / U7 n9 |: L1 h) ?
  2. {
    " t- u0 G( S" R7 M' m7 e% q
  3.   uint32_t Mode;                            . u( c2 B" T, M1 [+ y; L6 l9 U
  4.   uint32_t Direction;                     
    - Q; q7 \" n% m9 U5 i3 G* x
  5.   uint32_t DataSize;                          5 I3 l- s8 h( Y3 |& `! f% c3 c
  6.   uint32_t CLKPolarity;                       
    " v9 o+ T$ H" i; Q: f4 A/ l
  7.   uint32_t CLKPhase;                         & R4 ?6 k) {# b* o
  8.   uint32_t NSS;                             
    % i2 Y8 r+ ^- }+ ~3 X% ^
  9.   uint32_t BaudRatePrescaler;                ( c& v6 {# _! w. R: R. f. {
  10.   uint32_t FirstBit;                        
    ; b5 X" w- }* H# Y/ i3 {
  11.   uint32_t TIMode;                          
    4 ^" D( n+ p8 k' I# q
  12.   uint32_t CRCCalculation;                  
    . I, L2 |+ ~$ H2 z; F8 ^
  13.   uint32_t CRCPolynomial;                     
    ; y$ s$ Y+ `, m' E. |7 h
  14.   uint32_t CRCLength;                        ! W5 u/ h6 [0 f% q; Y. a
  15.   uint32_t NSSPMode;                        
    4 @6 W8 F3 o% n6 l8 [( M! n: c
  16.   uint32_t NSSPolarity;                    ' v6 m* z5 T" x; T8 [: m4 g' `
  17.   uint32_t TxCRCInitializationPattern;       7 f) x+ U# U1 h
  18.   uint32_t RxCRCInitializationPattern;       7 a+ c6 N( h  q
  19.   uint32_t MasterSSIdleness;                 5 T; [+ u$ e# m
  20.   uint32_t MasterInterDataIdleness;           
    7 h6 T8 G: p; A* M' B
  21.   uint32_t MasterReceiverAutoSusp;         
    ! X3 @/ l' _( E/ g: o/ r5 d* B
  22.   uint32_t MasterKeepIOState;               
    6 e! M9 r/ z! t4 s9 V1 c# o9 \
  23.   uint32_t IOSwap;                          9 A& l8 k- G/ H) t) b, F
  24. } SPI_InitTypeDef;
复制代码

. k0 b# T& [5 ?( ?* w% l5 A下面将结构体成员逐一做个说明:
, q6 D& K/ K1 U% R  Mode, G* p: I+ J) y8 P$ b
4 w0 c7 c8 \/ x" j* y# L
用于设置工作在主机模式还是从机模式。: b! P! A+ ^0 w
  1. #define SPI_MODE_SLAVE              (0x00000000UL)4 ^$ U9 y7 S( i3 w, z0 G# V
  2. #define SPI_MODE_MASTER             SPI_CFG2_MASTER
复制代码

0 G" g0 _5 x7 k' J9 Z  Direction/ V( |" \/ ]4 `2 e: g
用于设置SPI工作在全双工,单工,还是半双工模式。
: w1 R# K( `8 L  X( d! W" |* t; ?" l9 k& m
  1. #define SPI_DIRECTION_2LINES           (0x00000000UL)     /* 全双工 */" b4 _( b  l1 u! a/ `, {
  2. #define SPI_DIRECTION_2LINES_TXONLY     SPI_CFG2_COMM_0   /* 单工,仅发送 */6 b5 L* Q: `7 a! t$ M
  3. #define SPI_DIRECTION_2LINES_RXONLY     SPI_CFG2_COMM_1   /* 单工,仅接收 */! |. O. D/ G; g
  4. #define SPI_DIRECTION_1LINE             SPI_CFG2_COMM     /* 半双工 */
复制代码

: y& p6 a) [/ ~. R$ t2 l! E, n  DataSize; _9 v, e& Z/ P
用于设置SPI总线数据收发的位宽,支持4-32bit。1 I; f% ?! v& I% d

2 J6 K) \$ ^8 q/ G! |- Y
  1. #define SPI_DATASIZE_4BIT                             (0x00000003UL)$ d: b, z5 U3 i: k9 D- g
  2. #define SPI_DATASIZE_5BIT                             (0x00000004UL). O1 t  B+ R% J
  3. #define SPI_DATASIZE_6BIT                             (0x00000005UL)7 K; M. o" j; S1 k7 t$ {6 x9 s0 r
  4. #define SPI_DATASIZE_7BIT                             (0x00000006UL)5 d: \9 z" v' S
  5. #define SPI_DATASIZE_8BIT                             (0x00000007UL)
    : V4 Z/ s7 w, T- @* W, |* l: G- {
  6. #define SPI_DATASIZE_9BIT                             (0x00000008UL)5 o6 T3 R8 w/ `: w  b2 u% [5 n
  7. #define SPI_DATASIZE_10BIT                            (0x00000009UL)
    ! u, J/ i! b0 R
  8. #define SPI_DATASIZE_11BIT                            (0x0000000AUL)
    7 C' b, f$ n* k) A1 E
  9. #define SPI_DATASIZE_12BIT                            (0x0000000BUL)+ d9 B& h* |' {1 z0 \0 m$ o2 p
  10. #define SPI_DATASIZE_13BIT                            (0x0000000CUL)
    - ^5 Z: l5 u+ ?8 P/ _% n$ z" r
  11. #define SPI_DATASIZE_14BIT                            (0x0000000DUL)
    / q2 Y+ i+ t; D8 d0 j5 c2 u) `0 o
  12. #define SPI_DATASIZE_15BIT                            (0x0000000EUL)2 Y. C( r# x' n! t- A7 j" ~" b
  13. #define SPI_DATASIZE_16BIT                            (0x0000000FUL): M8 _9 _# D' c* @9 }
  14. #define SPI_DATASIZE_17BIT                            (0x00000010UL)% M/ ^. t4 m; A1 }
  15. #define SPI_DATASIZE_18BIT                            (0x00000011UL)  j; H9 j( Y7 Y, m1 e/ f6 i! ]0 i
  16. #define SPI_DATASIZE_19BIT                            (0x00000012UL)) `$ G# H& z9 x3 A5 T4 Z* e
  17. #define SPI_DATASIZE_20BIT                            (0x00000013UL)
    * h8 Y+ F$ ]+ w0 i
  18. #define SPI_DATASIZE_21BIT                            (0x00000014UL)
    - Z2 L" w% u7 M& }9 k; n. z
  19. #define SPI_DATASIZE_22BIT                            (0x00000015UL)
    , V' j& h* w' a% ]
  20. #define SPI_DATASIZE_23BIT                            (0x00000016UL)
    ) _1 }5 ?7 `# _2 |  N
  21. #define SPI_DATASIZE_24BIT                            (0x00000017UL)" J. {! H7 U' e' X; _. p9 m+ z0 J
  22. #define SPI_DATASIZE_25BIT                            (0x00000018UL)
    ' J# }3 h" n6 w% |" P4 I1 O
  23. #define SPI_DATASIZE_26BIT                            (0x00000019UL)
    : T1 _- X  E1 S' C* N" w1 {0 O
  24. #define SPI_DATASIZE_27BIT                            (0x0000001AUL)
    , k  U& _6 x* b
  25. #define SPI_DATASIZE_28BIT                            (0x0000001BUL)
    . J  M9 B. C* J
  26. #define SPI_DATASIZE_29BIT                            (0x0000001CUL)
    + s( B7 G' N% r! L: E: M& ^% O7 m# L& k
  27. #define SPI_DATASIZE_30BIT                            (0x0000001DUL)- U: Z0 O6 Z- Y$ n
  28. #define SPI_DATASIZE_31BIT                            (0x0000001EUL)7 j. Y4 \1 K, H- ~9 B8 j8 i9 I
  29. #define SPI_DATASIZE_32BIT                            (0x0000001FUL)$ L8 W- ]% Y, R) ~
复制代码
  Y  ~; X5 F% I4 M

, b$ ]( Q$ @/ f6 u& a+ F) |  CLKPolarity$ ~8 M) V( R6 A
用于设置空闲状态时,CLK是高电平还是低电平。6 T9 A3 O& P" u. _  R! h! V6 [
  1. #define SPI_POLARITY_LOW       (0x00000000UL)( E2 ^+ D) p8 P) c
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码
" K5 R: }, X$ K, V! ^
  NSS
6 D5 _5 J' ~* c4 [- H6 P& G0 B0 ~用于设置NSS信号由硬件NSS引脚管理或者软件SSI位管理。5 d5 ~% G+ r9 T" a
# H0 F* q+ s) t; a
  1. #define SPI_NSS_SOFT                                  SPI_CFG2_SSM
    4 E# f- u* n& B: n6 V# {6 M9 ?* a
  2. #define SPI_NSS_HARD_INPUT                            (0x00000000UL)
    3 i4 C4 F* K* A% F
  3. #define SPI_NSS_HARD_OUTPUT                           SPI_CFG2_SSOE
复制代码

# P5 G9 d, y" }1 A* a, H  BaudRatePrescaler
2 S! d5 F. R% c. p/ {! s用于设置SPI时钟分频,仅SPI工作在主控模式下起作用,对SPI从机模式不起作用。7 ^. O$ e5 J2 Q, e
) \/ {* h0 C' n% \2 U
  1. #define SPI_BAUDRATEPRESCALER_2                       (0x00000000UL)( C, c' D$ z$ G2 I; X2 G
  2. #define SPI_BAUDRATEPRESCALER_4                       (0x10000000UL)# l& y, D+ l% x" }+ Z/ u4 |
  3. #define SPI_BAUDRATEPRESCALER_8                       (0x20000000UL)
    $ R+ f/ `8 Z& I% i! H
  4. #define SPI_BAUDRATEPRESCALER_16                      (0x30000000UL)
    4 J7 H6 ?# B$ j4 D0 F! n
  5. #define SPI_BAUDRATEPRESCALER_32                      (0x40000000UL)8 N+ n( u- Q9 a9 j
  6. #define SPI_BAUDRATEPRESCALER_64                      (0x50000000UL)
    - R5 Y( m" L% Z7 L- K- C9 E4 P- z
  7. #define SPI_BAUDRATEPRESCALER_128                     (0x60000000UL)
    ; @3 d/ H" Q' |8 x: a
  8. #define SPI_BAUDRATEPRESCALER_256                     (0x70000000UL)
复制代码
- f( C, Z& Q$ X% U
  FirstBit) A2 g5 g3 r0 }: x; _6 \5 W, ?
用于设置数据传输从最高bit开始还是从最低bit开始。
5 ]8 X" F: d0 q/ l# t1 F* R
  1. #define SPI_FIRSTBIT_MSB                              (0x00000000UL)) J5 w: g! ?0 y0 u
  2. #define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST
复制代码

0 o+ O; {5 f& o6 J# S  T  TIMode
# k1 H! l' K  y/ ?8 r用于设置是否使能SPI总线的TI模式。" |7 E+ o+ ?# o. a* q8 q5 f
  1. #define SPI_TIMODE_DISABLE               (0x00000000UL)
    : e/ v" F9 ]+ O  N  G
  2. #define SPI_TIMODE_ENABLE                SPI_CFG2_SP_0
复制代码

: M' k3 w  u0 o4 s# {3 r; ?  CRCCalculation+ j' I# A6 F& j) M4 n" h- n* Y
用于设置是否使能CRC计算。
2 [2 ^7 h; q) x/ E
  1. #define SPI_CRCCALCULATION_DISABLE                    (0x00000000UL)
    3 w) p6 S+ n- |( g' q* c2 M
  2. #define SPI_CRCCALCULATION_ENABLE                     SPI_CFG1_CRCEN
复制代码

) @1 l8 P( C2 a" g5 Q  CRCPolynomial
$ G9 P; j' k" v( L1 |用于设置CRC计算使用的多项式,必须是奇数,范围0到65535。' w0 q* w& ~% F% p: J  N% U
( m9 f/ E2 j/ c4 t" A
  CRCLength
+ S7 @6 m4 c4 A4 }用于设置CRC计算时的CRC长度。大小要与同属此结构体的DataSize一致。或是DataSize的整数倍。
0 v6 b0 w0 e+ ~2 U/ z8 V" }2 [' Z6 t7 ^5 M" w. O2 A* p
  1. #define SPI_CRC_LENGTH_DATASIZE                       (0x00000000UL)
    ' R+ g& i9 z2 [
  2. #define SPI_CRC_LENGTH_4BIT                           (0x00030000UL)! c' K/ B) U) ?* I* E4 [% l
  3. #define SPI_CRC_LENGTH_5BIT                           (0x00040000UL)& c6 y( E; G0 f9 }
  4. #define SPI_CRC_LENGTH_6BIT                           (0x00050000UL)3 c: n  H8 n0 v- E% w8 R: i, {
  5. #define SPI_CRC_LENGTH_7BIT                           (0x00060000UL)
    + F1 [- h. Y8 H3 r5 j! J9 U
  6. #define SPI_CRC_LENGTH_8BIT                           (0x00070000UL): q+ C8 H% h1 H. X7 k- G/ Y& B
  7. #define SPI_CRC_LENGTH_9BIT                           (0x00080000UL)
    8 _. @/ N; l  V+ j" D, ?
  8. #define SPI_CRC_LENGTH_10BIT                          (0x00090000UL)* p. M2 m5 x$ U8 y7 D1 H0 w* G+ q
  9. #define SPI_CRC_LENGTH_11BIT                          (0x000A0000UL)$ Y3 u& e1 G* h; R" E- k1 B6 L) y2 ^. ^
  10. #define SPI_CRC_LENGTH_12BIT                          (0x000B0000UL)
    ' _( c: o+ ]% ^
  11. #define SPI_CRC_LENGTH_13BIT                          (0x000C0000UL)
    6 q9 _/ i) r5 t; U
  12. #define SPI_CRC_LENGTH_14BIT                          (0x000D0000UL)
    * {( i! q5 u  J
  13. #define SPI_CRC_LENGTH_15BIT                          (0x000E0000UL)
    - f& S8 x( N( |# P& b
  14. #define SPI_CRC_LENGTH_16BIT                          (0x000F0000UL)
    1 _5 Y" e' r8 d
  15. #define SPI_CRC_LENGTH_17BIT                          (0x00100000UL)
    $ |# a* f8 t5 ?8 S3 p4 q. E
  16. #define SPI_CRC_LENGTH_18BIT                          (0x00110000UL)# Z5 C( x6 i& @+ d8 v
  17. #define SPI_CRC_LENGTH_19BIT                          (0x00120000UL)
    + D% a$ G  v# \8 i/ _) n
  18. #define SPI_CRC_LENGTH_20BIT                          (0x00130000UL)
    + D$ P5 S$ E- ~! N* E
  19. #define SPI_CRC_LENGTH_21BIT                          (0x00140000UL)
    : r* I* F" A. S9 ~" O$ D2 f6 B0 t
  20. #define SPI_CRC_LENGTH_22BIT                          (0x00150000UL)
    3 [* ~5 z" k2 M& s2 M6 ?
  21. #define SPI_CRC_LENGTH_23BIT                          (0x00160000UL); j7 d! ^; z1 ^# F, G% T9 b. h( G/ C
  22. #define SPI_CRC_LENGTH_24BIT                          (0x00170000UL)% r9 g7 X+ y0 P/ G' `
  23. #define SPI_CRC_LENGTH_25BIT                          (0x00180000UL)% Z, `# o/ z& s
  24. #define SPI_CRC_LENGTH_26BIT                          (0x00190000UL)* z! C' O! B: k+ F' ?
  25. #define SPI_CRC_LENGTH_27BIT                          (0x001A0000UL)6 c1 s% t+ ^0 R( I4 H
  26. #define SPI_CRC_LENGTH_28BIT                          (0x001B0000UL)+ ^' l3 u4 }2 X' P3 `
  27. #define SPI_CRC_LENGTH_29BIT                          (0x001C0000UL)0 h5 j5 {# T9 u2 j! O' ]( A+ O# K
  28. #define SPI_CRC_LENGTH_30BIT                          (0x001D0000UL)
    & d8 v: b( h1 \' l
  29. #define SPI_CRC_LENGTH_31BIT                          (0x001E0000UL)
    & E' f) c3 P, _9 [1 E  ]/ T2 H
  30. #define SPI_CRC_LENGTH_32BIT                          (0x001F0000UL)
    $ x$ [; g$ x) f3 ]: S
复制代码

. s0 G# A; b1 |# ]/ x: P  NSSPMode( P- A+ L; F6 ]6 g
用于设置是否使能NSSP信号,可以通过SPIx_CR2寄存器的SSOM位使能。注意,只有配置为摩托罗拉SPI主控模式时设置此成员才有用。; r5 v" j; B7 V, q. ?- P
  1. #define SPI_NSS_PULSE_DISABLE                         (0x00000000UL)
    . F$ ?2 ^1 C3 n/ u
  2. #define SPI_NSS_PULSE_ENABLE                          SPI_CFG2_SSOM
复制代码

2 c5 d) S9 t1 o' Z8 l& ], D/ J  NSSPolarity  r- z2 B0 U: V0 l9 X
用于设置NSS引脚上的高电平或者低电平作为激活电平。6 V5 w; L; ], e" ]& L

9 P0 }! C; W7 T5 H. H% Q- |( Q: R, f& N
  1. #define SPI_NSS_POLARITY_LOW                          (0x00000000UL)
    - T: y& I! q! H4 Z2 m
  2. #define SPI_NSS_POLARITY_HIGH                          SPI_CFG2_SSIOP
复制代码

5 T4 E1 F7 C0 L  FifoThreshold
- l' ^& J1 R4 H5 n7 L用于设置SPI的FIFO阀值。
8 D: m# M- V+ j5 c2 l& a0 t  _6 }3 ]" A5 l* W7 Z) Y7 F
  1. #define SPI_FIFO_THRESHOLD_01DATA                     (0x00000000UL)
    ( i2 c7 H( D7 q) M
  2. #define SPI_FIFO_THRESHOLD_02DATA                     (0x00000020UL)
    . u2 |, D0 \) o, _
  3. #define SPI_FIFO_THRESHOLD_03DATA                     (0x00000040UL)
    ( H5 R7 q* X! K, m0 q+ }: Y$ c
  4. #define SPI_FIFO_THRESHOLD_04DATA                     (0x00000060UL)% Q8 |8 |2 q4 [9 Q9 d
  5. #define SPI_FIFO_THRESHOLD_05DATA                     (0x00000080UL)
    / |% R' X( X, y/ W9 J8 u
  6. #define SPI_FIFO_THRESHOLD_06DATA                     (0x000000A0UL)
    . E1 u0 w" P! M6 x
  7. #define SPI_FIFO_THRESHOLD_07DATA                     (0x000000C0UL)
    # T4 j% v4 u6 B; T* B! h
  8. #define SPI_FIFO_THRESHOLD_08DATA                     (0x000000E0UL)3 }. v6 L/ v2 b9 ~2 W; A
  9. #define SPI_FIFO_THRESHOLD_09DATA                     (0x00000100UL)$ z" U# ~' `3 I, t  u7 n
  10. #define SPI_FIFO_THRESHOLD_10DATA                     (0x00000120UL)
    : I$ w! N* Q- Z. F& y- ~# K5 M
  11. #define SPI_FIFO_THRESHOLD_11DATA                     (0x00000140UL)
    8 l; J+ i( M# {9 ^1 s0 H
  12. #define SPI_FIFO_THRESHOLD_12DATA                     (0x00000160UL)
    7 H* i5 O# j: a- b! e
  13. #define SPI_FIFO_THRESHOLD_13DATA                     (0x00000180UL)" x2 h' B6 [* R  \! V
  14. #define SPI_FIFO_THRESHOLD_14DATA                     (0x000001A0UL)0 u, B# m' P  u4 m* H
  15. #define SPI_FIFO_THRESHOLD_15DATA                     (0x000001C0UL)
    - ?$ A0 V2 P) ^
  16. #define SPI_FIFO_THRESHOLD_16DATA                     (0x000001E0UL)
复制代码

9 F2 w! J) y6 A- I7 E& i6 {  TxCRCInitializationPattern5 t. B- s/ [1 q$ r/ a
发送CRC初始化模式。  {4 X1 s, T, \% E9 w: {# P+ v
; _* f: \  ]. j: m$ m  Q' g/ s
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)
    ' Q0 `4 W' N$ Z1 C) l( H
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码

: A3 a9 o( v+ D2 C" W  RxCRCInitializationPattern+ e% y2 V% u8 r3 }' A% \
接收CRC初始化模式. {4 L% I! c1 i  e! w
  1. #define SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN       (0x00000000UL)1 D/ e, S1 t/ Y3 m. U$ S5 v
  2. #define SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN        (0x00000001UL)
复制代码
6 }4 o, M% T: f9 t! u- e
MasterSSIdleness( f/ z/ x$ d7 d9 \" D4 D! q
在主模式下插入到SS有效边沿和第一个数据开始之间的额外延迟,单位SPI时钟周期个数。7 t  ]: Q( w6 N1 D2 o/ D" x3 ]5 [4 T

* I: r$ h2 U$ g& h. S+ H
  1. #define SPI_MASTER_SS_IDLENESS_00CYCLE                (0x00000000UL)* Y  F7 I, @& ~3 z/ a2 K  n+ h
  2. #define SPI_MASTER_SS_IDLENESS_01CYCLE                (0x00000001UL)3 I( Y. T/ g* I" F4 J
  3. #define SPI_MASTER_SS_IDLENESS_02CYCLE                (0x00000002UL)
    % P1 K$ D2 {( g1 B* Y+ \
  4. #define SPI_MASTER_SS_IDLENESS_03CYCLE                (0x00000003UL)
    4 Q  ?. S, T; h2 y" ^+ N7 p
  5. #define SPI_MASTER_SS_IDLENESS_04CYCLE                (0x00000004UL)
    4 g, `. x( k( V- U
  6. #define SPI_MASTER_SS_IDLENESS_05CYCLE                (0x00000005UL)
    4 f% B- b" J5 k2 L6 y* F) [
  7. #define SPI_MASTER_SS_IDLENESS_06CYCLE                (0x00000006UL)) \6 _4 ~& z- e& e5 Y
  8. #define SPI_MASTER_SS_IDLENESS_07CYCLE                (0x00000007UL)( i( a" D8 V* r5 K# w& |
  9. #define SPI_MASTER_SS_IDLENESS_08CYCLE                (0x00000008UL)0 m' R7 k& u. Q8 S- k" s
  10. #define SPI_MASTER_SS_IDLENESS_09CYCLE                (0x00000009UL). w/ u) C: t/ i  @. T% Y
  11. #define SPI_MASTER_SS_IDLENESS_10CYCLE                (0x0000000AUL)
    ! m2 D& L3 D5 k
  12. #define SPI_MASTER_SS_IDLENESS_11CYCLE                (0x0000000BUL)
    0 Z; `5 O7 |" M* k) {2 N
  13. #define SPI_MASTER_SS_IDLENESS_12CYCLE                (0x0000000CUL): z/ U1 |1 n3 U
  14. #define SPI_MASTER_SS_IDLENESS_13CYCLE                (0x0000000DUL)2 \5 k& A2 t" Q
  15. #define SPI_MASTER_SS_IDLENESS_14CYCLE                (0x0000000EUL)7 o7 }: _- s; C$ S( i8 a- |/ n/ q
  16. #define SPI_MASTER_SS_IDLENESS_15CYCLE                (0x0000000FUL)2 n! x4 @1 n9 v( \4 F' a
复制代码
$ e- Z  X( \' y( D& _# y
  MasterInterDataIdleness
& e, Y( |: H' ?$ e2 F; s主模式下在两个连续数据帧之间插入的最小时间延迟,单位SPI时钟周期个数。
6 }9 R- ?$ s: N; M/ o+ s$ T( m
) E, F% w+ U8 _- n- Y
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)
    " ]$ g7 _' O6 `- X' C
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
复制代码
' y7 i* t: B* @0 C+ T
  MasterReceiverAutoSusp4 J7 P; g8 K, d
用于控制主器件接收器模式下的连续 SPI 传输以及自动管理,以避免出现上溢情况。# X. C9 i! K; O6 L0 p2 i, n/ W

& z) P& ~9 A; l! Z2 {  {/ l
  1. #define SPI_MASTER_RX_AUTOSUSP_DISABLE                (0x00000000UL)# J1 `: p& I6 r) v2 I  A
  2. #define SPI_MASTER_RX_AUTOSUSP_ENABLE                 SPI_CR1_MASRX
    . m9 g) V# i6 D4 I* u: g
复制代码

/ ~) `! l+ @& c9 n9 s- ?; m% E1 C  MasterKeepIOState" {1 c1 V% ?4 k% [$ J0 C( q; H8 o
禁止SPI后,SPI相关引脚保持当前状态,以防止出现毛刺。在从模式下,该位不应该使用。1 j! O2 p/ t- q
  1. #define SPI_MASTER_KEEP_IO_STATE_DISABLE              (0x00000000UL)
    9 X& F" P  O& c: \+ p, m  p% M' q" R
  2. #define SPI_MASTER_KEEP_IO_STATE_ENABLE               SPI_CFG2_AFCNTR
复制代码
  |% K! {6 x; `, J- t0 h! k9 y0 p
  IOSwap
3 @  t5 A' {" J* p/ Z+ S8 e7 v用于交换MISO和MOSI引脚。' w2 Q4 S) H1 k
# y- G# ]( A; x! q
  1. #define SPI_IO_SWAP_DISABLE                           (0x00000000UL)
    * }  m- T0 m; N; ?6 [
  2. #define SPI_IO_SWAP_ENABLE                            SPI_CFG2_IOSWP
复制代码
' _8 O: p$ G2 u1 v  t8 i
72.3.3 SPI总线句柄结构体SPI_HandleTypeDef

7 `7 L2 c# y3 p; w% a4 K下面是SPI总线的初始化结构体,用到的地方比较多:9 g$ q: Y+ L% j
: ~, v! b: i! m% X; _
  1. typedef struct __SPI_HandleTypeDef
    3 S9 z0 T* [. }3 p' n
  2. {" ~% c/ g6 s# ~+ |  J3 [1 V) u' h
  3.   SPI_TypeDef                *Instance;                 8 O2 z; c! n+ q- C
  4.   SPI_InitTypeDef            Init;                        
    ! I: G# ^( s0 T( p  S
  5.   uint8_t                    *pTxBuffPtr;                 ; y7 u5 K( h4 u+ n: C
  6.   uint16_t                   TxXferSize;                  
    - H* f; Q3 j& G, d0 j: C: p4 \. l
  7.   __IO uint16_t              TxXferCount;                  
    1 B: H3 ?& R  v# n9 @/ W& m4 O. X
  8.   uint8_t                    *pRxBuffPtr;                , v1 H7 O  K, t  }  V
  9.   uint16_t                   RxXferSize;                  + A2 @3 G. u3 U+ k" d6 J6 ?; p
  10.   __IO uint16_t              RxXferCount;                 ( p/ W$ ]) B$ A' k; t, w$ k4 K  k
  11.   uint32_t                   CRCSize;                     $ b+ w9 k% z6 v9 F# _- r( M
  12.   void (*RxISR)(struct __SPI_HandleTypeDef *hspi);      
    3 a5 c" G1 {% f0 H9 h( r- j6 R$ G
  13.   void (*TxISR)(struct __SPI_HandleTypeDef *hspi);        ) N# k6 }* @4 G# ]6 j. r' u! E
  14.   DMA_HandleTypeDef          *hdmatx;                     
    % V; C# f- u( @" Z9 O* k
  15.   DMA_HandleTypeDef          *hdmarx;                     
    - y, g) Q1 ~4 E
  16.   HAL_LockTypeDef            Lock;                        
    & J; X1 f* g) h- H- i% y
  17.   __IO HAL_SPI_StateTypeDef  State;                        , y* X' h2 C+ X9 @+ ?3 }
  18.   __IO uint32_t              ErrorCode;                  
    3 q& ]  A2 g. {8 @2 H0 |( L
  19. #if defined(USE_SPI_RELOAD_TRANSFER)
    + _0 H* _7 t  ^, J
  20.   SPI_ReloadTypeDef          Reload;                     
    1 S: T* g. J( Z" ~) i2 n, O/ P
  21. #endif
    6 c. q1 }6 N0 v8 R: c$ O4 b

  22. 3 c* |/ M% I6 O# h
  23. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
    2 ]1 K, r3 L$ T3 Q& z3 H6 P: b
  24.   void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      $ `' L# M" l- ~- i6 \
  25.   void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi);      : B# G6 |: ], q, B- A
  26.   void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    6 p% L" v" J' `
  27.   void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  0 B( Q/ x8 E6 c3 s) `" c
  28.   void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);  ) p! t2 w/ w, Y, D5 J
  29.   void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);
    & |; e, I- _9 F# N
  30.   void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi);       - _8 G$ }; M( ?( E; \% I! r
  31.   void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi);   
    / o: x; x8 P+ K& m7 a
  32.   void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi);   
    8 v3 _1 N& h' L5 u
  33.   void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi); + t, c7 m3 ]( }# k  t3 T- L
  34. #endif  
    & j6 m- K/ T  o; V
  35. } SPI_HandleTypeDef;
    / X, c6 ?0 T) y! K- z8 ^" J
复制代码

- c4 g$ n# v1 q! w; J! X注意事项:
; N2 P- c7 b# \6 P& j: m' u& t& N6 z7 e/ r8 R, @
条件编译USE_HAL_SPI_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:
( N+ ?+ l$ d% I$ I% N5 `0 `2 X6 R; N7 D# Y) y, T! Y- a
  #define   USE_HAL_SPI_REGISTER_CALLBACKS   1
- h1 ^) ]8 A# O0 B" X3 m) |  P/ T6 U2 j$ j5 c
通过函数HAL_SPI_RegisterCallback注册回调,取消注册使用函数HAL_SPI_UnRegisterCallback。5 d; t6 ^6 l% x6 W0 m( i
* w  G5 o) m6 R+ s# @% n) T3 W
这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。& Q) s0 {! ^2 s: W, n0 X  i

& |7 x( U6 K# O: R1 ?1 @& F  SPI_TypeDef   *Instance
1 C$ {7 T( H7 _& B( G这个参数是寄存器的例化,方便操作寄存器,比如使能SPI1。9 H3 N2 V* E7 C6 J7 F- u9 A8 U  a( w
5 m3 s% W3 S- n% ?5 `
SET_BIT(SPI1 ->CR1,  SPI_CR1_SPE)。6 y4 Y/ S- N2 Q" A0 b( k9 P
, X0 ~$ j4 r1 g3 j# u: a9 f. Y
  SPI_InitTypeDef  Init
8 x+ _0 K0 I; m% L' T/ ]这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。  G5 m% i* d( y7 L

. v; [* n! L" _. }  DMA_HandleTypeDef          *hdmatx               
9 I7 M  r8 B6 K+ P  DMA_HandleTypeDef          *hdmarx# N/ [5 N1 T* [) O& \3 B% O
用于SPI句柄关联DMA句柄,方便操作调用。- G9 }4 o/ s4 K; @- c

( o' A* a- U+ f& |72.4 SPI总线源文件stm32h7xx_hal_spi.c
4 z+ l' L' ~& C; I; Z* [  A# A此文件涉及到的函数较多,这里把几个常用的函数做个说明:
) q. W7 K  ^2 i) r
9 Y' ]" z( X; e: R* }  HAL_SPI_Init3 \# F1 I2 U, v
  HAL_SPI_DeInit
) t* U" M/ {/ O: _  HAL_SPI_TransmitReceive
( I+ w( a# |9 k1 ~  HAL_SPI_TransmitReceive_IT
6 x8 x* e5 s  m) P' Z$ z6 O  HAL_SPI_TransmitReceive_DMA: X: [1 _6 O( }9 H3 e
7 Y' U( R4 R2 a$ g
72.4.1 函数HAL_SPI_Init+ P& h- i" q: }5 X. r! b7 [" f
函数原型:# a! M& D0 I" j3 W

  q) W; Z& o; p3 o+ N1 H
  1. HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)
    8 P$ M/ H. O* S' Y2 r5 }# f
  2. {
    3 n6 @. }8 C. E4 W
  3.   uint32_t crc_length = 0UL;
    5 K2 I3 a: r/ b+ j# i+ k$ Q
  4.   uint32_t packet_length;
    $ y, j: x" U, C: F7 |" n

  5. 4 T- I) V% C5 c2 m5 k0 E
  6.   /* 省略未写 */  A( e1 Z  n, u( F' F3 s' ]
  7. - N$ U6 K% f. \: M. H8 f; k
  8.   /* 如果数据位宽大于16bit,必须是SPI1,SPI2或者SPI3,而SPI4,SPI5和SPI6不支持大于16bit */
    2 r% Q# a# b8 I$ v7 x
  9.   if ((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (hspi->Init.DataSize > SPI_DATASIZE_16BIT))# e3 m+ r4 C2 }7 J
  10.   {+ v9 F1 ~. I/ s) N( _
  11.     return HAL_ERROR;* C- H/ }+ o8 Q- y+ a/ c
  12.   }' d) I5 i" `& ?/ d% b  r

  13. 8 O+ j7 ?% C+ q/ m( ^' n
  14.   /* SPI1,SPI2和SPI3的FIFO大小是16*8bit,而SPI4,SPI5和SPI6的FIFO大小是8*8bit
      h1 ?: p5 N* X1 h* \0 d, `, _
  15.      这里是查看设置的缓冲大小是否超出了FIFO支持的大小。* B! ^; U9 H7 M: n; `
  16. */
    ! v4 S" f0 A1 s6 R. F5 z6 A
  17.   packet_length = SPI_GetPacketSize(hspi);
    $ V) D4 E: G1 J1 |$ }
  18.   if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_LOWEND_FIFO_SIZE)) ||
    1 }+ e/ G. G8 l- K
  19.       ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (packet_length > SPI_HIGHEND_FIFO_SIZE)))
    ) B# [/ F1 C, y8 b+ ?3 \! ~4 ~& {
  20.   {: `  G: y* ~6 A1 B: s* o1 [& g' ?3 n: z
  21.     return HAL_ERROR;+ o: X1 O3 I* W% g  Z4 W& H9 q) f
  22.   }
    + k$ G9 G2 T1 z: K( C  H$ u

  23. % Y' l& U( w# ~$ g
  24. #if (USE_SPI_CRC != 0UL)2 o+ E; e; w* Y4 u
  25.     /* 省略未写 */
    1 n' x1 ]2 n* [9 l( y' N
  26. #endif 6 b. s% B& S* E; d! ^# d9 j

  27. ( E3 u7 r! i: r+ Q8 b7 p
  28.   if (hspi->State == HAL_SPI_STATE_RESET)
    2 M2 {6 f4 p8 ]" N, ?
  29.   {* ?" z* U1 Y' s
  30.     /* 解锁 */
    7 x# p( P+ z$ a# ]* j
  31.     hspi->Lock = HAL_UNLOCKED;
    1 x  M6 f! [6 d% L: |
  32. 5 ^) ~% k8 }3 U, d
  33.     /* 使用自定义回调 */
    4 p( b+ _: J! n. ]
  34. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)0 R+ M: _& v+ ?% D) z/ w
  35.     /* 设置默认回调函数 */( b; g3 l& K* G9 V
  36.     hspi->TxCpltCallback       = HAL_SPI_TxCpltCallback;       /* Legacy weak TxCpltCallback       */5 f$ l4 x1 W; }6 Q* j: |0 c+ r
  37.     hspi->RxCpltCallback       = HAL_SPI_RxCpltCallback;       /* Legacy weak RxCpltCallback       */
    1 ]# ^6 I7 L  S+ W
  38.     hspi->TxRxCpltCallback     = HAL_SPI_TxRxCpltCallback;     /* Legacy weak TxRxCpltCallback     */
    - M; Z) ]% Z1 J
  39.     hspi->TxHalfCpltCallback   = HAL_SPI_TxHalfCpltCallback;   /* Legacy weak TxHalfCpltCallback   */
    ( p9 w% p$ M. J* Q1 f2 q
  40.     hspi->RxHalfCpltCallback   = HAL_SPI_RxHalfCpltCallback;   /* Legacy weak RxHalfCpltCallback   */
    ) M( ]. D& B+ p/ _/ ^& n
  41.     hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */
    6 y# I( S1 b+ w( Y. p  G! o
  42.     hspi->ErrorCallback        = HAL_SPI_ErrorCallback;        /* Legacy weak ErrorCallback        */& H( {: t+ ^; j! t
  43.     hspi->AbortCpltCallback    = HAL_SPI_AbortCpltCallback;    /* Legacy weak AbortCpltCallback    */
    - M0 X& u+ i" x1 _$ U* H
  44. 4 Q# [6 s7 q1 z9 Q1 t8 A* D# Y
  45.     if (hspi->MspInitCallback == NULL)9 w% m9 C- q5 o+ l; p2 P
  46.     {* t; D# S4 ^6 B9 O
  47.       hspi->MspInitCallback = HAL_SPI_MspInit; ! v5 \" z1 C4 g* V4 N% t. m, t
  48.     }1 I' I( s2 H- R3 y

  49. ' a- X. d+ Z+ L% f0 A2 E
  50.     /* 初始化地址硬件: GPIO, CLOCK, NVIC... */
    % L6 K# O$ F8 V/ {
  51.     hspi->MspInitCallback(hspi);
    3 o, T7 Y) m0 x1 I' X! f
  52. #else
    # g; u; `8 z6 H0 `) I/ U) c, [
  53.     /* 初始化底层硬件: GPIO, CLOCK, NVIC... */
    1 K# l3 w& V# n$ o: V$ ?
  54.     HAL_SPI_MspInit(hspi);
    * i0 W, h- p- P6 r, q
  55. #endif
    2 U/ j7 L6 `1 h7 j
  56.   }5 {! W- w$ f3 |% b) o" n

  57. 1 t! }9 f& Y/ q- y9 e
  58.   hspi->State = HAL_SPI_STATE_BUSY;! R& t9 N: \2 }  m: E2 v: l

  59. 7 S0 _7 [8 }, c* \! C1 u3 l
  60.   /* 禁止SPI外设 */& u6 `6 G4 u$ b/ s
  61.   __HAL_SPI_DISABLE(hspi);
    , g5 F  ]7 o& z- i; Y4 N
  62. ; Y* W3 q& w, |9 R& {
  63.   /*----------------------- SPIx CR1 & CR2 配置---------------------*/4 X# z) N5 m7 P0 Q, |8 w% |
  64.   if ((hspi->Init.NSS == SPI_NSS_SOFT) && (hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.NSSPolarity ==; O/ o; s. Q3 X" e& L4 P
  65. SPI_NSS_POLARITY_LOW))
    8 X( R) u+ J2 ~% b
  66.   {
    ! t+ A7 C# ~0 e7 X2 b
  67.       SET_BIT(hspi->Instance->CR1, SPI_CR1_SSI);
      S! X% f  S! s, Z# b, t( D' _& I
  68.   }
    4 q+ T9 V$ K! H5 j6 S9 E

  69. 7 e# y* l5 T+ c, o6 |( r: z( H) }
  70.   /* SPIx CFG1配置 */+ X' k' P# D5 h" {" f4 ?+ u
  71.   WRITE_REG(hspi->Instance->CFG1, (hspi->Init.BaudRatePrescaler | hspi->Init.CRCCalculation | crc_length |
    / b, i  z7 J" X8 @& x+ }7 X
  72.                                    hspi->Init.FifoThreshold     | hspi->Init.DataSize));
    4 `, w( D" L( y. n, p: U7 l

  73. % m1 ~7 k& a) I5 _1 {
  74.   /* SPIx CFG2配置 */
    1 h5 W5 ]  i/ ^- x
  75.   WRITE_REG(hspi->Instance->CFG2, (hspi->Init.NSSPMode     | hspi->Init.TIMode           | hspi->Init.NSSPolarity  |
    . {) Z% j% B$ N4 Q' a$ Q
  76.                                    hspi->Init.NSS          | hspi->Init.CLKPolarity      | hspi->Init.CLKPhase     |* c: b! [8 X; T3 D
  77.                                    hspi->Init.FirstBit     | hspi->Init.Mode             | hspi->Init.MasterInterDataIdleness |  @2 e5 t1 d' n9 U
  78.                                    hspi->Init.Direction    | hspi->Init.MasterSSIdleness | hspi->Init.IOSwap));1 J) J7 v3 {, w( B2 n

  79. ' z" s- }) W+ ]- g% A2 O) Z
  80. #if (USE_SPI_CRC != 0UL)3 c; a+ H5 Q) Q' O
  81.   /*---------------------------- SPIx CRC配置 ------------------*/
    ' L2 `5 v4 b5 `
  82.   /* 配置SPI CRC */
    4 E$ Z2 S$ ?7 C" M4 m( R( l
  83.   if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
      M' O  c5 k3 @9 S" L1 `  }9 G
  84.   {
    ; ?. g# [  w: X) _+ R$ G7 q, G
  85.     /* 初始化TX CRC初始值 */
    ) s7 \0 s8 A* W, d- x# d
  86.     if (hspi->Init.TxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)1 a, ]' P/ I$ h; z
  87.     {8 o! O* S; d2 z  g% F/ O' T
  88.       SET_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);
    1 [8 t+ q* P- M
  89.     }9 |& d9 Q4 l! [/ [' e# e) J2 J6 Q
  90.     else! q/ f, E: v! A* T- c
  91.     {
    # R; l( r# d% Y" |' w
  92.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_TCRCINI);
    8 K5 ]) h; v: f0 A7 \# y
  93.     }# J- |( n$ I+ F3 B4 U, V
  94. 7 m/ D4 ?; y3 ~4 r
  95.     /* 初始化RXCRC初始值 */4 z) y! j. S; {& B
  96.     if (hspi->Init.RxCRCInitializationPattern == SPI_CRC_INITIALIZATION_ALL_ONE_PATTERN)
    . y( v: Q, _1 e$ G
  97.     {' G  J. N5 v% \% s
  98.       SET_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);, h. P! C6 R. K4 U; z3 L% c  I
  99.     }
    . [- z/ g( N, @( Y7 }. [7 N- F, i
  100.     else
    - [  k6 w+ Z% q5 {
  101.     {" M; S' H! |. i# H% v  c
  102.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_RCRCINI);
    ) f% G1 N; z: j' H# F0 P
  103.     }
    ' R1 S2 J9 N5 F- ~7 g3 e
  104. 9 W  m# [  z: m, D2 G
  105.     /* 使能 33/17 bit CRC计算 */
    9 y3 Q7 O4 Y- e% X3 @$ e0 {' @; u
  106.     if (((!IS_SPI_HIGHEND_INSTANCE(hspi->Instance)) && (crc_length == SPI_CRC_LENGTH_16BIT)) ||8 i2 M  Q/ ]& M, \5 x! @) x
  107.         ((IS_SPI_HIGHEND_INSTANCE(hspi->Instance))  && (crc_length == SPI_CRC_LENGTH_32BIT)))
    $ n2 o) s2 [$ R; g- [. u
  108.     {# [/ R9 o: {: m5 i" L
  109.       SET_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);7 y1 f% o5 z1 A8 r+ E; J- e% e
  110.     }3 p6 g4 P1 e* ^& Z* H
  111.     else
    ! h( \; d! r2 X' g# C$ `0 }
  112.     {; v7 h& N2 l  Z% u: e& f
  113.       CLEAR_BIT(hspi->Instance->CR1, SPI_CR1_CRC33_17);
    ' v9 P0 _% N. D: A  `2 B3 x$ s
  114.     }
    0 M, Z2 B+ b4 U, I

  115. ' g  l2 `7 N6 w& T2 l
  116.     /* 写CRC多项式到SPI寄存器 */
    ' L8 E& b' E0 V# P
  117.     WRITE_REG(hspi->Instance->CRCPOLY, hspi->Init.CRCPolynomial);% m# H' U. w! _+ B! z$ @
  118.   }
    : O: f9 i2 k  k- }. r, |0 k
  119. #endif ) V! W1 b; t# N: G6 t' J
  120. : O8 B- O( ~6 v! ^6 R3 S. |- t  e
  121.   /* SPI从模式,下溢配置 */* p  C7 j/ z) ?$ s7 G2 E
  122.   if (hspi->Init.Mode == SPI_MODE_SLAVE)
    . S* S* i# j* c/ `
  123.   {* J; w. w, L, D, N( e
  124.     /* 设置默认下溢配置 */
    ( `- a0 E: m$ z5 L1 y: v, r; P
  125. #if (USE_SPI_CRC != 0UL)' {8 i7 n9 @5 q* f2 x, [
  126.     if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_DISABLE)
    : ]- g( W% X! E2 S
  127. #endif; A1 t* B3 g$ O. ^
  128.     {# X  l/ ]* y( U* M0 j
  129.       MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRDET, SPI_CFG1_UDRDET_0);
    . c4 g7 _7 m- t* T# \
  130.     }& P+ E& @+ k2 ]( a) |
  131.     MODIFY_REG(hspi->Instance->CFG1, SPI_CFG1_UDRCFG, SPI_CFG1_UDRCFG_1);
    & A5 G& {2 l) {0 h3 W! `' J- o+ ]
  132.   }) W: t6 A4 m, [6 N
  133. ; u  n6 M3 X- O) w
  134. #if defined(SPI_I2SCFGR_I2SMOD)
    # ]3 b5 \+ }$ x/ T' d0 a
  135.   CLEAR_BIT(hspi->Instance->I2SCFGR, SPI_I2SCFGR_I2SMOD);
    ! i) c' l# @# W% E; O
  136. #endif
    * v. ]( h% m( `6 F4 x" y" {
  137. 4 Z! g3 R, `' h' E6 j+ h- x  C0 M  L
  138.   /* 确保AFCNTR bit由SPI主机模式管理 */5 G/ Q" V) X+ c0 o# H
  139.   if ((hspi->Init.Mode & SPI_MODE_MASTER) == SPI_MODE_MASTER)0 K: k  E4 J" d9 g2 R
  140.   {" s  a* }* J, X: k6 ]
  141.     /* Alternate function GPIOs control */
    # T" |$ W" O0 y; u- U* D
  142.     MODIFY_REG(hspi->Instance->CFG2, SPI_CFG2_AFCNTR, (hspi->Init.MasterKeepIOState));
    5 f2 `1 C* M+ T& o+ Z) d9 c* {, T
  143.   }
    4 s) _# R! F; p) E4 a* Y& ^
  144. + A, ]  I( E  ^$ f' j
  145.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;8 k/ A2 {' C+ b+ v& ?6 D1 N  A
  146.   hspi->State     = HAL_SPI_STATE_READY;
      g) M9 Z0 _7 y) J4 m& Q2 F- B: n
  147. , o- l6 S8 p, A  c0 @( o7 |. C3 {
  148.   return HAL_OK;
    ' V2 f  C+ B% {' U# y: j
  149. }
    6 J. G8 O7 k! ~. L0 d
复制代码
$ j: u- _8 q3 g- @2 [! e
1 w$ u8 G7 c$ m
函数描述:& n$ w2 N- L* ]4 g) W' d
  J' c/ M; y/ F1 C* B& A$ t
此函数用于初始化SPI。
9 R7 x4 P, q! ~6 Z7 O) B" Z2 k6 M1 e# O1 [# h0 J; k1 P
函数参数:9 q( u/ I( _" X- h5 Y

) G. _" A2 E+ T' T! h! a7 h  第1个参数是SPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。' M4 I5 K4 c: k2 f, h0 U1 a1 r
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。" b+ z  \0 y9 P* I
& ]" ^( e) v0 [' ~% J

) k9 c! B5 G  i( J0 R, b) u6 i/ w注意事项:; _. p. c9 l. b- l( S1 h
函数HAL_SPI_MspInit用于初始化SPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
" [" H& W$ |9 c如果形参hspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SPI_HandleTypeDef SpiHandle。
8 e' W% L: C8 u& F对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SPI_STATE_RESET  = 0x00U。
1 b0 Z+ Y9 B! c" b) O: @( ]$ u: ~8 j. l
解决办法有三
& S: q) b/ ~. u1 V' U' T* ]2 B0 ]8 ?5 `3 w
方法1:用户自己初始化SPI和涉及到的GPIO等。! p2 o. P5 N( O# E* s
+ [4 @/ h& d2 p
方法2:定义SPI_HandleTypeDef SpiHandle为全局变量。
: @, \! z/ P3 }! R/ j5 L9 d
" H9 P/ D. R- L5 Z/ j方法3:下面的方法
- W9 C9 f. N+ D0 S+ O( @$ h1 e+ h/ G8 O
  1. if(HAL_SPI_DeInit(&SpiHandle) != HAL_OK)) ?5 ^) @( p4 h. I5 q
  2. {0 z! O* g. R9 _! b! F% l
  3.     Error_Handler();
    6 G# g8 t+ d4 {/ H( k! D: U
  4. }  , c8 I0 W% ]  e, ?9 L
  5. if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
    / m0 }& h' b5 T- g4 B6 m
  6. {% `5 H" P. z9 |4 K) S
  7.     Error_Handler();+ U4 M8 F1 n" F
  8. }
复制代码
( p7 y( v$ W+ l- }
使用举例:) R+ j. ]6 F  N

5 X. N- G) |6 D# v' ?3 t/ d3 w6 o
  1. SPI_HandleTypeDef hspi = {0};( b) |1 y( v8 z4 M
  2. 5 X0 v; g! k7 _% P4 d9 D5 p
  3. /* 设置SPI参数 */
    + ?2 d( j8 n  _; z/ Q0 R
  4. hspi.Instance               = SPIx;                   /* 例化SPI */  ?4 A; [4 y$ _
  5. hspi.Init.BaudRatePrescaler = _BaudRatePrescaler;     /* 设置波特率 */: C+ G/ d$ M8 F" \. m9 o- j
  6. hspi.Init.Direction         = SPI_DIRECTION_2LINES;   /* 全双工 */
    6 ^" F/ N5 O9 O% A  v: I! v, N2 U
  7. hspi.Init.CLKPhase          = _CLKPhase;              /* 配置时钟相位 */6 {9 T+ [8 B/ g6 s$ e2 ]2 k, \
  8. hspi.Init.CLKPolarity       = _CLKPolarity;           /* 配置时钟极性 */6 n& _/ @4 Y2 d/ }5 @/ B% ^
  9. hspi.Init.DataSize          = SPI_DATASIZE_8BIT;      /* 设置数据宽度 */7 e/ H! G' v6 ?/ ^
  10. hspi.Init.FirstBit          = SPI_FIRSTBIT_MSB;       /* 数据传输先传高位 */1 ?, u+ H4 ]5 |
  11. hspi.Init.TIMode            = SPI_TIMODE_DISABLE;     /* 禁止TI模式  */" Q, g- E5 x$ z& G" x
  12. hspi.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;      /* 禁止CRC */' e  u8 s7 H/ ?
  13. hspi.Init.CRCPolynomial     = 7;                               /* 禁止CRC后,此位无效 */
    " ?, D2 f! U/ j0 B+ f# q
  14. hspi.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;             /* 禁止CRC后,此位无效 */
    + P& ~2 u8 ~; x' V! c$ \
  15. hspi.Init.NSS               = SPI_NSS_SOFT;                    /* 使用软件方式管理片选引脚 */8 |! T5 k/ d' w! k" z4 A
  16. hspi.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_01DATA;       /* 设置FIFO大小是一个数据项 */8 E2 J# T- R) |7 p8 h
  17. hspi.Init.NSSPMode          = SPI_NSS_PULSE_DISABLE;           /* 禁止脉冲输出 */0 }3 t8 o' H& g" W
  18. hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* 禁止SPI后,SPI相关引脚保持当前状态 */  
    9 b  c% Q& y( L( N7 E. ?5 @
  19. hspi.Init.Mode                  = SPI_MODE_MASTER;            /* SPI工作在主控模式 */% b6 P6 E8 N- C% w

  20. * `; {2 }* a% p* z
  21. if (HAL_SPI_Init(&hspi) != HAL_OK)
    2 e6 A$ s* H3 |) q" l6 C
  22. {
    ; y6 g& p# |, ~# M! }2 G1 h
  23.     Error_Handler(__FILE__, __LINE__);
    2 c7 c- }" g" W0 U7 C6 U4 Q' E
  24. }
复制代码

# s0 d7 _! K" F- y5 [72.4.2 函数HAL_SPI_DeInit
; ]1 ^5 K6 Q  O* L函数原型:; p. C2 h  [3 \
  1. HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)7 S5 t3 j$ Z0 ]4 f+ y4 N0 }
  2. {
    $ `9 W" j( J' w2 ^  b0 \3 W# z
  3. /* 检测SPI句柄是否有效 */
    6 m6 V! `; z, `3 T* w' b
  4.   if (hspi == NULL)
    & u8 D/ K" W$ [* @
  5.   {
    3 |# V% S* J% E5 P3 E  J9 Q
  6.     return HAL_ERROR;: h5 Z& _! ?5 f) m) E' d  t& m& k3 k
  7.   }
    2 @/ @3 h" u3 t: t7 S4 t

  8. * {/ ]8 m9 ?& t" X
  9. /* 检查SPI例化参数 */
    . \" ~, h. N. b" L+ {+ r8 }' C
  10.   assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));* e, P8 G: R/ d. _

  11. 5 s2 s  N. E- z1 u
  12.   hspi->State = HAL_SPI_STATE_BUSY;
    4 `. j" n4 D0 z1 h3 ]* l$ @4 t
  13. " P+ h$ D/ J3 q; c
  14.   /* 禁止SPI外设时钟 */
    # `" x' D5 Q# }- j, h
  15.   __HAL_SPI_DISABLE(hspi);
    ; |' I+ [5 c' v" q. b3 `

  16. , S( W' \- E: ]5 @# k1 X
  17. #if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)% E; x0 z' V; k$ R2 N6 e) `
  18.   if (hspi->MspDeInitCallback == NULL)- f, N' y" |& m+ ~& m
  19.   {
    & c$ Q: ~$ g* @5 S0 O
  20.     hspi->MspDeInitCallback = HAL_SPI_MspDeInit;
    2 }! t# V; v8 q3 {: {% @
  21.   }
    6 L5 C: r; y6 a' M& z7 P

  22. ) N$ i* M3 ?' l# C; b1 \% S
  23.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */
    ; W& R  S6 k8 W& K
  24.   hspi->MspDeInitCallback(hspi);
    , r3 D) }& N8 a9 m/ `5 e/ D  t, G% g
  25. #else
    8 K2 S( a2 X- a& \, G
  26.   /* 复位底层硬件: GPIO, CLOCK, NVIC... */
    4 u  O( S3 [8 A" p; @  |
  27.   HAL_SPI_MspDeInit(hspi);) T" o5 D1 z$ s$ S& c7 V
  28. #endif 1 U% I' b3 v. c$ ^( V* _
  29. . B& B" S4 j; M9 u5 w
  30.   /* 设置无错误,复位状态标记 */+ v; I0 I3 y" `6 g3 Q
  31.   hspi->ErrorCode = HAL_SPI_ERROR_NONE;
    5 h! h6 }1 w. [) Z& }
  32.   hspi->State = HAL_SPI_STATE_RESET;1 [' b: z# {+ Y* g6 l
  33. 7 L2 o* F% W2 ~
  34.   /* 解锁SPI */
    4 j, I& n7 D( \; e
  35.   __HAL_UNLOCK(hspi);
    1 `6 d% Q# K+ d2 i4 ^( ?, b3 X1 V- I
  36. ) g8 P1 ~- T7 N4 L; P
  37.   return HAL_OK;9 @$ \! `9 N3 @1 P
  38. }
复制代码
0 e+ z( }+ R  H$ |- u
函数描述:
1 v- f: {( l; Z( ?
) m% }7 d# g) T用于复位SPI总线初始化。  A' h* Z# h& J/ e
8 Q3 ?5 D: A; W6 ]8 l5 a
函数参数:8 p) p& m- o3 V: }1 `1 B
) i. N1 h. o: N; n$ c1 N
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。) k1 \/ Y# f) A* y) @( U
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中
4 f3 W* Y0 s5 ^. {- ]* x3 s( Q: z0 i0 h, t

: x" }  F8 Z9 x% i72.4.3 函数HAL_SPI_TransmitReceive. P% W' J% V9 q4 s2 W6 M
函数原型:
" w+ C. p8 X5 t% Q2 p! j! x# z' u1 q/ K# S+ E- G
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
    2 G) x8 B* o1 \4 m4 v
  2. {. G+ o# d5 w! _) D+ m6 M' @: Q
  3. ! b6 [1 q4 H/ y6 z5 h2 I* J
  4.    /* 省略未写 */+ ]7 u" u' S# F$ p

  5. % ?, R7 K9 v( a. L! s( P
  6.   /* 大于16bit的数据收发 */
      \. ~2 Y! X1 o5 l
  7.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
    ) m8 d2 F3 G7 x2 M
  8.   {
    2 O; H5 m- i& J; e. Y1 }" q
  9.        /* 省略未写 */
    ( y8 R( Z. l; X
  10.   }4 {+ n$ Z( E! \8 V' v" g
  11.   /* 大于8bit,小于16bi的数据收发 */
    , o/ H. o. y' H" t1 ^/ i' ?
  12.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)% y9 p1 j5 F# ?, C) Z
  13.   {8 U6 ?0 b$ x( Y/ _
  14.       /* 省略未写 */* `( k* D! t, n  e: v; O, p
  15.   }$ U% X- D1 P% X$ u, ~' q8 |
  16.   /* 小于等于8bit的数据收发 */
    . v# s' X0 W  P, g
  17.   else
    4 c' ^$ S! R5 @- K- o$ @2 Y
  18.   {
    1 J7 R" ^, }0 U: O1 N0 l) o
  19.        /* 省略未写 */
    6 u- F1 t6 t; z. }
  20.   }% U; R: I4 P' J' K& r0 I
  21. , I" ?; K: Q, x
  22. }
复制代码
8 p" ^: h8 F8 W# c2 i9 \4 p
函数描述:
" Z+ H9 \& T* H' o. h0 Y) N1 {2 w% ~
此函数主要用于SPI数据收发,全双工查询方式。1 \% s5 `8 ]5 j( q: Y

/ g+ O3 f: ~7 f* E) m函数参数:1 L; `( K. i/ ^9 Q3 z
8 q: X0 n/ l/ p- k, w& d% Y
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
- q/ u5 U0 t. f4 Q) e( Q  第2个参数是发送数据缓冲地址。( y' ^, u9 `6 H  A: u
  第3个参数是接收数据缓冲地址。) B  w/ T3 M# Z: v- N6 U
  第4个参数是传输的数据大小,单位字节个数。
% W% \6 F: x+ F+ E0 l( T  第5个参数是传输过程的溢出时间,单位ms。
3 j, `3 U! H8 f; ?: F  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
, j; z5 w1 O1 u: l
5 O/ C) F) R( B7 G2 h6 u: L: R$ q
使用举例:! W& t2 V0 Z+ V( M* N

. E7 e5 u5 P+ O$ [6 B
  1. SPI_HandleTypeDef hspi = {0};
    , f9 v! ~4 M1 L
  2. * h! x3 q1 \  t! }
  3. if(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)7 K  p. T1 q, X7 M! [2 }9 M
  4. {# o* Z+ p; o% J, A& C
  5.     Error_Handler(__FILE__, __LINE__);% l0 V( P& u, Q0 ~
  6. }
复制代码

/ I+ R/ R! d" I9 q$ [4 ~( W72.4.4 函数HAL_SPI_TransmitReceive_IT

" J8 O; k$ F- z) t' x0 O函数原型:/ q6 o0 P' Q% {
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)8 B, L0 f4 l: O5 t: M% C* [  f
  2. {; K* u! D7 u' \# C+ E" E# O
  3.    /* 省略未写 */. W. f  d, d. V; `7 E
  4. 4 A) u2 |' A6 i3 j
  5.   /* 设置传输参数 */
    5 ?/ z* M3 s0 k" a3 D4 Q
  6.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;  \7 X# ]  c  ?2 m6 G
  7.   hspi->pTxBuffPtr  = (uint8_t *)pTxData;
    7 e/ L; n% x3 T
  8.   hspi->TxXferSize  = Size;
    2 D8 q, p7 ]' q; y7 `
  9.   hspi->TxXferCount = Size;; {8 I: @2 l, y; J  I: B
  10.   hspi->pRxBuffPtr  = (uint8_t *)pRxData;+ p! }! T5 ~8 `
  11.   hspi->RxXferSize  = Size;2 X0 _; H% ^; ?& d7 [1 h
  12.   hspi->RxXferCount = Size;
    , x# @0 F6 |) }! B! V

  13. 3 q. U0 ]/ Q% `
  14.   /* 设置中断处理 */" m' \. D7 I+ D+ T
  15.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)6 Y* g! ~" h# P* |( J" Z
  16.   {2 \. \- M2 k% Y0 ?. I; z: l
  17.     hspi->TxISR     = SPI_TxISR_32BIT;
    " v* o" Y- k, p- X8 W5 p
  18.     hspi->RxISR     = SPI_RxISR_32BIT;# v+ t; v3 }- G8 W: p
  19.   }
    8 t! t9 B' \& {! z
  20.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)% j& K$ t  n" E& v
  21.   {3 D* ]9 T) v. a7 A( |
  22.     hspi->RxISR     = SPI_RxISR_16BIT;
    9 q9 j* R1 Y1 K6 D5 @
  23.     hspi->TxISR     = SPI_TxISR_16BIT;) B4 J$ B! ]& H$ M% |
  24.   }$ k0 J/ o1 ^3 s3 t
  25.   else
    $ {! |; r1 X  c( F+ D
  26.   {2 K6 x% p7 G" p2 f
  27.     hspi->RxISR     = SPI_RxISR_8BIT;
    6 E  H3 E) l, }+ q" D; [
  28.     hspi->TxISR     = SPI_TxISR_8BIT;
    * L0 P) \' T2 U- ]
  29.   }$ H5 }/ W' J4 J9 V, }9 \

  30. % M. ~, L2 G4 I2 L9 u
  31.   /* 设置当前传输数据大小 */$ U" F6 ]+ e7 z7 `* B
  32.   MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);
    " ^9 S# ?1 N3 O# h

  33. $ |9 r4 \! l5 t1 U; I3 x. ]
  34.   /* 使能SPI外设 */8 |4 K+ U  d8 D% s. T. y, B
  35.   __HAL_SPI_ENABLE(hspi);
    ! I0 B2 x, P8 E8 u; ~9 I0 n4 [

  36. ; \  o6 D$ C( W
  37.   /* 使能各种中断标志 */
    0 Y, a2 E' ~+ j& [4 E$ h+ i
  38.   __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_EOT | SPI_IT_RXP | SPI_IT_TXP | SPI_IT_DXP | SPI_IT_UDR | SPI_IT_OVR |
    ) K! C: {. V$ }" x3 [- Y
  39. SPI_IT_FRE | SPI_IT_MODF | SPI_IT_TSERF));
      f3 M( Y! X& A3 {" V+ v6 d+ L
  40. 8 v- h' _7 _( E: S
  41.   if (hspi->Init.Mode == SPI_MODE_MASTER)
    4 A8 I7 E  {  u
  42.   {
    # o( A6 h2 b3 Z0 U+ X
  43.     /* 启动传输 */- z; Z* m+ v. ^
  44.     SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);2 s5 F* k3 i, `% c# W$ `- h, m
  45.   }
    % c& x6 h' y/ ^5 o7 c8 l
  46. 2 ^. {9 k; r! m. b
  47.   /* 解锁 */
    0 e. ?) o& g( f# S
  48.   __HAL_UNLOCK(hspi);
    8 v, {0 n- b, u/ C5 `" B" U
  49.   return errorcode;/ I$ Z3 ^# f8 p) g% M0 T1 ~% [
  50. }
    # E9 k/ k0 o2 y, @. O5 y
复制代码

8 ?+ k( @4 s8 D2 `$ l5 c' K函数描述:! P! S+ v8 P7 N7 Y3 |4 W

& y1 G. n. s* }/ m5 |2 R, A7 f此函数主要用于SPI数据收发,全双工中断方式。& B  a  U: L) w( B
; O7 }, |) \" C4 u; b
函数参数:
/ z5 M, M$ Y" }3 [2 _) o* X& k" I$ m* U. a8 r& u& ~2 \4 M
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。: p' V! I/ c; ]8 p3 m. W
  第2个参数是发送数据缓冲地址。
' g. y1 i2 R5 t) O  第3个参数是接收数据缓冲地址。
/ C/ ^) q; v  H* K1 T/ A. G" v  第4个参数是传输的数据大小,单位字节个数。
/ y& x: f+ @) N* Y' H  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。6 q5 d( j2 Z, c5 B& J
9 S! A! N7 _1 E4 e9 F+ q

7 h8 K" M! t! [7 p- P使用举例:
4 t# a; R" y% ?1 C' w# l, [5 t$ e& s% W6 r5 ]" o  @
  1. SPI_HandleTypeDef hspi = {0};5 m9 F+ ^* c9 `# r$ j4 B1 a* E- C

  2. 8 L4 G' R% y3 f! F7 h% p
  3. if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)   
    1 f/ F- ^. D  {- p
  4. {/ h0 u6 P% F8 _! T* {' H8 L
  5.     Error_Handler(__FILE__, __LINE__);
    # V+ u, L+ B) J1 Z3 A. E4 P
  6. }
复制代码

) P8 L) C+ p" P7 A. q9 O8 z& j72.4.5 函数HAL_SPI_TransmitReceive_DMA
- g1 U2 L) ], N' |. b2 u8 `
函数原型:
' N# @" q; x6 x4 \8 X- A8 P# b; O8 R. }8 i  A( J
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,- F1 s& r/ Q1 `  e
  2.                                               uint16_t Size)
    ' K( b, o$ g0 t" s7 y$ L
  3. {
    * k6 z8 c2 X3 r  C
  4.    /* 省略未写 */
    : c7 q1 |( E  g: C' u7 k, P$ S

  5. 5 c, ?' O# f5 `3 G6 E! m4 r1 Y
  6. /* 注意DMA的位宽和对齐设置 */( y  t: ^1 R" J: K
  7.   if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && (hspi->hdmarx->Init.MemDataAlignment !=
    & `5 J- C8 q3 d% q/ R
  8. DMA_MDATAALIGN_WORD))  || , h' g9 Y; j' }" f! Q0 s
  9.       ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) && ((hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_HALFWORD) && (hspi->hdmarx->Init.MemDataAlignment != DMA_MDATAALIGN_WORD))))
      a( Q, j8 b; M  y5 ^7 w
  10.   {0 u" J- U" H+ }, k1 F( A# ^
  11.   }8 _* ^9 |  e$ M+ I0 {: c( q

  12. ( V" I2 L2 a. v  Y8 [
  13. /* 调整DMA对齐和数据大小 */
    7 i! j* u0 _* o, C
  14.   if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)" r2 y2 W* T5 v9 g1 v6 F5 e, F4 R# i
  15.   {
    , f3 V2 Y, N+ r; ~/ [- m
  16.      /* 省略未写 */
      Y! f7 Q' |6 T$ B* f
  17.   }2 ^& A0 Q) ?% [% O$ H6 v$ Q
  18.   else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)
    ! y/ [4 |' e0 ?/ f7 D2 d2 |
  19.   {
    " Y2 X& W# {0 K' k+ B# ]$ C
  20.      /* 省略未写 */
    ( H2 h; \" W2 s' S# M0 s  F
  21.   }3 ^, i4 j1 H) c
  22.   else
    - B" O, a4 [9 {  p
  23.   {
    . ], e. S" ]/ [! H% X& L3 T
  24.       /* 省略未写 */% o! B0 E9 N2 N) t
  25.   }
    4 r, w4 O1 H9 n# H6 ^( {

  26. 2 R3 z5 v; S6 S8 a, R
  27. /*  DMA接收配置 */; ^/ }6 [2 J& I3 N7 x. @
  28.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->RXDR, (uint32_t)hspi->pRxBuffPtr,6 g* p; E! |; J" d; x  \, {  r
  29. hspi->RxXferCount))& _0 ]/ x& z2 [+ u
  30.   {
    . u- |2 j) B4 ^/ b, t: j

  31. ( R0 `0 f# ^9 T5 H9 {/ R
  32.   }  c& r$ d8 n. U2 t6 ~

  33. $ R! s9 R5 m/ C: A; J* }
  34. /* DMA发送配置 */5 _) u  s1 V. M
  35.   if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->TXDR,
      x! u% [, Z6 A) a
  36. hspi->TxXferCount))# e5 M5 y3 V  n3 T" B
  37.   {
    , \. B; J  r( v; L- _* v1 j9 E. B
  38.   }
    2 n% j% y8 X# F0 e5 j
  39. . `) q: E5 y7 j  [' u7 `9 j
  40.   /* 省略未写 */
    9 T' y/ I6 k7 d: M! n# C9 [2 u" g
  41. }
    ) N" K4 H! @9 e) t
复制代码
. ?7 B& Z! x3 Y
函数描述:" F, f' ]* y* V, j: H
: Q/ ^, O9 x$ t. S& g
此函数主要用于SPI数据收发,全双工DMA方式。
3 {9 W0 j# t! r$ \2 D- C1 P2 H% N
6 z1 V2 g, r5 s$ W0 p+ r函数参数:/ K) s) {" E0 u! ?6 F
, p9 j' P+ G# I/ @6 B4 j
  第1个参数是SPI_HandleTypeDef类型结构体指针变量。
, g$ b5 k( x( t' [4 X6 M  第2个参数是发送数据缓冲地址。
% X$ [' P7 C" p% I  第3个参数是接收数据缓冲地址。
) X+ A1 F3 b- s# G* A# S% v0 s8 I  第4个参数是传输的数据大小,单位字节个数。" {7 H  ?2 z2 K& ?
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。8 X1 {0 ?( ~2 [
" @- n: @3 v2 w8 C% S4 O  Z# L

) g4 V) h$ V' M使用举例:- a" M' q* d) r+ w1 j+ e# ~

* t; l* `7 ]4 C$ ~- e% D4 n( P
  1. SPI_HandleTypeDef hspi = {0};( I5 p4 \4 q$ j; ?1 t0 B
  2. % w5 _0 E4 {! J7 m
  3. if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)    6 Y9 q. P9 E4 Q- T1 C( r
  4. {5 [+ U7 Z. R& w0 k
  5.     Error_Handler(__FILE__, __LINE__);
    2 Y0 R' k& l5 }% B; u- L6 W3 J
  6. }* ^; S' y! m% E, h
复制代码

2 D0 P) W9 r3 U* Q6 J72.5 总结9 e. |( u* y% A2 ~- s/ X2 J
本章节就为大家讲解这么多,要熟练掌握SPI总线的查询,中断和DMA方式的实现,因为基于SPI接口的外设芯片很多,熟练后,可以方便的驱动各种SPI接口芯片,以便选择合适的驱动方式。
1 b6 ?/ R8 P+ W: L+ R- b
1 p4 z" }, c+ Z% ]+ G6 F: T  l" o5 z3 n  Y' D; m  G( c

! c% m& @8 V  E5 U- f) k" E
0 q$ L9 v: N3 I: p& H, V# B& f
* K; @3 _% L% f! _
收藏 评论0 发布时间:2021-12-20 19:00

举报

0个回答

所属标签

相似分享

官网相关资源

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