最近做数据传输要用到DMA,通过验证测试并分析官方的Demo,移植到自己的代码中,通过学习为我所用。 官方提供的Demo里有FlashToRAM的例程,先从这个例程下手。通过阅读手册可以知道,H503有2个DMA,感觉能扩展应用还挺多的,如图1所示:. w' h0 t/ i1 \2 ?, h
# K) L3 Z0 s6 i- ^6 @
图1
5 V# E$ R. J5 @/ P 简单分析一下代码,先从初始化部分开始,这部分做了部分注释,如下所示:3 _9 y& a2 ?1 {' {! Z; M' O# l0 J) }
& a+ u9 }/ t: S- handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; //通道号; j& i$ C1 v3 s# }# i
- handle_GPDMA1_Channel1.Init.Request = DMA_REQUEST_SW; //请求来源,软件触发
! ~+ f% J1 d4 ~3 }/ I - handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;//硬件请求类型,单次触发模式
& {& J% I3 w" `! s7 y6 m2 o - handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; //传输方向,内存到内存
/ G& B! Q) R8 l$ l7 g q0 O4 U - handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED; // 源地址增量模式
+ o! D! n8 \+ w- ^0 r - handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; //目标地址增量模式. e6 } b) Q/ C7 ]8 f
- handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; // 数据源的宽度,以字为单位
: |6 ]. r' p* }7 P/ v- U - handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; //1 s0 E1 x' C' K# Z$ d
- handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; // DMA的优先级,低优先级高权重$ H) f% e9 ^5 A/ ` z8 U& W+ t2 W
- handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; //Burst长度以数据单位表示$ r o+ ~3 }& ^1 c* M9 J& Y0 Z
- handle_GPDMA1_Channel1.Init.DestBurstLength = 1; //
2 _' A/ @! q& e - handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; //分配给DMA传输的源和目标端口,都分配到PORT0$ O8 S& [# C3 N( o4 t& ?; j3 W+ H6 P
- handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; //传输事件的模式为Block块传输模式
1 g2 Z$ W/ r# N0 q1 z# w# }# r& k - handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; //工作模式为正常模式
复制代码
" i5 G* r0 s/ L' Z8 {0 W3 [ 然后就是主函数,先定义了两个callback函数,一个用于发送完成,一个用于发送错误。传输完成,中断响应后调用回调函数。! g% \: |. W z4 Z) ]
F2 |# ~9 z/ w2 C! ?, L- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
2 T! w0 a6 o/ \ - HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
复制代码 通过两个变量标志位的状态,来判断是否完成和是否继续进行,并有两个回调函数来完成,如下:- static void TransferComplete(DMA_HandleTypeDef *handle_GPDMA1_Channel1)' w4 G4 a) N' S' C+ Y" O: u: ~- ^, D/ x
- {' C" C+ `, k0 u# p# [( y. i
- transferCompleteDetected = 1;) W% @ E1 Y, q; p# ?* `
- }. e* W3 g/ D" b2 v, }& S8 G; C+ w0 B
复制代码- static void TransferError(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
' X% m2 w, b# { - {
" O4 u/ L( b' M1 }( j3 [6 } - transferErrorDetected = 1;
/ U- c" p' ^) d; t - }
复制代码 其实官方的注释中写的也是比较详细的。然后就是配置源和目的地址,启动传输,如下:
9 w) F6 ^% A* _, X: i- if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, (BUFFER_SIZE * 4U)) != HAL_OK)
( x% E) J% m& P9 c, ~" j - {
9 [' [' X; ?2 Y" K$ T - /* Transfer Error */5 d- |) d0 _1 U8 G) x
- Error_Handler();( |- W: ^! I6 C6 a2 }3 ?
- }
复制代码 其他部分可以参考源程序,测试结果如图2所示:* ~6 p0 A" [& g2 o& {& a
' A; Z* Q5 f5 S: _: [% V" L& o
图2
# `4 p1 e6 C& c s m2 I软件部分相对要简单一点,主要是通过测试和分析,理解和了解DMA的使用,为后续工作方便调用准备。1 s& q8 ]+ o+ y S( i' y+ p
|
必须得整,得深入挖掘。