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

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

[复制链接]
donatello1996 发布时间:2025-6-16 23:01
       上一帖评测了STM32U385的SPIDMA发送功能用作ST7789液晶屏刷图,这次来评测一下SPIDMA接收实现读取SPI FLASH数据并显示到屏幕上,原理差不多。- a6 Q/ K0 b" [0 L1 J$ d
       看CubeMX配置:6 [) w" M+ Y3 U3 ]/ F% [/ J1 c* y
10.JPG ; e. N  ?% X1 u/ t1 Z% J6 T' k
      - ], E! p9 C" f9 B& R. T' J
        可以看到,配置跟SPIDMA发送基本大同小异,有不同的地方是,SPIDMA接收是不跟SPIDMA发送用同一个通道的,比如我这里就用新的通道即通道2,然后就是跟SPIDMA发送颠倒过来,是外设到内存,内存地址自增(如果内存地址非自增的话,那就只有内存首地址会收到源源不断的数据)。SPI的接收机制是,主机拉低片选并对从机发送【从机开始接收】指令之后,CLK脚会一直产生脉冲时钟信号给到从机,从机收到脉冲就会源源不断发给主机,只要主机的时钟信号不停就表示主机一直在接收状态,而SPIDMA接收呢则是在此基础上把SPI外设给DMA外设相应通道接管,因此CPU也是需要等待DMA外设完成接收产生中断的,所以代码必须要有中断,并且是DMA通道产生的中断:
  1. HAL_NVIC_SetPriority(GPDMA1_Channel2_IRQn, 0, 0);
    5 K3 p) M6 t4 b( e9 y: _0 J4 M
  2. HAL_NVIC_EnableIRQ(GPDMA1_Channel2_IRQn);
    & }4 [- R# c' `+ r% |

  3. ! A6 v) i* `( P7 [# F/ o
  4. void GPDMA1_Channel2_IRQHandler(void)
    3 ~5 }% F3 ?9 j, y" H4 x
  5. {% N6 q2 f3 b% F
  6.   HAL_DMA_IRQHandler(&handle_GPDMA1_Channel2);% p% _9 H. I8 O# O
  7. }
复制代码

- M( |7 c/ O. m然后是DMA配置函数,跟上文说的一致,外设到内存,内存地址自增:
' P  T$ s' d+ }
  1. void SPI1_RX_DMA_Config_PID_MIE_Byte_Normal()5 z2 d- u5 _7 _
  2. {
    3 J# V) i* _7 u% L& _
  3.     handle_GPDMA1_Channel2.Instance = GPDMA1_Channel2;
    7 k& J& ~" c0 K
  4.     handle_GPDMA1_Channel2.Init.Request = GPDMA1_REQUEST_SPI1_RX;
      S. K) n4 }; f5 d/ e
  5.     handle_GPDMA1_Channel2.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;) O+ p0 L; h7 `: b
  6.     handle_GPDMA1_Channel2.Init.Direction = DMA_PERIPH_TO_MEMORY;
    ; ~% d4 l1 P, @" H8 C
  7.     handle_GPDMA1_Channel2.Init.SrcInc = DMA_SINC_FIXED;- R! q8 @3 E' W0 N
  8.     handle_GPDMA1_Channel2.Init.DestInc = DMA_DINC_INCREMENTED;+ U! p( P0 w8 D0 u3 G8 p( u  |& k
  9.     handle_GPDMA1_Channel2.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
    ! _# J: A4 g7 U9 G* `, F
  10.     handle_GPDMA1_Channel2.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
    $ f* J2 |, u9 v5 q! a" q
  11.     handle_GPDMA1_Channel2.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
    ) r- o' K8 m& S5 H% P, V
  12.     handle_GPDMA1_Channel2.Init.SrcBurstLength = 1;
    7 r& T7 K/ C+ }* o5 u
  13.     handle_GPDMA1_Channel2.Init.DestBurstLength = 1;
    2 B8 w' ~' Q/ x1 ~" p7 L9 v
  14.     handle_GPDMA1_Channel2.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0;
    2 G, a6 v7 r0 _
  15.     handle_GPDMA1_Channel2.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
    # \3 p5 u3 A* H$ n& |8 t) y
  16.     handle_GPDMA1_Channel2.Init.Mode = DMA_NORMAL;) p- e! [) _( S  x
  17.     HAL_DMA_Init(&handle_GPDMA1_Channel2);
    0 k6 \  g5 Q  l& i% ~6 X

  18. 1 l& s2 P- h3 g& a$ D
  19.     __HAL_LINKDMA(&hspi1 , hdmarx , handle_GPDMA1_Channel2);% s7 q9 [0 e& ?4 v8 T2 {

  20. / d  s1 W& `; _
  21.     HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel2 , DMA_CHANNEL_NPRIV);9 H' Z$ w- g& {( v( g, W
  22. }
复制代码
, D7 f4 Z( R* k

  p4 Y* m5 F/ u( W# u4 {对于SPI FLASH从机而言,无论主机是否使用DMA接收,都是通过主机的指令行事,因此代码区别只在主机发完【从机开始接收】这个指令给从机之后的接收方式不同而已:8 v+ e4 k3 V7 K/ F6 q9 x
  1. void W25QXX_Read(uint8_t* pBuffer , uint32_t addr , uint16_t num)   
    & z  L- v5 j6 N
  2. {
    % M  X8 W! a# p! \1 Y9 G& K: o
  3.      uint16_t i;                                               
    9 W" z* V, x5 x0 M- F
  4.     XX25QXX_CS_LOW;
    ! I: z0 u7 P0 F7 j: n
  5.     ( H, V3 o6 J0 ~; p9 {
  6.     SPI1_PA5_PA6_PA7_Read_Write_Byte(W25X_ReadData);
    2 z7 ?0 ^' w; a% {* ~9 P
  7.     if(XX25QXX_TYPE == W25Q256)
    ) c4 A& e" o- W5 i# r2 L: V
  8.     {! R" r. @5 l; e; }- c3 y1 p
  9.         SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>24));   
    ! U/ v' N# |8 f5 l2 C5 e
  10.     }5 K: |& c7 n( g4 _. a! ]
  11.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>16));
    : S. |3 F  {+ {5 g4 q7 |6 |6 {6 K
  12.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>8));; v$ f* D. T  C0 m5 J& s7 V
  13.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)addr);
    8 v4 w' i" `3 v# f
  14.     9 E$ E+ h- A( I+ ]/ n2 s: k
  15.     for(i = 0 ; i < num ; i ++)
    + M: t8 _  K, j: w  H, L3 X
  16.     {
    , M: r8 {# o0 n
  17.         pBuffer[i]=SPI1_PA5_PA6_PA7_Read_Write_Byte(0xff);& l/ Q, Y/ q0 P
  18.     }# c: N3 w% y# m- n
  19.     " v' }/ [' b0 O0 ^: D- F
  20.     XX25QXX_CS_HIGH;                                
    2 i2 O' H4 l# J% s
  21. }  / F/ ]# T+ L: R  Y! q

  22. ) q) H2 r( e! T! I, r
  23. void XX25QXX_Read_DMA(uint8_t* pBuffer , uint32_t addr , uint16_t num)% f) J$ b; g% p  k2 ?1 l
  24. { 8 ^& y9 F; q8 ?. y2 h
  25.      uint16_t i;                                               . u6 H" i; d' `# }+ }
  26.     XX25QXX_CS_LOW;
    ' w0 R. k# H8 `& ?  `
  27.     SPI1_PA5_PA6_PA7_Read_Write_Byte(W25X_ReadData);
    * n8 I: w% _' B6 B, S) H5 ?* O$ ?7 ~3 M
  28.     if(XX25QXX_TYPE == W25Q256)
    0 ?0 N% a3 ^( x3 M) \1 p
  29.     {9 V& p: n% f: B) L" u% T2 s
  30.         SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>24));    9 p) p1 x9 u- r* ~0 D
  31.     }9 P; D3 S$ q3 w; Q# o3 V
  32.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>16));
    1 o) x! R6 Q3 ?- c$ @
  33.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>8));   
    + u/ q7 M2 X" F1 f  f) q' K
  34.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)addr);
      i0 r) f) G1 J
  35.   
    + ^, v0 R5 T6 y, d
  36.     SPI1_RX_DMA_Config_PID_MIE_Byte_Normal();& m% w; Z, j6 \! n
  37.     HAL_SPI_Receive_DMA(&hspi1 , pBuffer , num);
    & q3 l  c0 e: E0 h; o' ?: l, V
  38.     while(HAL_SPI_GetState(&hspi1) == HAL_SPI_STATE_BUSY_RX);
    ) W0 i1 m1 C& R$ V* ?' t
  39.    
    ! v& l9 u; t* a/ A
  40.     XX25QXX_CS_HIGH;                                
    8 k1 g- C9 K/ i5 E: n
  41. }  3 Q7 m# _% ?- m9 K; T3 n( I
复制代码
. C) J; G) {2 l! |3 d! Y1 y
我这里用SPIDMA接收所实现的功能是从SPI FLASH读出图片数据并显示到SPITFTLCD液晶屏上,而MCU的RAM大小以及DMA通道大小是有限制的,所以必须要采用分块读取的方式实现,将320*480分辨率,16位色的屏幕,平均分成6块,每块就是320*480*2/6=51200大小:+ F4 c/ Z! d' D2 ?* A! l
  1. uint8_t datatemp[51200];) k; E% c1 i' G/ r
  2. ) e0 r; U2 n$ F1 m8 k5 y2 |
  3.         for(j = 0 ; j < 6 ; j ++)
    : _$ V: b6 R) |+ |( S
  4.         {. B4 a& w! \! h% j
  5.             W25QXX_Write((uint8_t*)(gImage_u3_logo + j * 51200 ) , WRITE_READ_ADDR + j * 51200 , 51200);2 }, ^7 k* _" }" T3 w
  6.             XX25QXX_Read_DMA(datatemp , WRITE_READ_ADDR + j * 51200 , 51200);  _. w: Q2 V; A
  7.    
      j- \- B4 z; t' k! l4 `2 S" Y/ X
  8.             SPITFTLCD_ST7789_ShowPicture_DMA(0 , j * 80 , SPITFTLCD_ST7789_W , 80 , datatemp);
    3 z4 V' U( k# M8 n( O9 K
  9.         }
复制代码
5 p4 A' u' y/ v3 r- Q/ n- D
演示效果:
' f6 e$ K9 Q( { VID_20250616_222131 00_00_00-00_00_30.gif + ~- [9 a5 l' y9 Y" a4 Q
' v! r9 l- C1 l
. p4 d- X$ v1 N% H
赞 收藏 评论0 发布时间:2025-6-16 23:01

举报

0个回答

所属标签

相似技术帖

官网相关资源

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