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

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

[复制链接]
donatello1996 发布时间:2025-6-16 23:01
       上一帖评测了STM32U385的SPIDMA发送功能用作ST7789液晶屏刷图,这次来评测一下SPIDMA接收实现读取SPI FLASH数据并显示到屏幕上,原理差不多。
) A0 p# d' @  v$ e1 b5 j       看CubeMX配置:/ }5 p/ x- c, E8 ~* d8 [3 H+ N
10.JPG 0 U( a' v5 O0 c! }( t2 c, C
      ( ~5 K$ j7 D: q6 x3 D2 s4 r7 @
        可以看到,配置跟SPIDMA发送基本大同小异,有不同的地方是,SPIDMA接收是不跟SPIDMA发送用同一个通道的,比如我这里就用新的通道即通道2,然后就是跟SPIDMA发送颠倒过来,是外设到内存,内存地址自增(如果内存地址非自增的话,那就只有内存首地址会收到源源不断的数据)。SPI的接收机制是,主机拉低片选并对从机发送【从机开始接收】指令之后,CLK脚会一直产生脉冲时钟信号给到从机,从机收到脉冲就会源源不断发给主机,只要主机的时钟信号不停就表示主机一直在接收状态,而SPIDMA接收呢则是在此基础上把SPI外设给DMA外设相应通道接管,因此CPU也是需要等待DMA外设完成接收产生中断的,所以代码必须要有中断,并且是DMA通道产生的中断:
  1. HAL_NVIC_SetPriority(GPDMA1_Channel2_IRQn, 0, 0);- E- t5 {: q1 ]
  2. HAL_NVIC_EnableIRQ(GPDMA1_Channel2_IRQn);- D( I0 S! w' N, |5 L6 t, k

  3. 0 N9 v1 \% H) T8 T. Q3 e9 C- j
  4. void GPDMA1_Channel2_IRQHandler(void)$ w6 t6 _6 B3 k& ]% p2 u7 W+ r
  5. {
    : L2 X3 D, [1 v! b  |6 N
  6.   HAL_DMA_IRQHandler(&handle_GPDMA1_Channel2);4 u( v  r$ j' T5 S" i; ?: Z7 A: z
  7. }
复制代码
2 ^8 Q/ _! Q1 v; W* V. H
然后是DMA配置函数,跟上文说的一致,外设到内存,内存地址自增:
, W7 S7 e) f7 x1 j
  1. void SPI1_RX_DMA_Config_PID_MIE_Byte_Normal()
    0 y5 ]: x6 T9 _  x7 l
  2. {
    0 q; u$ Q0 B! ?$ ?! |4 ]. S6 V( R
  3.     handle_GPDMA1_Channel2.Instance = GPDMA1_Channel2;" m0 g- W. v& B4 w1 A( u
  4.     handle_GPDMA1_Channel2.Init.Request = GPDMA1_REQUEST_SPI1_RX;
    ( l( D/ F& E3 r8 i2 X( C$ F
  5.     handle_GPDMA1_Channel2.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;, k$ ]5 Z5 V3 i3 w, ^
  6.     handle_GPDMA1_Channel2.Init.Direction = DMA_PERIPH_TO_MEMORY;1 N' ~4 ]" }8 `: N& n3 }, Y. q
  7.     handle_GPDMA1_Channel2.Init.SrcInc = DMA_SINC_FIXED;+ f& J. y. ~# r$ y
  8.     handle_GPDMA1_Channel2.Init.DestInc = DMA_DINC_INCREMENTED;
    . C* k+ q, d' v7 }" L" a) A, [
  9.     handle_GPDMA1_Channel2.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
    / C( x; z; y; c/ B4 a1 O6 N4 J
  10.     handle_GPDMA1_Channel2.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
    4 G' v' R1 f* ^# B6 J. }
  11.     handle_GPDMA1_Channel2.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
    & A" N! v; ?# n6 n$ }
  12.     handle_GPDMA1_Channel2.Init.SrcBurstLength = 1;3 S0 I" j- r2 w. Q
  13.     handle_GPDMA1_Channel2.Init.DestBurstLength = 1;
    + [! n! e3 ?7 V0 w) C
  14.     handle_GPDMA1_Channel2.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0;
    8 _3 I! \4 \7 m2 h# }! I7 }
  15.     handle_GPDMA1_Channel2.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;: n/ w/ K9 \2 N
  16.     handle_GPDMA1_Channel2.Init.Mode = DMA_NORMAL;% P% y* }! Y* a4 j  f  `
  17.     HAL_DMA_Init(&handle_GPDMA1_Channel2);
    5 O  R7 l( }) Q5 f' H  w

  18.   j4 @6 C7 I0 \, e/ x
  19.     __HAL_LINKDMA(&hspi1 , hdmarx , handle_GPDMA1_Channel2);" H0 T, W# d5 Q5 m
  20. * Q# Q7 J* x+ g& e6 ?; i  Q
  21.     HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel2 , DMA_CHANNEL_NPRIV);
    / ?" M$ p! C0 I
  22. }
复制代码
- O% r( f; I* U2 J% v1 M3 U) v

7 L* M; o3 B( c7 u8 o+ y对于SPI FLASH从机而言,无论主机是否使用DMA接收,都是通过主机的指令行事,因此代码区别只在主机发完【从机开始接收】这个指令给从机之后的接收方式不同而已:
8 l. l" K5 T4 x
  1. void W25QXX_Read(uint8_t* pBuffer , uint32_t addr , uint16_t num)   
    . z; d$ F# c9 a; [: A9 p4 |
  2. {
    0 N6 J: `9 u- ^3 {# R7 p5 t% a
  3.      uint16_t i;                                               8 i. ?7 [; {  ?9 S
  4.     XX25QXX_CS_LOW;* z% `5 D% E% p# M
  5.    
    ; F4 |2 L3 d6 i  {3 R: O
  6.     SPI1_PA5_PA6_PA7_Read_Write_Byte(W25X_ReadData);4 y. ~4 T6 x9 H
  7.     if(XX25QXX_TYPE == W25Q256) $ }: }7 v0 d: A* I$ z% C/ }: s; K8 o
  8.     {% d$ V; [9 c# L
  9.         SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>24));   
    ! {  |8 N7 m7 L5 O9 j( T$ r2 }
  10.     }
      {% G( `5 o" c
  11.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>16));! ^# y; J# k5 \& L6 ]7 n
  12.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>8));9 f- Q6 _: q/ f+ q) z0 S
  13.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)addr);
    $ y0 c1 W" `# N) K( ?& o
  14.    
    , a, Z7 Y3 O( r+ p) Y% w
  15.     for(i = 0 ; i < num ; i ++)
    ) O7 I- N: H" O& f$ W. U6 [
  16.     { 7 B* \3 d# X# ?
  17.         pBuffer[i]=SPI1_PA5_PA6_PA7_Read_Write_Byte(0xff);; O+ @5 t! H  J1 Y. c( q
  18.     }1 F0 T" f. N" r5 p, c( H# |
  19.     2 o) N% h( R' H' H
  20.     XX25QXX_CS_HIGH;                                . t0 h9 U7 Q8 t2 L  z# k% o
  21. }  
      v$ G( v1 Z7 @& L
  22. 2 `1 s% G$ H  a$ @( ~! V
  23. void XX25QXX_Read_DMA(uint8_t* pBuffer , uint32_t addr , uint16_t num)
    + O+ ?' F" {& z* [$ y' q* y9 W
  24. { ! y5 K# V4 o, N$ L" y7 ~3 V
  25.      uint16_t i;                                               * {7 A8 f: }% C
  26.     XX25QXX_CS_LOW;4 I) ^, @5 X' ]2 w) p1 ]
  27.     SPI1_PA5_PA6_PA7_Read_Write_Byte(W25X_ReadData);+ g9 w6 {$ u; Z+ p9 u
  28.     if(XX25QXX_TYPE == W25Q256)
    6 v, D$ K/ d8 z( ^9 S, V. P
  29.     {
    $ b, g4 M) g! o3 X
  30.         SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>24));   
    7 Q: B8 H9 v- |8 [# H3 n
  31.     }
    6 ?4 @7 d8 e1 x! U: F% q+ q- n
  32.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>16));
    0 }5 v- V  C5 m0 b5 x
  33.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)((addr)>>8));   / K" G8 |- Q. }- d! `
  34.     SPI1_PA5_PA6_PA7_Read_Write_Byte((uint8_t)addr);
    / d5 Q  W* J  i* S* P2 T: ~( p
  35.   1 x& {4 t: i6 ^! p. N/ i, h' `
  36.     SPI1_RX_DMA_Config_PID_MIE_Byte_Normal();; u4 h1 K7 h6 d% s! z
  37.     HAL_SPI_Receive_DMA(&hspi1 , pBuffer , num);
    8 A- l8 m+ {1 L1 v  w
  38.     while(HAL_SPI_GetState(&hspi1) == HAL_SPI_STATE_BUSY_RX);
    + o& ?6 P4 Z7 ]7 f) Q6 Q' @
  39.     + X! U* b, l2 ]% O/ }! c
  40.     XX25QXX_CS_HIGH;                                % ]1 f% x) X2 a  W) N
  41. }  : ?7 A* j& B& B5 k. J; Y
复制代码
! ^" c0 W" Q. @; A% x
我这里用SPIDMA接收所实现的功能是从SPI FLASH读出图片数据并显示到SPITFTLCD液晶屏上,而MCU的RAM大小以及DMA通道大小是有限制的,所以必须要采用分块读取的方式实现,将320*480分辨率,16位色的屏幕,平均分成6块,每块就是320*480*2/6=51200大小:
, t# m& j/ T4 U* i
  1. uint8_t datatemp[51200];5 e0 K# P, \( C
  2. 9 L0 U, z5 {' s/ Q8 ?5 ]
  3.         for(j = 0 ; j < 6 ; j ++)8 I7 [2 g' E( B& V' I! y
  4.         {
    2 m3 Z/ a- m. S0 B. L
  5.             W25QXX_Write((uint8_t*)(gImage_u3_logo + j * 51200 ) , WRITE_READ_ADDR + j * 51200 , 51200);
    * R0 O4 \/ x+ n6 h, X  a8 g, v
  6.             XX25QXX_Read_DMA(datatemp , WRITE_READ_ADDR + j * 51200 , 51200);8 A  p) o: H# ?# M9 I9 V/ B
  7.    
    2 C9 H' B# x- D5 W* l
  8.             SPITFTLCD_ST7789_ShowPicture_DMA(0 , j * 80 , SPITFTLCD_ST7789_W , 80 , datatemp);1 b1 a9 Z. _. E
  9.         }
复制代码
: g0 M8 ~* Z: U' A& q+ h
演示效果:
! T/ k* j1 Y2 k% v  h VID_20250616_222131 00_00_00-00_00_30.gif 1 g1 |+ F" J4 b! I

/ i% P, \) Y8 ^/ g* c% o: G2 v- e9 e$ j" U, i9 e
收藏 评论0 发布时间:2025-6-16 23:01

举报

0个回答

所属标签

相似技术帖

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