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

【STM32U3评测】SPIDMA接收功能读取SPI FLASH数据

[复制链接]
donatello1996 发布时间:2025-6-16 23:01
       上一帖评测了STM32U385的SPIDMA发送功能用作ST7789液晶屏刷图,这次来评测一下SPIDMA接收实现读取SPI FLASH数据并显示到屏幕上,原理差不多。  Z6 z4 L. O" d, R, i/ k" P
       看CubeMX配置:' b* ~" J; e  d; @0 Z& v& Q
10.JPG ' f- W% t* D+ d8 ~' n2 X
      
7 a& l1 S+ C  q        可以看到,配置跟SPIDMA发送基本大同小异,有不同的地方是,SPIDMA接收是不跟SPIDMA发送用同一个通道的,比如我这里就用新的通道即通道2,然后就是跟SPIDMA发送颠倒过来,是外设到内存,内存地址自增(如果内存地址非自增的话,那就只有内存首地址会收到源源不断的数据)。SPI的接收机制是,主机拉低片选并对从机发送【从机开始接收】指令之后,CLK脚会一直产生脉冲时钟信号给到从机,从机收到脉冲就会源源不断发给主机,只要主机的时钟信号不停就表示主机一直在接收状态,而SPIDMA接收呢则是在此基础上把SPI外设给DMA外设相应通道接管,因此CPU也是需要等待DMA外设完成接收产生中断的,所以代码必须要有中断,并且是DMA通道产生的中断:
  1. HAL_NVIC_SetPriority(GPDMA1_Channel2_IRQn, 0, 0);* |+ m6 E+ R% w
  2. HAL_NVIC_EnableIRQ(GPDMA1_Channel2_IRQn);6 ]# N7 `$ y# Z9 M
  3.   h' a7 a  U+ l# c8 O6 O3 }1 A* ~
  4. void GPDMA1_Channel2_IRQHandler(void)) R0 H# |9 Q1 b# E: \' X* L# S& P& O
  5. {
    1 y; ]# i% V; P* ]1 h, c( U1 f
  6.   HAL_DMA_IRQHandler(&handle_GPDMA1_Channel2);+ @5 L9 Q0 L" n
  7. }
复制代码

+ x* G: y6 Y+ p" C, y然后是DMA配置函数,跟上文说的一致,外设到内存,内存地址自增:7 I; x& T9 r) ?% ^4 H# Y
  1. void SPI1_RX_DMA_Config_PID_MIE_Byte_Normal()
    " w+ R- O  a" z$ I& t
  2. {
    ( P8 w0 _, H3 {5 J1 d1 U/ j( J
  3.     handle_GPDMA1_Channel2.Instance = GPDMA1_Channel2;0 `- P% T4 C6 r5 X
  4.     handle_GPDMA1_Channel2.Init.Request = GPDMA1_REQUEST_SPI1_RX;
    0 L5 B3 u, u; y  @& g" ^
  5.     handle_GPDMA1_Channel2.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
    ; G4 k$ x3 H9 ^) d4 ]! d5 Y9 k
  6.     handle_GPDMA1_Channel2.Init.Direction = DMA_PERIPH_TO_MEMORY;
    1 u% F9 G. I3 D$ v
  7.     handle_GPDMA1_Channel2.Init.SrcInc = DMA_SINC_FIXED;
    - Y3 P1 I& R6 j7 ~4 d
  8.     handle_GPDMA1_Channel2.Init.DestInc = DMA_DINC_INCREMENTED;  e4 R# M( {; h- P1 o
  9.     handle_GPDMA1_Channel2.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
    ) u. h& C: d2 @+ G
  10.     handle_GPDMA1_Channel2.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;- s/ R& r: @/ J( X8 r6 [) r
  11.     handle_GPDMA1_Channel2.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;3 s4 J. Y- n1 O% d0 m$ V
  12.     handle_GPDMA1_Channel2.Init.SrcBurstLength = 1;5 L# x  M6 m4 S8 ?/ ?
  13.     handle_GPDMA1_Channel2.Init.DestBurstLength = 1;6 M% z& k& R" K) \& }
  14.     handle_GPDMA1_Channel2.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0;
    0 u' Y) i+ }6 j, D
  15.     handle_GPDMA1_Channel2.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;% n; h( T/ E: Y+ d; K
  16.     handle_GPDMA1_Channel2.Init.Mode = DMA_NORMAL;8 e) _# U9 F& o9 Q
  17.     HAL_DMA_Init(&handle_GPDMA1_Channel2);/ G# o. ]% }1 f9 h' [3 e

  18. 4 Z/ }! |% X* {% _
  19.     __HAL_LINKDMA(&hspi1 , hdmarx , handle_GPDMA1_Channel2);6 |$ u% u$ K4 L/ [& f5 v3 r
  20. , G% x' \# G" z2 L; @/ T: Z. m
  21.     HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel2 , DMA_CHANNEL_NPRIV);2 a" [' a6 ?! |/ Y2 }- a+ N
  22. }
复制代码

3 C. l  b) C" C: }/ H1 b$ U- l; G3 P
对于SPI FLASH从机而言,无论主机是否使用DMA接收,都是通过主机的指令行事,因此代码区别只在主机发完【从机开始接收】这个指令给从机之后的接收方式不同而已:9 C0 K* j; u. F
  1. void W25QXX_Read(uint8_t* pBuffer , uint32_t addr , uint16_t num)   
    1 w; s& g$ F" m4 E3 ^4 u7 B
  2. { / p" {- i' f# H  e5 q
  3.      uint16_t i;                                               - K. T5 \; C- Z4 L0 k
  4.     XX25QXX_CS_LOW;
    $ [4 z; P- P6 C( U3 A
  5.    
    4 k/ @( a0 q2 J  T6 P. H
  6.     SPI1_PA5_PA6_PA7_Read_Write_Byte(W25X_ReadData);
    - {- p' }7 X. b5 L' J; v
  7.     if(XX25QXX_TYPE == W25Q256) " e* P3 C- I; H9 W
  8.     {$ j. J/ l- l3 n, d$ `
  9.         SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>24));    - V$ Q( {6 h7 h) P( Q) k( R: L
  10.     }1 y0 w8 A3 z! A5 A- A( r
  11.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>16));
    ' t2 I3 M5 M( _; N2 l0 L
  12.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>8));2 d$ }2 |2 x" r
  13.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)addr);# t+ I2 A( q1 a% M; e7 u. T
  14.    
    8 I3 Z6 \# d0 A* r" y: I  k
  15.     for(i = 0 ; i < num ; i ++)
    / X7 X* H2 @9 @- w$ j, }
  16.     { 5 c+ L* M0 r' j9 Y) m' @
  17.         pBuffer[i]=SPI1_PA5_PA6_PA7_Read_Write_Byte(0xff);# k( P- p" R, S* ~
  18.     }9 J+ W) J. z) h1 S' c9 A+ N
  19.     ! G' i9 u( b) O
  20.     XX25QXX_CS_HIGH;                                
    + Q( H) X  Y" h( M* C" Q
  21. }  
    % y" P: l. x0 [6 k- l
  22. # g& p6 z  N( v' x7 t
  23. void XX25QXX_Read_DMA(uint8_t* pBuffer , uint32_t addr , uint16_t num)
    0 Y+ [) q( @; V9 b0 D
  24. { * V) c6 ?, g$ i1 A3 A
  25.      uint16_t i;                                               & a% y4 _/ `& o! t2 J" J
  26.     XX25QXX_CS_LOW;
    ! X; _7 c8 @# L+ g7 _
  27.     SPI1_PA5_PA6_PA7_Read_Write_Byte(W25X_ReadData);
    * c. T$ C+ x6 o, Y1 ?4 X
  28.     if(XX25QXX_TYPE == W25Q256)
    % s- S$ w' X0 z1 F6 [1 \9 y) F' I
  29.     {
    " A8 x$ H$ h7 X0 c) ]
  30.         SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>24));    3 z5 d. j7 J' w9 z
  31.     }" J/ r7 f8 {; e
  32.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>16));
    6 }: D) A9 i8 M! C
  33.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>8));   / v2 k7 Z, ]* [( ^# A0 L1 e; l  G
  34.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)addr);
    - {8 W% l- ?; i5 X3 o- `
  35.   ) h* w* d' J0 q( Z) H; z; c
  36.     SPI1_RX_DMA_Config_PID_MIE_Byte_Normal();
    1 i+ {: U- T* A7 X
  37.     HAL_SPI_Receive_DMA(&hspi1 , pBuffer , num);
    * o) s0 V& p% b- p# W
  38.     while(HAL_SPI_GetState(&hspi1) == HAL_SPI_STATE_BUSY_RX);; Q$ x% w# ~: x  @7 v$ |
  39.     6 O9 U# R# M& H, }* n
  40.     XX25QXX_CS_HIGH;                                6 [- l" n! \9 [6 L/ w
  41. }  
    9 W$ y; \# Y- }0 Z$ p0 |- `) u
复制代码
# {8 _, M. B/ ~" E
我这里用SPIDMA接收所实现的功能是从SPI FLASH读出图片数据并显示到SPITFTLCD液晶屏上,而MCU的RAM大小以及DMA通道大小是有限制的,所以必须要采用分块读取的方式实现,将320*480分辨率,16位色的屏幕,平均分成6块,每块就是320*480*2/6=51200大小:
% V7 a/ k3 @! ?) H3 m* z( ^
  1. uint8_t datatemp[51200];0 ]" \4 D/ P" h) j/ w2 ?+ ~
  2. 4 m5 Y: a0 a1 `$ p, F  {
  3.         for(j = 0 ; j < 6 ; j ++)" {4 |) k! P# i! V- v; b
  4.         {' T3 L$ f4 W9 n: L! _5 s
  5.             W25QXX_Write((uint8_t*)(gImage_u3_logo + j * 51200 ) , WRITE_READ_ADDR + j * 51200 , 51200);
    ( C7 N& g/ c6 c0 A0 g
  6.             XX25QXX_Read_DMA(datatemp , WRITE_READ_ADDR + j * 51200 , 51200);
    , ]7 v9 g, C8 P  t" }2 N' J3 H
  7.    
    + |. S7 I7 ?3 S! \9 m" Z
  8.             SPITFTLCD_ST7789_ShowPicture_DMA(0 , j * 80 , SPITFTLCD_ST7789_W , 80 , datatemp);
    9 D7 x* T8 R- I0 b
  9.         }
复制代码

2 C! W; c: M9 y5 ^演示效果:5 [* f" K7 C1 \9 U& w5 a9 X
VID_20250616_222131 00_00_00-00_00_30.gif 8 O8 L! `' p7 w( H8 M/ I& o
* I' b: E- q3 U' V0 @, [% ?
4 L% g; P! `' K6 G! T4 I
赞 收藏 评论0 发布时间:2025-6-16 23:01

举报

0个回答

所属标签

相似技术帖

官网相关资源

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