最近做数据传输要用到DMA,通过验证测试并分析官方的Demo,移植到自己的代码中,通过学习为我所用。 官方提供的Demo里有FlashToRAM的例程,先从这个例程下手。通过阅读手册可以知道,H503有2个DMA,感觉能扩展应用还挺多的,如图1所示:3 L- P0 G8 j# F/ |& _/ S
( E; y5 P1 p8 A* h' K# } 图1
. ~9 v! T% `# ` 简单分析一下代码,先从初始化部分开始,这部分做了部分注释,如下所示:
9 h2 K1 c$ F+ Q
& @2 K: l& V. D' J2 w/ A- handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; //通道号( X- a' c4 F/ w' J' _6 O
- handle_GPDMA1_Channel1.Init.Request = DMA_REQUEST_SW; //请求来源,软件触发: T! K' q, F7 J! e( [8 ^# N
- handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;//硬件请求类型,单次触发模式$ _: G+ ?+ _) V/ B, x3 D" D
- handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; //传输方向,内存到内存
9 [6 Y* G) o' y" f% ] - handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED; // 源地址增量模式& x$ C" x! Y+ b, r) v
- handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; //目标地址增量模式/ \- f& Z; v5 J" k1 E
- handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; // 数据源的宽度,以字为单位, Z8 l& A0 Q( Z% _/ f
- handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; //, C }3 @% d, m; c, _4 \# ?
- handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; // DMA的优先级,低优先级高权重
, h3 @& P1 ]6 n4 N) V2 | - handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; //Burst长度以数据单位表示2 I8 a1 g9 n7 w6 e% l
- handle_GPDMA1_Channel1.Init.DestBurstLength = 1; //
U3 o/ N* h j - handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; //分配给DMA传输的源和目标端口,都分配到PORT06 c/ O& {4 ]7 ^9 {- }3 P
- handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; //传输事件的模式为Block块传输模式# n7 K7 }* p+ k0 r. I
- handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; //工作模式为正常模式
复制代码 ! C. B" w2 W s6 E4 z y
然后就是主函数,先定义了两个callback函数,一个用于发送完成,一个用于发送错误。传输完成,中断响应后调用回调函数。; @) E$ }8 ~5 G! i+ a
4 d7 }, h V% A2 V- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);! w( f9 F1 [* s1 A; G9 i5 h0 ^! O
- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
复制代码 通过两个变量标志位的状态,来判断是否完成和是否继续进行,并有两个回调函数来完成,如下:- static void TransferComplete(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
" S8 b$ ~1 B; ~; I# ] - {! }" f' ]* ~. R5 [* F) Q( Y
- transferCompleteDetected = 1;3 C5 b0 R" j9 E* r9 w. ~
- }( c% c! m$ _) s, z {0 k
复制代码- static void TransferError(DMA_HandleTypeDef *handle_GPDMA1_Channel1)4 ?+ q1 t u" ]: `, u( g ?
- {
) W( i3 i/ y# y! A - transferErrorDetected = 1;
% \0 Q5 ^$ B0 W. O' t - }
复制代码 其实官方的注释中写的也是比较详细的。然后就是配置源和目的地址,启动传输,如下:0 o! j7 v3 N3 F& b2 T1 M5 a; G
- if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, (BUFFER_SIZE * 4U)) != HAL_OK)* W6 e3 h: W4 E
- {
* \) C! W, { @* O: K+ @ - /* Transfer Error */
- r* `9 q. N- `3 `) Z) l0 @7 l0 h - Error_Handler();* X6 b4 t8 r+ L1 Z% b, T
- }
复制代码 其他部分可以参考源程序,测试结果如图2所示:
$ G: ~1 P/ N0 W7 ]
4 a- V" H0 A+ z; \6 j( w" h
图2
9 f" _, b5 l; J. Q; z软件部分相对要简单一点,主要是通过测试和分析,理解和了解DMA的使用,为后续工作方便调用准备。3 D9 ~& k$ Q( _6 x9 ?9 o
|
必须得整,得深入挖掘。