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

STM32 DMA 应用之(一)SRAM 与flash 间数据传输

[复制链接]
aimejia 发布时间:2018-5-24 11:22
本帖最后由 aimejia 于 2018-5-24 11:23 编辑 , L5 J# M, U* @: A4 }
8 I1 W. P# r, F8 O
一、为什么要用DMA?! {8 k2 C' d# X4 o! h
% U* }: O  A& ^% k1 P
DMA  全称:Direct MemoryAccess 就是可以直接内存存取;5 W8 x! k; ^* B& v% N3 R# n

0 G# X3 k' n6 r- e( j4 Y' l正是它可以直接操作内存所以具备以下优点:$ @9 G$ ]9 W, ?

, j5 G" s- ]  \6 U, b而无需经过CPU去操作内存的存取,这样可以解放CPU出来干其他的事情;2 ]* X. ]  B# }' b2 |
) j& ~) n: I, Z4 m  @( _# d/ l# |
因为他可以进行存储器时间的数据传输,而不需经过cpu,所以大大加快了数据传输速度—是一种高速的数据传输;
% I+ G# A+ f# B: x. S' c
) Q. o$ j( W2 n0 A" |7 o) h! B二.DMA有几种传输数据方式:
5 ?( q1 O! c  t7 ?
7 l7 q) U; n" J* V% |0 \(1)内存到 内存之间的;即:SRAMßà SRAM, h# y! K# U  `* X% l

7 J9 d8 J5 _: Y: ~# Z: K  (2)内存到 外设之间的;  (例如:串口收到的数据 从数据寄存器 à 内存)
+ {% U$ S2 x% B- s! Z, \: S
. O& Q: G# K; F% f  (3)  外设到内存之间的;
9 g: i- m1 l% P# k" J/ e. \# w: u* `" j" R* N. r* S
三.传输的数据宽度是怎样的,数据是什么样的形式传输?DMA 能传输多大的数据量?8 S- @' B) w0 t- f/ R! W, E0 E9 l
% j$ n2 O! Z) M: V) X4 @8 f
A. 数据源地址到数据目的地址 传输宽度或者说传输数据的形式,有几种:1)字节;2)半字;3)全字 [1字节=8bit  1半字=2字节=16位   1全字=2半字=4字节=32位]4 V" z' [5 f5 ]6 x4 \  D8 F: i

1 \! e# v8 [' {B.传输的最大数据量是65536
! K; G) ~) m. U# [5 @4 ^- g6 M: b4 X4 q8 ]: o6 S8 q
我们来看一下stm32f103ve的数据手册第九章DMA 大概的了解一下DMA的特性:
5 Q9 e% d4 Y/ F- ^+ D! e
. O/ Y$ ]7 `$ K& I* T  Q* e 1.jpg
  r. s+ `: Z5 M, n3 ^# J& ?$ { 2.jpg ! a9 E3 {, }7 L

5 ?% {- ?; J& ]; m& {1 ~* j四、怎样配置软件来使用DMA?
3 |$ x) e1 @& I. W" O5 `( t! [
. r  D- n) M; L1配置dma; N+ U* }* w+ k8 e3 r1 p5 f8 p
  1. [plain] view plain copy0 s5 P& l; d6 _: D8 {5 n
  2. /*****************************************************************    & w/ s+ U8 C: B+ [" u
  3. *函数名称:  Dma_Init    0 h; g+ c3 l1 G/ q& ~( |
  4. *功能描述: 利用DMA 把内存的数据 传输到flash 达到高速传输的目的  
    . F6 B# J8 B/ n# R: _8 \
  5. *     
    5 c/ Y- t. _' o+ ]! {- |) t4 W3 X
  6. *输入参数:无   - t6 K& L4 {* k3 N/ w* a& d; O
  7. *返回值  :无  
    - Q/ ~- A# @* X6 L4 W# ?2 s
  8. *其他说明:无  
    ! l8 l! T7 W! p1 o
  9. *当前版本:v1.0    # s# }+ b6 S6 B$ g
  10. *作者  :尹宣   
    ) L$ g/ d6 k1 t' s0 M& q9 `! J
  11. *完成时间:2013年12月1日   
    : ]: o" a% C; e
  12. *修改日期       版本号     修改人     修改内容   
    - R$ {+ a! P6 b9 t, x) g
  13. *-----------------------------------------------------------------   
    # ?! S# V: x& j: X, A( x
  14. *    & ?  y! i" n5 z) H6 L
  15. ******************************************************************/    ' g2 q: b. T8 W* M
  16. void Dma_Init(void)  6 }8 p. d9 c! p# s% p: J
  17. {  
    ! D$ j! z+ B+ }4 i0 u
  18.   DMA_InitTypeDef  DMA_InitStructure;  
    " e/ {8 ?; C+ I
  19.       6 E2 H  W9 ~0 H( k5 @( A, \/ F
  20.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  
    - w6 V' \+ [) e
  21.     /* DMA channel6 configuration */  2 y! o/ G2 `, j3 Z' X) P2 E% k' D9 T
  22.   DMA_DeInit(DMA1_Channel1);  " h8 c2 S3 \7 D' k7 s" I
  23.   DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_Const_Buffer;         //外设地址  
    5 b. l5 d5 X! M
  24.   DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DST_Buffer;                   //内存地址  & s+ v# H5 J, Y8 K" |" p
  25.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                        //外设作为DMA的源端     DMA_DIR_PeripheralDST;   //外设作为目的地址   & l) Z# Z% a$ z3 D
  26.   DMA_InitStructure.DMA_BufferSize = BufferSize;                            //传输大小  " r( P+ ~3 ?) s; Z9 s
  27.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;           //外设地址增加  
    ) b8 O# v+ `% X& A# N
  28.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                   //内存地址自增使能  ) o- H5 s6 l0 o. A4 t, |7 _0 g
  29.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;   //内存存储方式:字节  DMA_MemoryDataSize_Word;//字(32位)  
    & G& C2 k. _) U
  30.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;  # C2 C3 Z: M/ z" q
  31.   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;     //DMA_Mode_Normal 正常模式,只传送一次;  DMA_Mode_Circular:循环模式,不停的传送;  
    ' b% Z9 r% c. w$ m1 r6 O  D
  32.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;  5 s8 O* p$ _( |0 `# u
  33.   DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;  6 p$ q; K9 K# n8 M3 M$ a; t
  34.   DMA_Init(DMA1_Channel1, &DMA_InitStructure);  
    # G3 a% Q( a& ?' \( b+ ~" i
  35.   
    : j. O" Q7 `% d) S
  36.   /* Enable DMA Channel1 Transfer Complete interrupt */    C$ D( L2 {/ c' G
  37.   DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);  " S1 n3 F3 V. e# l4 |
  38.       , W( G! s8 p2 [. z* j
  39.   /* Get Current Data Counter value before transfer begins */  
    ' M7 Y; o6 a: H& S/ h
  40.   CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1);  + S" [, }4 }8 P  B- d
  41.       4 P& {5 M2 e  X
  42.   /* Enable DMA Channel6 transfer */  
      n: r. Z- c6 A' \4 b
  43.   DMA_Cmd(DMA1_Channel1, ENABLE);  
    7 P& R6 r0 u, T2 G" G
  44.       0 x& z! t' G) G
  45. }
复制代码
2.设置DMA优先级/ ?, A! `2 r  p7 r# O
  1. [plain] view plain copy" R7 e6 V+ b3 ]
  2. /*****************************************************************    , @' ~2 Z1 M: y. k) |1 {- a9 I  ]
  3. *函数名称:  NVIC_Config    . u3 {' D! q5 V4 k' k
  4. *功能描述:  配置DMA的中断优先级  ! h1 S( H6 v) T5 f  G5 R
  5. *     6 Y! K0 h  _/ w; c
  6. *输入参数:无   - r9 V9 P6 i* M9 H* f' Q
  7. *返回值  :无    f$ o8 ~5 o$ j$ Y0 V
  8. *其他说明:无  8 X- L4 n* a* w9 F( G# x$ Z
  9. *当前版本:v1.0   
    ( ^1 `3 }, V" k+ T$ x2 ]
  10. *作者  :尹宣   / b- t  g1 h7 Y- T: {
  11. *完成时间:2013年12月1日   
    ( k2 K. P" {4 F) g
  12. *修改日期       版本号     修改人     修改内容   
    + A) P- Y6 C* E% j' [
  13. *-----------------------------------------------------------------    1 U, z. o( g6 ^/ y/ N
  14. *    9 c  k4 U) |/ d
  15. ******************************************************************/    " p+ f% M" T- H. Y
  16. void NVIC_Config(void)  
    6 D, K* a+ L- q+ Y  x  y3 V+ j
  17. {  
    - P, G& @' g) u  Z
  18.     NVIC_InitTypeDef NVIC_InitStructure;  
    5 ~$ s( H7 W1 k/ D
  19.       
    * i: C/ R- @9 S$ O
  20.     /* Configure one bit for preemption priority -------------------------------- */  
    , e0 y0 q# f' X
  21.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);  
    ' X* T. `  c/ `8 H/ g/ l% L
  22.   
    / C, I. U3 c8 b6 c% \
  23.      /* Enable DMA channel1 IRQ Channel */  ) v4 T; F4 d2 F: O
  24.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;  
    $ z- G3 o% L5 b7 U/ ~; X
  25.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  & M( D& I& M8 v( W
  26.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
    " u$ @. h( O& E
  27.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
    ' S6 t; ^8 F& ?0 ]+ a1 A. E
  28.     NVIC_Init(&NVIC_InitStructure);  
    , z7 \3 |2 m6 U5 Z+ Q: ~- }
  29. }
复制代码
3.在stm3210x_it.c 文件中添加 DMA中断处理函数) f$ r- ]2 |3 t) V# S# O) V/ V8 S
  1. [plain] view plain copy8 y+ e/ a# e3 P- G
  2. /*******************************************************************************  
    9 \3 @4 l- k7 @' L
  3. * Function Name  : DMAChannel1_IRQHandler  / X9 F  a1 C' B5 C, D# r
  4. * Description    : This function handles DMA Stream 1 interrupt request.  - b# a/ d. f1 x/ r6 v
  5. * Input          : None  ; |9 e0 I+ t' u9 N! N7 s/ G& U
  6. * Output         : None  
    5 e6 R0 u8 ]' o8 `2 S3 B
  7. * Return         : None  
    & T1 m, d4 h  }- X
  8. *******************************************************************************/  
    . V" F( W- D) N; [" n  M" Y
  9.        1 M3 e# j( ~. e4 }# ^7 t9 t, l$ a
  10. void DMA1_Channel1_IRQHandler(void)  7 c: O) ]2 U2 C& s& X4 o0 u# i! C8 p
  11. {    ' F4 v$ k# J" k6 q, t, E+ x
  12.     /* Test on DMA Channel1 Transfer Complete interrupt */  
    * R$ R: n8 U2 B$ i: W$ X/ ]
  13.   if(DMA_GetITStatus(DMA1_IT_TC1))      //DMA1_IT_TC1:通道1传输完成中断    d0 N6 x1 [4 x2 I  k2 W4 F! s% j
  14.   {  . @" C- i, N3 ~" C3 C
  15.     /* Get Current Data Counter value after complete transfer */  
    5 D$ H  ?( i: [+ [  h$ K
  16.    CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1);  //返回当前DMA通道1 剩余的待传输的数据数目  4 D. W1 C+ x5 k
  17.     /* Clear DMA Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */  
    % O6 D, o, f$ O+ S
  18.     DMA_ClearITPendingBit(DMA1_IT_GL1);     //清中断1全局中断  ( |6 @# ~# a% H% R
  19.   }  
    % `8 f' [' Z' D+ G6 x5 f' _
  20.       
    5 F/ X& @( F- z: S6 b7 U# s& Z& u: B
  21. }
复制代码
4主函数部分:9 R% L2 d9 d4 h9 _1 B
  1. [plain] view plain copy
    & W$ m: B3 Z: C) P4 Q
  2. int main(void)  , G! ^- ~* o1 {" D% B
  3. {     
    * c9 ]- l1 F# s; x
  4. //  int count;  : B1 w6 q/ ^) j( w! x
  5.     uint32 judge;  ! j- j/ Y0 _+ D& }1 n
  6.       
    7 e3 w! C: F! W) Y
  7.     NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x00);  // NVIC_VectTab_FLASH=0x08000000  ' H% d) @  p+ L( E9 v" R, J
  8. //  RCC_Config();  
    6 R! ~$ j2 E, l8 h) A. m9 I
  9.     SysTick_Init();  
    9 p' b) ^9 A8 F3 S" o6 j* P
  10.     GPIO_Config();  
    ' `  R+ d1 h! U& h0 C1 @
  11.     USART1_Init(19200);   - ?: M1 P: }, S& Z% J
  12.       & ~$ I$ u% u0 [
  13.     NVIC_Config();  5 H7 U. T( o6 Q' E. j
  14.       " Z0 _& [( s' i
  15.     FLASH_SetLatency(FLASH_Latency_1);          //延时2个时钟周期  
    7 c4 h7 @* J6 ~! \- p. X
  16.     /* Enable Prefetch Buffer --使能预取指缓存*/  ; o1 v1 E# ?  H- k. `, G7 V
  17.     FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);  ' D) W3 j# L( U; S  V6 M
  18.     Dma_Init();  
    3 l  @/ M2 ^* h0 S) M. C+ W0 z4 \- M# J
  19.     /* Get Current Data Counter value before transfer begins */  
    / U; }) B( i( X# A8 ~
  20.     CurrDataCounter = DMA_GetCurrDataCounter(DMA1_Channel1);    //返回当前DMA通道x, 剩余待传输数据数目  6 c; l% S% ^: S0 I( Q; q
  21.       ' w- T) I+ M+ T" e* s3 [  s
  22.     while( CurrDataCounter!=0) ;  + {5 W4 c/ U5 e+ r/ D
  23.     judge = memcmp(SRC_Const_Buffer,DST_Buffer,BufferSize);  
    $ s. ^3 c! a4 T# i+ ~
  24.       
    - y$ \/ Y: S3 \8 y1 {% [
  25.     if(0==judge)  
    . _4 `) b5 @6 j/ U$ r2 U
  26.     {    Q8 Z) b6 ~# |7 p) q5 T2 R
  27.         USART1_SendData(" Same !!!\r\n",sizeof(" Same !!!\r\n"));  0 E! A$ ?! W) T
  28.     }  $ n& _7 f, D& |4 {! j4 M! w+ y
  29.     else  - W  l; C2 F+ k( K9 a# b0 ?, ]
  30.     {  6 L3 ]( D* P" O, C
  31.         USART1_SendData(" different !!!\r\n",sizeof(" different !!!\r\n"));  
    : X* }" `1 l" g" R9 e) H! ^1 e
  32.     }  
    , T+ K3 l! x; o9 S+ o
  33.   
    6 v* e: I" @6 k3 j. n9 E, D7 P$ D) o) F
  34.     Delay_ms(1);  + [: Z" W% c: R# c! B; P
  35.       
    & o3 f9 U% N% \" q4 L0 V( }% `" {# E  f
  36. }  
    4 b2 V5 w  l( T3 J
复制代码
五、测试验证
8 U, K: ^# w0 L5 B5 l7 }6 r* Z# K$ H- M; p% C( T! r
1.我们先看看看下图
3 Y# O. K" ]+ W: I# {6 r( g; |5 h8 D/ F3 i
3.jpg 6 Z& G. D* [3 M/ K1 c& s0 I

( m) z1 m4 {) N  S) J! ?" O" Q看点0:
, J/ Z; m' Q/ w$ v3 ]' @2 G+ e/ L8 w7 r+ b& c1 ]+ V4 q; W) b- d& P
问1:* u& w: V9 M2 K+ S7 E4 o
" r& t" H3 b; Z: h& ?
使用内存窗口观测SRC_Const_Buffer和DST_Buffer所在的位置,可以发现SRC_Const_Buffer
& i2 G4 O9 }& s" S0 |; U7 R. T& `% N0 ?. e, k, F
地址为0x08001B24,,即Flash中;DST_Buffer地址为0x2000002c,即RAM中;* p/ X& f" i7 x8 i3 q2 i9 S
3 X3 t$ s# e, X' Y5 ]" e) r. K6 [' ^
答1:
5 ~; H) J" n5 U; V5 F5 [9 J' }( t  o0 t3 m3 l7 w
不能改变其值得变量(包括全局和局部)都是存储在FLASH中的,能改变的都储存在SRAM中" s: X2 o4 ?* {6 k% k' q0 X# o$ P

) M2 b- f( j; |& mSRC_Const_Buffer  的定义:uc32 SRC_Const_Buffert. B# \7 Q4 x1 ]* a2 B" Q
! p% E! @7 C; _! l9 P
搜索了一下uc32的出处----/ Z1 I" e( U" H, c% e4 d1 G

( |. A. k* ~  U) _typedef const uint32_tuc32;  /*!< Read Only */  
& l  [5 B: |/ p- Z1 ]' d& w, V& v3 ^( A9 N$ D
DST_Buffer 的定义:u32DST_Buffer[BufferSize];; I( b; X' }' k  i
9 Q. v$ Y( Z5 V: S! O) [" {9 c
搜索了一下u32的出处----
! K% \( j/ W) d7 B$ R$ X0 G$ {6 o1 h' I+ R
Typedef uint32_t   u32;  # W9 C3 l3 ~' e

. U! m4 r3 u5 T; o# ?看点1:断点设置开始DMA传输前,
$ O1 y: f% j  @9 x. @( J" j# ~2 r  E
- x# S( Y; p- A7 U2 E$ jCurrDataCounter = DMA_GetCurrDataCounter(DMA1_Channel1);可以读出待传输的数据长度为0x20=32 跟我我们定义的待传输的数据长度是一样的;  k, h& p1 s- y0 y, z" h

) i$ \! E# M1 s/ s8 ~" F看点2:开始传输前,目的数组DST_Buffer里面的全部为空即为:0x00;
' t0 L% p) r2 a7 R6 ^  y& c0 X/ c. v- `
2.传输完成时,CurrDataCounter 值已经为0,即待传输数据为0;同时目的数组 DST_Buffer 已经有数据,我们用对比了一下源数组 和目的数组 相同则返回0; 证实了是相同的;
5 U. W) s. D3 J, n) O! B5 E
% Z0 K( m0 J1 T  ?- A6 z/ J% R 4.jpg ( O& m0 E2 ~# E- K8 w

' C$ o' y0 b& a& |6 C: j3 m
; j; I( m0 Y0 z" f" q6 ~  W/ C* |# U7 F2 S1 [

8 G) H6 p0 Y# m) a6 P# I& ^) s) q8 D* |& z/ @! O
转载自yx-l128125
% ^. i, P2 d" N, v; m2 u% k+ T
+ ~: O% m: O7 ?5 r5 A9 e; m! L  L, O) ?/ E% u
赞 收藏 1 评论0 发布时间:2018-5-24 11:22

举报

0个回答

所属标签

相似技术帖

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