STM32H7的MDMA基础知识
MDMA(Master direct memory access),可以这么理解其是DMA的加强版。
MDMA 位于 D1 域,使用的 64 位的 AXI 总线,可以操作 TCM 空间(前面章节讲解的 DMA2D,通
用 DMA 和 BDMA 不支持操作 TCM 空间)。
对于本节,重点要了解 MDMA 的 buffer 缓冲传输,block 块传输和 list 列表模式的区别。
MDMA的基础特性
- MDMA 有两个主控总线接口,一个是 AXI/AHB 总线接口,主要用存储器或者外设访问,另一个是AHBS 总线接口,仅用于 TCM 空间访问。
- 有个 16 个通道,32 个硬件触发源。每个通道都可以选择 1 个触发源,当然,也可以通过软件触发。
- 16 个通道的传输请求,既可以外设,也可以来自 DMA1 或 DMA2
- MDMA 具有一个 256 级的 DMA 空间,被分为两个 128 级空间使用。
- MDMA 的优先级可通过软件配置,支持 very high, high, medium, low 四个等级,如果配置的优先级相同,则由 channel 的序号决定,channel0 最高,channel15 最低。
- 数据宽度可以设置字节,半字,字和双字。源地址和目的地址的数据宽度可不同。
- 源地址和目标地址的大小和地址增量可以独立选择。
- 数据的打包和拆解是采用的小端格式。
- 支持突发模式,最大可传输 128 字节。
- 当源地址和目的地址的增量和数据大小相同,且位宽小于等于 32bit 时,才允许 TCM 使用突发模式。
MDMA的硬件框图
◆ mdma_it
mdma 的中断触发信号。
◆ mdma_str0 到 mdma_str31 触发源
mdma 的输入请求。
◆ mdma_hclk
MDMA 的 HCLK 时钟。
MDMA块传输、缓冲传输和列表传输的区别(重要)
初学MDMA、要搞清楚MDMA支持的块传输,缓冲传输和列表传输的区别。
缓冲传输(MDMA_BUFFER_TRANSFER)
这个模式主要用于 QSPI,DCMI,硬件 JPEG 等外设上。每个请求都会触发 BufferTransferLength
(最大 128 字节)大小的数据传输,此大小由 HAL_MDMA_Init 调用的参数配置。
块传输(MDMA_BLOCK_TRANSFER)
此方式与 DMA1 和 DMA2 的数据传输相似,每次请求,触发一次块传输,块大小由
HAL_MDMA_Start/HAL_MDMA_Start_IT 定义,或者列表模式里面的参数。
多块传输(MDMA_REPEAT_BLOCK_TRANSFER)
顾名思义,多块传输就是执行多次块传输,每次请求,触发多次的块传输,块大小和块数由
HAL_MDMA_Start/HAL_MDMA_Start_IT 定义,或者列表模式里面的参数。
列表传输(MDMA_FULL_TRANSFER)
这种模式可以方便的实现多种 MDMA 配置进行切换,轮番实现,而且可以实现列表的循环方式。每次请求,将触发所有块和节点的传输(如果用户调用了函数HAL_MDMA_LinkedList_CreateNode \HAL_MDMA_LinkedList_AddNode),
MDMA列表模式及其循环方式
列表模式包含多种 MDMA 的配置表,每个表包含一组完整 MDMA 配置。用户可以使用函数
HAL_MDMA_LinkedList_CreateNode 创建节点,再通过函数 HAL_MDMA_LinkedList_AddNode 将节点添加到列表里面。
◆ 使用列表模式的话,函数 HAL_MDMA_Init 创建的是节点 0。
◆ 使用函数 HAL_MDMA_LinkedList_EnableCircularMode 使能循环模式,注意是从节点 1 开始循环的,将节点 1 和末尾的节点相连,不包含 HAL_MDMA_Init 创建的节点 0。
◆ 节点 0 是初始配置,仅在初始化 MDMA 传输时使用一次,比如调用函数 HAL_MDMA_Start_IT。
◆ 如果要禁止循环模式,可以调用函数 HAL_MDMA_LinkedList_DisableCircularMode。
◆ 通过函数 HAL_MDMA_LinkedList_RemoveNode 还可以删除指定节点。
MDMA的触发源
MDMA支持的触发源如下,主要包含 DMA1,DMA2,DMA2D,LTDC,JPEG,QSPI,DSI,SDMMC和软件触发:
#define MDMA_REQUEST_DMA1_Stream0_TC ((uint32_t)0x00000000U)
#define MDMA_REQUEST_DMA1_Stream1_TC ((uint32_t)0x00000001U)
#define MDMA_REQUEST_DMA1_Stream2_TC ((uint32_t)0x00000002U)
#define MDMA_REQUEST_DMA1_Stream3_TC ((uint32_t)0x00000003U)
#define MDMA_REQUEST_DMA1_Stream4_TC ((uint32_t)0x00000004U)
#define MDMA_REQUEST_DMA1_Stream5_TC ((uint32_t)0x00000005U)
#define MDMA_REQUEST_DMA1_Stream6_TC ((uint32_t)0x00000006U)
#define MDMA_REQUEST_DMA1_Stream7_TC ((uint32_t)0x00000007U)
#define MDMA_REQUEST_DMA2_Stream0_TC ((uint32_t)0x00000008U)
#define MDMA_REQUEST_DMA2_Stream1_TC ((uint32_t)0x00000009U)
#define MDMA_REQUEST_DMA2_Stream2_TC ((uint32_t)0x0000000AU)
#define MDMA_REQUEST_DMA2_Stream3_TC ((uint32_t)0x0000000BU)
#define MDMA_REQUEST_DMA2_Stream4_TC ((uint32_t)0x0000000CU)
#define MDMA_REQUEST_DMA2_Stream5_TC ((uint32_t)0x0000000DU)
#define MDMA_REQUEST_DMA2_Stream6_TC ((uint32_t)0x0000000EU)
#define MDMA_REQUEST_DMA2_Stream7_TC ((uint32_t)0x0000000FU)
#define MDMA_REQUEST_LTDC_LINE_IT ((uint32_t)0x00000010U)
#define MDMA_REQUEST_JPEG_INFIFO_TH ((uint32_t)0x00000011U)
#define MDMA_REQUEST_JPEG_INFIFO_NF ((uint32_t)0x00000012U)
#define MDMA_REQUEST_JPEG_OUTFIFO_TH ((uint32_t)0x00000013U)
#define MDMA_REQUEST_JPEG_OUTFIFO_NE ((uint32_t)0x00000014U)
#define MDMA_REQUEST_JPEG_END_CONVERSION ((uint32_t)0x00000015U)
#define MDMA_REQUEST_QUADSPI_FIFO_TH ((uint32_t)0x00000016U)
#define MDMA_REQUEST_QUADSPI_TC ((uint32_t)0x00000017U)
#define MDMA_REQUEST_DMA2D_CLUT_TC ((uint32_t)0x00000018U)
#define MDMA_REQUEST_DMA2D_TC ((uint32_t)0x00000019U)
#define MDMA_REQUEST_DMA2D_TW ((uint32_t)0x0000001AU)
#if defined(DSI)
#define MDMA_REQUEST_DSI_TEARINGE_FFECT ((uint32_t)0x0000001BU)
#define MDMA_REQUEST_DSI_END_REFRESH ((uint32_t)0x0000001CU)
#endif /* DSI */
#define MDMA_REQUEST_SDMMC1_ED_DATA ((uint32_t)0x0000001DU)
#define MDMA_REQUEST_SW ((uint32_t)0x40000000U)
MDMA软件触发
MDMA 配置为 MDMA_REQUEST_SW 软件触发时,可以通过函数
HAL_MDMA_GenerateSWRequest 产生触发请求,使用此函数要注意以下两个问题:
◆ 如果传输结束或者传输还没有启动,调用此函数会返回 error。
◆ 如果传输还在进行中断,调用此函数会返回 error,这次请求会被忽略。
◆ MDMA 配置为 MDMA_BUFFER_TRANSFER 模式,软件触发。
◆ 注册回调函数 HAL_MDMA_XFER_BUFFERCPLT_CB_ID。
◆ 调用函数 HAL_MDMA_Start_IT 会触发一次 BufferTransferLength 长度的数据传输。
◆ 传输结束会进入回调函数,用户可以在回调函数里面再次调用HAL_MDMA_GenerateSWRequest
启动传输。
MDMA的初始化流程总结
第 1 步:基本的初始化。
函数 HAL_MDMA_Init 配置 MDMA 的基本参数。
第 2 步:列表模式。
如果使用列表模式,用户可以使用函数 HAL_MDMA_LinkedList_CreateNode 创建节点,再通过函
数 HAL_MDMA_LinkedList_AddNode 将节点添加到列表里面。
第 3 步:查询模式。
函数 HAL_MDMA_Start 启动传输。
函数 HAL_MDMA_PollForTransfer 查询传输完成。
函数 HAL_MDMA_Abort 终止传输。
第 4 步:中断方式。
函数 HAL_NVIC_SetPriority 设置 MDMA 中断优先级。
函数 HAL_NVIC_EnableIRQ 使能中断。
函数 HAL_MDMA_Start_IT 启动中断传输。
MDMA 的中断服务程序 MDMA_IRQHandler 里面调用 HAL_MDMA_IRQHandler,如果用户
注册了各种回调函数,会在此函数里面执行。
函数 HAL_MDMA_Abort_IT 可以终止 MDMA 中断传输,终止完成后,会调用回调函数XferAbortCallback(如果设置了的话)
第 5 步:中断回调函数。
函数 HAL_MDMA_RegisterCallback 注册回调函数,函数 HAL_MDMA_UnRegisterCallback 取消
注册回调函数。
XferCpltCallback : 传输完成回调。
XferBufferCpltCallback : buffer 传输完成回调。
XferBlockCpltCallback : block 传输完成回调。
XferRepeatBlockCpltCallback : repeated block 传输完成回调。
XferErrorCallback : 传输错误回调。
XferAbortCallback : 传输终止回调。