最近做数据传输要用到DMA,通过验证测试并分析官方的Demo,移植到自己的代码中,通过学习为我所用。 官方提供的Demo里有FlashToRAM的例程,先从这个例程下手。通过阅读手册可以知道,H503有2个DMA,感觉能扩展应用还挺多的,如图1所示:' \* L, R9 v, n
, M/ u! Y: I C3 g5 c. C. U
图1; N- x- C5 W0 l3 @3 a$ h+ R
简单分析一下代码,先从初始化部分开始,这部分做了部分注释,如下所示:, V6 u. d% i3 {$ m0 Y# f- k
! w0 H0 ~; ]/ N( R& y: m
- handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; //通道号
0 [% K* |) S( y' H4 J - handle_GPDMA1_Channel1.Init.Request = DMA_REQUEST_SW; //请求来源,软件触发
. H8 T) b) c1 m$ E* B1 V7 D1 g( f - handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;//硬件请求类型,单次触发模式0 L" j* g* j, u2 \+ ^; ]. @& Q
- handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; //传输方向,内存到内存% Y$ `$ k9 f) {9 m- W
- handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED; // 源地址增量模式6 S% t% x! R3 C1 |7 N/ V* r
- handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; //目标地址增量模式
M- _' i2 }: r2 N6 M I - handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; // 数据源的宽度,以字为单位
3 ?1 K: I, m$ Z. p - handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; //
5 \6 \9 R# E$ a0 m - handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; // DMA的优先级,低优先级高权重
! `; v9 R( D# g9 {# x' e6 w - handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; //Burst长度以数据单位表示" e2 E0 C! s/ U
- handle_GPDMA1_Channel1.Init.DestBurstLength = 1; //
% g) ~ o+ w+ |- F - handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; //分配给DMA传输的源和目标端口,都分配到PORT01 O8 J. Y( P5 w
- handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; //传输事件的模式为Block块传输模式
; a8 X: v1 A8 ]3 Z% p - handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; //工作模式为正常模式
复制代码 ! C7 u4 `3 ^ y3 C/ c
然后就是主函数,先定义了两个callback函数,一个用于发送完成,一个用于发送错误。传输完成,中断响应后调用回调函数。* T! O* A. T" H$ c, F0 R
6 H: z, I5 L& Y6 a4 c/ J- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
! }; p5 Z0 ~6 b( e - HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
复制代码 通过两个变量标志位的状态,来判断是否完成和是否继续进行,并有两个回调函数来完成,如下:- static void TransferComplete(DMA_HandleTypeDef *handle_GPDMA1_Channel1)4 u2 X% L+ _/ P' G' G6 w
- {4 _9 ]9 ~( r! H0 z( z( Q
- transferCompleteDetected = 1;
/ z% }+ F. s: d7 S$ ?' V4 b - }" x$ [' w. k( a/ G
复制代码- static void TransferError(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
5 E h- y3 Y4 _4 {7 o - {" q9 J0 a3 Q1 @3 x4 L
- transferErrorDetected = 1;
" R% H2 H9 ~: Q- i8 G1 j - }
复制代码 其实官方的注释中写的也是比较详细的。然后就是配置源和目的地址,启动传输,如下:& M2 W- ], F% `6 j: v. |) P
- if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, (BUFFER_SIZE * 4U)) != HAL_OK)
2 ~" \/ I5 F+ S. u* m$ h! c9 G7 q - {! ~+ E( [$ m# D( x
- /* Transfer Error *// t$ F, C6 c, W7 J0 d3 h: r5 _5 g
- Error_Handler();
$ f/ M8 G+ x* k K' G! n p9 ?3 g - }
复制代码 其他部分可以参考源程序,测试结果如图2所示:
$ z3 `& ]' U$ s& i
; E1 Y- w+ q4 A0 x- T% a- |
图2
& d5 F) |" M: l/ `" E9 O' R9 n软件部分相对要简单一点,主要是通过测试和分析,理解和了解DMA的使用,为后续工作方便调用准备。! ?! ~3 l: u$ l: a
|
必须得整,得深入挖掘。