最近做数据传输要用到DMA,通过验证测试并分析官方的Demo,移植到自己的代码中,通过学习为我所用。 官方提供的Demo里有FlashToRAM的例程,先从这个例程下手。通过阅读手册可以知道,H503有2个DMA,感觉能扩展应用还挺多的,如图1所示:
5 c5 C9 |- |/ s" I" h' k5 X
8 L1 a7 a% C4 J: z1 p8 ? 图13 M: V' x- G; F9 e! y- q" F0 @
简单分析一下代码,先从初始化部分开始,这部分做了部分注释,如下所示:2 u v# u% W- ?2 C" b4 p7 j
4 E9 Q4 k" v/ k! c
- handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; //通道号* g4 s) |* F/ x7 @+ I7 u6 P9 A
- handle_GPDMA1_Channel1.Init.Request = DMA_REQUEST_SW; //请求来源,软件触发5 H$ N) f# K! y' {" n* s6 n
- handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;//硬件请求类型,单次触发模式, R& ?, H0 a+ X
- handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; //传输方向,内存到内存1 N% a6 h; B( S- N: v
- handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED; // 源地址增量模式+ B3 u* u$ n5 w! e
- handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; //目标地址增量模式& B+ h" j% P8 W6 A4 Q: @5 N* n
- handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; // 数据源的宽度,以字为单位
9 E% I7 ?: b1 K4 `. U - handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; //8 K1 y6 \ U5 w4 k; l Y
- handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; // DMA的优先级,低优先级高权重
$ @8 \ F, U/ Z4 x/ a2 P - handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; //Burst长度以数据单位表示
( {7 Z7 g4 v/ C. T. R( U - handle_GPDMA1_Channel1.Init.DestBurstLength = 1; //4 Z" A# h# A5 X5 m/ [) S
- handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; //分配给DMA传输的源和目标端口,都分配到PORT0
6 e8 [5 f( ?# l e s3 D) g - handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; //传输事件的模式为Block块传输模式: A8 j: V* Z5 R% v" a& }" @
- handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; //工作模式为正常模式
复制代码 7 M0 y: T6 r3 s. ?9 F2 {/ W6 l' w
然后就是主函数,先定义了两个callback函数,一个用于发送完成,一个用于发送错误。传输完成,中断响应后调用回调函数。
4 A" a2 O/ h; @# t" K/ `+ E, o
( W5 p- L: G+ y- }1 O- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
0 {% a+ }. ?% r" J* ` - HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
复制代码 通过两个变量标志位的状态,来判断是否完成和是否继续进行,并有两个回调函数来完成,如下:- static void TransferComplete(DMA_HandleTypeDef *handle_GPDMA1_Channel1)/ J" c4 w3 G4 B' ?
- {! E7 J! p) P8 ], C1 C$ s
- transferCompleteDetected = 1;
( B/ R1 ^% e) z4 w6 r! c/ R% c - }* P) N2 J1 Z) m% p4 i+ I$ _
复制代码- static void TransferError(DMA_HandleTypeDef *handle_GPDMA1_Channel1), M- b7 s* U/ H7 h4 a2 t$ Q
- {
! D5 K, b* ~3 l9 T" d - transferErrorDetected = 1;- N) a& q5 @% v3 b P; ?2 z
- }
复制代码 其实官方的注释中写的也是比较详细的。然后就是配置源和目的地址,启动传输,如下:
( _0 k+ p6 p" e) d" O- if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, (BUFFER_SIZE * 4U)) != HAL_OK)6 W2 t# ?7 P/ n. n
- {
' i4 h4 G5 v5 y* F - /* Transfer Error */0 ? F8 w7 X- c; z
- Error_Handler();
2 e- A4 Q' [9 O9 I5 q - }
复制代码 其他部分可以参考源程序,测试结果如图2所示:% v- r0 o! P! I1 p$ |9 j0 k8 T- _; z
7 X3 z% p* H: k
图2
$ y) p' C; N! v; q$ [# Q软件部分相对要简单一点,主要是通过测试和分析,理解和了解DMA的使用,为后续工作方便调用准备。! B) S. a- A* O( w) |# Z
|
必须得整,得深入挖掘。