最近做数据传输要用到DMA,通过验证测试并分析官方的Demo,移植到自己的代码中,通过学习为我所用。 官方提供的Demo里有FlashToRAM的例程,先从这个例程下手。通过阅读手册可以知道,H503有2个DMA,感觉能扩展应用还挺多的,如图1所示:
5 k! u) p ?. J g" N$ x
* C8 L' w j% U, n, Z 图1
" P3 i6 n$ ~, _ s4 h 简单分析一下代码,先从初始化部分开始,这部分做了部分注释,如下所示:; |% l% A, X6 B6 ]6 n
4 A. P/ l, a2 ` q# M- handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; //通道号" f8 |' B' J2 c1 A; f9 t: n
- handle_GPDMA1_Channel1.Init.Request = DMA_REQUEST_SW; //请求来源,软件触发8 d4 M7 S; f5 w' h( r
- handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;//硬件请求类型,单次触发模式
4 @5 `+ d9 R1 W - handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; //传输方向,内存到内存6 R2 j# z5 R, e8 |) E4 I0 T
- handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED; // 源地址增量模式+ h, s! `( u% a5 x4 F' z
- handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; //目标地址增量模式* @" @8 {* y2 w) `
- handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; // 数据源的宽度,以字为单位
; b# v( n0 y' ], z4 E9 q% |0 {' C - handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; //) p* { E. H; ^5 J1 z& r
- handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; // DMA的优先级,低优先级高权重$ K. w6 W7 B, c: y. |: a" ~) C) ~
- handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; //Burst长度以数据单位表示8 F, N1 B* ]* L$ S& A# o0 S! K
- handle_GPDMA1_Channel1.Init.DestBurstLength = 1; //
4 c0 X- ~9 L5 t - handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; //分配给DMA传输的源和目标端口,都分配到PORT07 @) K3 A! b( s3 K$ l. g
- handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; //传输事件的模式为Block块传输模式5 i, c% l+ G) F' k4 J& x+ n
- handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; //工作模式为正常模式
复制代码 3 h- E" v7 ]. X
然后就是主函数,先定义了两个callback函数,一个用于发送完成,一个用于发送错误。传输完成,中断响应后调用回调函数。
@8 N I* X9 q7 F6 A, G8 S+ F' @! X, u3 @6 A
- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
# ^% P9 ~% ~5 M9 d* j/ l9 g/ w4 h - HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
复制代码 通过两个变量标志位的状态,来判断是否完成和是否继续进行,并有两个回调函数来完成,如下:- static void TransferComplete(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
% @: p4 w5 ^2 y; R - {7 k4 n6 a3 Q5 n% B# `2 J) P' Z2 _
- transferCompleteDetected = 1;
- [ Y8 C5 @+ U% I+ A) `# T - }
+ s4 w4 l& n0 F
复制代码- static void TransferError(DMA_HandleTypeDef *handle_GPDMA1_Channel1)/ O& h9 |/ M* c1 S' I1 V
- {/ r6 w7 F. c; q; g
- transferErrorDetected = 1;
# ^$ v/ d X, Y1 h" k# W - }
复制代码 其实官方的注释中写的也是比较详细的。然后就是配置源和目的地址,启动传输,如下:9 _; z7 T3 l- C+ X6 O
- if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, (BUFFER_SIZE * 4U)) != HAL_OK)! X& @; Q, G4 a+ j; m/ A
- {$ @+ H/ l9 p: e/ T8 R$ Y# r
- /* Transfer Error */
+ U# }/ T7 b |. m - Error_Handler();2 y2 x5 C& V4 ~# w& `1 Y$ K# |
- }
复制代码 其他部分可以参考源程序,测试结果如图2所示:
4 i$ C# t9 j4 V' D# [( z
' V. L" X7 c" a图2
! Q$ P+ V N* C6 a: C6 G6 j; `软件部分相对要简单一点,主要是通过测试和分析,理解和了解DMA的使用,为后续工作方便调用准备。
6 L7 p0 {* m' w7 g0 y |
必须得整,得深入挖掘。