最近做数据传输要用到DMA,通过验证测试并分析官方的Demo,移植到自己的代码中,通过学习为我所用。 官方提供的Demo里有FlashToRAM的例程,先从这个例程下手。通过阅读手册可以知道,H503有2个DMA,感觉能扩展应用还挺多的,如图1所示:5 U i" v0 V) a
; F4 e# w$ S, \
图1
1 W7 k* N% n1 _ 简单分析一下代码,先从初始化部分开始,这部分做了部分注释,如下所示:
0 C f6 s. F4 l6 P- K" `: }( r1 I* L Y3 j: ^
- handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; //通道号$ Y! W x$ `; j9 a% i% D- F
- handle_GPDMA1_Channel1.Init.Request = DMA_REQUEST_SW; //请求来源,软件触发6 ^8 P. ~& g: ]* q8 Q. i
- handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;//硬件请求类型,单次触发模式: w9 r2 _& h4 z
- handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; //传输方向,内存到内存3 a+ D& y4 v6 x+ W: K& C
- handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED; // 源地址增量模式+ I3 D5 Z4 C0 a3 K: V# b5 q, m
- handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; //目标地址增量模式3 P( d' w0 s5 Z9 h+ G7 @4 C/ p/ w
- handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; // 数据源的宽度,以字为单位$ T) @% K0 m" V. A1 b, k
- handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; //
5 \( ]4 b8 M" b+ J8 Z- Y/ x1 _ - handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; // DMA的优先级,低优先级高权重
2 Y; _5 T" m {9 d6 z - handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; //Burst长度以数据单位表示0 X5 q) T& w% i4 h$ {
- handle_GPDMA1_Channel1.Init.DestBurstLength = 1; //
: r5 J" n7 V0 ~( Q1 ?# v) ^5 R - handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; //分配给DMA传输的源和目标端口,都分配到PORT0
* E8 \- A B- v( B$ V - handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; //传输事件的模式为Block块传输模式* q, ^/ L7 B. w$ ~" ]
- handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; //工作模式为正常模式
复制代码
' H- [) ~' i# j0 R- Y 然后就是主函数,先定义了两个callback函数,一个用于发送完成,一个用于发送错误。传输完成,中断响应后调用回调函数。
; G" y0 T2 o, S. }8 \
7 Y1 }( E# c! M5 `2 l) A: P. E- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
2 }1 F6 P5 c0 y @. D# R - HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
复制代码 通过两个变量标志位的状态,来判断是否完成和是否继续进行,并有两个回调函数来完成,如下:- static void TransferComplete(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
1 W6 {. m7 i6 q2 k9 [5 h - {
& V6 Z$ [# T, O0 S - transferCompleteDetected = 1;. [$ j4 N/ l% U# e$ F! n5 u! X
- }
' I! M2 B; [' J; c
复制代码- static void TransferError(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
5 S0 v0 \9 k( y5 P/ a2 O3 _: C1 o - {% T% m( I! D1 l- `- @; B
- transferErrorDetected = 1;8 q5 ?# |* I; K& k4 U: N3 J7 b
- }
复制代码 其实官方的注释中写的也是比较详细的。然后就是配置源和目的地址,启动传输,如下:
7 H( w2 p }$ m! D# o7 @: d- if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, (BUFFER_SIZE * 4U)) != HAL_OK)% l: g. N; C* `% I
- {
* m, P) c! Y. \ - /* Transfer Error */
& I' [0 o. ^/ [; L - Error_Handler();7 L, o7 b* G+ i K( A& m
- }
复制代码 其他部分可以参考源程序,测试结果如图2所示:
5 |) Y3 v3 _8 A1 w! R: U
9 C! `) x2 p( [' x. P. J& _/ m
图2! [ j4 J4 _# O
软件部分相对要简单一点,主要是通过测试和分析,理解和了解DMA的使用,为后续工作方便调用准备。1 T' z+ ?; y% R3 S! A
|
必须得整,得深入挖掘。