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

【经验分享】STM32 DMA 应用之SRAM 与flash 间数据传

[复制链接]
STMCU小助手 发布时间:2022-5-23 22:00
一、为什么要用DMA?2 B% }2 z  @- {- h4 T; H% Z

' U+ w! \( q) q: x- V! WDMA  全称:Direct MemoryAccess 就是可以直接内存存取;8 y9 ]5 |; o, p2 |
' Q  _; l! C" _5 }' W5 C; b. p
正是它可以直接操作内存所以具备以下优点:; }4 r) Y  ^8 X9 r0 T
  C4 [6 {* P4 N  r, X. ~
而无需经过CPU去操作内存的存取,这样可以解放CPU出来干其他的事情;
. G8 |0 Y8 a# ~% ]* ^7 X0 j; C" P) z
因为他可以进行存储器时间的数据传输,而不需经过cpu,所以大大加快了数据传输速度—是一种高速的数据传输;
2 [3 Y/ U9 p( L9 p, k9 \$ Q/ }! m8 \# }  d" p
- \2 _/ V0 H) T. T
& s: ?) ~  B7 m7 x
二.DMA有几种传输数据方式:
6 [0 s. j2 ~  F* u. N, Q, ~# P! h. F# \: m
(1)内存到 内存之间的;即:SRAMßà SRAM
& ~( o% `9 w6 ~: {
4 M: \' O( u4 d/ ]  y+ i* m' ^( P(2)内存到 外设之间的;  (例如:串口收到的数据 从数据寄存器 à 内存)% o- h" V. h& \4 V4 c

$ X9 Y1 E3 W) d1 V1 _5 F- n(3)  外设到内存之间的;$ R  B7 V) W7 Z
. @+ L, \3 z% t3 v+ K: j
3 S& s% X4 T" Q5 }. W

) [7 f: d0 c3 c/ l4 R' ~( g三.传输的数据宽度是怎样的,数据是什么样的形式传输?DMA 能传输多大的数据量?
  D- o  S. c0 y0 L# T" X3 v" w% @% J  S& I" y3 Y7 A
A. 数据源地址到数据目的地址 传输宽度或者说传输数据的形式,有几种:1)字节;2)半字;3)全字 [1字节=8bit  1半字=2字节=16位   1全字=2半字=4字节=32位]: ?5 v5 A1 F. w4 D3 D6 D& ?
& Z4 @/ ]' b& J" j8 e
B.传输的最大数据量是655369 T, }4 i8 G! @( E' `. M5 T
, T" g7 E5 E+ j. p" z
我们来看一下stm32f103ve的数据手册第九章DMA 大概的了解一下DMA的特性:
, D& |4 [- g0 V! I5 I% E3 R
3 l, Y; [/ w1 D ZO@F)_D~6_8YIME1$EGPMHU.png
. l" v7 \: Y  t- J# B3 h 95L}{3S@Y%KG%{9BZOP4XLU.png
6 u; K4 B0 T' W% N+ @
8 I* p3 p2 X& I1 |. M/ `
% N) }, e5 q! \/ f( [- V( l四、怎样配置软件来使用DMA?* d9 N* U3 Z3 \5 Q& s0 \* M
4 w7 G" @5 K5 a
(1)配置dma' s+ |- \( x) q* V) U; P7 I, b+ q

* B" a. e5 w; [4 q* p
  1. /*****************************************************************  ; p$ f' B! R9 N
  2. *函数名称:  Dma_Init  6 C- n" _9 I* C  t( G8 S) z! j3 p
  3. *功能描述: 利用DMA 把内存的数据 传输到flash 达到高速传输的目的0 T7 [+ o3 ^' Z/ J( ?/ E- P7 {! V
  4. *   ' R7 o# E, F! ?' q4 ~
  5. *输入参数:无 , I' e  r/ _- y: e" v1 o, U
  6. *返回值  :无+ M# G, g/ a0 ]3 E$ |
  7. *其他说明:无
    6 F1 L( Y; M8 j+ o% F! ^& q! g
  8. *当前版本:v1.0  7 y) {& U/ T0 Z: k
  9. *作者         :尹宣 $ {4 B% S/ O& }3 W3 B/ n( E
  10. *完成时间:2013年12月1日 " j2 C5 ^: H  y
  11. *修改日期                版本号                修改人                修改内容
    ) M* D- h' o# E# U3 n; V
  12. *-----------------------------------------------------------------  ; m- T& F5 \  g2 ?% o* I2 m! L
  13. *  
    1 A, k1 U7 m' N4 X, L: M
  14. ******************************************************************/  
    1 X! k; c# S; {9 }3 D) |
  15. void Dma_Init(void): n" t8 R( q1 R) z$ h+ X
  16. {
    0 e# H0 O4 a  N3 U/ [% V# W" p
  17.   DMA_InitTypeDef  DMA_InitStructure;, ~: H5 y  U/ @9 R: h
  18.         
    8 N( ], V9 y# z8 ~0 S2 U& Q
  19.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);3 q; B& B  z; h) P! i$ r4 L
  20.         /* DMA channel6 configuration */# m. v) C2 Q' y8 U: E6 H! @
  21.   DMA_DeInit(DMA1_Channel1);4 J+ a& Q! R6 w$ ?9 T
  22.   DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_Const_Buffer;                        //外设地址
    $ j* p3 S) @1 C+ |
  23.   DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DST_Buffer;                                        //内存地址
    : K- J+ k; T' k6 o
  24.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                                   //外设作为DMA的源端     DMA_DIR_PeripheralDST;   //外设作为目的地址
    ; G0 b0 X+ E/ ~( _
  25.   DMA_InitStructure.DMA_BufferSize = BufferSize;                                                        //传输大小
    7 V: s1 u0 O7 O0 Q9 U4 Z# ~
  26.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;                        //外设地址增加$ O" r/ q! l2 t; P( U" M
  27.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                        //内存地址自增使能
    ( @: g) O/ E" J. K4 D
  28.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;        //内存存储方式:字节  DMA_MemoryDataSize_Word;//字(32位). X) f- x3 k9 \  F' M0 x
  29.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
    6 A$ m* @# h; o! ~& Y
  30.   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                //DMA_Mode_Normal 正常模式,只传送一次;  DMA_Mode_Circular:循环模式,不停的传送;! ^, l6 n7 T$ |2 `4 [6 ^2 H
  31.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;5 u0 s* |( a, {' N. `. H. B. C
  32.   DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
    4 p; [2 O1 ]' [3 `; V. W  o
  33.   DMA_Init(DMA1_Channel1, &DMA_InitStructure);0 ^" l* t) L2 p% [

  34. / j! l; t" r; Y/ s6 O2 P/ Z" f
  35.   /* Enable DMA Channel1 Transfer Complete interrupt */! S" _* R* E* c; [& M* {6 z
  36.   DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
    : j% m7 L- a& d, K8 S% W
  37.         
    " ]. `7 \5 W4 m+ S
  38.   /* Get Current Data Counter value before transfer begins *// o  G& w4 Z* e
  39.   CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1);
    / {; K3 X/ M( K) I5 p
  40.         7 J( x" {6 N3 ^/ C: m8 A* l
  41.   /* Enable DMA Channel6 transfer */" G: N. o4 _7 u5 ^! r) X6 `
  42.   DMA_Cmd(DMA1_Channel1, ENABLE);7 U- B0 @- F  A4 O% r3 q: _
  43.         
    ! Q' R' t! [) B  @. U
  44. }
复制代码
& x' W* s# z! m: Y
2.设置DMA优先级  W9 r  V! P% D4 I

" r' K, S% m, j2 W8 f
  1. /*****************************************************************  
    9 u- J3 ~/ @' y8 h, _2 c9 J
  2. *函数名称:  NVIC_Config  . b1 }2 c  h4 d# A
  3. *功能描述:        配置DMA的中断优先级
    5 W3 t1 _; {% F2 d6 @& f7 a! `; s: \
  4. *   
    1 v8 J/ Y0 X. @! d* ^" t$ M8 k" k
  5. *输入参数:无 & q' Z" }- P; P$ g# ^8 x
  6. *返回值  :无8 ?: `( _, G$ V9 g
  7. *其他说明:无
    + }; k; P9 X! l- G9 Z
  8. *当前版本:v1.0  
    7 t8 S$ o- c$ ~: L! U
  9. *作者         :尹宣 0 F& d$ v2 `& M4 J3 A! F) c
  10. *完成时间:2013年12月1日 ) E8 i, Q" C4 k. b
  11. *修改日期                版本号                修改人                修改内容 ' P, y8 t; L8 y$ }2 E" X- H' L2 l% m
  12. *-----------------------------------------------------------------  
    ' [8 p# `; I% R# e* ^! |
  13. *  * M  H: W5 j0 \  }1 p8 ?! v5 L$ D
  14. ******************************************************************/  
    ' K9 `% C; `. j1 |9 J/ h) o
  15. void NVIC_Config(void)2 |) q2 N; Z/ p* V7 x9 e
  16. {
    ! y$ C, R) G0 s. W# |1 K
  17.         NVIC_InitTypeDef NVIC_InitStructure;
    ( ~2 j4 g8 u) p8 Z* K& q9 {1 K
  18.         " t' |, R; k: s8 e. l  ~7 b
  19.         /* Configure one bit for preemption priority -------------------------------- */
    0 ?2 N! @4 Y5 q0 i
  20.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);6 H7 G! b& D6 ?; ]0 r+ n

  21. ; ~! a1 A/ n, I
  22.          /* Enable DMA channel1 IRQ Channel */  D9 O: C  u4 e
  23.         NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    7 b, {  E1 m7 E2 k8 O3 F
  24.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    " Q- m4 G8 Q# X* {; G6 x4 ^
  25.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;2 L  P, K, Q9 o, R5 x' K" E9 R
  26.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    $ D! Q5 w' w2 @5 }, ^
  27.         NVIC_Init(&NVIC_InitStructure);" _: x, F. [/ `. R$ p0 B* S1 t# f9 g3 r0 a
  28. }
复制代码
# {. m7 d: H# T7 h7 J) w
3.在stm3210x_it.c 文件中添加 DMA中断处理函数5 _/ F. R( ~5 o0 W! Z, _+ T
) C2 V3 r( Q; ^+ D( o# a3 y
  1. /*******************************************************************************
    ( L& V: g3 }# U3 w3 q) w: |
  2. * Function Name  : DMAChannel1_IRQHandler6 f* }" f1 z7 }5 B5 Z' A, X
  3. * Description    : This function handles DMA Stream 1 interrupt request.
    4 ~- q& B- ]7 I# O
  4. * Input          : None
    , v* A) G$ [. s9 F% G/ f
  5. * Output         : None1 N. w; C( K# a' k& ?
  6. * Return         : None5 n  y+ y* N! o* s4 G# o
  7. *******************************************************************************/! f) t; J7 O: u/ {- D
  8.          1 h; X+ B1 l/ @# z  B  z0 `
  9. void DMA1_Channel1_IRQHandler(void), e8 p. Q$ T' L- a' z
  10. {  ) Z( B# L& J; ^: d
  11.         /* Test on DMA Channel1 Transfer Complete interrupt */
    & W$ a1 w5 C0 y- M7 S7 ^' I! ^7 I: X' W
  12.   if(DMA_GetITStatus(DMA1_IT_TC1))                //DMA1_IT_TC1:通道1传输完成中断5 h7 M# M+ d. D2 R3 I
  13.   {1 M8 u3 z! B, k3 L, `
  14.     /* Get Current Data Counter value after complete transfer */
    & @+ h5 z0 Q6 Z1 S2 W, F
  15.    CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1);         //返回当前DMA通道1 剩余的待传输的数据数目" |' V4 |% G+ U4 H+ j6 T0 o
  16.     /* Clear DMA Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */7 d! R5 D7 u; J4 U/ V
  17.     DMA_ClearITPendingBit(DMA1_IT_GL1);                //清中断1全局中断
    . w, ]+ u, w$ f/ f
  18.   }, Y) N  S& F9 j( N8 d  ~+ }
  19.         8 V( m, L' Y: w1 e
  20. }
复制代码
4 [4 W  A! v' B/ G1 `* c
4主函数部分:
6 G! d$ a  Z8 N  S% v. L7 m1 k% O2 m4 D$ ~6 i
  1. int main(void)
    ! O0 J% B/ k; ~+ Q' {6 Y$ d
  2. {   
    7 \  q$ _8 G/ k+ t/ }1 J
  3. //         int count;+ g% Q3 ]8 \5 M( c- \6 P3 d
  4.         uint32 judge;
    0 p% A# \) G. D8 F
  5.         / a! `7 |7 N/ i5 g, e
  6.         NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x00);  // NVIC_VectTab_FLASH=0x08000000
    # B/ c3 v  ?8 \7 p* Z7 D) Z
  7. //         RCC_Config();9 O6 b, H+ z; k+ {# P
  8.          SysTick_Init();& l! n" ^6 {- K& m" q: M; m
  9.         GPIO_Config();0 M# L# F0 r& \
  10.         USART1_Init(19200);        , K, F  a, o9 @# e/ V' C  ]
  11.          ) t2 d9 u6 X+ u' Y
  12.          NVIC_Config();& w# `: ]5 i/ f( c2 m  V
  13.         $ J6 _0 f6 L1 f0 q
  14.         FLASH_SetLatency(FLASH_Latency_1);                        //延时2个时钟周期+ H" z; l& F' R# L
  15.     /* Enable Prefetch Buffer --使能预取指缓存*/
    : y+ W+ i5 z" E+ s; D
  16.     FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);5 f+ D3 ~/ `6 C3 t- r+ N- R
  17.         Dma_Init();* @7 X; j+ s" I( h# T, |# ]
  18.         /* Get Current Data Counter value before transfer begins */
    ; b) C* `& q  d5 p1 D
  19.         CurrDataCounter = DMA_GetCurrDataCounter(DMA1_Channel1);        //返回当前DMA通道x, 剩余待传输数据数目
    3 K% A. X: Q% N' C
  20.         
    1 }' e2 O* G7 b; s% g. P
  21.          while( CurrDataCounter!=0) ;  X' l" G# l$ z- y
  22.         judge = memcmp(SRC_Const_Buffer,DST_Buffer,BufferSize);
    * i% [) j& d; u* e& g, y
  23. ; `9 L$ v# p. ?' ?! [- N
  24.         if(0==judge)' F3 n0 z* |5 S
  25.         {( ^( I- G* {4 p% l$ M4 d" N" i! w
  26.                 USART1_SendData(" Same !!!\r\n",sizeof(" Same !!!\r\n"));3 F3 I7 k2 @  B' D3 h
  27.         }5 c0 f2 s/ K, v4 b  z
  28.         else7 `& l- ~5 E3 s; A+ j2 W- Z2 ~
  29.         {" J, a, H4 c- @4 C
  30.                 USART1_SendData(" different !!!\r\n",sizeof(" different !!!\r\n"));: e+ o5 G. M  s" [
  31.         }
    4 r% D: }! T: g, s0 J+ {0 K. b

  32.   A  ?1 ~5 ?2 E7 a- ?
  33.         Delay_ms(1);
    6 ^. Y$ k* I# T4 D, B" w: M
  34.         
    4 u3 K8 @8 e4 B8 M, U
  35. }  u8 D5 Z% M, Y5 U, w
复制代码

, F- s# Y, D% u* Q! u) B1 X五、测试验证* K( d$ r" r3 P; P! |" ]1 t& k

5 j) H' o4 N5 P' f2 x9 J1.我们先看看看下图4 o2 B. ^/ c$ x8 M! Y% s5 ~1 v
0 K: }5 h# V5 m8 m. V% m" P7 k
20131206104544015.jpg ) H" t: y! ]- [3 `: V5 n

3 Y* v- \4 a: q- W看点0:
- j5 \) I9 `: I, d1 ~. Z问1:4 k3 v1 }3 [: v/ S; [% [8 O

+ b- ^' n0 u4 u  |. w! o         使用内存窗口观测SRC_Const_Buffer和DST_Buffer所在的位置,可以发现SRC_Const_Buffer
  c/ F& \7 o9 D+ q( e: O, e8 z+ N# p5 J2 j
地址为0x08001B24,,即Flash中;DST_Buffer地址为0x2000002c,即RAM中;2 t4 F+ Z. r$ U' j: L7 _1 M
( l7 Y9 H: N; @$ ?) G

. R5 H+ s* w$ }% ?2 T( [7 t
6 F/ ]+ {4 `; N: ]% b% `7 ~5 c+ M  n答1:2 K9 Q# Y- S! a6 O( k0 h, S) @- E

; [+ W" y& m8 M( B5 [/ ]: q不能改变其值得变量(包括全局和局部)都是存储在FLASH中的,能改变的都储存在SRAM中
! a" J9 r. E# F3 u' R! d3 O; r
  N! X0 X" L; Q- ^SRC_Const_Buffer  的定义:uc32 SRC_Const_Buffert+ ?( K. T9 u7 A

$ y7 \! H6 e% Y+ o8 _搜索了一下uc32的出处----4 H1 ?+ U! H. B8 E0 [4 M

1 ~' I0 E, B5 Atypedef const uint32_tuc32;  /*!< Read Only */  
, e- }& |) o0 w3 H; R5 I6 A, p; C  `, k; T: i7 q
% \9 {$ L. \6 I8 l! w- Q

8 k' i, k' ?$ K" Y& a( w9 x( vDST_Buffer 的定义:u32DST_Buffer[BufferSize];, d& i3 q* c/ Y( U; ^& _: I0 B

& Q  K4 ?8 [  q# ^2 X8 P/ U搜索了一下u32的出处----% y, B' Z0 s1 [  F8 s4 y, ]4 u; i
, n5 `% _' A9 D  }2 U
Typedef uint32_t   u32;  6 a& r  X9 `. x
! ?, Q/ N3 X: q
2 v( U/ t, t  g6 q- B$ p! M1 d
看点1:断点设置开始DMA传输前,
3 k1 H: n! ]7 M2 h1 F/ V( x' n
) y: k0 l: t1 p! B( dCurrDataCounter = DMA_GetCurrDataCounter(DMA1_Channel1);可以读出待传输的数据长度为0x20=32 跟我我们定义的待传输的数据长度是一样的;9 l9 U% z2 z' g1 T

7 I+ o+ ?; }' C* h& _: }看点2:开始传输前,目的数组DST_Buffer里面的全部为空即为:0x00;/ }* ?+ M" E, M" a/ a  e

$ e9 e0 e6 x0 c8 Y: Q. r* _0 V3 E, C! t2 ]+ E8 H1 _+ Z. a% C! q
2.传输完成时,CurrDataCounter 值已经为0,即待传输数据为0;同时目的数组 DST_Buffer 已经有数据,我们用对比了一下源数组 和目的数组 相同则返回0; 证实了是相同的;# j* `0 ~5 l/ k7 P

! ~' k& |. ?9 E& \0 Q 20131206104447156.jpg 8 E% R" T! I' f" P" z+ o# k5 S
3 q! l; S9 M# Q/ D4 G

3 j- I! |, l. G$ u$ Y4 ?+ B9 A6 G4 k( \3 |1 Z

' a# _& y1 [5 i
赞 收藏 评论0 发布时间:2022-5-23 22:00

举报

0个回答

所属标签

相似技术帖

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