【STM32H7教程】第61章 STM32H7的MDMA基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
第61章 STM32H7的MDMA基础知识和HAL库API
本章节为大家讲解MDMA(Master direct memory access)基础知识,主要用于提供高速的数据传输。
61.1 初学者重要提示
61.2 MDMA基础知识
61.3 MDMA的HAL库用法
61.4 源文件stm32h7xx_hal_mdma.c
61.5 总结
61.1 初学者重要提示
- MDMA位于D1域,使用的64位的AXI总线,可以操作TCM空间(前面章节讲解的DMA2D,通用DMA和BDMA不支持操作TCM空间)。
- 对于本章节,重点要了解MDMA的buffer缓冲传输,block块传输和list列表模式的区别,详情见本章2.2小节。
61.2 MDMA基础知识
对于STM32H7的MDMA了解到以下几点即可:
- 由于总线矩阵的存在,各个主控的道路四通八达,从而可以让DMA和CPU同时开工,但是注意一点,如果他们同时访问的同一个外设,会有一点性能影响的。
- 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使用突发模式。
61.2.1 MDMA硬件框图
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解MDMA的基本功能,然后再看手册了解细节。框图如下所示:
通过这个框图,我们可以得到如下信息:
- mdma_it
mdma的中断触发信号。
- mdma_str0到mdma_str31触发源
mdma的输入请求。
- mdma_hclk
MDMA的HCLK时钟。
61.2.2 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),
61.2.3 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还可以删除指定节点。
61.2.4 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)
61.2.5 MDMA的软件触发方式
MDMA配置为MDMA_REQUEST_SW软件触发时,可以通过函数HAL_MDMA_GenerateSWRequest产生触发请求,使用此函数要注意以下两个问题:
- 如果传输结束或者传输还没有启动,调用此函数会返回error。
- 如果传输还在进行中断,调用此函数会返回error,这次请求会被忽略。
应用示例1:
- MDMA配置为MDMA_BUFFER_TRANSFER模式,软件触发。
- 注册回调函数HAL_MDMA_XFER_BUFFERCPLT_CB_ID。
- 调用函数HAL_MDMA_Start_IT会触发一次BufferTransferLength长度的数据传输。
- 传输结束会进入回调函数,用户可以在回调函数里面再次调用HAL_MDMA_GenerateSWRequest启动传输。
应用示例2:
- MDMA配置为MDMA_BLOCK_TRANSFER模式,软件触发。
- 注册回调函数HAL_MDMA_XFER_BLOCKCPLT_CB_ID。
- 调用函数HAL_MDMA_Start_IT会触发一次块传输。
- 传输结束会进入回调函数,用户可以再回调函数里面再次调用HAL_MDMA_GenerateSWRequest再次启动传输。
61.3 MDMA的HAL库用法
MDMA的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。
61.3.1 MDMA寄存器结构体MDMA_Channel_TypeDef和MDMA_TypeDef
MDMA相关的寄存器是通过HAL库中的结构体MDMA_Channel_TypeDef和MDMA_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:
typedef struct
{
__IO uint32_t CISR; /*!< MDMA channel x interrupt/status register, Address offset: 0x40 */
__IO uint32_t CIFCR; /*!< MDMA channel x interrupt flag clear register, Address offset: 0x44 */
__IO uint32_t CESR; /*!< MDMA Channel x error status register, Address offset: 0x48 */
__IO uint32_t CCR; /*!< MDMA channel x control register, Address offset: 0x4C */
__IO uint32_t CTCR; /*!< MDMA channel x Transfer Configuration register, Address offset: 0x50 */
__IO uint32_t CBNDTR; /*!< MDMA Channel x block number of data register, Address offset: 0x54 */
__IO uint32_t CSAR; /*!< MDMA channel x source address register, Address offset: 0x58 */
__IO uint32_t CDAR; /*!< MDMA channel x destination address register, Address offset: 0x5C */
__IO uint32_t CBRUR; /*!< MDMA channel x Block Repeat address Update register, Address offset: 0x60 */
__IO uint32_t CLAR; /*!< MDMA channel x Link Address register, Address offset: 0x64 */
__IO uint32_t CTBR; /*!< MDMA channel x Trigger and Bus selection Register, Address offset: 0x68 */
uint32_t RESERVED0; /*!< Reserved, 0x68 */
__IO uint32_t CMAR; /*!< MDMA channel x Mask address register, Address offset: 0x70 */
__IO uint32_t CMDR; /*!< MDMA channel x Mask Data register, Address offset: 0x74 */
}MDMA_Channel_TypeDef; typedef struct
{
__IO uint32_t GISR0; /*!< MDMA Global Interrupt/Status Register 0, Address offset: 0x00 */
}MDMA_TypeDef;
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
下面我们再看MDMA的定义,在stm32h743xx.h文件。
#define PERIPH_BASE ((uint32_t)0x40000000)
#define D1_AHB1PERIPH_BASE (PERIPH_BASE + 0x12000000)
#define MDMA_BASE (D1_AHB1PERIPH_BASE + 0x0000) #define MDMA_Channel0_BASE (MDMA_BASE + 0x00000040)
#define MDMA_Channel1_BASE (MDMA_BASE + 0x00000080)
#define MDMA_Channel2_BASE (MDMA_BASE + 0x000000C0)
#define MDMA_Channel3_BASE (MDMA_BASE + 0x00000100)
#define MDMA_Channel4_BASE (MDMA_BASE + 0x00000140)
#define MDMA_Channel5_BASE (MDMA_BASE + 0x00000180)
#define MDMA_Channel6_BASE (MDMA_BASE + 0x000001C0)
#define MDMA_Channel7_BASE (MDMA_BASE + 0x00000200)
#define MDMA_Channel8_BASE (MDMA_BASE + 0x00000240)
#define MDMA_Channel9_BASE (MDMA_BASE + 0x00000280)
#define MDMA_Channel10_BASE (MDMA_BASE + 0x000002C0)
#define MDMA_Channel11_BASE (MDMA_BASE + 0x00000300)
#define MDMA_Channel12_BASE (MDMA_BASE + 0x00000340)
#define MDMA_Channel13_BASE (MDMA_BASE + 0x00000380)
#define MDMA_Channel14_BASE (MDMA_BASE + 0x000003C0)
#define MDMA_Channel15_BASE (MDMA_BASE + 0x00000400) #define MDMA ((MDMA_TypeDef *)MDMA_BASE) <----- 展开这个宏,(MDMA_TypeDef *) 0x52000000
#define MDMA_Channel0 ((MDMA_Channel_TypeDef *)MDMA_Channel0_BASE)
#define MDMA_Channel1 ((MDMA_Channel_TypeDef *)MDMA_Channel1_BASE)
#define MDMA_Channel2 ((MDMA_Channel_TypeDef *)MDMA_Channel2_BASE)
#define MDMA_Channel3 ((MDMA_Channel_TypeDef *)MDMA_Channel3_BASE)
#define MDMA_Channel4 ((MDMA_Channel_TypeDef *)MDMA_Channel4_BASE)
#define MDMA_Channel5 ((MDMA_Channel_TypeDef *)MDMA_Channel5_BASE)
#define MDMA_Channel6 ((MDMA_Channel_TypeDef *)MDMA_Channel6_BASE)
#define MDMA_Channel7 ((MDMA_Channel_TypeDef *)MDMA_Channel7_BASE)
#define MDMA_Channel8 ((MDMA_Channel_TypeDef *)MDMA_Channel8_BASE)
#define MDMA_Channel9 ((MDMA_Channel_TypeDef *)MDMA_Channel9_BASE)
#define MDMA_Channel10 ((MDMA_Channel_TypeDef *)MDMA_Channel10_BASE)
#define MDMA_Channel11 ((MDMA_Channel_TypeDef *)MDMA_Channel11_BASE)
#define MDMA_Channel12 ((MDMA_Channel_TypeDef *)MDMA_Channel12_BASE)
#define MDMA_Channel13 ((MDMA_Channel_TypeDef *)MDMA_Channel13_BASE)
#define MDMA_Channel14 ((MDMA_Channel_TypeDef *)MDMA_Channel14_BASE)
#define MDMA_Channel15 ((MDMA_Channel_TypeDef *)MDMA_Channel15_BASE)
我们访问MDMA的GISR0寄存器可以采用这种形式:MDMA->GISR0 = 0。
61.3.2 MDMA的参数结构体MDMA_InitTypeDef
此结构体用于MDMA的参数配置,具体定义如下:
typedef struct
{
uint32_t Request;
uint32_t TransferTriggerMode;
uint32_t Priority;
uint32_t Endianness;
uint32_t SourceInc;
uint32_t DestinationInc;
uint32_t SourceDataSize;
uint32_t DestDataSize;
uint32_t DataAlignment;
uint32_t BufferTransferLength;
uint32_t SourceBurst;
uint32_t DestBurst;
int32_t SourceBlockAddressOffset;
int32_t DestBlockAddressOffset;
}MDMA_InitTypeDef;
下面将这几个参数逐一为大家做个说明:
- uint32_t Request
触发MDMA的请求源,支持请求源如下:
#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_END_DATA ((uint32_t)0x0000001DU)
#define MDMA_REQUEST_SW ((uint32_t)0x40000000U)
- uint32_t TransferTriggerMode
MDMA的传输模式,具体支持的参数如下:
#define MDMA_BUFFER_TRANSFER ((uint32_t)0x00000000U) /* 缓冲传输 */
#define MDMA_BLOCK_TRANSFER ((uint32_t)MDMA_CTCR_TRGM_0) /* 块传输 */
#define MDMA_REPEAT_BLOCK_TRANSFER ((uint32_t)MDMA_CTCR_TRGM_1) /* 多块传输 */
#define MDMA_FULL_TRANSFER ((uint32_t)MDMA_CTCR_TRGM) /* 链表传输 */
- uint32_t Priority
MDMA通道的优先级设置,具体支持的参数如下:
#define MDMA_PRIORITY_LOW ((uint32_t)0x00000000U)
#define MDMA_PRIORITY_MEDIUM ((uint32_t)MDMA_CCR_PL_0)
#define MDMA_PRIORITY_HIGH ((uint32_t)MDMA_CCR_PL_1)
#define MDMA_PRIORITY_VERY_HIGH ((uint32_t)MDMA_CCR_PL)
- uint32_t Endianness
MDMA数据传输格式,具体支持的参数如下:
#define MDMA_LITTLE_ENDIANNESS_PRESERVE ((uint32_t)0x00000000U)
#define MDMA_LITTLE_BYTE_ENDIANNESS_EXCHANGE ((uint32_t)MDMA_CCR_BEX)
#define MDMA_LITTLE_HALFWORD_ENDIANNESS_EXCHANGE ((uint32_t)MDMA_CCR_HEX)
#define MDMA_LITTLE_WORD_ENDIANNESS_EXCHANGE ((uint32_t)MDMA_CCR_WEX)
MDMA_LITTLE_ENDIANNESS_PRESERVE:正常的小端格式。
MDMA_LITTLE_BYTE_ENDIANNESS_EXCHANGE:以半字为单位,交互高低字节。
MDMA_LITTLE_HALFWORD_ENDIANNESS_EXCHANGE:以字为单位,交互半字。
MDMA_LITTLE_WORD_ENDIANNESS_EXCHANGE:以双字为单位,交换字。
- uint32_t SourceInc
MDMA源数据自增或者自减模式,具体支持的参数如下:
#define MDMA_SRC_INC_DISABLE ((uint32_t)0x00000000U)
#define MDMA_SRC_INC_BYTE ((uint32_t)MDMA_CTCR_SINC_1)
#define MDMA_SRC_INC_HALFWORD ((uint32_t)MDMA_CTCR_SINC_1 | (uint32_t)MDMA_CTCR_SINCOS_0)
#define MDMA_SRC_INC_WORD ((uint32_t)MDMA_CTCR_SINC_1 | (uint32_t)MDMA_CTCR_SINCOS_1)
#define MDMA_SRC_INC_DOUBLEWORD ((uint32_t)MDMA_CTCR_SINC_1 | (uint32_t)MDMA_CTCR_SINCOS)
#define MDMA_SRC_DEC_BYTE ((uint32_t)MDMA_CTCR_SINC)
#define MDMA_SRC_DEC_HALFWORD ((uint32_t)MDMA_CTCR_SINC | (uint32_t)MDMA_CTCR_SINCOS_0)
#define MDMA_SRC_DEC_WORD ((uint32_t)MDMA_CTCR_SINC | (uint32_t)MDMA_CTCR_SINCOS_1)
#define MDMA_SRC_DEC_DOUBLEWORD ((uint32_t)MDMA_CTCR_SINC | (uint32_t)MDMA_CTCR_SINCOS)
- DestinationInc
MDMA目的数据自增或者自减模式,具体支持的参数如下:
#define MDMA_DEST_INC_DISABLE ((uint32_t)0x00000000U)
#define MDMA_DEST_INC_BYTE ((uint32_t)MDMA_CTCR_DINC_1)
#define MDMA_DEST_INC_HALFWORD ((uint32_t)MDMA_CTCR_DINC_1 | (uint32_t)MDMA_CTCR_DINCOS_0)
#define MDMA_DEST_INC_WORD ((uint32_t)MDMA_CTCR_DINC_1 | (uint32_t)MDMA_CTCR_DINCOS_1)
#define MDMA_DEST_INC_DOUBLEWORD ((uint32_t)MDMA_CTCR_DINC_1 | (uint32_t)MDMA_CTCR_DINCOS)
#define MDMA_DEST_DEC_BYTE ((uint32_t)MDMA_CTCR_DINC)
#define MDMA_DEST_DEC_HALFWORD ((uint32_t)MDMA_CTCR_DINC | (uint32_t)MDMA_CTCR_DINCOS_0)
#define MDMA_DEST_DEC_WORD ((uint32_t)MDMA_CTCR_DINC | (uint32_t)MDMA_CTCR_DINCOS_1)
#define MDMA_DEST_DEC_DOUBLEWORD ((uint32_t)MDMA_CTCR_DINC | (uint32_t)MDMA_CTCR_DINCOS)
- SourceDataSize
MDMA源数据带宽,具体支持的参数如下:
#define MDMA_SRC_DATASIZE_BYTE ((uint32_t)0x00000000U)
#define MDMA_SRC_DATASIZE_HALFWORD ((uint32_t)MDMA_CTCR_SSIZE_0)
#define MDMA_SRC_DATASIZE_WORD ((uint32_t)MDMA_CTCR_SSIZE_1)
#define MDMA_SRC_DATASIZE_DOUBLEWORD ((uint32_t)MDMA_CTCR_SSIZE)
- DestDataSize
MDMA目的数据带宽,具体支持的参数如下:
#define MDMA_DEST_DATASIZE_BYTE ((uint32_t)0x00000000U)
#define MDMA_DEST_DATASIZE_HALFWORD ((uint32_t)MDMA_CTCR_DSIZE_0)
#define MDMA_DEST_DATASIZE_WORD ((uint32_t)MDMA_CTCR_DSIZE_1)
#define MDMA_DEST_DATASIZE_DOUBLEWORD ((uint32_t)MDMA_CTCR_DSIZE)
- DataAlignment
MDMA的填充/对齐设置,具体支持的参数如下:
#define MDMA_DATAALIGN_PACKENABLE (uint32_t)MDMA_CTCR_PKE)
#define MDMA_DATAALIGN_RIGHT ((uint32_t)0x00000000U)
#define MDMA_DATAALIGN_RIGHT_SIGNED ((uint32_t)MDMA_CTCR_PAM_0)
#define MDMA_DATAALIGN_LEFT ((uint32_t)MDMA_CTCR_PAM_1)
MDMA_DATAALIGN_PACKENABLE:
将源数据封装/解封为目标数据大小。所有数据均右对齐(采用小端模式)。
MDMA_DATAALIGN_RIGHT
右对齐,用 0 进行填充(默认值)
MDMA_DATAALIGN_RIGHT_SIGNED
右对齐,符号扩展
MDMA_DATAALIGN_LEFT
左对齐(用 0 进行填充)
- BufferTransferLength
单次传输长度设置,范围1-128,单位字节。
- SourceBurst
源数据端突发设置,特别注意突发传输的数量不能超过BufferTransferLength参数设置的大小,具体支持的参数如下:
#define MDMA_SOURCE_BURST_SINGLE ((uint32_t)0x00000000U)
#define MDMA_SOURCE_BURST_2BEATS ((uint32_t)MDMA_CTCR_SBURST_0) #define MDMA_SOURCE_BURST_4BEATS ((uint32_t)MDMA_CTCR_SBURST_1) #define MDMA_SOURCE_BURST_8BEATS ((uint32_t)MDMA_CTCR_SBURST_0 | (uint32_t)MDMA_CTCR_SBURST_1)
#define MDMA_SOURCE_BURST_16BEATS ((uint32_t)MDMA_CTCR_SBURST_2)
#define MDMA_SOURCE_BURST_32BEATS ((uint32_t)MDMA_CTCR_SBURST_0 | (uint32_t)MDMA_CTCR_SBURST_2)
#define MDMA_SOURCE_BURST_64BEATS ((uint32_t)MDMA_CTCR_SBURST_1 | (uint32_t)MDMA_CTCR_SBURST_2)
#define MDMA_SOURCE_BURST_128BEATS ((uint32_t)MDMA_CTCR_SBURST)
- DestBurst
目的数据端突发设置,特别注意突发传输的数量不能超过BufferTransferLength参数设置的大小,具体支持的参数如下
#define MDMA_DEST_BURST_SINGLE ((uint32_t)0x00000000U)
#define MDMA_DEST_BURST_2BEATS ((uint32_t)MDMA_CTCR_DBURST_0)
#define MDMA_DEST_BURST_4BEATS ((uint32_t)MDMA_CTCR_DBURST_1) #define MDMA_DEST_BURST_8BEATS ((uint32_t)MDMA_CTCR_DBURST_0 | (uint32_t)MDMA_CTCR_DBURST_1)
#define MDMA_DEST_BURST_16BEATS ((uint32_t)MDMA_CTCR_DBURST_2)
#define MDMA_DEST_BURST_32BEATS ((uint32_t)MDMA_CTCR_DBURST_0 | (uint32_t)MDMA_CTCR_DBURST_2)
#define MDMA_DEST_BURST_64BEATS ((uint32_t)MDMA_CTCR_DBURST_1 | (uint32_t)MDMA_CTCR_DBURST_2)
#define MDMA_DEST_BURST_128BEATS ((uint32_t)MDMA_CTCR_DBURST)
- SourceBlockAddressOffset
用于设置源地址端数据偏移。
- DestBlockAddressOffset
用于设置目的地址端数据偏移。
61.3.3 MDMA结构体句柄MDMA_HandleTypeDef
HAL库在MDMA_Channel_TypeDef和MDMA_InitTypeDef的基础上封装了一个结构体MDMA_HandleTypeDef,定义如下:
typedef struct __MDMA_HandleTypeDef
{
MDMA_Channel_TypeDef *Instance;
MDMA_InitTypeDef Init;
HAL_LockTypeDef Lock;
__IO HAL_MDMA_StateTypeDef State;
void *Parent;
void (* XferCpltCallback)( struct __MDMA_HandleTypeDef * hmdma);
void (* XferBufferCpltCallback)( struct __MDMA_HandleTypeDef * hmdma);
void (* XferBlockCpltCallback)( struct __MDMA_HandleTypeDef * hmdma);
void (* XferRepeatBlockCpltCallback)( struct __MDMA_HandleTypeDef * hmdma);
void (* XferErrorCallback)( struct __MDMA_HandleTypeDef * hmdma);
void (* XferAbortCallback)( struct __MDMA_HandleTypeDef * hmdma);
MDMA_LinkNodeTypeDef *FirstLinkedListNodeAddress;
MDMA_LinkNodeTypeDef *LastLinkedListNodeAddress;
uint32_t LinkedListNodeCounter;
__IO uint32_t ErrorCode;
} MDMA_HandleTypeDef;
下面将这几个参数逐一做个说明。
- MDMA_Channel_TypeDef *Instance
这个参数MDMA通道的例化,方便操作寄存器,详见本章3.1小节。
- MDMA_InitTypeDef Init
这个参数用于MDMA的通道参数初始化,详见本章3.2小节。
- void *Parent
用于记录MDMA关联的外设。
- void (* XferCpltCallback)( struct __MDMA_HandleTypeDef * hmdma);
- void (* XferBufferCpltCallback)( struct __MDMA_HandleTypeDef * hmdma);
- void (* XferBlockCpltCallback)( struct __MDMA_HandleTypeDef * hmdma);
- void (* XferRepeatBlockCpltCallback)( struct __MDMA_HandleTypeDef * hmdma);
- void (* XferErrorCallback)( struct __MDMA_HandleTypeDef * hmdma);
- void (* XferAbortCallback)( struct __MDMA_HandleTypeDef * hmdma);
MDMA的各种回调函数。
- MDMA_LinkNodeTypeDef *FirstLinkedListNodeAddress;
- MDMA_LinkNodeTypeDef *LastLinkedListNodeAddress;
- uint32_t LinkedListNodeCounter;
用于MDMA的列表模式。
- HAL_LockTypeDef Lock
- __IO HAL_DAC_STATETypeDef State
- __IO uint32_t ErrorCode
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DAC状态,而ErrorCode用于配置代码错误。
61.3.4 MDMA初始化流程总结
使用方法由HAL库提供:
第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 : 传输终止回调。
61.4 源文件stm32h7xx_hal_mdma.c
这里把我们把如下几个常用到的函数做个说明:
- HAL_MDMA_Init
- HAL_MDMA_Start_IT
61.4.1 函数HAL_MDMA_Init
函数原型:
HAL_StatusTypeDef HAL_MDMA_Init(MDMA_HandleTypeDef *hmdma)
{
uint32_t tickstart = HAL_GetTick(); /* 检测句柄是否有效 */
if(hmdma == NULL)
{
return HAL_ERROR;
} /* 检测参数 */
assert_param(IS_MDMA_STREAM_ALL_INSTANCE(hmdma->Instance));
assert_param(IS_MDMA_PRIORITY(hmdma->Init.Priority));
assert_param(IS_MDMA_ENDIANNESS_MODE(hmdma->Init.Endianness));
assert_param(IS_MDMA_REQUEST(hmdma->Init.Request));
assert_param(IS_MDMA_SOURCE_INC(hmdma->Init.SourceInc));
assert_param(IS_MDMA_DESTINATION_INC(hmdma->Init.DestinationInc));
assert_param(IS_MDMA_SOURCE_DATASIZE(hmdma->Init.SourceDataSize));
assert_param(IS_MDMA_DESTINATION_DATASIZE(hmdma->Init.DestDataSize));
assert_param(IS_MDMA_DATA_ALIGNMENT(hmdma->Init.DataAlignment));
assert_param(IS_MDMA_SOURCE_BURST(hmdma->Init.SourceBurst));
assert_param(IS_MDMA_DESTINATION_BURST(hmdma->Init.DestBurst));
assert_param(IS_MDMA_BUFFER_TRANSFER_LENGTH(hmdma->Init.BufferTransferLength));
assert_param(IS_MDMA_TRANSFER_TRIGGER_MODE(hmdma->Init.TransferTriggerMode));
assert_param(IS_MDMA_BLOCK_ADDR_OFFSET(hmdma->Init.SourceBlockAddressOffset));
assert_param(IS_MDMA_BLOCK_ADDR_OFFSET(hmdma->Init.DestBlockAddressOffset)); /* 解锁 */
__HAL_UNLOCK(hmdma); /* Change MDMA peripheral state */
hmdma->State = HAL_MDMA_STATE_BUSY; /* 禁止MDMA */
__HAL_MDMA_DISABLE(hmdma); /* 等待禁止成功 */
while((hmdma->Instance->CCR & MDMA_CCR_EN) != RESET)
{
if((HAL_GetTick() - tickstart ) > HAL_TIMEOUT_MDMA_ABORT)
{
hmdma->ErrorCode = HAL_MDMA_ERROR_TIMEOUT; hmdma->State = HAL_MDMA_STATE_ERROR; return HAL_ERROR;
}
} /* 初始化 MDMA */
MDMA_Init(hmdma); /* 复位列表模式相关设置 */
hmdma->FirstLinkedListNodeAddress = ;
hmdma->LastLinkedListNodeAddress = ;
hmdma->LinkedListNodeCounter = ; /* 设置无错误 */
hmdma->ErrorCode = HAL_MDMA_ERROR_NONE; /* 设置就绪 */
hmdma->State = HAL_MDMA_STATE_READY; return HAL_OK;
}
函数描述:
此函数用于初始化MDMA。
函数参数:
- 第1个参数是MDMA_HandleTypeDef类型结构体指针变量,结构体变量成员的详细介绍看本章3.3小节。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
使用举例:
MDMA_HandleTypeDef MDMA_Handle; __HAL_RCC_MDMA_CLK_ENABLE(); MDMA_Handle.Instance = MDMA_Channel0; MDMA_Handle.Init.Request = MDMA_REQUEST_SW; /* 软件触发 */
MDMA_Handle.Init.TransferTriggerMode = MDMA_BLOCK_TRANSFER; /* 块传输 */
MDMA_Handle.Init.Priority = MDMA_PRIORITY_HIGH; /* 优先级高*/
MDMA_Handle.Init.Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE; /* 小端 */
MDMA_Handle.Init.SourceInc = MDMA_SRC_INC_DOUBLEWORD; /* 源地址自增,双字,即8字节 */
MDMA_Handle.Init.DestinationInc = MDMA_DEST_INC_DOUBLEWORD; /* 目的地址自增,双字,即8字节 */
MDMA_Handle.Init.SourceDataSize = MDMA_SRC_DATASIZE_DOUBLEWORD; /* 源地址数据宽度双字,即8字节 */
MDMA_Handle.Init.DestDataSize = MDMA_DEST_DATASIZE_DOUBLEWORD; /* 目的地址数据宽度双字,即8字节 */
MDMA_Handle.Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE; /* 小端,右对齐 */
MDMA_Handle.Init.SourceBurst = MDMA_SOURCE_BURST_16BEATS; /* 源数据突发传输 */
MDMA_Handle.Init.DestBurst = MDMA_DEST_BURST_16BEATS; /* 目的数据突发传输 */ MDMA_Handle.Init.BufferTransferLength = ; /* 每次传输128个字节 */ MDMA_Handle.Init.SourceBlockAddressOffset = ; /* 用于block传输,地址偏移0 */
MDMA_Handle.Init.DestBlockAddressOffset = ; /* 用于block传输,地址偏移0 */ /* 初始化MDMA */
if(HAL_MDMA_Init(&MDMA_Handle) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
61.4.2 函数HAL_MDMA_Start_IT
函数原型:
HAL_StatusTypeDef HAL_MDMA_Start_IT(MDMA_HandleTypeDef *hmdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t BlockDataLength, uint32_t BlockCount)
{
/* 检测参数 */
assert_param(IS_MDMA_TRANSFER_LENGTH(BlockDataLength));
assert_param(IS_MDMA_BLOCK_COUNT(BlockCount)); /* 检测句柄是否有效 */
if(hmdma == NULL)
{
return HAL_ERROR;
} /* 上锁 */
__HAL_LOCK(hmdma); if(HAL_MDMA_STATE_READY == hmdma->State)
{
hmdma->State = HAL_MDMA_STATE_BUSY; hmdma->ErrorCode = HAL_MDMA_ERROR_NONE; __HAL_MDMA_DISABLE(hmdma); /* 配置MDMA */
MDMA_SetConfig(hmdma, SrcAddress, DstAddress, BlockDataLength, BlockCount); /* 使能传输错误和传输完成中断 */
__HAL_MDMA_ENABLE_IT(hmdma, (MDMA_IT_TE | MDMA_IT_CTC)); if(hmdma->XferBlockCpltCallback != NULL)
{
/* 使能块传输完成中断 */
__HAL_MDMA_ENABLE_IT(hmdma, MDMA_IT_BT);
} if(hmdma->XferRepeatBlockCpltCallback != NULL)
{
/* 使能多块传输完成中断 */
__HAL_MDMA_ENABLE_IT(hmdma, MDMA_IT_BRT);
} if(hmdma->XferBufferCpltCallback != NULL)
{
/* 使能传输完成中断 */
__HAL_MDMA_ENABLE_IT(hmdma, MDMA_IT_BFTC);
} /* 使能外设 */
__HAL_MDMA_ENABLE(hmdma); if(hmdma->Init.Request == MDMA_REQUEST_SW)
{
/* 使能软件请求 */
hmdma->Instance->CCR |= MDMA_CCR_SWRQ;
}
}
else
{
/* 解锁 */
__HAL_UNLOCK(hmdma); /* 返回忙 */
return HAL_BUSY;
} return HAL_OK;
}
函数描述:
此函数主要用于配置MDMA的中断方式传输。
函数参数:
- 第1个参数是MDMA_HandleTypeDef类型结构体指针变量,结构体变量成员的详细介绍看本章3.3小节。
- 第2个参数是源缓冲地址。
- 第3个参数是目的地址。
- 第4个参数是传输的块大小,单位字节,范围不可以超过65536字节。
- 第5个参数是传输的块数,范围不可以超过4095块。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
使用举例:
/* 将地址0x24000000开始的64KB数据复制到地址0x24000000 + 64*1024 */
HAL_MDMA_Start_IT(&MDMA_Handle,
(uint32_t)0x24000000,
(uint32_t)(0x24000000 + *),
*,
);
61.5 总结
本章节就为大家讲解这么多,MDMA功能用到的地方还是比较多的,后面的章节会为大家做讲解。
【STM32H7教程】第61章 STM32H7的MDMA基础知识和HAL库API的更多相关文章
- 【STM32H7教程】第47章 STM32H7的FMC总线基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第47章 STM32H7的FMC总线基础知识和HA ...
- 【STM32H7教程】第57章 STM32H7硬件JPEG编解码基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第57章 STM32H7硬件JPEG编解码基础知识 ...
- 【STM32H7教程】第55章 STM32H7的图形加速器DMA2D的基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第55章 STM32H7的图形加速器DMA2D的基 ...
- 【STM32H7教程】第50章 STM32H7的LCD控制器LTDC基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第50章 STM32H7的LCD控制器LTDC基础 ...
- 【STM32H7教程】第32章 STM32H7的TIM定时器基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第32章 STM32H7的TIM定时器基础知识和H ...
- 【STM32H7教程】第29章 STM32H7的USART串口基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第29章 STM32H7的USART串口基础知识和 ...
- 【STM32H7教程】第59章 STM32H7的DAC基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第59章 STM32H7的DAC基础知识和HAL库 ...
- 【STM32H7教程】第17章 STM32H7之GPIO的HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第17章 STM32H7之GPIO的HAL库API ...
- 【STM32H7教程】第16章 STM32H7必备的HAL库API(重要)
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第16章 STM32H7必备的HAL库API(重要 ...
随机推荐
- 7.Java帝国的诞生
1972年,C诞生,而Java是1995年诞生的.它贴近硬件,有汇编语言的特性,运行极快,效率极高.早期,用在操作系统.编译器.数据库.网络系统等.但它有两把沉重的枷锁一直在程序员身上,那就是指针和内 ...
- C#中TripleDES对应Java中的DESede即大家说的3DES,附C#及Java加解密结果一致的控制台程序例子
直接上代码了. Java控制台代码: package Test; import java.security.Key; import javax.crypto.Cipher; import javax. ...
- 18年第一弹射 和网络有关; 艾曲塞嗯诶系列篇 two
35: 华为AR G3系列路由器可以通过FTP和TFTP更新系统文件,AR G3系列路由器可以作为FTP Client , FTP Server ,TFTP Client 36: 两台路由器间通过串口 ...
- WinSCP整合SecureCRT打开终端
使用WinSCP直接操作文件非常方便,但是如果用它来连入SSH进行指令交互就不方便了,使用XShell.SecureCRT.Putty等SSH终端软件敲指令却很不错,于是想能不能将两者结合起来使用.我 ...
- 使用ob缓存简单实现页面静态化
<?php //接收新闻id,传统的方法查询数据库并显示数据 $id=intval($_GET['id']); //先判断该新闻对于的静态页面是否存在,如果有,则直接返回,如果 //没有,则查询 ...
- ios--->cell里面 self 和self.contentview的区别
一般我们向cell中添加子视图,有两种方式 [cell addSubview:] [cell.contentView addSubview:] 区别在于进行cell编辑时,比如cell内容向左移或者右 ...
- Linux下启动/关闭Oracle
一.Linux下启动Oracle Linux下启动Oracle分为两步: 1)启动监听: 2)启动数据库实例: 1.登录服务器,切换到oracle用户,或者以oracle用户登录 [admin@dat ...
- Marginalize
在David M.Blei 的Distance Dependent Chinese Restaurant Processes 中提到:DDCRP 的一个重要性质,也是和dependent DP 的一个 ...
- VirtualBox桥接网络,设置虚拟机联网,连接VirtualBox虚拟系统中的数据库等
由于最近搭建一个项目自己的阿里云的服务器内存不足,自己笔记本使用VitrualBox电脑虚拟linux系统来搭建,把这次使用过程遇到的问题记录下来也能帮助遇到同样的小伙伴. 软件: VirtualBo ...
- 吐血推荐珍藏的IDEA插件
之前给大家推荐了一些我自己常用的VS Code插件,很多同学表示很受用,并私信我说要再推荐一些IDEA插件.作为一名职业Java程序员/业余js开发者,我平时还是用IDEA比较多,所以也确实珍藏了一些 ...