最近做数据传输要用到DMA,通过验证测试并分析官方的Demo,移植到自己的代码中,通过学习为我所用。 官方提供的Demo里有FlashToRAM的例程,先从这个例程下手。通过阅读手册可以知道,H503有2个DMA,感觉能扩展应用还挺多的,如图1所示:* e0 ~. k- i3 Y
( q( q. y" b# M# C 图1
1 W1 o1 G/ c, z7 ? 简单分析一下代码,先从初始化部分开始,这部分做了部分注释,如下所示:
: b$ X9 A4 x9 {3 [5 t# m- K: i# Y9 I0 w$ h# ]3 N
- handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; //通道号# m0 A# k& T8 @' e: a& }
- handle_GPDMA1_Channel1.Init.Request = DMA_REQUEST_SW; //请求来源,软件触发
; s2 p, t( b$ z - handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;//硬件请求类型,单次触发模式
' q7 O# X/ T3 Z/ {7 Z, ^ - handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; //传输方向,内存到内存$ L' E& ~6 S% T! u! \
- handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED; // 源地址增量模式% z/ l4 N& n* W
- handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; //目标地址增量模式
: }5 O O2 i# ~& F - handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; // 数据源的宽度,以字为单位
' _+ E4 C$ T( ]1 E/ J# p - handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; //$ j3 |4 [- ?2 d+ W- g
- handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; // DMA的优先级,低优先级高权重; }+ L! o* d1 E) s5 j
- handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; //Burst长度以数据单位表示
/ b# W2 J/ N# m& X - handle_GPDMA1_Channel1.Init.DestBurstLength = 1; //9 F1 J" N! i7 v' M
- handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; //分配给DMA传输的源和目标端口,都分配到PORT0
I: ]8 V2 X$ k - handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; //传输事件的模式为Block块传输模式
3 J' `0 X' n& D @, T% p; R - handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; //工作模式为正常模式
复制代码
, P) r! l: I! \. N! H) `8 e' e* o 然后就是主函数,先定义了两个callback函数,一个用于发送完成,一个用于发送错误。传输完成,中断响应后调用回调函数。; V! W J% L& Y7 t* }
* o/ E; S3 }, c9 s# s3 L# ^+ c
- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);9 S, K F0 a/ D" L3 q
- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
复制代码 通过两个变量标志位的状态,来判断是否完成和是否继续进行,并有两个回调函数来完成,如下:- static void TransferComplete(DMA_HandleTypeDef *handle_GPDMA1_Channel1)9 k+ \4 U& c% g. X
- {6 g& q( E1 E$ p# A4 U `
- transferCompleteDetected = 1;
8 y9 z9 } _; e. Y+ K8 ~ - }
" o3 v- K) X( {
复制代码- static void TransferError(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
- ?- c8 d' `: j' S; f# Z8 ? - {
7 r, r& z( R2 U1 h* M8 R8 J* T - transferErrorDetected = 1;3 ~7 A4 B% t; T3 n( \3 N w
- }
复制代码 其实官方的注释中写的也是比较详细的。然后就是配置源和目的地址,启动传输,如下:
& w ^4 S* E. k/ y3 B% `- if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, (BUFFER_SIZE * 4U)) != HAL_OK)
' [! @2 E: o, x: U - {
- L) m: W5 s/ v5 A - /* Transfer Error */
7 ?1 C0 [1 G9 ^( S: m - Error_Handler();5 B- G% E& t. g) u; E# K& l1 o
- }
复制代码 其他部分可以参考源程序,测试结果如图2所示: `7 R# q6 n6 g& |' }2 w
' m& f4 M; u* J6 P1 D图2
* g6 Z5 j* {8 L2 h软件部分相对要简单一点,主要是通过测试和分析,理解和了解DMA的使用,为后续工作方便调用准备。
1 _9 D# J# \; \% R2 Y O: J! B' A |
必须得整,得深入挖掘。