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

【STM32U3评测】SPIDMA发送

[复制链接]
donatello1996 发布时间:2025-5-27 00:09
      SPIDMA发送/接收是非常常见的MCU应用,用于与高速SPI器件通信并提高效率,这个帖子是评测STM32U385RG的SPI1接口,并启用SPI1的DMA发送功能。
/ m! I" }& \: H8 f$ s& S! @& v+ k. H
       在上一个帖子中提到,STM32U3的DMA外设名为GPDMA,在ST新出的系列中,任意支持DMA的外设都可以绑定到DMA的任意通道/流/节点上,不像F103和F4系列那样规定通道号,来看看SPI1DMA的配置:+ A  `, I2 D8 t# F# B
* a! t' {4 S* r: O9 T+ }5 e
8.JPG   ]# @* S( W$ I7 H* |& ]( {7 n

3 A; \& p( g5 S  D5 FNormal模式表示每次调用DMA发送函数只会发送一次,Circular模式表示只调用一次DMA发送函数就一直发;在外设所使用的DMA中一般配置外设地址非自增,内存地址可配置为自增或者非自增,内存地址非自增表示DMA发送的数据是同一个数据,也就是内存首地址的数据;源地址和目标地址的数据格式必须一致,都是8位或者16位;只要SPI使用了DMA进行发送或者接收,就必须要把SPI中断和DMA中断都打开,少打开一个都不会正常工作。
% [  D! s" d; U8 Q4 X+ H7 e4 g. r! p4 W8 F8 s3 [
SPI初始化代码如下,在ST新系列中加入了一些不太常用的SPI机制,如CS片选引脚空闲等待节拍,Ready模式,因为在大部分场景中片选引脚都由GPIO进行控制,比较少用到SPI外设自带的NSS引脚功能,除非是双MCU通信:
5 @: d) t3 L* ?/ n
  1. void SPI1_PA5_PA6_PA7_Init(void)4 J! G% d2 e* N4 b
  2. {
    ; G/ [1 {  u6 h* O& }
  3.    
    ) |# V, ?; `& J  p2 F4 z
  4.   __HAL_RCC_GPIOA_CLK_ENABLE();1 ]# P. d# `- |# f
  5.     __HAL_RCC_SPI1_CLK_ENABLE();
    3 j5 L3 R3 }- P! Q6 l
  6.     __HAL_RCC_GPDMA1_CLK_ENABLE();
    0 J. e0 [/ _( B. L2 o0 ^( T
  7.    
    * L7 W& T+ E- h- G/ W: P: [. ^
  8.     RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};. Y5 D+ _& _; j3 D' U: @) I, R& y
  9.     GPIO_InitTypeDef GPIO_InitStruct = {0};% ]* _/ z+ K# U
  10.   SPI_AutonomousModeConfTypeDef HAL_SPI_AutonomousMode_Cfg_Struct = {0};
    * o, T, W. H$ a, U5 o$ F
  11.    
    9 G/ L9 a8 E% L% J9 ]
  12.     PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI1;9 p% F% n, Z, T( a1 G, u
  13.   PeriphClkInit.Spi1ClockSelection = RCC_SPI1CLKSOURCE_PCLK2;
    . n& H. a9 U& q% O5 f0 J! K* I
  14.   HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);! |8 m: u/ v' V/ G8 F% D, t* j
  15.     6 t! y$ y/ K; u/ k6 y( e7 i
  16.     GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
    6 |/ r7 M) z* S
  17.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    ' _8 ^' T5 r. B4 E  u- C
  18.     GPIO_InitStruct.Pull = GPIO_NOPULL;
    * d, |" `% b% E* |# U  t
  19.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    8 n* n. R  d* ]- m
  20.     GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    ) ?  D3 i" T$ u5 w$ w2 b/ d/ Y
  21.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);5 l( Q& H$ s; k; r$ v& y( _
  22. # Q' [4 z& u# C5 C, k" t$ G
  23.   hspi1.Instance = SPI1;% P2 }! I; s; A' i$ q( s
  24.   hspi1.Init.Mode = SPI_MODE_MASTER;9 F1 A6 ]( S9 ~( p6 a8 c2 n' b
  25.   hspi1.Init.Direction = SPI_DIRECTION_2LINES;' G5 X2 a6 `  P9 h  A) o3 l( _
  26.   hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    3 X( B. _0 e' l1 ~) P, [5 b
  27.   hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
    ( \' t1 H0 V9 c/ G9 h
  28.   hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
    & x/ H- x0 I9 I5 ~6 a/ J" H3 }0 z
  29.   hspi1.Init.NSS = SPI_NSS_SOFT;* S( E- R# Y) a8 `
  30.   hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;% i1 E  T( J1 Y& e7 b
  31.   hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    3 s- o! k, Q8 U& Q. a
  32.   hspi1.Init.TIMode = SPI_TIMODE_DISABLE;% x9 c4 B1 m# ]4 R
  33.   hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    * q" j: N8 M+ v" T
  34.   hspi1.Init.CRCPolynomial = 0x7;9 k- T+ [% U0 v6 S( ^( [/ L
  35.   hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
    6 m5 C! Z& K7 M; f8 @' f
  36.   hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;( f: b  u+ e/ p  D$ g2 i" V
  37.   hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
    5 C* V/ i0 h( L& P2 x$ X
  38.   hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;4 |5 ?1 p+ Q4 g4 b2 E' U
  39.   hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;$ Z' C" E$ g) X/ |0 X# x3 G- X
  40.   hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;( Y( b. M' U! X& ~! d
  41.   hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
    ) m2 I) J' h' V; \
  42.   hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
    3 y7 _/ R4 [) e" k
  43.   hspi1.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
    + S0 `: c1 P6 R' K! i( j: C% j* f
  44.   hspi1.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;5 d7 G" z; [% i6 u; x1 x
  45.   HAL_SPI_Init(&hspi1);/ a4 ?& s& f7 H4 d6 R4 i
  46.     __HAL_SPI_ENABLE(&hspi1);
    7 w5 ]# g8 [+ Y) d' r( y" S
  47.     3 m- W6 M  t( j' K" G& Y
  48.     HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);' e- W/ _$ F, h. ^+ g& B5 w
  49.     HAL_NVIC_EnableIRQ(SPI1_IRQn);5 b8 ?: Y* i2 L1 v& o2 L, {5 d
  50.    
      W6 h1 p( M/ d" j* n7 Z0 }
  51.   HAL_SPI_AutonomousMode_Cfg_Struct.TriggerState = SPI_AUTO_MODE_DISABLE;$ u# E( Y2 k8 a8 m) \
  52.   HAL_SPI_AutonomousMode_Cfg_Struct.TriggerSelection = SPI_GRP1_GPDMA_CH0_TCF_TRG;
    4 a9 d3 c1 l! G
  53.   HAL_SPI_AutonomousMode_Cfg_Struct.TriggerPolarity = SPI_TRIG_POLARITY_RISING;
    ! q5 U. Z7 X9 U+ b  g0 s: e! [) y
  54.   HAL_SPIEx_SetConfigAutonomousMode(&hspi1, &HAL_SPI_AutonomousMode_Cfg_Struct);4 s$ n# v! a1 C6 l/ J& L- H
  55. * P' [; e" k' d8 y/ p/ y1 e6 M, U
  56.     handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1;
    : J$ f+ N, h7 G- m7 z8 u0 _
  57.     handle_GPDMA1_Channel1.Init.Request = GPDMA1_REQUEST_SPI1_TX;# K  L$ T+ e1 m3 `, q
  58.     handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
    # @0 {2 n1 |+ o' y9 w5 z
  59.     handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_PERIPH;
    5 |& e, J( g- G3 Z% t$ V  s( ?
  60.     handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED;
    7 U1 ^0 H' K3 M( T5 o7 h- ]$ R
  61.     handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_FIXED;% Q3 m& e2 y7 Z. s/ \8 ~9 y
  62.     handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
      o3 B; ?# r3 r8 G' P4 v
  63.     handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
    $ }" N7 z" P, h( R& }6 b" Z
  64.     handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
    * G5 y. K- Y+ E7 F# X2 s& f& r& J
  65.     handle_GPDMA1_Channel1.Init.SrcBurstLength = 1;  z3 G  H* X0 g$ i1 H2 g, o4 M; C" g
  66.     handle_GPDMA1_Channel1.Init.DestBurstLength = 1;
    3 Y5 T' D7 @$ U  ~
  67.     handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
    / `9 _9 N" R6 g8 ^6 j* X, m
  68.     handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;: @; k* W) g/ N( R8 O* C
  69.     handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL;( B# g9 N, n7 u+ j
  70.     HAL_DMA_Init(&handle_GPDMA1_Channel1);
    ! {5 M4 w. Q# d4 g8 ~0 Z

  71. - @3 ^# ^6 |2 p3 b5 ^+ o6 Q
  72.     __HAL_LINKDMA(&hspi1 , hdmatx , handle_GPDMA1_Channel1);* T: }% X9 J0 |( x: y' R
  73. 6 t& P4 i7 S  \; f
  74.     HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel1, DMA_CHANNEL_NPRIV);
    % d' L" H) M5 n7 {! R; L
  75.    
    . r3 A  k0 J- w8 H, X4 {, p* l6 ~1 x4 n
  76.     HAL_NVIC_SetPriority(GPDMA1_Channel1_IRQn, 0, 0);' L" M/ ]; ~: X+ X  J
  77.   HAL_NVIC_EnableIRQ(GPDMA1_Channel1_IRQn);
    + U9 J" O, {% L

  78. * O: V9 v9 P& W9 _
  79. }
    " K5 z0 @. L. e9 k

  80. " r' T& S+ s7 k; x2 _
  81. void GPDMA1_Channel1_IRQHandler(void). s- s0 v; o+ k+ ?6 g% ]
  82. {- f# A0 V9 b% y8 r$ F  G4 g
  83.   HAL_DMA_IRQHandler(&handle_GPDMA1_Channel1);
    , Q8 k* J- P/ K' ~# Z
  84. }
    7 h) v% [$ [( F1 }+ i, A: q
  85. : B0 R+ U# J* m9 }$ N3 D" h6 L
  86. void SPI1_IRQHandler(void)0 Q$ k* d9 z8 U8 N  i" m) K
  87. {! }$ J& f# S0 o. Z  k$ ]
  88.   HAL_SPI_IRQHandler(&hspi1);
    * o* ?! K$ S4 M, ]
  89. }
复制代码

3 z) U. Z2 r) R. x) j4 c8 l# g; g- Z7 f
SPI发送或者发送+接收代码如下:
, b5 S2 ]" M7 Q! x5 {" F
  1. uint8_t SPI1_PA5_PA6_PA7_Read_Write_Byte(uint8_t TxData)3 ~! |/ u+ p3 T* i9 O( z' P
  2. {
    - [- s+ @! N/ U' G
  3.     uint8_t Rxdata;
    0 }5 `+ n! G& g1 Y
  4.     HAL_SPI_TransmitReceive(&hspi1 , &TxData , &Rxdata , 1 , 1000);      
    & {5 z3 u1 `, s  X
  5.     return Rxdata;
    0 d' i& k; b$ x5 c# G/ R% n
  6. }. m) U: M6 X) G$ E6 B
  7. ; k- d' m2 ~, S% u+ g
  8. void SPI1_PA5_PA7_Write_Byte(uint8_t TxData)
    4 F8 a3 }+ z3 G1 ~9 P! U0 a
  9. {" I& d! z2 X  A
  10.     HAL_SPI_Transmit(&hspi1 , &TxData , 1 , 1000);( Z7 B/ Y( A% x6 [6 \) f& Z. e8 I
  11. }
复制代码
4 o$ B7 K4 j& d8 u; d
1 h3 b; O0 i" n, e$ J3 a. t- n
" u  f) V8 w( @8 U, l( ^; j
SPI随时需要调整数据位数为16位或者改回8位:% D6 S. C. A# B; n8 {
  1. hspi1.Init.DataSize=SPI_DATASIZE_16BIT;
    5 \: T$ Z' z+ w) v
  2. HAL_SPI_Init(&hspi1);# G4 ]" T! ]* D/ m

  3. & g  W3 b/ e' u6 T; E
  4. hspi1.Init.DataSize=SPI_DATASIZE_8BIT;
    0 I+ I1 W5 |- d6 ?" g3 G
  5. HAL_SPI_Init(&hspi1);
复制代码
% Y6 {$ I  h5 r. D1 u5 R" _& `' R
在实际应用中,常常需要修改DMA参数,最常见的就是内存地址自增或者非自增,数据是8位或者16位(Halfword半字)对齐:! p; t3 q- e. }) W
  1. void SPI1_TX_DMA_Config_PID_MID_HalfWord_Normal()
    4 ]  F; ?+ Z9 j' s4 ~: n
  2. {
    5 ^( |3 X: F+ |0 @5 f
  3.     handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1;
    . W* u, R7 [4 W. e8 Q2 t* {
  4.     handle_GPDMA1_Channel1.Init.Request = GPDMA1_REQUEST_SPI1_TX;& V% l0 N8 F8 d$ j- l. v
  5.     handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
      F! C+ e2 ^1 f) b! f% q
  6.     handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_PERIPH;& F) f' x- }7 _! N1 r7 d0 r' |
  7.     handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_FIXED;* y$ `' @) I5 K' I% V: }6 j, z
  8.     handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_FIXED;2 o+ n, [8 G# [- k) Y- ~8 z
  9.     handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_HALFWORD;1 ?; @- x! m. f% h- o2 g; T$ V
  10.     handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_HALFWORD;
    / n- Y% m0 c! n" M5 }, K/ M
  11.     handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
    6 K6 \  ~, |1 r0 ^9 K5 u# F
  12.     handle_GPDMA1_Channel1.Init.SrcBurstLength = 1;
    . C8 x3 \0 d1 _: |( R
  13.     handle_GPDMA1_Channel1.Init.DestBurstLength = 1;
    6 Q; J; t% t. [$ _
  14.     handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;6 x5 Y( T. J2 Q& `* c2 T. A- i. \
  15.     handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
    1 H/ u" W; [6 H& Y+ K
  16.     handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL;) X% x( l/ b; e$ H" D1 l# s

  17. & V$ N, Z% N/ n8 r/ v" W1 Z
  18.   HAL_DMA_Init(&handle_GPDMA1_Channel1);
    $ T$ b$ D# }, v" X/ h; i& ]
  19.    
    6 a$ ^% T9 c0 ^' y0 X6 @, G
  20.     __HAL_LINKDMA(&hspi1 , hdmatx , handle_GPDMA1_Channel1);* a7 t1 b0 g$ S/ p4 j1 J: E
  21.    
    4 E  Q' z! c+ q. j4 f9 g- N
  22. }, y; n0 K5 z+ V/ P

  23. ( G& Z( }& w; {, E
  24. void SPI1_TX_DMA_Config_PID_MIE_Byte_Normal()( P+ F. R! }" }) H! Q
  25. {* W% k6 X- {, O7 F" t+ @+ }0 v
  26.     handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1;
    ( o  t6 j9 |- k; M7 x( b
  27.     handle_GPDMA1_Channel1.Init.Request = GPDMA1_REQUEST_SPI1_TX;$ q  |3 X7 O1 O, h- Y+ \
  28.     handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
    / X- W  A9 i& m. V: c* y
  29.     handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_PERIPH;
    4 B1 n9 y& w, q3 E
  30.     handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED;' v% N# T9 H. k% ]! n
  31.     handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_FIXED;
    5 b' E) j- f* I3 y0 N
  32.     handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
    ; j6 X; I# v. M+ y. }
  33.     handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
    9 }8 r  E( o7 H& c4 S# F
  34.     handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
    1 C2 ^# \" p$ n+ b
  35.     handle_GPDMA1_Channel1.Init.SrcBurstLength = 1;0 e3 F! @8 n- c$ C8 U. A5 i2 l9 Y
  36.     handle_GPDMA1_Channel1.Init.DestBurstLength = 1;' e- h) g4 Z* O% e) b7 O- |/ ~
  37.     handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
    , Z8 g$ m0 d) F
  38.     handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;- O# Z1 G; N$ z$ t: j9 K! u6 g
  39.     handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL;
    & w! ?# G. H2 k3 Y  N
  40. ; j  t9 e3 H+ K! }5 f
  41.   HAL_DMA_Init(&handle_GPDMA1_Channel1);, z$ r7 ~  z/ [; b0 t  W
  42.     9 ~1 Y6 ?4 k* T- b9 T2 i/ C
  43.     __HAL_LINKDMA(&hspi1 , hdmatx , handle_GPDMA1_Channel1);9 \( k1 v# ?7 ~
  44.    
    . W. G/ A0 @& K) B3 r
  45. }
复制代码
  |6 s* ?# Y5 d' K4 U8 r
我这里用SPI1去驱动ST7789的屏幕,使用SPI1的DMA发送功能,因此使用DMA传输函数:) C  n- i: Y& Z$ Q6 i' h
  1. HAL_SPI_Transmit_DMA(&hspi1 , pic , num1);
复制代码
2 w+ u7 V7 d- J4 ~) I
SPI不使用DMA的波形如图:( j4 i; @+ Z0 q2 Z5 M8 ]
IMG_20250522_224448.jpg % Y7 V: Q9 o& @% C+ x8 Y
这里有个ST新系列的SPI波形问题,MOSI脚会在发送结束的时候拉低相当长的一段时间才会恢复高电平。
, W& n- @) k0 o! _0 h0 M6 J  {% ^+ m4 q) q0 {; x8 \
SPI使用DMA的波形如图:
6 c- A- `9 U3 m$ P IMG_20250526_224854.jpg
- I. c: U# J2 C) `4 A( s( x5 `8 \( L  c5 k3 l3 U
使用SPI引脚驱动ST7789液晶彩屏:7 d. x: M" V* C5 L1 h1 z
u3.JPG . L4 ^! y$ C/ ?( @; w2 U9 V
IMG_20250526_235555.jpg 4 Y( @6 ^) b" J
6 X; k: @  c+ X7 S0 _+ n
赞 收藏 评论0 发布时间:2025-5-27 00:09

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版