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

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

[复制链接]
STMCU小助手 发布时间:2022-5-23 22:00
一、为什么要用DMA?: v) C7 ?. Y9 k. P, b, P7 H: Q

9 ^) h( x1 R' k! L: \( j- PDMA  全称:Direct MemoryAccess 就是可以直接内存存取;
0 P. {# x, H; _1 y
" M% g& `, U( j正是它可以直接操作内存所以具备以下优点:
; i# F" k2 F2 Y5 Z( e
2 s4 V' q1 }4 [) U6 d% J而无需经过CPU去操作内存的存取,这样可以解放CPU出来干其他的事情;! t2 c  Y6 S! K# J- J
+ f3 p. Y9 V6 m+ G& o6 \' ^
因为他可以进行存储器时间的数据传输,而不需经过cpu,所以大大加快了数据传输速度—是一种高速的数据传输;
2 c) L) @4 k! m% ~1 _& E. Y
8 {2 _/ J- J+ E, b8 e: S; O' m- e. C0 R3 k
  C6 h5 ?( j1 B1 M
二.DMA有几种传输数据方式:
7 f% O# \/ ?. t( S; Q/ K' u
% A- H1 g; A2 s: v; {9 z# y(1)内存到 内存之间的;即:SRAMßà SRAM# L% n! w/ G+ h6 Q7 E% G* G* q

: z( \5 s' f' u% W8 v(2)内存到 外设之间的;  (例如:串口收到的数据 从数据寄存器 à 内存)
/ J# p1 d* N) t. g9 }* L0 U* Z9 c: @( D: m. g/ D
(3)  外设到内存之间的;
3 R" ^& |+ S3 @  F& M5 X& a& l8 ~1 S+ K
" c- m% @0 N2 M! Y$ Z% }

+ F' w* a, y, w* W' U- y$ M三.传输的数据宽度是怎样的,数据是什么样的形式传输?DMA 能传输多大的数据量?" I/ t- _  K4 g: l7 |
4 U6 S# V' d$ E+ b' {0 g, r
A. 数据源地址到数据目的地址 传输宽度或者说传输数据的形式,有几种:1)字节;2)半字;3)全字 [1字节=8bit  1半字=2字节=16位   1全字=2半字=4字节=32位]. X/ A' m: @% t1 y7 Q' W5 d  s
6 a% U) P5 d# k2 p3 W, d
B.传输的最大数据量是655363 ~/ y' O8 {( A
6 N$ D  c) F! B1 X
我们来看一下stm32f103ve的数据手册第九章DMA 大概的了解一下DMA的特性:
1 E  ^4 I- d! I. y5 b
* X$ g2 t# \# i) I ZO@F)_D~6_8YIME1$EGPMHU.png
) t- O9 W* z; u) r( h# [ 95L}{3S@Y%KG%{9BZOP4XLU.png ' |5 p& F9 b" M  m7 L

- q' A6 O* T+ @& v- T$ I  w* x8 R# p/ j) P$ l3 |
四、怎样配置软件来使用DMA?
# K' v& a) d; q: I8 K3 L
0 s4 g& x& s7 }' m. q(1)配置dma' n' H: z, N7 l( ^2 ?
, E' j$ E4 `3 S5 z4 c4 `7 h/ v
  1. /*****************************************************************  
    & M; w* B7 l- g& M9 G5 C/ I
  2. *函数名称:  Dma_Init  % P! e' M+ \7 R2 `: x" c: E
  3. *功能描述: 利用DMA 把内存的数据 传输到flash 达到高速传输的目的/ z9 z7 Y9 I% Q+ V# ]) m4 _" h
  4. *   6 t7 P& v6 |5 _+ L% j
  5. *输入参数:无 " G3 \* H' S. q$ g. A
  6. *返回值  :无
    3 {( c! l* k/ g( |$ h  X8 X2 L
  7. *其他说明:无
    1 H+ `* f% ]  B. X3 c
  8. *当前版本:v1.0  6 F% B% E6 P" C- X. h+ K2 `
  9. *作者         :尹宣 + I/ x" O/ J2 {, e- ]/ p4 `
  10. *完成时间:2013年12月1日 2 c% {. t8 \' t
  11. *修改日期                版本号                修改人                修改内容 ! t# O3 _1 g% T' d/ y, Q0 Y
  12. *-----------------------------------------------------------------  
    1 `9 F. {+ ?  C" |  w+ h
  13. *  4 X* m- U; W' u$ m' o
  14. ******************************************************************/  # d" q$ j& d3 m" [( K
  15. void Dma_Init(void)' O7 ^' v" f) a0 I" E0 h4 l
  16. {4 l- l+ y( J/ s, i. L$ j. h
  17.   DMA_InitTypeDef  DMA_InitStructure;
    5 N1 K- B0 K: W+ B7 c$ |
  18.         
    1 x- m+ b& `0 m) W- r2 y4 l
  19.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);* ]9 I1 z% t, t- ?( a6 c
  20.         /* DMA channel6 configuration */& Z$ l( ^* `" y7 {
  21.   DMA_DeInit(DMA1_Channel1);! C+ q4 z2 G9 _- b5 z) s
  22.   DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_Const_Buffer;                        //外设地址2 M, X; i* t, b" `/ ]
  23.   DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DST_Buffer;                                        //内存地址
    8 x& o/ A" A* Z! i/ A' E7 x( c
  24.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                                   //外设作为DMA的源端     DMA_DIR_PeripheralDST;   //外设作为目的地址 . W+ a2 P& y) E) V( r
  25.   DMA_InitStructure.DMA_BufferSize = BufferSize;                                                        //传输大小
    4 H# R" I4 n: r1 k
  26.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;                        //外设地址增加2 Q5 M7 }/ V0 a" J+ `5 y% i
  27.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                        //内存地址自增使能
    , V- s5 K# m! M0 P
  28.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;        //内存存储方式:字节  DMA_MemoryDataSize_Word;//字(32位)
    , J+ q' k: f6 p  g
  29.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;: F  v2 T, F: ^% H/ A* y# u
  30.   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                //DMA_Mode_Normal 正常模式,只传送一次;  DMA_Mode_Circular:循环模式,不停的传送;  @- E( `) u# M1 _7 Y
  31.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    " k* K# Q: C8 T6 ?; \
  32.   DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
    8 a$ O4 x7 s& C, j
  33.   DMA_Init(DMA1_Channel1, &DMA_InitStructure);% _& c# c) V0 n8 D, i

  34. 3 V# t2 c9 X$ |, G" Y, c
  35.   /* Enable DMA Channel1 Transfer Complete interrupt */
    3 [+ `/ s$ d& J4 {1 y# L8 @3 q. _  d
  36.   DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
    + P2 U% L4 z$ k3 c$ P
  37.         3 x1 h- Y/ k$ q* V/ u! i
  38.   /* Get Current Data Counter value before transfer begins */  {- J6 j: @- ~( G
  39.   CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1);, q3 F3 p2 `, u) ]+ q. [  J
  40.         
    ( [3 a% m% L- g" g! d- z/ \
  41.   /* Enable DMA Channel6 transfer */
    7 J" S- O3 D% y, `0 R
  42.   DMA_Cmd(DMA1_Channel1, ENABLE);
    % W. k2 D# H( y- {! C. d
  43.         
    0 h) F. n( t+ ^  G2 Z% h
  44. }
复制代码
. L9 g( |! _4 p. x1 p
2.设置DMA优先级, W& `% u1 T1 Y4 f8 c# v* `

0 S  {( @: C3 ?' \
  1. /*****************************************************************  : v7 [+ i  G; d) D& i2 H
  2. *函数名称:  NVIC_Config  1 B0 F5 H4 p4 J' Y2 Q0 a3 J' E
  3. *功能描述:        配置DMA的中断优先级9 I: \' ~4 M  u
  4. *   
    9 j4 W6 @9 N- E% E7 L
  5. *输入参数:无 . K9 m% L! {% H( K& Q
  6. *返回值  :无3 }" T9 X5 H+ S
  7. *其他说明:无0 T% i( s' [& U3 s# T3 D" I: C
  8. *当前版本:v1.0  8 M4 Z* ^( H. q1 ]
  9. *作者         :尹宣
    1 M# c( T( d4 R, S. Q9 A4 V: y
  10. *完成时间:2013年12月1日 . |& \  k; z1 _4 \/ O$ ]
  11. *修改日期                版本号                修改人                修改内容
    / f4 J; [6 k9 d5 f8 L' _
  12. *-----------------------------------------------------------------  1 p% a' y: B# C6 n. z( y
  13. *  5 t5 w' T2 W; [. q. p
  14. ******************************************************************/  
    0 S; Z6 N/ P! x/ @; a
  15. void NVIC_Config(void)
    - b* V7 F# t: U" z9 U( q2 Z
  16. {2 c8 |* O5 p7 a4 \! h
  17.         NVIC_InitTypeDef NVIC_InitStructure;
    " P; Q- e! S- g% L
  18.         
    9 q+ Q; k7 Z9 d6 H; Z9 H
  19.         /* Configure one bit for preemption priority -------------------------------- */* S' m3 [" \: L- \$ F
  20.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    ( \2 }5 q0 n$ M6 _

  21. ; q- @5 R! }9 R/ x, s1 q
  22.          /* Enable DMA channel1 IRQ Channel */
    7 e% w% k2 y) |
  23.         NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    # ]( R6 [5 o  q& r
  24.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    ' R% J1 ]% g; O3 I
  25.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    9 R% i+ d3 z& U
  26.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    ) o) I( ^* y0 U, p
  27.         NVIC_Init(&NVIC_InitStructure);# w3 F2 e5 ~; F1 x; F0 \
  28. }
复制代码
. p+ R) q1 Y9 m' A. I- m5 C  R
3.在stm3210x_it.c 文件中添加 DMA中断处理函数
/ Y% {5 Q0 ?' ?! [1 I2 v0 V6 |% T/ Z! X) ?/ N
  1. /*******************************************************************************
    " U. y0 H' G  j, d; I
  2. * Function Name  : DMAChannel1_IRQHandler
    7 B- |- _& L+ N/ Z; m
  3. * Description    : This function handles DMA Stream 1 interrupt request.( j+ K; S7 ^0 Q2 n
  4. * Input          : None
    9 h% u5 f+ Q: B; z+ H" J) b
  5. * Output         : None
    8 k8 V' N0 t# U4 H6 i8 t9 s
  6. * Return         : None
    * [8 ~; V- q9 N5 n& b; [
  7. *******************************************************************************/
    6 Y& \1 r0 l' J! c# z
  8.          
    5 L0 [; o- ^4 p; I
  9. void DMA1_Channel1_IRQHandler(void)
    ( `9 P8 x$ a4 S- |9 e2 e
  10. {  
    3 @& O/ f7 \+ @4 ^! l6 L  i
  11.         /* Test on DMA Channel1 Transfer Complete interrupt */
    # w: W: ?7 [8 ]; I( {
  12.   if(DMA_GetITStatus(DMA1_IT_TC1))                //DMA1_IT_TC1:通道1传输完成中断
    1 O' D& T  p% U+ q' W1 e
  13.   {
    2 v6 C8 o% E, h" A9 Q
  14.     /* Get Current Data Counter value after complete transfer */
    : Q, B- ]9 f" K+ Z( `& v- l# w- L
  15.    CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1);         //返回当前DMA通道1 剩余的待传输的数据数目
    ' o( q9 W8 u8 x& t
  16.     /* Clear DMA Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */
    7 p$ k! K6 d7 v; a3 \
  17.     DMA_ClearITPendingBit(DMA1_IT_GL1);                //清中断1全局中断
    # h- m! D' d! L
  18.   }1 _/ Y/ ]1 Q( W9 u; p
  19.         
    0 o( O5 P$ ~8 N( O, K
  20. }
复制代码

  l0 R- j7 e& A# o1 W( B5 ]7 w4主函数部分:# Z# ?0 H( F. `% [8 e! g4 ^; G' |

9 p( P/ u/ `$ `* E
  1. int main(void)2 l6 Y7 F  f1 t5 [
  2. {   % X7 P8 Z6 D, d9 D
  3. //         int count;
    ( i6 f4 n/ u- |' C
  4.         uint32 judge;
    & D3 @! F: {# f0 R7 O
  5.         8 Y& K! K! v" g. A; G1 A
  6.         NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x00);  // NVIC_VectTab_FLASH=0x08000000+ l+ T' [7 t) n% m1 f: H
  7. //         RCC_Config();3 ^( ~0 }6 D* D, Q: S
  8.          SysTick_Init();
    6 t) P& A0 U6 J) A" _" X
  9.         GPIO_Config();4 [+ r1 ^# l% B
  10.         USART1_Init(19200);        
    " g6 c* G1 A- O
  11.          + k. @5 \# A- D" d5 R4 {
  12.          NVIC_Config();
    ; @: u. r1 `. j; P8 F/ Y3 s
  13.         & U6 C7 a  {  M. D1 {7 h
  14.         FLASH_SetLatency(FLASH_Latency_1);                        //延时2个时钟周期2 e+ Y% @  u; n1 o0 d2 T) w
  15.     /* Enable Prefetch Buffer --使能预取指缓存*/6 }) d7 }5 K- W0 H6 ]/ J1 J0 g$ i
  16.     FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);  z% @. _) o  C- T. h  L- O% E
  17.         Dma_Init();
    6 |' O7 X( s6 L
  18.         /* Get Current Data Counter value before transfer begins */: v' R5 m. o* c1 X8 O. O3 M
  19.         CurrDataCounter = DMA_GetCurrDataCounter(DMA1_Channel1);        //返回当前DMA通道x, 剩余待传输数据数目7 R5 D- Q7 _, [2 |
  20.         " b8 O( `4 r/ k* ?5 F
  21.          while( CurrDataCounter!=0) ;( K2 z2 g6 X& q2 r5 b$ F- E; X
  22.         judge = memcmp(SRC_Const_Buffer,DST_Buffer,BufferSize);
    & @3 T3 X, p, @5 e
  23. - \5 e1 z. T+ @, [
  24.         if(0==judge)( G& @- C0 d3 c' U' h1 h
  25.         {
    / R0 Y4 s. p! y
  26.                 USART1_SendData(" Same !!!\r\n",sizeof(" Same !!!\r\n"));$ y; ?8 N+ v$ b! N5 f
  27.         }
    ' j" W9 H! n8 ^: c
  28.         else
    , u7 m1 p) |! W& N
  29.         {
    7 x; n$ |# n; |9 U" U
  30.                 USART1_SendData(" different !!!\r\n",sizeof(" different !!!\r\n"));3 z. X6 [) v9 X
  31.         }& X9 _/ `3 e3 n& W% P

  32. , k  d: A4 G. h  Q
  33.         Delay_ms(1);
    4 |; C% }4 x# k+ p# h7 T* E4 [
  34.         + o8 C6 X4 H, v3 ?0 ?) }
  35. }" f. k* V' ?2 x7 B" Z& p+ K
复制代码

4 W+ X+ G7 n  i五、测试验证
# Y( C7 Y. E  L/ X( Z- Z9 n- d
) N( M, l& ?& o( R# s# t
1.我们先看看看下图
8 x$ O4 }; N5 |: u: K1 m# S: [
20131206104544015.jpg
0 b+ p% Y- F6 P) Q5 j$ ~; z
$ _! V* H3 m+ ^: }) E看点0:+ P9 G% A3 F! [8 {( J. Q3 K7 e* \
问1:
0 ~# c. i5 w9 A: q" H! z. L2 e" M- M; |
         使用内存窗口观测SRC_Const_Buffer和DST_Buffer所在的位置,可以发现SRC_Const_Buffer# K1 e4 F. y  X
; P5 @* t0 }- S6 Y& I
地址为0x08001B24,,即Flash中;DST_Buffer地址为0x2000002c,即RAM中;" B5 P. g1 [' G
6 _- A* U4 |+ F( L( g4 [
- q8 a( I2 u% _' R3 E" w4 L

: F# a" |& x( S* I. y; ?答1:
! k9 U3 W/ R+ d/ ?8 X* d, n4 ~
* O; k- X& U% `2 K不能改变其值得变量(包括全局和局部)都是存储在FLASH中的,能改变的都储存在SRAM中2 X/ o- Y% O6 N
2 X# o! ]# P8 \) W
SRC_Const_Buffer  的定义:uc32 SRC_Const_Buffert
# M( E9 w& [* n9 K, W) I; ~; k( F6 b% w2 z/ F6 D5 T& \
搜索了一下uc32的出处----& {  {, i) _6 j# s+ _4 x# D
( G9 I- d2 ?( Q* [$ G
typedef const uint32_tuc32;  /*!< Read Only */  
1 o7 v  ]7 l) J6 W5 Z
5 ~- f, b5 O! {+ t. R7 R& ^2 _
4 V8 |8 |9 b  ^6 W7 m& c* b# A
# |" P2 W9 N9 s+ W- |1 C. gDST_Buffer 的定义:u32DST_Buffer[BufferSize];
% i: M1 e* \5 c8 ]/ e7 r. }6 M" b$ R. W
搜索了一下u32的出处----6 h& E! ^! E- M8 M
2 W$ \0 d# [! {
Typedef uint32_t   u32;  9 t& k! Q( p6 U1 q# [

3 e3 E7 A/ @, \/ I
( L: y2 i/ g: |: R& h看点1:断点设置开始DMA传输前,+ b8 G' q9 V( m+ A' l
- G7 Z$ z' X9 W! P: _9 s" F
CurrDataCounter = DMA_GetCurrDataCounter(DMA1_Channel1);可以读出待传输的数据长度为0x20=32 跟我我们定义的待传输的数据长度是一样的;" y( V2 s: n) h0 c" ]. w' n3 i( e! D
/ @/ \9 C$ v' F$ h4 {+ J, c
看点2:开始传输前,目的数组DST_Buffer里面的全部为空即为:0x00;8 p1 V2 E# a9 q6 w. C) f. d- i2 A

/ m% A' n+ F3 B0 n  T  p
! R! |' l, ~. ~! s4 m2.传输完成时,CurrDataCounter 值已经为0,即待传输数据为0;同时目的数组 DST_Buffer 已经有数据,我们用对比了一下源数组 和目的数组 相同则返回0; 证实了是相同的;
- U* H( `' u! d9 Q3 Z' W* ^8 _0 y+ s9 @1 f! i
20131206104447156.jpg
" f/ I' Y( Q7 p( S5 e0 h( x* i: o# S$ _, t9 V( {& s

( S' T4 `6 z8 H) a) _6 m, w4 U+ C- s2 ^  D

; [8 o: B* r( i, I+ H# E
赞 收藏 评论0 发布时间:2022-5-23 22:00

举报

0个回答

所属标签

相似技术帖

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