本帖最后由 aimejia 于 2018-5-24 11:23 编辑 , L5 J# M, U* @: A4 }
8 I1 W. P# r, F8 O
一、为什么要用DMA?! {8 k2 C' d# X4 o! h
% U* }: O A& ^% k1 P
DMA 全称:Direct MemoryAccess 就是可以直接内存存取;5 W8 x! k; ^* B& v% N3 R# n
0 G# X3 k' n6 r- e( j4 Y' l正是它可以直接操作内存所以具备以下优点:$ @9 G$ ]9 W, ?
, j5 G" s- ] \6 U, b而无需经过CPU去操作内存的存取,这样可以解放CPU出来干其他的事情;2 ]* X. ] B# }' b2 |
) j& ~) n: I, Z4 m @( _# d/ l# |
因为他可以进行存储器时间的数据传输,而不需经过cpu,所以大大加快了数据传输速度—是一种高速的数据传输;
% I+ G# A+ f# B: x. S' c
) Q. o$ j( W2 n0 A" |7 o) h! B二.DMA有几种传输数据方式:
5 ?( q1 O! c t7 ?
7 l7 q) U; n" J* V% |0 \(1)内存到 内存之间的;即:SRAMßà SRAM, h# y! K# U `* X% l
7 J9 d8 J5 _: Y: ~# Z: K (2)内存到 外设之间的; (例如:串口收到的数据 从数据寄存器 à 内存)
+ {% U$ S2 x% B- s! Z, \: S
. O& Q: G# K; F% f (3) 外设到内存之间的;
9 g: i- m1 l% P# k" J/ e. \# w: u* `" j" R* N. r* S
三.传输的数据宽度是怎样的,数据是什么样的形式传输?DMA 能传输多大的数据量?8 S- @' B) w0 t- f/ R! W, E0 E9 l
% j$ n2 O! Z) M: V) X4 @8 f
A. 数据源地址到数据目的地址 传输宽度或者说传输数据的形式,有几种:1)字节;2)半字;3)全字 [1字节=8bit 1半字=2字节=16位 1全字=2半字=4字节=32位]4 V" z' [5 f5 ]6 x4 \ D8 F: i
1 \! e# v8 [' {B.传输的最大数据量是65536
! K; G) ~) m. U# [5 @4 ^- g6 M: b4 X4 q8 ]: o6 S8 q
我们来看一下stm32f103ve的数据手册第九章DMA 大概的了解一下DMA的特性:
5 Q9 e% d4 Y/ F- ^+ D! e
. O/ Y$ ]7 `$ K& I* T Q* e
r. s+ `: Z5 M, n3 ^# J& ?$ {
! a9 E3 {, }7 L
5 ?% {- ?; J& ]; m& {1 ~* j四、怎样配置软件来使用DMA?
3 |$ x) e1 @& I. W" O5 `( t! [
. r D- n) M; L1配置dma; N+ U* }* w+ k8 e3 r1 p5 f8 p
- [plain] view plain copy0 s5 P& l; d6 _: D8 {5 n
- /***************************************************************** & w/ s+ U8 C: B+ [" u
- *函数名称: Dma_Init 0 h; g+ c3 l1 G/ q& ~( |
- *功能描述: 利用DMA 把内存的数据 传输到flash 达到高速传输的目的
. F6 B# J8 B/ n# R: _8 \ - *
5 c/ Y- t. _' o+ ]! {- |) t4 W3 X - *输入参数:无 - t6 K& L4 {* k3 N/ w* a& d; O
- *返回值 :无
- Q/ ~- A# @* X6 L4 W# ?2 s - *其他说明:无
! l8 l! T7 W! p1 o - *当前版本:v1.0 # s# }+ b6 S6 B$ g
- *作者 :尹宣
) L$ g/ d6 k1 t' s0 M& q9 `! J - *完成时间:2013年12月1日
: ]: o" a% C; e - *修改日期 版本号 修改人 修改内容
- R$ {+ a! P6 b9 t, x) g - *-----------------------------------------------------------------
# ?! S# V: x& j: X, A( x - * & ? y! i" n5 z) H6 L
- ******************************************************************/ ' g2 q: b. T8 W* M
- void Dma_Init(void) 6 }8 p. d9 c! p# s% p: J
- {
! D$ j! z+ B+ }4 i0 u - DMA_InitTypeDef DMA_InitStructure;
" e/ {8 ?; C+ I - 6 E2 H W9 ~0 H( k5 @( A, \/ F
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
- w6 V' \+ [) e - /* DMA channel6 configuration */ 2 y! o/ G2 `, j3 Z' X) P2 E% k' D9 T
- DMA_DeInit(DMA1_Channel1); " h8 c2 S3 \7 D' k7 s" I
- DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_Const_Buffer; //外设地址
5 b. l5 d5 X! M - DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DST_Buffer; //内存地址 & s+ v# H5 J, Y8 K" |" p
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设作为DMA的源端 DMA_DIR_PeripheralDST; //外设作为目的地址 & l) Z# Z% a$ z3 D
- DMA_InitStructure.DMA_BufferSize = BufferSize; //传输大小 " r( P+ ~3 ?) s; Z9 s
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //外设地址增加
) b8 O# v+ `% X& A# N - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增使能 ) o- H5 s6 l0 o. A4 t, |7 _0 g
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //内存存储方式:字节 DMA_MemoryDataSize_Word;//字(32位)
& G& C2 k. _) U - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; # C2 C3 Z: M/ z" q
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA_Mode_Normal 正常模式,只传送一次; DMA_Mode_Circular:循环模式,不停的传送;
' b% Z9 r% c. w$ m1 r6 O D - DMA_InitStructure.DMA_Priority = DMA_Priority_High; 5 s8 O* p$ _( |0 `# u
- DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; 6 p$ q; K9 K# n8 M3 M$ a; t
- DMA_Init(DMA1_Channel1, &DMA_InitStructure);
# G3 a% Q( a& ?' \( b+ ~" i -
: j. O" Q7 `% d) S - /* Enable DMA Channel1 Transfer Complete interrupt */ C$ D( L2 {/ c' G
- DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); " S1 n3 F3 V. e# l4 |
- , W( G! s8 p2 [. z* j
- /* Get Current Data Counter value before transfer begins */
' M7 Y; o6 a: H& S/ h - CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1); + S" [, }4 }8 P B- d
- 4 P& {5 M2 e X
- /* Enable DMA Channel6 transfer */
n: r. Z- c6 A' \4 b - DMA_Cmd(DMA1_Channel1, ENABLE);
7 P& R6 r0 u, T2 G" G - 0 x& z! t' G) G
- }
复制代码 2.设置DMA优先级/ ?, A! `2 r p7 r# O
- [plain] view plain copy" R7 e6 V+ b3 ]
- /***************************************************************** , @' ~2 Z1 M: y. k) |1 {- a9 I ]
- *函数名称: NVIC_Config . u3 {' D! q5 V4 k' k
- *功能描述: 配置DMA的中断优先级 ! h1 S( H6 v) T5 f G5 R
- * 6 Y! K0 h _/ w; c
- *输入参数:无 - r9 V9 P6 i* M9 H* f' Q
- *返回值 :无 f$ o8 ~5 o$ j$ Y0 V
- *其他说明:无 8 X- L4 n* a* w9 F( G# x$ Z
- *当前版本:v1.0
( ^1 `3 }, V" k+ T$ x2 ] - *作者 :尹宣 / b- t g1 h7 Y- T: {
- *完成时间:2013年12月1日
( k2 K. P" {4 F) g - *修改日期 版本号 修改人 修改内容
+ A) P- Y6 C* E% j' [ - *----------------------------------------------------------------- 1 U, z. o( g6 ^/ y/ N
- * 9 c k4 U) |/ d
- ******************************************************************/ " p+ f% M" T- H. Y
- void NVIC_Config(void)
6 D, K* a+ L- q+ Y x y3 V+ j - {
- P, G& @' g) u Z - NVIC_InitTypeDef NVIC_InitStructure;
5 ~$ s( H7 W1 k/ D -
* i: C/ R- @9 S$ O - /* Configure one bit for preemption priority -------------------------------- */
, e0 y0 q# f' X - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
' X* T. ` c/ `8 H/ g/ l% L -
/ C, I. U3 c8 b6 c% \ - /* Enable DMA channel1 IRQ Channel */ ) v4 T; F4 d2 F: O
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
$ z- G3 o% L5 b7 U/ ~; X - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; & M( D& I& M8 v( W
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
" u$ @. h( O& E - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
' S6 t; ^8 F& ?0 ]+ a1 A. E - NVIC_Init(&NVIC_InitStructure);
, z7 \3 |2 m6 U5 Z+ Q: ~- } - }
复制代码 3.在stm3210x_it.c 文件中添加 DMA中断处理函数) f$ r- ]2 |3 t) V# S# O) V/ V8 S
- [plain] view plain copy8 y+ e/ a# e3 P- G
- /*******************************************************************************
9 \3 @4 l- k7 @' L - * Function Name : DMAChannel1_IRQHandler / X9 F a1 C' B5 C, D# r
- * Description : This function handles DMA Stream 1 interrupt request. - b# a/ d. f1 x/ r6 v
- * Input : None ; |9 e0 I+ t' u9 N! N7 s/ G& U
- * Output : None
5 e6 R0 u8 ]' o8 `2 S3 B - * Return : None
& T1 m, d4 h }- X - *******************************************************************************/
. V" F( W- D) N; [" n M" Y - 1 M3 e# j( ~. e4 }# ^7 t9 t, l$ a
- void DMA1_Channel1_IRQHandler(void) 7 c: O) ]2 U2 C& s& X4 o0 u# i! C8 p
- { ' F4 v$ k# J" k6 q, t, E+ x
- /* Test on DMA Channel1 Transfer Complete interrupt */
* R$ R: n8 U2 B$ i: W$ X/ ] - if(DMA_GetITStatus(DMA1_IT_TC1)) //DMA1_IT_TC1:通道1传输完成中断 d0 N6 x1 [4 x2 I k2 W4 F! s% j
- { . @" C- i, N3 ~" C3 C
- /* Get Current Data Counter value after complete transfer */
5 D$ H ?( i: [+ [ h$ K - CurrDataCounter= DMA_GetCurrDataCounter(DMA1_Channel1); //返回当前DMA通道1 剩余的待传输的数据数目 4 D. W1 C+ x5 k
- /* Clear DMA Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */
% O6 D, o, f$ O+ S - DMA_ClearITPendingBit(DMA1_IT_GL1); //清中断1全局中断 ( |6 @# ~# a% H% R
- }
% `8 f' [' Z' D+ G6 x5 f' _ -
5 F/ X& @( F- z: S6 b7 U# s& Z& u: B - }
复制代码 4主函数部分:9 R% L2 d9 d4 h9 _1 B
- [plain] view plain copy
& W$ m: B3 Z: C) P4 Q - int main(void) , G! ^- ~* o1 {" D% B
- {
* c9 ]- l1 F# s; x - // int count; : B1 w6 q/ ^) j( w! x
- uint32 judge; ! j- j/ Y0 _+ D& }1 n
-
7 e3 w! C: F! W) Y - NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x00); // NVIC_VectTab_FLASH=0x08000000 ' H% d) @ p+ L( E9 v" R, J
- // RCC_Config();
6 R! ~$ j2 E, l8 h) A. m9 I - SysTick_Init();
9 p' b) ^9 A8 F3 S" o6 j* P - GPIO_Config();
' ` R+ d1 h! U& h0 C1 @ - USART1_Init(19200); - ?: M1 P: }, S& Z% J
- & ~$ I$ u% u0 [
- NVIC_Config(); 5 H7 U. T( o6 Q' E. j
- " Z0 _& [( s' i
- FLASH_SetLatency(FLASH_Latency_1); //延时2个时钟周期
7 c4 h7 @* J6 ~! \- p. X - /* Enable Prefetch Buffer --使能预取指缓存*/ ; o1 v1 E# ? H- k. `, G7 V
- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); ' D) W3 j# L( U; S V6 M
- Dma_Init();
3 l @/ M2 ^* h0 S) M. C+ W0 z4 \- M# J - /* Get Current Data Counter value before transfer begins */
/ U; }) B( i( X# A8 ~ - CurrDataCounter = DMA_GetCurrDataCounter(DMA1_Channel1); //返回当前DMA通道x, 剩余待传输数据数目 6 c; l% S% ^: S0 I( Q; q
- ' w- T) I+ M+ T" e* s3 [ s
- while( CurrDataCounter!=0) ; + {5 W4 c/ U5 e+ r/ D
- judge = memcmp(SRC_Const_Buffer,DST_Buffer,BufferSize);
$ s. ^3 c! a4 T# i+ ~ -
- y$ \/ Y: S3 \8 y1 {% [ - if(0==judge)
. _4 `) b5 @6 j/ U$ r2 U - { Q8 Z) b6 ~# |7 p) q5 T2 R
- USART1_SendData(" Same !!!\r\n",sizeof(" Same !!!\r\n")); 0 E! A$ ?! W) T
- } $ n& _7 f, D& |4 {! j4 M! w+ y
- else - W l; C2 F+ k( K9 a# b0 ?, ]
- { 6 L3 ]( D* P" O, C
- USART1_SendData(" different !!!\r\n",sizeof(" different !!!\r\n"));
: X* }" `1 l" g" R9 e) H! ^1 e - }
, T+ K3 l! x; o9 S+ o -
6 v* e: I" @6 k3 j. n9 E, D7 P$ D) o) F - Delay_ms(1); + [: Z" W% c: R# c! B; P
-
& o3 f9 U% N% \" q4 L0 V( }% `" {# E f - }
4 b2 V5 w l( T3 J
复制代码 五、测试验证
8 U, K: ^# w0 L5 B5 l7 }6 r* Z# K$ H- M; p% C( T! r
1.我们先看看看下图
3 Y# O. K" ]+ W: I# {6 r( g; |5 h8 D/ F3 i
6 Z& G. D* [3 M/ K1 c& s0 I
( m) z1 m4 {) N S) J! ?" O" Q看点0:
, J/ Z; m' Q/ w$ v3 ]' @2 G+ e/ L8 w7 r+ b& c1 ]+ V4 q; W) b- d& P
问1:* u& w: V9 M2 K+ S7 E4 o
" r& t" H3 b; Z: h& ?
使用内存窗口观测SRC_Const_Buffer和DST_Buffer所在的位置,可以发现SRC_Const_Buffer
& i2 G4 O9 }& s" S0 |; U7 R. T& `% N0 ?. e, k, F
地址为0x08001B24,,即Flash中;DST_Buffer地址为0x2000002c,即RAM中;* p/ X& f" i7 x8 i3 q2 i9 S
3 X3 t$ s# e, X' Y5 ]" e) r. K6 [' ^
答1:
5 ~; H) J" n5 U; V5 F5 [9 J' }( t o0 t3 m3 l7 w
不能改变其值得变量(包括全局和局部)都是存储在FLASH中的,能改变的都储存在SRAM中" s: X2 o4 ?* {6 k% k' q0 X# o$ P
) M2 b- f( j; |& mSRC_Const_Buffer 的定义:uc32 SRC_Const_Buffert. B# \7 Q4 x1 ]* a2 B" Q
! p% E! @7 C; _! l9 P
搜索了一下uc32的出处----/ Z1 I" e( U" H, c% e4 d1 G
( |. A. k* ~ U) _typedef const uint32_tuc32; /*!< Read Only */
& l [5 B: |/ p- Z1 ]' d& w, V& v3 ^( A9 N$ D
DST_Buffer 的定义:u32DST_Buffer[BufferSize];; I( b; X' }' k i
9 Q. v$ Y( Z5 V: S! O) [" {9 c
搜索了一下u32的出处----
! K% \( j/ W) d7 B$ R$ X0 G$ {6 o1 h' I+ R
Typedef uint32_t u32; # W9 C3 l3 ~' e
. U! m4 r3 u5 T; o# ?看点1:断点设置开始DMA传输前,
$ O1 y: f% j @9 x. @( J" j# ~2 r E
- x# S( Y; p- A7 U2 E$ jCurrDataCounter = DMA_GetCurrDataCounter(DMA1_Channel1);可以读出待传输的数据长度为0x20=32 跟我我们定义的待传输的数据长度是一样的; k, h& p1 s- y0 y, z" h
) i$ \! E# M1 s/ s8 ~" F看点2:开始传输前,目的数组DST_Buffer里面的全部为空即为:0x00;
' t0 L% p) r2 a7 R6 ^ y& c0 X/ c. v- `
2.传输完成时,CurrDataCounter 值已经为0,即待传输数据为0;同时目的数组 DST_Buffer 已经有数据,我们用对比了一下源数组 和目的数组 相同则返回0; 证实了是相同的;
5 U. W) s. D3 J, n) O! B5 E
% Z0 K( m0 J1 T ?- A6 z/ J% R
( O& m0 E2 ~# E- K8 w
' C$ o' y0 b& a& |6 C: j3 m
; j; I( m0 Y0 z" f" q6 ~ W/ C* |# U7 F2 S1 [
8 G) H6 p0 Y# m) a6 P# I& ^) s) q8 D* |& z/ @! O
转载自yx-l128125
% ^. i, P2 d" N, v; m2 u% k+ T
+ ~: O% m: O7 ?5 r5 A9 e; m! L L, O) ?/ E% u
|