本帖最后由 kkhkbb 于 2018-4-3 21:17 编辑 " v) M* O8 H6 }) ^. ~, V1 W
# j- o. f: r1 e( p" M9 b
一、概述:. v9 p* ^0 V& s
1、DMA简介
; z9 q# ]1 B. H7 P" Q DMA的英文拼写是"Direct Memory Access",汉语的意思就是直接内存访问,是一种不经过CPU而直接从内存存取数据的数据交换模式。在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样就很大程度上减轻了CPU资源占有率,可以大大节省系统资源。DMA模式又可以分为Single-Word DMA(单字节DMA)和Multi-Word DMA(多字节DMA)两种。9 \) V- [/ ] r: z" U- k
2、 DMA工作原理
; x$ U0 d& O/ ~( z; x0 ~ DMA 允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把他们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。
5 Q% g; J$ G+ [; K DMA 传输主要地将一个内存区从一个装置复制到另外一个。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存去。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。所以,DMA传输对于高效能嵌入式系统算法和网络是很重要的。
: a8 ~1 s: W/ D* r# t! h. e 3、DMA类别6 w- o% F3 m. j% Y
按键主要有两种类型:单字节DMA、多字节DMA。
0 [* a; R: q: z- G8 X% p. ^, P 单字节DMA:一次传送一个字节,效率较低,但它会保证在两次DMA传送之间,CPU有机会获得总线控制权,执行一次CPU总线周期。- l J1 ^( e* z! }( }
多字节DMA:一次请求传送一个数据块,效率高,但在整个DMA传送期间,CPU长时间无法控制总线(无法响应其他DMA请求,无法处理其他中断等)。 二、实验原理: DMA(直接存储器访问)传输不需要占用CPU,可以在存储器至实现高速的数据传输。本实验采用DMA2控制器的数据流0,选用通道0进行数据传输。通过LED的颜色来判断传输是否成功。 三、源代码: 1.主函数及DMA设置7 {3 ^/ \+ s! e! T0 ]
- /*6 j/ s) x) F5 ]) B8 J
- * Name : main
) o5 J* o/ @3 H% R3 d6 L, C - * Description : ---. d! ~1 P0 L2 Q+ O Q4 e4 ~2 x8 C
- * Author : ysloveivy.8 J% P& Z. I6 y+ { {. L
- *1 e' W( o: {7 r/ X" e
- * History( J2 [2 Y6 J0 \; H, e0 b0 @
- * --------------------
9 B. t( u9 s& p( X4 N7 U - * Rev : 0.009 ~3 H M$ K3 d" M
- * Date : 11/21/2015% C6 v+ R4 C# ]& n/ p, h
- *
& l3 {1 h, i4 B& l2 i - * create.% y+ g- ?+ g" ~8 e# b4 @
- * --------------------( i5 m9 D8 M: Z5 o+ P- \! A- J _
- */
5 K* |+ ?: R7 x8 ? - int main(void)5 a6 H; f+ O) G) d. \
- {( h2 A8 E: c& h2 g
- int i,k;2 D" q: B! q# |* L2 T5 o
- DMA_InitTypeDef DMA_InitStructure;
1 G0 R. G( U' S# D2 z9 h - . A3 Z- L# q$ S
- led.initialize();
+ ^3 E6 m& ]- E- R( k5 \4 `0 T - dma.initialize();* l4 c7 G" N9 ^$ c- R
6 ^+ [8 J6 A. d9 R8 S+ b- //测试DMA,测试成功蓝灯闪烁,测试失败,红灯闪烁
' _6 t8 y+ N" h - DMA_InitStructure.DMA_Channel = DMA_Channel_0; //选择通道0
+ j- t; d4 o: y) f - DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned long int)src_buffer; //DMA外设基地址
* Q) i0 k6 Q6 C- [ - DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned long int)dst_buffer; //DMA存储器地址 d; d6 g# ^& t4 s% m
- DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory; //方向为存储器到存储器
' J# C8 s+ T6 s c0 J7 @ - DMA_InitStructure.DMA_BufferSize = (unsigned long int)BUFFER_SIZE; //数据传输量
1 w$ D9 K. J4 l3 c - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设增量模式
8 c+ a; d6 u, Z - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式7 h9 a7 H; Q7 ]+ c2 v8 ]* L t3 B% g
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //设置外设数据宽度
, t& I+ a w W) q: l9 e" G - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //设置存储器数据宽度
$ C0 i" x- u+ x+ m; S9 p5 X" R - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //运行模式为普通模式
! ?2 z% i( ]( _ - DMA_InitStructure.DMA_Priority = DMA_Priority_High; //优先级级别为高! {3 Q9 i$ @+ a
- DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //FIFO模式禁止
! S+ D% ~4 g$ |) C- H, b0 y- Z# }6 t- E - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; //FIFO阈值! g* j% A6 l( n3 W
- DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输* r; n- x) J" d- }
- DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输" }1 B1 d e+ ~, m% u, U M
- DMA_Init(DMA2_Stream0, &DMA_InitStructure);
" `5 X! p! F& {. R - DMA_Cmd(DMA2_Stream0, ENABLE); //使能DMA2_Stream0
+ r$ x# |& _9 o5 _! Q3 @9 j
( A# h; F a, i1 M# B( Z- while(DMA_GetCmdStatus(DMA2_Stream0) != DISABLE);
0 D6 @) [! ?8 o1 s9 W$ @) w* R6 Y
4 ^9 a$ h: l2 k9 ^; q- for(i = 0;i < BUFFER_SIZE;i++){
; S4 n. K/ w5 i - if(dst_buffer[i] != src_buffer[i]){
2 ~: }7 G% |. S) i - //测试失败
7 q. ^3 m" A. w8 ` C! \3 A - while(1){
( t: w4 g/ M1 ~! e - for(k = 0;k < 10000000;k++);- a; r( n7 D; W- \
- LED_RED_ON;
. @) P: Y) h ?2 w5 p: ` - for(k = 0;k < 10000000;k++);
|; F: [9 M: u" U" p - LED_RED_OFF;/ _7 {" N( b* g5 j* b3 A
- }
& ?4 b: ], D1 ~( i: J' x S - }# o% d {6 w2 m2 C, {6 F o$ z' U
- }
+ z9 d. K0 S' Y" n) t - //测试成功
3 A0 P. g% U3 d2 x- } - while(1){
; k- A+ N: n2 y" c& L - for(k = 0;k < 10000000;k++);& L# I/ A6 h, z- P5 ^
- LED_BLUE_ON;
2 c z( X8 }! f& S" @' u - for(k = 0;k < 10000000;k++);
: E7 ^ d8 \+ ] - LED_BLUE_OFF;
' j5 o( b9 {! ^/ w9 ^9 q x: |$ m8 I: W - }
' X3 Y' Q" ~, O; p. |7 { - }; {- M9 w! J: Q0 k# x& z9 Q
复制代码2.DMA初始化函数" a+ ~; O4 P" K4 m' ^9 V
- /*9 t. Q6 ]1 h6 E- Z, t6 ?2 h, S- o5 D5 O
- * Name : initialize- e: X ?6 E9 _" `+ M( b1 D" \* ^, a
- * Description : ---
0 z6 ^* _* D6 `$ b% ^- r: ]* s - * Author : ysloveivy.
9 o. R3 z. W4 y - *! S7 B* K/ x1 B( M
- * History: w+ V, |& w: w i
- * --------------------
3 Q% ?) Y5 Q. R W0 O - * Rev : 0.00
5 o6 q$ L: _- r: I) }5 o# ^ Y4 p, J - * Date : 11/29/2015% b$ I7 {. [( m8 ]; Z
- *
4 i% R N& a* X" |& b8 O - * create.
& W: E5 P/ T. ?& r/ e& r9 R+ ~ - * --------------------% k' T, d/ s( q2 J# T2 _
- */
A3 P2 {, S2 j9 c! h q
* m7 Z# P& @# E7 P/ G8 S- static int initialize(void). h( Z' M" k9 m6 ^# Q' D& B
- {
* b; y& U9 O9 J1 [ - RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
6 A1 g0 |+ x6 F5 F - //使能DMA2时钟" m/ ]1 `* `* L2 w% @4 g
- DMA_DeInit(DMA2_Stream0); //配置DMA2
- A8 H( y& R' T0 s* u - while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE) //等待DMA可配置
! F1 m5 {3 f+ l: \; H( n - {
' q& U2 H: {! a - }
& K9 i/ E& b% G3 ]- C3 S
- A: K& E3 N& p* }7 X: L$ A- return 0;
( }0 x$ U) X( G3 }) T* W6 ? - }
复制代码3、小知识 在DMA的设置中我们遇到了关于DMA设置的结构体,我们通过配置其相关参数,以实现我们想要的功能,其解释如下: - typedef struct
% {; z$ i3 ~4 F" H - {
5 w$ F+ J( h. K+ u& d - uint32_t DMA_Channel; //选择通道3 u" Z& L, ]/ _+ M- ^9 u
- uint32_t DMA_PeripheralBaseAddr; //DMA外设基地址& c& {- s) l. @
- uint32_t DMA_Memory0BaseAddr; //DMA存储器地址
8 u7 G9 O1 u+ g! [; \3 E* L - uint32_t DMA_DIR; //DMA传输方向
" v. C, L3 D& T6 O9 m8 i* f - uint32_t DMA_BufferSize; //数据传输量
; p' X2 R! x7 k6 V! Q - uint32_t DMA_PeripheralInc; //外设增量模式选择+ c; c- I3 L2 P2 }9 o$ n
- uint32_t DMA_MemoryInc; //存储器增量模式5 s' Y9 _6 r; w+ @" K0 }
- uint32_t DMA_PeripheralDataSize; //设置外设数据宽度
; [: t5 W1 j- f2 f! ~- D, S# ^ - uint32_t DMA_MemoryDataSize; //设置存储器数据宽度
6 l- f4 c) D+ H6 X' ?$ w/ x2 ? - uint32_t DMA_Mode; //运行模式选择2 l8 d; d, w. N5 h+ p- P1 f- ~% r2 i* R
- uint32_t DMA_Priority; //优先级选择
4 ]3 y) |6 X/ h5 b9 r# @ - uint32_t DMA_FIFOMode; //FIFO模式选择5 \& j8 N8 w( ~# ^* y
- uint32_t DMA_FIFOThreshold; //FIFO阀值
]# W# k5 a" P8 i% Q& {) V - uint32_t DMA_MemoryBurst; //存储器突发单次传输
' S, ~- u: b& u t$ g# j - uint32_t DMA_PeripheralBurst; //外设突发单次传输 & }) I* O# @+ ]) f
- }DMA_InitTypeDef;
复制代码四、实验现象: 试验成功蓝色LED灯闪烁,试验反败红色LED灯闪烁。 五、代码包下载连接:
# Y) S/ Z: m8 q5 z# \
$ y4 i, s3 x1 o: @& m# N; V( l% B( I
0 t# V- ~( d$ A6 Q7 T; S3 H) s; ]: ?5 f$ h0 Z/ K" u% V$ u
9 o4 O7 h( Y+ ?$ \7 P( o1 z9 ^8 X
|