最近做数据传输要用到DMA,通过验证测试并分析官方的Demo,移植到自己的代码中,通过学习为我所用。 官方提供的Demo里有FlashToRAM的例程,先从这个例程下手。通过阅读手册可以知道,H503有2个DMA,感觉能扩展应用还挺多的,如图1所示:
$ |5 F ~( \4 C" Q
, N# n) }; q- Z* u* h( ]; P: k+ Q 图14 ^2 n6 V( X. z' _% t5 n
简单分析一下代码,先从初始化部分开始,这部分做了部分注释,如下所示:0 s+ f4 D' @- N1 f
; P& n: y+ X9 U' ] E
- handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; //通道号! d9 _4 }6 l- \" ?/ h) H7 N/ V/ ^6 [8 E
- handle_GPDMA1_Channel1.Init.Request = DMA_REQUEST_SW; //请求来源,软件触发8 Q8 N; F; l! C6 g/ d* a
- handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;//硬件请求类型,单次触发模式
! ~* |7 y6 d! i* [+ [& ^ - handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; //传输方向,内存到内存# O( n2 K) m- [( L' H
- handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED; // 源地址增量模式- |$ r9 {* {, Q( N
- handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; //目标地址增量模式
% ^. G3 _5 W- X% R- b( m - handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; // 数据源的宽度,以字为单位
* w1 `7 o- U: n6 S1 ~ - handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; //. ]/ ^3 |0 P0 s/ V
- handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; // DMA的优先级,低优先级高权重7 A8 H8 r0 n) S2 c
- handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; //Burst长度以数据单位表示6 q7 N9 d; Z* a i
- handle_GPDMA1_Channel1.Init.DestBurstLength = 1; //
, U' H" ^% i' A% P. O* `7 W/ F - handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; //分配给DMA传输的源和目标端口,都分配到PORT0$ R; E: e5 q4 U3 y1 i+ u* Y
- handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; //传输事件的模式为Block块传输模式
) |- B& d! t1 _! R/ R( n8 ?! O - handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; //工作模式为正常模式
复制代码 ; ^1 C2 b. V( s2 F% V d6 r8 L
然后就是主函数,先定义了两个callback函数,一个用于发送完成,一个用于发送错误。传输完成,中断响应后调用回调函数。/ @% V6 V4 L5 t& d2 J. c0 U1 U
{: }9 x: |$ Z* S. Y% X4 ?: u* b- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
$ D. `4 K3 t% Z- X0 A - HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
复制代码 通过两个变量标志位的状态,来判断是否完成和是否继续进行,并有两个回调函数来完成,如下:- static void TransferComplete(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
; t; a* \6 I3 I. E - {6 C+ A, F/ X* [, m: r, J
- transferCompleteDetected = 1;9 i/ E/ f2 z, A8 L: w
- }
# _, j, ^, P$ t
复制代码- static void TransferError(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
+ r# N0 Z5 Z3 `* i - {
& E7 \/ m8 ~* d: |+ K' \ - transferErrorDetected = 1;
# z6 Q9 f# X. q/ `5 G4 K4 ? - }
复制代码 其实官方的注释中写的也是比较详细的。然后就是配置源和目的地址,启动传输,如下:# Q- H& d+ P3 d7 c- Z Z1 `$ }" d
- if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, (BUFFER_SIZE * 4U)) != HAL_OK)9 N7 o; q- m: B2 o+ L- @% i- C/ `
- {
) }! w6 P) _% ^ {- r - /* Transfer Error */; w8 h& u7 p; r: J
- Error_Handler();: v# G; g7 b8 s* k
- }
复制代码 其他部分可以参考源程序,测试结果如图2所示:# n+ A0 C o( o7 w
8 x E4 U" g: f/ a- g图21 D& z4 w' h. m
软件部分相对要简单一点,主要是通过测试和分析,理解和了解DMA的使用,为后续工作方便调用准备。7 ^) E ?, ~2 C
|
必须得整,得深入挖掘。