最近做数据传输要用到DMA,通过验证测试并分析官方的Demo,移植到自己的代码中,通过学习为我所用。 官方提供的Demo里有FlashToRAM的例程,先从这个例程下手。通过阅读手册可以知道,H503有2个DMA,感觉能扩展应用还挺多的,如图1所示:
' L+ `: p- ^" P2 a8 V
+ r2 Y9 @4 y, Q1 T
图1
1 b7 I8 E% y P Q8 D3 k- v+ ~ 简单分析一下代码,先从初始化部分开始,这部分做了部分注释,如下所示: m6 M! q! n4 w* N& T; Q: J
1 p- R0 V& ^) g: r% ]4 r' u/ z
- handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; //通道号0 q Y c% K" d1 c4 Q
- handle_GPDMA1_Channel1.Init.Request = DMA_REQUEST_SW; //请求来源,软件触发
: k9 ^& _* K$ k; C) p6 w - handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;//硬件请求类型,单次触发模式8 R3 b" |' l- a. z4 t
- handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; //传输方向,内存到内存
) ^5 X2 e5 F5 C1 \ - handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED; // 源地址增量模式
* z/ l9 @ z2 j% N" D) C4 N - handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; //目标地址增量模式
1 W% ~8 K0 y0 I5 ^- l - handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; // 数据源的宽度,以字为单位1 m* x2 y9 m. z/ o8 ~
- handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; //9 h, d; [* q+ A
- handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; // DMA的优先级,低优先级高权重
' l- V9 d' N/ s3 ^# t' `/ s - handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; //Burst长度以数据单位表示) j$ @* y% f: B2 ^" k+ Y, m3 k4 a/ f9 i/ W
- handle_GPDMA1_Channel1.Init.DestBurstLength = 1; //
$ T# R3 i+ b; {3 A* A+ Q& } - handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; //分配给DMA传输的源和目标端口,都分配到PORT0+ J, ] v7 K5 L: d. {
- handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; //传输事件的模式为Block块传输模式
) A; b; G- D. d, m - handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; //工作模式为正常模式
复制代码 3 `2 j, i# f) P% i
然后就是主函数,先定义了两个callback函数,一个用于发送完成,一个用于发送错误。传输完成,中断响应后调用回调函数。
( V3 O8 B9 e% r; I2 F, \8 U: f1 E
, p; ? z( Z' H- ^/ [6 O; l# D- HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
) }1 T/ R) Z7 L* E9 T4 o - HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
复制代码 通过两个变量标志位的状态,来判断是否完成和是否继续进行,并有两个回调函数来完成,如下:- static void TransferComplete(DMA_HandleTypeDef *handle_GPDMA1_Channel1)/ W/ m# \ P5 y" i. x& N
- {
+ F! h c4 Q/ m. P - transferCompleteDetected = 1;
! }# x* y( j- T. L3 r* Q! U - }* U; {* O4 ]3 }3 M5 n- g
复制代码- static void TransferError(DMA_HandleTypeDef *handle_GPDMA1_Channel1)% |% Q5 E4 [. A8 N* @- I4 v0 [) ]
- {- v! u/ ^7 d! t2 `# S3 v$ f2 ` P
- transferErrorDetected = 1;
$ V a" `6 }" t' }0 o - }
复制代码 其实官方的注释中写的也是比较详细的。然后就是配置源和目的地址,启动传输,如下:4 l- U- t+ ^8 M9 Y' e
- if (HAL_DMA_Start_IT(&handle_GPDMA1_Channel1, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, (BUFFER_SIZE * 4U)) != HAL_OK)7 O; a3 F: `0 _& p1 V; W
- {
) T" o( A6 Q: e( i - /* Transfer Error */
, m% Q+ G4 T$ Q5 M. b% T- k - Error_Handler();8 C6 E! o/ q" l/ Z+ K1 `
- }
复制代码 其他部分可以参考源程序,测试结果如图2所示:
6 P/ V. s/ H" @6 K! x( o6 N7 G' R
! _* ^2 c2 D' l' C2 i9 C: t6 G图2% q, P4 e' O, R4 Y: Y" C/ U( k
软件部分相对要简单一点,主要是通过测试和分析,理解和了解DMA的使用,为后续工作方便调用准备。/ M: K4 m2 ~, d' Z, e
|
必须得整,得深入挖掘。