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

【零基础学习STM32】第十一讲:DMA实验——存储器到存储器...

[复制链接]
kkhkbb 发布时间:2018-4-3 11:48
本帖最后由 kkhkbb 于 2018-4-3 21:17 编辑
0 ~" p7 @9 @; a" Q$ W+ J$ W
6 V+ ]' w6 F3 g$ z' \
一、概述:
4 q# y- }# d3 Q8 f
1、DMA简介+ X$ X; a% A6 U" x9 \
      DMA的英文拼写是"Direct Memory Access",汉语的意思就是直接内存访问,是一种不经过CPU而直接从内存存取数据的数据交换模式。在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样就很大程度上减轻了CPU资源占有率,可以大大节省系统资源。DMA模式又可以分为Single-Word DMA(单字节DMA)和Multi-Word DMA(多字节DMA)两种。
7 r8 x, m  T  m2 v- \% {: a
2、 DMA工作原理5 Z0 V+ G& r# _) G& _
      DMA 允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把他们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。
3 ~: i; f3 M$ @1 `1 L! F0 D5 h
      DMA 传输主要地将一个内存区从一个装置复制到另外一个。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存去。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。所以,DMA传输对于高效能嵌入式系统算法和网络是很重要的。, {, _) u( W/ x+ \$ s7 T
3、DMA类别0 [1 m1 D+ q5 o2 @" c$ ~
     按键主要有两种类型:单字节DMA、多字节DMA。  E" r7 q6 @$ k# H  A
        单字节DMA:一次传送一个字节,效率较低,但它会保证在两次DMA传送之间,CPU有机会获得总线控制权,执行一次CPU总线周期。
, E' c8 {( h3 [: v& d7 z
       多字节DMA:一次请求传送一个数据块,效率高,但在整个DMA传送期间,CPU长时间无法控制总线(无法响应其他DMA请求,无法处理其他中断等)。
二、实验原理:
      DMA(直接存储器访问)传输不需要占用CPU,可以在存储器至实现高速的数据传输。本实验采用DMA2控制器的数据流0,选用通道0进行数据传输。通过LED的颜色来判断传输是否成功。
三、源代码:
1.主函数及DMA设置
/ C, q3 L1 ]  ~8 M! U# I5 G
  1. /*! W5 E7 G) A, g0 ^
  2. * Name                : main
    5 Q& K. L! }+ @
  3. * Description         : ---+ w0 U# E) O9 m
  4. * Author              : ysloveivy.4 o6 f) D9 h7 K
  5. *( E- s% ?/ D* ]1 l
  6. * History
    8 s- l4 M6 g( ~3 {# l  f
  7. * --------------------
    & F3 a7 z" K" w- s4 _" u: X$ p/ U  q& J
  8. * Rev                 : 0.00. \6 n+ K9 e& b9 v7 Z
  9. * Date                : 11/21/2015
    , e0 s; H, y/ B! r( n( o/ o
  10. * 6 ^; f! C( N# T3 q" ~0 ?3 i
  11. * create.' ?( E: ?( f& M7 i; `* K# D$ V
  12. * --------------------+ r! t) a0 X& I# \  C
  13. */
      M/ H+ {2 O3 ?$ i  Z4 \1 }+ ^
  14. int main(void)5 L8 m8 }) b9 T8 ^
  15. {+ B1 i' Y$ F1 k. ~+ ^  m' O6 X
  16.         int i,k;
      ]0 z' H2 Z# m2 K: o3 y, b6 ~& [
  17.         DMA_InitTypeDef  DMA_InitStructure;
    + n% t6 Z. M( L/ J5 \
  18. ! M) e/ O- M: M0 n; S
  19.         led.initialize();9 k; C: S$ i4 M9 L0 x
  20.         dma.initialize();
    9 B3 u# c0 P3 }  R

  21. / Q/ m# i+ c  F3 v  }. k+ W
  22.         //测试DMA,测试成功蓝灯闪烁,测试失败,红灯闪烁
    % O4 {0 k- _. f8 q8 s
  23.         DMA_InitStructure.DMA_Channel = DMA_Channel_0;                              //选择通道0
    ' h; r2 l) O! p+ {( n7 H% ~5 f) V
  24.         DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned long int)src_buffer;     //DMA外设基地址0 w0 X; G* t6 }
  25.         DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned long int)dst_buffer;    //DMA存储器地址
    / [- D6 b+ U' \( ]: P: k  T
  26.         DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;               //方向为存储器到存储器
    ! J0 H8 o; |' M7 a/ @5 l
  27.         DMA_InitStructure.DMA_BufferSize = (unsigned long int)BUFFER_SIZE;         //数据传输量
    . ?" L6 z: t0 F4 A* e
  28.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;    //外设增量模式' ?& C  B/ s' L8 \4 F( \' u& d
  29.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                     //存储器增量模式: N! B- s  Q* k1 T
  30.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //设置外设数据宽度
    / i4 @; ?6 A, |0 N* `) B& [  a
  31.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;      //设置存储器数据宽度
    " M# d( a' ^+ K6 t2 a
  32.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                          //运行模式为普通模式' N4 X- Y" Z  n) _' S: h* e
  33.         DMA_InitStructure.DMA_Priority = DMA_Priority_High;                     //优先级级别为高
    ( I6 B* z  T/ u( o: m% J+ A1 E
  34.         DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                    //FIFO模式禁止
    ) t% O# Z% L/ v2 v0 v$ K
  35.         DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;        //FIFO阈值
    # \/ H5 e7 @. \# M" M! H
  36.         DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;            //存储器突发单次传输
    ! N& ?+ n0 m% t2 g5 r/ W1 V* W3 _
  37.         DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;   //外设突发单次传输. Q, P, i2 G/ b
  38.         DMA_Init(DMA2_Stream0, &DMA_InitStructure);% F4 C0 o# W' K, K0 d" f' ]6 @, e
  39.         DMA_Cmd(DMA2_Stream0, ENABLE);       //使能DMA2_Stream0                                      
    1 G! h) h+ i" h1 A$ L% _

  40. 4 a, \: W3 L$ T7 H; y; H2 t
  41.         while(DMA_GetCmdStatus(DMA2_Stream0) != DISABLE);' g! m& I' {4 D3 V7 o! X
  42. $ F# E8 _# j2 G+ i3 e
  43.         for(i = 0;i < BUFFER_SIZE;i++){
    # |# `, l8 Z. H5 v% n
  44.                 if(dst_buffer[i] != src_buffer[i]){/ m( ?* [- e: |4 v5 U' {: b
  45.                         //测试失败
    4 O5 h) A% ]* F8 ^& r$ N  g: f
  46.                         while(1){
    ! A# V$ b( j( f/ V8 f- m4 P3 i
  47.                                         for(k = 0;k < 10000000;k++);: V8 c/ Z" I6 t5 X, G  _; J
  48.                                         LED_RED_ON;6 a4 V0 p7 y. d$ V9 Y7 m8 }
  49.                                         for(k = 0;k < 10000000;k++);
    8 [5 @+ i! E$ N8 w$ K7 S- Y
  50.                                         LED_RED_OFF;7 J; G  i) B2 [, Q2 x. s& f
  51.                         }
    0 V" f* Y( w7 ]- W/ [
  52.                 }9 P8 b" i) Q- ~
  53.         }0 I: q% s7 c* \3 j. ^% f! h" q
  54.         //测试成功
    $ X" [! r7 |* y# ~
  55.         while(1){
      H* I9 B' t  H3 m+ V) H$ C+ @
  56.                 for(k = 0;k < 10000000;k++);& m# A+ {6 j0 g' I, a7 F
  57.                 LED_BLUE_ON;
    6 m) C. o% z; `" H/ X
  58.                 for(k = 0;k < 10000000;k++);
    0 `6 B- v  K! F( y
  59.                 LED_BLUE_OFF;
    " X: V9 j' ?# q1 R9 a
  60.         }" B6 h( {9 F0 l; S6 e( I1 c$ g
  61. }0 R* Q4 a! z! N  r& y9 `
复制代码
2.DMA初始化函数6 \6 H( f$ Y  `& S7 a' Q
  1. /*- s! \& W- ^$ R! ^
  2. * Name                : initialize) ^: ?2 a6 d3 ~, Q: u
  3. * Description         : ---
    3 X3 a- i: k, C# x# [
  4. * Author              : ysloveivy.9 t3 O5 i1 J6 o0 X
  5. *
    5 d& D- p+ [  X* T' N: J
  6. * History
    5 X, [% c& M, R( d: p+ s
  7. * --------------------$ B- t3 j# S$ _2 e
  8. * Rev                 : 0.00
      Y5 }1 J& m# |, H( J
  9. * Date                : 11/29/2015
    - k& ~5 d. }6 H$ ]
  10. *
      X! J% D9 Y0 `5 p5 L( [. i" a
  11. * create.
    2 A/ X8 h9 u3 K
  12. * --------------------
    8 U* I" }9 m$ w) |4 W: B
  13. */: n: O  J' w3 G% k8 M" V" A
  14. 6 s0 r& d/ ^! J+ Q
  15. static int initialize(void)
    " U0 K- m) h' T1 K8 _
  16. {
    % K* f% r) @) }
  17.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);     7 J8 V7 \: _% k9 e
  18. //使能DMA2时钟5 e8 W0 a5 }: O1 y
  19.   DMA_DeInit(DMA2_Stream0);                                                        //配置DMA29 O0 X5 x# e+ F6 o
  20.   while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE)                                //等待DMA可配置6 H3 H+ c  H5 ^" o1 u* g# e1 b
  21.   {$ J2 o, Q+ S7 }. @7 x9 p
  22.   }6 m' s, k* t9 K3 F! l7 g2 Y

  23. + [1 U/ y3 a( y3 \: d
  24.         return 0;) T- I% a; Y% i
  25. }
复制代码
3、小知识
     在DMA的设置中我们遇到了关于DMA设置的结构体,我们通过配置其相关参数,以实现我们想要的功能,其解释如下:
  1. typedef struct! y/ @) O5 F/ E( M' _$ p
  2. {
      D$ E0 S$ P, N7 G% V9 H& j; C
  3.     uint32_t DMA_Channel;                   //选择通道* W9 N' L5 R, _
  4.     uint32_t DMA_PeripheralBaseAddr;     //DMA外设基地址6 U( a3 T7 Q( I5 N. d
  5.     uint32_t DMA_Memory0BaseAddr;         //DMA存储器地址                     
    $ T6 i# T/ O$ ~3 n5 N, D1 A* [
  6.     uint32_t DMA_DIR;                       //DMA传输方向
    9 m1 y' X! Q! u  a# t6 K
  7.     uint32_t DMA_BufferSize;               //数据传输量
    , R# `9 ]) q0 E4 j3 Y
  8.     uint32_t DMA_PeripheralInc;           //外设增量模式选择  a  X, p' b  ~6 v4 z+ t! c$ t
  9.     uint32_t DMA_MemoryInc;                //存储器增量模式- g6 v# \; _8 h  n
  10.     uint32_t DMA_PeripheralDataSize;     //设置外设数据宽度( ?' u" I7 H8 ~' t4 Q* _5 x# \6 a
  11.     uint32_t DMA_MemoryDataSize;          //设置存储器数据宽度! n" A" m- h. w, t2 y' i' y
  12.     uint32_t DMA_Mode;                      //运行模式选择
    ! B" L# X$ z6 B4 A& |+ I/ F* V
  13.     uint32_t DMA_Priority;                 //优先级选择" |. B6 t) n: b5 a. [
  14.     uint32_t DMA_FIFOMode;                 //FIFO模式选择
    ! K6 G, L6 N1 z+ w: ~* U3 X) V* u( j8 Q
  15.     uint32_t DMA_FIFOThreshold;           //FIFO阀值
    3 o/ }" l# {7 @8 L% ^/ K' M* l
  16.     uint32_t DMA_MemoryBurst;             //存储器突发单次传输
    & `  r5 ^3 s, S8 |1 O- o
  17.     uint32_t DMA_PeripheralBurst;        //外设突发单次传输                        ' A8 d8 w/ ?) k5 `- l) |
  18. }DMA_InitTypeDef;
复制代码
四、实验现象:
      试验成功蓝色LED灯闪烁,试验反败红色LED灯闪烁。
五、代码包下载连接:

) f  p8 T9 {% i. Z3 I( H
$ R+ I' M6 n  g( z# B( j

+ d" }7 p% g) ]- m9 \$ ~
6 \! j( X! y5 `% y( h

& [( _4 L+ I7 F( c. A! w, w6 D

( I3 p( E& V6 h( {) b3 C& D- u

评分

参与人数 1 ST金币 +2 收起 理由
MrJiu + 2 赞一个!

查看全部评分

赞 收藏 评论5 发布时间:2018-4-3 11:48

举报

5个回答
大陶 回答时间:2018-4-3 16:19:07
谢谢分享
MrJiu 回答时间:2018-4-4 09:40:00
非常不错!!!
a110-130038 回答时间:2018-4-4 14:49:16
谢谢分享
西点钟灵毓秀 回答时间:2018-4-4 23:14:59
不错,是要好好学习了
samhong 回答时间:2018-5-11 06:52:54
学习了。
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版