最近做数据传输要用到DMA,通过验证测试并分析官方的Demo,移植到自己的代码中,通过学习为我所用。 官方提供的Demo里有FlashToRAM的例程,先从这个例程下手。通过阅读手册可以知道,H503有2个DMA,感觉能扩展应用还挺多的,如图1所示:/ F R) i) d5 ^) ~( x0 Y
4 z+ ^5 P7 f% t2 i
图1
" ^ D$ B( e: @( y& m$ ?+ q 简单分析一下代码,先从初始化部分开始,这部分做了部分注释,如下所示:
: ]* ?( F: f: k9 o Q9 o/ V" S3 x
3 M' i5 A1 c) x# @8 R D- handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; //通道号
, C% P5 A0 G$ k! f. T - handle_GPDMA1_Channel1.Init.Request = DMA_REQUEST_SW; //请求来源,软件触发# ~. W8 j. q! h* N O! }
- handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;//硬件请求类型,单次触发模式5 g, c6 ^0 A3 E) C
- handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; //传输方向,内存到内存( ~2 F+ i: i" E8 Q9 y0 x
- handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED; // 源地址增量模式/ h' L8 ~* H, v
- handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; //目标地址增量模式& i( }' I J) `! @
- handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; // 数据源的宽度,以字为单位. j6 E. H* C& q% i8 }
- handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; //4 o7 h; ?4 A& d4 P) u; b' p
- handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; // DMA的优先级,低优先级高权重
( _$ n7 S+ v! I - handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; //Burst长度以数据单位表示7 l: X. D8 G1 B2 x7 a
- handle_GPDMA1_Channel1.Init.DestBurstLength = 1; //
6 x8 O: p. \1 p8 `5 @3 x- S - handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; //分配给DMA传输的源和目标端口,都分配到PORT0- Q' g/ O. |7 R; O- F7 L; r, M0 |% E; s4 v
- handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; //传输事件的模式为Block块传输模式
2 G+ ~6 T, h" q7 H9 E, [ @ - handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; //工作模式为正常模式
复制代码 8 k4 N# F) B, h$ q) N* N
然后就是主函数,先定义了两个callback函数,一个用于发送完成,一个用于发送错误。传输完成,中断响应后调用回调函数。& p/ H( A3 [: J$ b
, Z: M$ c9 A6 ~' V9 |; Q C
- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);& D3 l1 Y2 E# d& t. L" y
- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
复制代码 通过两个变量标志位的状态,来判断是否完成和是否继续进行,并有两个回调函数来完成,如下:- static void TransferComplete(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
8 e1 v( a0 x/ q2 P5 j! ^ - {
* \, f. c, w' W4 b - transferCompleteDetected = 1;/ T% q) t2 _" w4 Y6 X7 h$ w! B
- }
8 w" O5 E1 j8 U( j
复制代码- static void TransferError(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
& {$ g, I2 g! G& O, J# u - {3 J; j u5 F- M+ Q& W8 j/ C5 ^3 h
- transferErrorDetected = 1;0 X3 g c9 C1 Y! e4 a
- }
复制代码 其实官方的注释中写的也是比较详细的。然后就是配置源和目的地址,启动传输,如下:* P; y* v9 e0 E' V9 M1 ^$ w# X1 c+ Q
- if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, (BUFFER_SIZE * 4U)) != HAL_OK)
& N6 p7 F4 b9 `: X' G - {$ @0 v$ {0 E' V/ j1 A4 N
- /* Transfer Error */
" N: I% {- N8 n# F, V& B - Error_Handler();
5 r0 P! K7 K7 w P& F, ]6 k - }
复制代码 其他部分可以参考源程序,测试结果如图2所示:$ @2 [( ]7 X {4 X8 ^
: X+ W6 c; t7 c) t2 }* ^
图2
' v4 v/ g0 S/ {* t软件部分相对要简单一点,主要是通过测试和分析,理解和了解DMA的使用,为后续工作方便调用准备。
5 f3 r' l N4 a1 p+ j |
必须得整,得深入挖掘。