一、为什么要用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
- void Dma_Init(void); v I. |: |8 d1 [6 i, Y
- {
2 D+ r, z% }9 n - DMA_InitTypeDef DMA_InitStructure;
1 L7 s: G7 t4 w- f -
, @* d$ @2 Z1 | - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
- y# U7 K' ?5 i3 K2 U* Y! j6 i# j - /* DMA channel6 configuration */
. G8 h- g+ _) K p - DMA_DeInit(DMA1_Channel1);
# ~2 W; R% p ]; k* |; {7 i8 m8 Z - DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_Const_Buffer; //外设地址
% x3 ]- F1 O+ I; w. X - DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DST_Buffer; //内存地址
$ E( f2 O/ f( k6 Q: q - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设作为DMA的源端 DMA_DIR_PeripheralDST; //外设作为目的地址
3 M0 B2 X' l. K# t2 o - DMA_InitStructure.DMA_BufferSize = BufferSize; //传输大小
* U6 i- S; ^- j; S9 k; f% Z - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设地址增加. l& K, j$ y3 N5 b. M
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增使能- N& l- R ~% \& n% J
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //内存存储方式:字节 DMA_MemoryDataSize_Word;//字(32位)
+ {( ]9 h8 |, \0 J/ U) x - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
2 z$ d' A% W* F - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA_Mode_Normal 正常模式,只传送一次; DMA_Mode_Circular:循环模式,不停的传送;" Y3 W( w& H& f) Z* q9 w: Y: `
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;, _: e7 q' D l/ @& y1 D) l( z1 B; e5 ]& H
- DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
' ?5 g- B9 ?* w# t# r - DMA_Init(DMA1_Channel1, &DMA_InitStructure); l. m/ i' A) c( E7 u+ ? P
. @, c) r/ f* ~* Q; h m4 u- M I- /* Enable DMA Channel1 Transfer Complete interrupt */
& Q; W1 d+ Y" \: T- D' { - DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);* N, v! K$ c0 K9 Z; Y6 `7 d i
-
; h5 n+ i! Y% I( j- M5 J1 K* W# p - /* Get Current Data Counter value before transfer begins */& G: `# _: r, K" C/ i, k
- CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1);; x* B/ S+ G: I- N) u. ~7 c4 V
-
( r& B, t7 j9 ]7 P0 i% g: D - /* Enable DMA Channel6 transfer */0 P6 O( y5 H. Y: D S
- DMA_Cmd(DMA1_Channel1, ENABLE);2 l5 B4 c" _ V
-
- a! K3 e, U! h- A - }
复制代码 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- void NVIC_Config(void)
/ }7 p& a' _2 X, K; @ - {1 P6 r6 c! P2 `8 J' p8 q' m! I2 h
- NVIC_InitTypeDef NVIC_InitStructure;# @6 R/ P h2 `; f# K- z0 c
-
; ~3 T# K3 H- {4 X" v- R/ L - /* Configure one bit for preemption priority -------------------------------- */. H/ G' u; i' y3 `
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);+ a* J. Q. Q4 J; r8 Y
5 ^1 u Z0 V0 i7 P- /* Enable DMA channel1 IRQ Channel */
6 H W1 C% k0 R - NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;# f9 `, J& R7 k$ n
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;3 M+ `8 ?+ h+ X2 \
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
8 S7 z' u; O' [' |$ m0 b3 H - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;: c0 m2 M" d8 N# c+ z
- NVIC_Init(&NVIC_InitStructure);
! I4 G0 I y3 C, L! Z9 m - }
复制代码 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
- void DMA1_Channel1_IRQHandler(void)
2 i; c* A7 ?! _- a6 \7 ]* Q9 A - { , \' D* H1 Q1 I. w3 v5 a
- /* Test on DMA Channel1 Transfer Complete interrupt */5 ?7 h9 |# \- Y8 O$ C8 | o
- if(DMA_GetITStatus(DMA1_IT_TC1)) //DMA1_IT_TC1:通道1传输完成中断
; S1 E G- l; r - {
2 J, s4 F6 s" n5 x- r - /* Get Current Data Counter value after complete transfer */
( Z9 y$ t+ d# ]' h; R - CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1); //返回当前DMA通道1 剩余的待传输的数据数目4 Z( V8 S3 d& f: d+ B% A5 G: n" H
- /* Clear DMA Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */% u* X1 o- s6 b8 p
- DMA_ClearITPendingBit(DMA1_IT_GL1); //清中断1全局中断
- M" I7 q0 m" |* ?% F) D - }2 H8 e. Y* S+ W- ^$ w4 w: I0 {1 q: d
- 4 F8 q# B6 V, n% n' D8 \8 ^3 O2 c
- }
5 E/ A2 `1 \1 f0 F: S& K
; R$ S& S# F* g; B- 4主函数部分:+ U: d$ V# C2 B; d
- k) C/ A& @3 v( e- int main(void)/ ^' Y* }+ c5 t1 ?8 d
- {
/ [+ R! m: C% o. m8 s. K6 z. Z - // int count;
" } C) _3 u. P4 a( P - uint32 judge;
" B- _! ^, i) ^+ [- l4 l, s - 9 Q! |$ I5 n- P6 `. D6 O
- NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x00); // NVIC_VectTab_FLASH=0x080000005 v! g# r0 L% z; z% Z6 o/ x1 u
- // RCC_Config();
" |. O* k. L4 i; `' r/ c - SysTick_Init();* A7 H" y( L* Q8 n: r- K6 o5 d
- GPIO_Config();
% E! b$ ] _% t& l4 f7 b - USART1_Init(19200); 6 ^5 u) ]3 H/ K' @0 ]2 ]" @
- 3 e; a. Z0 D( ?4 J* J
- NVIC_Config();
! b7 w, M# Y% m, Z( g( L -
. D& A( v0 F' ?! T, F - FLASH_SetLatency(FLASH_Latency_1); //延时2个时钟周期
* h& Q( c+ M% }4 r" f5 B - /* Enable Prefetch Buffer --使能预取指缓存*/
6 o3 q% {) t$ W j1 [' T- w - FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);4 M2 F1 j$ N1 d
- Dma_Init();! Y- i4 L9 f5 z; S; S) A* e% G& o) ^
- /* Get Current Data Counter value before transfer begins */" y8 V( A" P5 K
- CurrDataCounter = DMA_GetCurrDataCounter(DMA1_Channel1); //返回当前DMA通道x, 剩余待传输数据数目
# ~. Y( o8 e, c0 K2 ? - , q* H: {7 y, t8 l
- while( CurrDataCounter!=0) ;
0 p& l X9 [! E; o) [ - judge = memcmp(SRC_Const_Buffer,DST_Buffer,BufferSize);" q# k7 h4 p1 }% K1 H1 |
-
# u$ a! x0 x& X+ X1 [; @* K& i - if(0==judge)3 c" u0 ]% o0 d! |; z7 u
- {
6 C$ C- z; V% R6 x% ?9 `6 W - USART1_SendData(" Same !!!\r\n",sizeof(" Same !!!\r\n"));
' U" w1 H6 @; E7 n# i - }
- M! m) _. s. g8 z - else
: f/ r" ?& L% p8 F - {/ |" e; P( K6 B, ~" k* c) p
- USART1_SendData(" different !!!\r\n",sizeof(" different !!!\r\n"));
# K& F+ ]3 T ?* I F' A - }
* y2 A4 n) o: K! G) q) V - % O$ B* f) j, d" ?7 T1 L) n
- Delay_ms(1);# }$ r, _% ?4 Q* A
-
, Y( |( {( a9 v) a) U `* {4 T4 x - }
复制代码 五、测试验证
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 O2 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
|