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

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

[复制链接]
STMCU小助手 发布时间:2021-9-7 17:01
一、为什么要用DMA?9 I2 Q; q, C6 i
' N" j+ A& @" D

- h: f7 G& ^, m0 c) [4 J' TDMA  全称:Direct MemoryAccess 就是可以直接内存存取;% A$ ?6 v0 ]3 C( B1 w2 [) D
正是它可以直接操作内存所以具备以下优点:
# ]* k' |" c* F  R3 _; c而无需经过CPU去操作内存的存取,这样可以解放CPU出来干其他的事情;8 _. R  e, O( A1 y7 P
因为他可以进行存储器时间的数据传输,而不需经过cpu,所以大大加快了数据传输速度—是一种高速的数据传输;0 j, E5 Q2 Z0 g& [
# _5 A. x2 ]0 r: M
二.DMA有几种传输数据方式:: M* S* E4 g8 U5 u  w
(1)内存到 内存之间的;即:SRAMßà SRAM% w- ?  f' |" M1 T' V
(2)内存到 外设之间的;  (例如:串口收到的数据 从数据寄存器 à 内存)
( B2 [. P; n# |) E5 p' c* c(3)  外设到内存之间的;. D, k5 p0 u2 v/ S% ~: O
+ u' S; X+ z8 Z) t( M
三.传输的数据宽度是怎样的,数据是什么样的形式传输?DMA 能传输多大的数据量?, a  N8 Y) l! o6 i" D& ]* Z  o% a

1 s4 _$ h0 c8 ?7 q; o$ L4 Q  G* i
; K8 e  H$ C" ?' n$ \
A. 数据源地址到数据目的地址 传输宽度或者说传输数据的形式,有几种:1)字节;2)半字;3)全字 [1字节=8bit  1半字=2字节=16位   1全字=2半字=4字节=32位]
- K( \( l- Q* f: |4 D# k) ^5 x6 U* m) a4 p

1 h# H* t! @: W  \B.传输的最大数据量是65536
7 \/ v1 }1 K. X0 O9 G- i
9 u' W& \* J" I% B8 i! F5 g我们来看一下stm32f103ve的数据手册第九章DMA 大概的了解一下DMA的特性:
4 C/ B$ t( R& j: {  p* E" n+ {& ?7 C" E+ |. |

" x$ k# o* W( C/ G% I% P" l四、怎样配置软件来使用DMA?
: R# @# }* T/ `: A7 I- T, T" m( s9 N
9 R: _) d$ l/ S: B9 U
; E: O7 W( U& S: c
(1)配置dma
1 ~1 P: }7 _# P# x8 u
( j9 c/ x3 D7 k( e) S  X2 c. H# L

6 E6 w( B1 Q0 i/*****************************************************************  , n, k: X5 g% ]' y1 n
*函数名称:  Dma_Init  
# `# ~0 E2 Q4 |/ r. N' M*功能描述: 利用DMA 把内存的数据 传输到flash 达到高速传输的目的
2 c( V- O1 t! Z2 d( T*   8 e" X7 ~! t' ^1 J- T
*输入参数:无 7 v$ X! }: u& Y8 [) e1 m
*返回值  :无: Y7 K: Z8 U0 X% K) v# c+ R/ x) m
*其他说明:无
, W" d  @' s8 E1 G9 z/ j2 j*当前版本:v1.0  * T. i; q) Z5 {1 y$ A! {
*作者     :尹宣 . |  z0 O2 m# ]7 z2 P/ [
*完成时间:2013年12月1日
8 k( T6 L7 Q7 Y*修改日期        版本号        修改人        修改内容 ; y+ v+ E- {* r
*-----------------------------------------------------------------  
: ~" J: T1 j, T& X' R: h*  + g8 X$ a' j: K- r  U
******************************************************************/  6 O: S- g7 v- Q  B0 l$ G
  1. void Dma_Init(void); v  I. |: |8 d1 [6 i, Y
  2. {
    2 D+ r, z% }9 n
  3.   DMA_InitTypeDef  DMA_InitStructure;
    1 L7 s: G7 t4 w- f
  4.    
    , @* d$ @2 Z1 |
  5.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    - y# U7 K' ?5 i3 K2 U* Y! j6 i# j
  6.     /* DMA channel6 configuration */
    . G8 h- g+ _) K  p
  7.   DMA_DeInit(DMA1_Channel1);
    # ~2 W; R% p  ]; k* |; {7 i8 m8 Z
  8.   DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_Const_Buffer;            //外设地址
    % x3 ]- F1 O+ I; w. X
  9.   DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DST_Buffer;                    //内存地址
    $ E( f2 O/ f( k6 Q: q
  10.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                           //外设作为DMA的源端     DMA_DIR_PeripheralDST;   //外设作为目的地址
    3 M0 B2 X' l. K# t2 o
  11.   DMA_InitStructure.DMA_BufferSize = BufferSize;                            //传输大小
    * U6 i- S; ^- j; S9 k; f% Z
  12.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;            //外设地址增加. l& K, j$ y3 N5 b. M
  13.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                    //内存地址自增使能- N& l- R  ~% \& n% J
  14.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;    //内存存储方式:字节  DMA_MemoryDataSize_Word;//字(32位)
    + {( ]9 h8 |, \0 J/ U) x
  15.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
    2 z$ d' A% W* F
  16.   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;        //DMA_Mode_Normal 正常模式,只传送一次;  DMA_Mode_Circular:循环模式,不停的传送;" Y3 W( w& H& f) Z* q9 w: Y: `
  17.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;, _: e7 q' D  l/ @& y1 D) l( z1 B; e5 ]& H
  18.   DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
    ' ?5 g- B9 ?* w# t# r
  19.   DMA_Init(DMA1_Channel1, &DMA_InitStructure);  l. m/ i' A) c( E7 u+ ?  P

  20. . @, c) r/ f* ~* Q; h  m4 u- M  I
  21.   /* Enable DMA Channel1 Transfer Complete interrupt */
    & Q; W1 d+ Y" \: T- D' {
  22.   DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);* N, v! K$ c0 K9 Z; Y6 `7 d  i
  23.    
    ; h5 n+ i! Y% I( j- M5 J1 K* W# p
  24.   /* Get Current Data Counter value before transfer begins */& G: `# _: r, K" C/ i, k
  25.   CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1);; x* B/ S+ G: I- N) u. ~7 c4 V
  26.    
    ( r& B, t7 j9 ]7 P0 i% g: D
  27.   /* Enable DMA Channel6 transfer */0 P6 O( y5 H. Y: D  S
  28.   DMA_Cmd(DMA1_Channel1, ENABLE);2 l5 B4 c" _  V
  29.    
    - a! K3 e, U! h- A
  30. }
复制代码
2.设置DMA优先级
8 H! o& e& ?5 H# Y3 y, B9 @. }  r, Z+ m+ {& y7 b+ x1 Z

# ^  O4 Y* Y9 O/*****************************************************************  
, ?! L4 M& w. y% K  C" ]) V*函数名称:  NVIC_Config  ) y: {6 P- |5 m1 w
*功能描述:    配置DMA的中断优先级
3 O$ {) g9 E+ H0 N$ x- x! B*   
- n" W2 `1 ~- f0 e*输入参数:无 ! I( A6 m+ V- C( s$ D
*返回值  :无
8 X! k  b8 v3 m1 f*其他说明:无3 h; k  d$ Z4 N
*当前版本:v1.0  
- Y- r5 l9 j0 z*作者     :尹宣
. Q8 G! a* U6 z4 h0 a*完成时间:2013年12月1日
+ p" P( u; l0 w*修改日期        版本号        修改人        修改内容 " d& P# Y4 n" S* m& u& I& t$ w
*-----------------------------------------------------------------  
! C. \) k. \6 y' ^*  2 A6 k4 B! d% q: e* n
******************************************************************/  
; J" f/ {4 \$ H& `) R% X
  1. void NVIC_Config(void)
    / }7 p& a' _2 X, K; @
  2. {1 P6 r6 c! P2 `8 J' p8 q' m! I2 h
  3.     NVIC_InitTypeDef NVIC_InitStructure;# @6 R/ P  h2 `; f# K- z0 c
  4.    
    ; ~3 T# K3 H- {4 X" v- R/ L
  5.     /* Configure one bit for preemption priority -------------------------------- */. H/ G' u; i' y3 `
  6.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);+ a* J. Q. Q4 J; r8 Y

  7. 5 ^1 u  Z0 V0 i7 P
  8.      /* Enable DMA channel1 IRQ Channel */
    6 H  W1 C% k0 R
  9.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;# f9 `, J& R7 k$ n
  10.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;3 M+ `8 ?+ h+ X2 \
  11.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    8 S7 z' u; O' [' |$ m0 b3 H
  12.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;: c0 m2 M" d8 N# c+ z
  13.     NVIC_Init(&NVIC_InitStructure);
    ! I4 G0 I  y3 C, L! Z9 m
  14. }
复制代码
3.在stm3210x_it.c 文件中添加 DMA中断处理函数! S/ r- k5 y" d; x3 D1 J

( ]7 ^. w) w, P, G( H
: b5 G! C2 V0 h7 ?+ z( [7 k" M9 d
/*******************************************************************************8 _2 k9 _7 z2 w1 @" v9 @* p
* Function Name  : DMAChannel1_IRQHandler
# g3 I- t+ ]  k* Description    : This function handles DMA Stream 1 interrupt request.
; [3 P% e  F! Y6 @$ X* Input          : None$ c3 p0 x& J. L4 F" W. r
* Output         : None, k- H6 J3 Q6 `7 _& z
* Return         : None
0 P( ~1 u# p; r9 F# q*******************************************************************************/4 \/ e! V7 h' Z
  1. void DMA1_Channel1_IRQHandler(void)
    2 i; c* A7 ?! _- a6 \7 ]* Q9 A
  2. {  , \' D* H1 Q1 I. w3 v5 a
  3.     /* Test on DMA Channel1 Transfer Complete interrupt */5 ?7 h9 |# \- Y8 O$ C8 |  o
  4.   if(DMA_GetITStatus(DMA1_IT_TC1))        //DMA1_IT_TC1:通道1传输完成中断
    ; S1 E  G- l; r
  5.   {
    2 J, s4 F6 s" n5 x- r
  6.     /* Get Current Data Counter value after complete transfer */
    ( Z9 y$ t+ d# ]' h; R
  7.    CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1);     //返回当前DMA通道1 剩余的待传输的数据数目4 Z( V8 S3 d& f: d+ B% A5 G: n" H
  8.     /* Clear DMA Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */% u* X1 o- s6 b8 p
  9.     DMA_ClearITPendingBit(DMA1_IT_GL1);        //清中断1全局中断
    - M" I7 q0 m" |* ?% F) D
  10.   }2 H8 e. Y* S+ W- ^$ w4 w: I0 {1 q: d
  11.     4 F8 q# B6 V, n% n' D8 \8 ^3 O2 c
  12. }
    5 E/ A2 `1 \1 f0 F: S& K

  13. ; R$ S& S# F* g; B
  14. 4主函数部分:+ U: d$ V# C2 B; d

  15. - k) C/ A& @3 v( e
  16. int main(void)/ ^' Y* }+ c5 t1 ?8 d
  17. {   
    / [+ R! m: C% o. m8 s. K6 z. Z
  18. //     int count;
    " }  C) _3 u. P4 a( P
  19.     uint32 judge;
    " B- _! ^, i) ^+ [- l4 l, s
  20.     9 Q! |$ I5 n- P6 `. D6 O
  21.     NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x00);  // NVIC_VectTab_FLASH=0x080000005 v! g# r0 L% z; z% Z6 o/ x1 u
  22. //     RCC_Config();
    " |. O* k. L4 i; `' r/ c
  23.      SysTick_Init();* A7 H" y( L* Q8 n: r- K6 o5 d
  24.     GPIO_Config();
    % E! b$ ]  _% t& l4 f7 b
  25.     USART1_Init(19200);    6 ^5 u) ]3 H/ K' @0 ]2 ]" @
  26.      3 e; a. Z0 D( ?4 J* J
  27.      NVIC_Config();
    ! b7 w, M# Y% m, Z( g( L
  28.    
    . D& A( v0 F' ?! T, F
  29.     FLASH_SetLatency(FLASH_Latency_1);            //延时2个时钟周期
    * h& Q( c+ M% }4 r" f5 B
  30.     /* Enable Prefetch Buffer --使能预取指缓存*/
    6 o3 q% {) t$ W  j1 [' T- w
  31.     FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);4 M2 F1 j$ N1 d
  32.     Dma_Init();! Y- i4 L9 f5 z; S; S) A* e% G& o) ^
  33.     /* Get Current Data Counter value before transfer begins */" y8 V( A" P5 K
  34.     CurrDataCounter = DMA_GetCurrDataCounter(DMA1_Channel1);    //返回当前DMA通道x, 剩余待传输数据数目
    # ~. Y( o8 e, c0 K2 ?
  35.     , q* H: {7 y, t8 l
  36.      while( CurrDataCounter!=0) ;
    0 p& l  X9 [! E; o) [
  37.     judge = memcmp(SRC_Const_Buffer,DST_Buffer,BufferSize);" q# k7 h4 p1 }% K1 H1 |
  38.    
    # u$ a! x0 x& X+ X1 [; @* K& i
  39.     if(0==judge)3 c" u0 ]% o0 d! |; z7 u
  40.     {
    6 C$ C- z; V% R6 x% ?9 `6 W
  41.         USART1_SendData(" Same !!!\r\n",sizeof(" Same !!!\r\n"));
    ' U" w1 H6 @; E7 n# i
  42.     }
    - M! m) _. s. g8 z
  43.     else
    : f/ r" ?& L% p8 F
  44.     {/ |" e; P( K6 B, ~" k* c) p
  45.         USART1_SendData(" different !!!\r\n",sizeof(" different !!!\r\n"));
    # K& F+ ]3 T  ?* I  F' A
  46.     }
    * y2 A4 n) o: K! G) q) V
  47. % O$ B* f) j, d" ?7 T1 L) n
  48.     Delay_ms(1);# }$ r, _% ?4 Q* A
  49.    
    , Y( |( {( a9 v) a) U  `* {4 T4 x
  50. }
复制代码
五、测试验证
1 F7 V4 @$ p6 v, k/ q3 A
3 J' T( z5 n  r$ n2 Z' H
; D- b, ]( z7 S2 j
1.我们先看看看下图8 p: d. N2 Z- W: [
+ V% s9 V" _; M8 ^3 l1 M$ V7 B

# I9 w0 Q' G3 ^; c6 b. J看点0:
3 t. o2 s& ?4 U; i& g; R" I$ h& k$ @3 |7 c5 j3 W
+ G3 T: l/ _8 \) E
问1:
4 m, F1 c% S7 C% Z% `2 ~         使用内存窗口观测SRC_Const_Buffer和DST_Buffer所在的位置,可以发现SRC_Const_Buffer% `, V& U. e5 T. m
5 t8 r/ |  Z0 S) j, B

' k' H3 }& l# O9 U地址为0x08001B24,,即Flash中;DST_Buffer地址为0x2000002c,即RAM中;, A2 e3 d# X+ Q, m
2 N3 X+ s6 d- P. o* p
答1:
! l. D; \( x6 Z! |  w! q% S
% k1 Y) O" C2 ^* t0 L2 `

' z+ P" T1 U9 H2 f不能改变其值得变量(包括全局和局部)都是存储在FLASH中的,能改变的都储存在SRAM中  P1 M2 D# o; x; ]; H3 G7 S/ l" v) D2 f

" U6 H; N* w. d) b7 b
: J1 c$ E8 X8 f0 Y+ {, R
SRC_Const_Buffer  的定义:uc32 SRC_Const_Buffert& T2 ^! @1 W0 J7 g7 s: K

8 W# s) L& i9 d& ?$ R

! `+ ~3 Q6 V. {, B1 n搜索了一下uc32的出处----! P  q+ z( H0 O% m) W; B  i
/ t, G" P. d# D: `0 M

. C) ?( D6 p/ j8 ?2 Q1 a0 b' xtypedef const uint32_tuc32;  /*!< Read Only */  
* I" e+ ?5 v5 Q! `. P/ s; B3 |, `# X4 ~( Q; |$ j
DST_Buffer 的定义:u32DST_Buffer[BufferSize];
8 e! F! o1 O6 Z) z+ o3 }2 v
. y5 E: [' o* |. G

2 M/ G( ~1 E, s/ x- h3 |. E. q搜索了一下u32的出处----+ a2 u" d5 s. b9 Q* E0 e; j( v: M
7 c* }  G3 L/ e; g9 h' k
. M+ ~. |4 c6 D' \
Typedef uint32_t   u32;  , @/ j2 A! H$ p; e  b2 c
' C7 `9 d3 O  y9 M- f
1 L! ]  r% G2 e2 t
看点1:断点设置开始DMA传输前,
$ u+ {" @5 `0 `% Q, f3 U: B% k6 b( n  g; R+ [  g2 u

  \( H+ p; w. }3 c& C5 KCurrDataCounter = DMA_GetCurrDataCounter(DMA1_Channel1);可以读出待传输的数据长度为0x20=32 跟我我们定义的待传输的数据长度是一样的;% B2 v$ v+ Y( N0 H  o1 G" d2 u

8 K& ?9 R1 s1 _6 ~# j
, ]# {0 K. i8 c0 j( @1 i
看点2:开始传输前,目的数组DST_Buffer里面的全部为空即为:0x00;
+ z9 p6 k: K0 z- F8 T/ @4 P5 L! O4 n! D+ m" U7 U
' g$ ?* j0 {2 y0 ^9 v
2.传输完成时,CurrDataCounter 值已经为0,即待传输数据为0;同时目的数组 DST_Buffer 已经有数据,我们用对比了一下源数组 和目的数组 相同则返回0; 证实了是相同的;
; n/ X* p: X4 a* u
  W! g) i3 J& z' |7 M5 a. Y% w
0 v8 f% Y; f" S1 s/ V8 O
2 X' [+ {  s& J1 ]/ z6 U

8 V3 f/ B% J: q% N, h

, B9 D; |2 }& W
) z7 u* R9 T, ?. ~

) j" h. J% O! X7 o: s3 [) ?* o
( R( q) D6 ?  r7 Z1 `9 ^1 m
  r" w! T7 f# S$ q

7 z$ o  q) o% ~
' V8 e& K7 s6 r2 N7 ]
% l, P7 `* X- f. w
赞 收藏 评论0 发布时间:2021-9-7 17:01

举报

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