最近做数据传输要用到DMA,通过验证测试并分析官方的Demo,移植到自己的代码中,通过学习为我所用。 官方提供的Demo里有FlashToRAM的例程,先从这个例程下手。通过阅读手册可以知道,H503有2个DMA,感觉能扩展应用还挺多的,如图1所示:
' N# |5 H, A$ [: z
! B k( T$ o. x4 ?& {
图1
$ z4 g6 M) p& ]9 H A; @+ C0 T 简单分析一下代码,先从初始化部分开始,这部分做了部分注释,如下所示: `6 Y/ T! U4 X3 H4 t
3 D) U" r" v: l" d# \
- handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; //通道号
8 ?, U6 o: E) n6 D; I - handle_GPDMA1_Channel1.Init.Request = DMA_REQUEST_SW; //请求来源,软件触发# z5 p6 d. I1 U% b. `
- handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;//硬件请求类型,单次触发模式1 c4 c0 }$ Y7 @, M, i$ B
- handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; //传输方向,内存到内存
" g" ?/ Y/ ~2 ]+ M) s - handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED; // 源地址增量模式
/ K1 H( z7 E7 a& C, Q - handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; //目标地址增量模式
; k/ S7 [' g2 v4 X% O' T% v, A - handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; // 数据源的宽度,以字为单位
, ~; p: V, z7 }: G& r; b - handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; //; F, c3 w+ ^- u, \/ y
- handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; // DMA的优先级,低优先级高权重9 W- w0 w/ v4 S2 d
- handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; //Burst长度以数据单位表示
, h8 F6 H H! [$ U1 d - handle_GPDMA1_Channel1.Init.DestBurstLength = 1; //* K- R! n# i* s6 H
- handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; //分配给DMA传输的源和目标端口,都分配到PORT0$ X" { P! I. r4 |- H* }
- handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; //传输事件的模式为Block块传输模式- A5 T+ z( n8 e/ j' J; e
- handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; //工作模式为正常模式
复制代码
4 `5 Q9 {8 f+ a/ C8 T" K2 p+ n 然后就是主函数,先定义了两个callback函数,一个用于发送完成,一个用于发送错误。传输完成,中断响应后调用回调函数。/ E. K: U% ~, d- y- X% u/ v, z) e
5 Q7 ^- J1 B" B
- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
: X- g0 R: W7 N) w' X - HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
复制代码 通过两个变量标志位的状态,来判断是否完成和是否继续进行,并有两个回调函数来完成,如下:- static void TransferComplete(DMA_HandleTypeDef *handle_GPDMA1_Channel1)
: A- y' @" T: p' g- B+ f; N8 k - {
- `6 E+ [; y! `$ u: Z - transferCompleteDetected = 1;
/ b( p$ R" v, ~* _. i* X0 Z. M - }
3 F8 ^6 u) c$ w9 a9 m
复制代码- static void TransferError(DMA_HandleTypeDef *handle_GPDMA1_Channel1)+ B( D/ {, D* {4 e; ~7 q( z' s) \
- {# N& \$ r- i9 y
- transferErrorDetected = 1;
( Z" _( X' t4 c' K" a o7 c - }
复制代码 其实官方的注释中写的也是比较详细的。然后就是配置源和目的地址,启动传输,如下:1 w/ b8 ^1 k) P m, G
- if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, (BUFFER_SIZE * 4U)) != HAL_OK)
& N4 a) y* V3 m0 j- ]0 H - {
% ]* `2 P" E# Z4 a" B. t - /* Transfer Error */- B' }/ `0 ]) p0 C7 A7 `
- Error_Handler();
$ v+ z& W- t1 T3 [ - }
复制代码 其他部分可以参考源程序,测试结果如图2所示:6 i P- P- k0 r$ t' A7 A) [% B+ ^
+ m6 E2 c: k7 }0 x& K) r
图25 U- J0 F* e# q. G0 a6 ~
软件部分相对要简单一点,主要是通过测试和分析,理解和了解DMA的使用,为后续工作方便调用准备。 `4 q0 ?: f- z @8 ]
|
必须得整,得深入挖掘。