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

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

[复制链接]
donatello1996 发布时间:2025-6-16 23:01
       上一帖评测了STM32U385的SPIDMA发送功能用作ST7789液晶屏刷图,这次来评测一下SPIDMA接收实现读取SPI FLASH数据并显示到屏幕上,原理差不多。, m2 q6 s- b4 R7 _* J
       看CubeMX配置:2 O) v! |' y5 O. H) e+ u. z/ x5 I
10.JPG
) {' l  ]1 A9 l! y- Q; h9 g0 ^7 D6 y1 p      ! J, |: k$ o. ~( ?# g
        可以看到,配置跟SPIDMA发送基本大同小异,有不同的地方是,SPIDMA接收是不跟SPIDMA发送用同一个通道的,比如我这里就用新的通道即通道2,然后就是跟SPIDMA发送颠倒过来,是外设到内存,内存地址自增(如果内存地址非自增的话,那就只有内存首地址会收到源源不断的数据)。SPI的接收机制是,主机拉低片选并对从机发送【从机开始接收】指令之后,CLK脚会一直产生脉冲时钟信号给到从机,从机收到脉冲就会源源不断发给主机,只要主机的时钟信号不停就表示主机一直在接收状态,而SPIDMA接收呢则是在此基础上把SPI外设给DMA外设相应通道接管,因此CPU也是需要等待DMA外设完成接收产生中断的,所以代码必须要有中断,并且是DMA通道产生的中断:
  1. HAL_NVIC_SetPriority(GPDMA1_Channel2_IRQn, 0, 0);
    6 T2 d+ a2 x, u  i4 {1 |3 W
  2. HAL_NVIC_EnableIRQ(GPDMA1_Channel2_IRQn);
    2 V' G$ ?6 a) S0 R  p8 d' Z( u% W0 l

  3. ( i6 o# O5 X$ I7 @7 _
  4. void GPDMA1_Channel2_IRQHandler(void)( W9 d- a5 {3 w/ t! W
  5. {( \( u$ ^# [6 }" B7 w
  6.   HAL_DMA_IRQHandler(&handle_GPDMA1_Channel2);
    / O0 O3 Y1 s2 }3 _1 G- T: Z( |& I
  7. }
复制代码
# W3 R7 b4 r" F5 u" r5 ^
然后是DMA配置函数,跟上文说的一致,外设到内存,内存地址自增:
% B7 x' C3 O. z  Z( ~
  1. void SPI1_RX_DMA_Config_PID_MIE_Byte_Normal()
    ; F6 u  L; w; p# \* B( ~' c5 t
  2. {2 B; H! B5 G% k
  3.     handle_GPDMA1_Channel2.Instance = GPDMA1_Channel2;5 z5 e+ m7 ]2 |, Y
  4.     handle_GPDMA1_Channel2.Init.Request = GPDMA1_REQUEST_SPI1_RX;$ X" [% Y+ U4 z
  5.     handle_GPDMA1_Channel2.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;+ S0 m% z6 F7 U0 ^& e
  6.     handle_GPDMA1_Channel2.Init.Direction = DMA_PERIPH_TO_MEMORY;+ s. j' E* P$ t9 F
  7.     handle_GPDMA1_Channel2.Init.SrcInc = DMA_SINC_FIXED;
    4 T& s( K( i* Q+ |7 n
  8.     handle_GPDMA1_Channel2.Init.DestInc = DMA_DINC_INCREMENTED;5 U- q& V4 ^; T6 a6 j% U3 _0 j1 W
  9.     handle_GPDMA1_Channel2.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;4 E3 R! Q* ]8 c. K, r
  10.     handle_GPDMA1_Channel2.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
    2 f6 o) {2 r1 o; D0 C- {
  11.     handle_GPDMA1_Channel2.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
    4 j" B. B% i4 ~4 t. F
  12.     handle_GPDMA1_Channel2.Init.SrcBurstLength = 1;3 i0 _, i$ Z, I4 x0 u3 K
  13.     handle_GPDMA1_Channel2.Init.DestBurstLength = 1;
    5 j9 i8 T' F/ s& g$ d. q& D
  14.     handle_GPDMA1_Channel2.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0;
    1 R% H4 _$ n% _0 o4 l% k; ?
  15.     handle_GPDMA1_Channel2.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;8 h2 r1 b/ e7 j  x  K) w
  16.     handle_GPDMA1_Channel2.Init.Mode = DMA_NORMAL;3 Z0 l& N6 w* f8 m2 Z* @
  17.     HAL_DMA_Init(&handle_GPDMA1_Channel2);" r0 I1 Q5 ?# ?9 X
  18. % }( b, d" ~0 R2 c: g
  19.     __HAL_LINKDMA(&hspi1 , hdmarx , handle_GPDMA1_Channel2);, }9 {) |9 J7 A: T6 D- m6 o

  20. , Q1 n6 k5 y: u1 ^9 ~
  21.     HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel2 , DMA_CHANNEL_NPRIV);
    & i) J0 B3 {+ Z8 H4 ]' B; O3 E
  22. }
复制代码
1 w& {2 ~: b# ~
( f. O; g, M  ^3 D7 R, I, X) l
对于SPI FLASH从机而言,无论主机是否使用DMA接收,都是通过主机的指令行事,因此代码区别只在主机发完【从机开始接收】这个指令给从机之后的接收方式不同而已:
2 P9 y5 n8 x1 b
  1. void W25QXX_Read(uint8_t* pBuffer , uint32_t addr , uint16_t num)   
    , U" w0 T: O+ ?1 J; S; X* U8 a( A4 d
  2. {
    & A2 d2 P) d" _! J# R: X7 p
  3.      uint16_t i;                                               
    1 a  C9 u8 b& E. d% P
  4.     XX25QXX_CS_LOW;, u) I. e% l1 t$ u1 G! [9 K
  5.     ! W" g" Q( N  R+ B9 y" g2 m
  6.     SPI1_PA5_PA6_PA7_Read_Write_Byte(W25X_ReadData);' y8 @6 s4 g- n9 L
  7.     if(XX25QXX_TYPE == W25Q256)
    5 m4 \" j5 J, M! n  }% ]9 S
  8.     {% X& Q# e3 h8 L( e- T- G: N6 C( s
  9.         SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>24));   
    4 w0 f3 a: _, ~) }- ?# E8 H
  10.     }
    & |) [/ K) a/ K, c) r! s4 l# |. Z
  11.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>16));7 H- j/ c6 [( z2 v
  12.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>8));. r) D5 }6 p( t8 a) E9 y: j
  13.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)addr);8 q. T2 V+ t; a) w- u
  14.    
    " o. W: _! G3 q  f9 j6 @9 g
  15.     for(i = 0 ; i < num ; i ++)
    + J* K& r! v) u8 c# v+ K3 I% T) Q
  16.     { # o9 u, C1 v# y, A* m' ?1 M! y4 y6 Q
  17.         pBuffer[i]=SPI1_PA5_PA6_PA7_Read_Write_Byte(0xff);
    ' ~* p) R: u) V8 S, H
  18.     }4 D7 z+ y4 b) K/ K
  19.     4 b9 G: p3 c$ S8 y
  20.     XX25QXX_CS_HIGH;                                # p9 d  e7 O! \6 N
  21. }  
    / d) C: ]% \3 A7 p
  22. / }; }! @7 W1 ?  C
  23. void XX25QXX_Read_DMA(uint8_t* pBuffer , uint32_t addr , uint16_t num)
    - p) j" z  b, Z1 c' r1 V
  24. {
    0 K% _) ]3 D1 c9 Q, L2 N
  25.      uint16_t i;                                               1 `" _  ~4 Z& I, Z4 T
  26.     XX25QXX_CS_LOW;
    & T: O4 C5 [5 Z: B
  27.     SPI1_PA5_PA6_PA7_Read_Write_Byte(W25X_ReadData);
    / Q4 i+ U6 O* w9 z6 }
  28.     if(XX25QXX_TYPE == W25Q256)0 l( F- g8 [: u4 h3 E
  29.     {
    8 O8 \3 M; Z/ y; j0 ~6 T9 ^& x
  30.         SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>24));   
    9 o1 r0 P0 l. r2 J% X- K7 h
  31.     }0 H% d/ j/ M; e( c& k3 |) u
  32.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>16));
    1 o; A3 p7 @# ?
  33.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>8));   
    1 X% {: F0 M" X5 [/ |, G
  34.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)addr); 6 o$ q( A9 s0 d0 ?- _0 R
  35.   4 L5 R/ K, T6 a3 u
  36.     SPI1_RX_DMA_Config_PID_MIE_Byte_Normal();. ?# i# X% R  n2 O! N3 R
  37.     HAL_SPI_Receive_DMA(&hspi1 , pBuffer , num);
    9 n, m# T$ \6 {# [  ^% K5 T+ U: @, T
  38.     while(HAL_SPI_GetState(&hspi1) == HAL_SPI_STATE_BUSY_RX);
    . ~! g$ j* t* K0 m0 N  l: o( ]; C* R
  39.     3 }! Y9 H4 y  Z& ~
  40.     XX25QXX_CS_HIGH;                                0 C1 t# b& Z% b/ R. M4 `$ D! x
  41. }  5 }7 Z9 z0 v5 V/ }% \0 U! ~
复制代码

- d) n0 }& H. O) t) x% V4 P5 m我这里用SPIDMA接收所实现的功能是从SPI FLASH读出图片数据并显示到SPITFTLCD液晶屏上,而MCU的RAM大小以及DMA通道大小是有限制的,所以必须要采用分块读取的方式实现,将320*480分辨率,16位色的屏幕,平均分成6块,每块就是320*480*2/6=51200大小:
# S8 T1 X- h8 @7 B' o
  1. uint8_t datatemp[51200];
    4 \+ L9 U8 s  C0 s$ B( h
  2. 8 n* ]0 I( k9 ~3 s* f5 }
  3.         for(j = 0 ; j < 6 ; j ++)
    ) Z' q$ Y5 D1 h7 h! i; b
  4.         {5 k% z8 m- A  h2 O4 ^
  5.             W25QXX_Write((uint8_t*)(gImage_u3_logo + j * 51200 ) , WRITE_READ_ADDR + j * 51200 , 51200);( g% W4 Y, w+ A3 j5 G" N
  6.             XX25QXX_Read_DMA(datatemp , WRITE_READ_ADDR + j * 51200 , 51200);
    : C* @/ O( Y$ ?2 s
  7.     - p& z; F  _7 D# V; Z
  8.             SPITFTLCD_ST7789_ShowPicture_DMA(0 , j * 80 , SPITFTLCD_ST7789_W , 80 , datatemp);" e% E4 M9 @. H9 c& M; M5 T
  9.         }
复制代码

8 ?6 w3 S% Z( a7 N% R演示效果:
- H- Z8 @$ V1 ?& k VID_20250616_222131 00_00_00-00_00_30.gif + U( P/ M/ b% [- C$ Q9 f
4 i6 v3 I6 u/ ?& s6 L) h" j
0 _/ E' R& h" g  S
收藏 评论0 发布时间:2025-6-16 23:01

举报

0个回答

所属标签

相似技术帖

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