zoukankan      html  css  js  c++  java
  • 【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 初学者重要提示

    1.   MDMA位于D1域,使用的64位的AXI总线,可以操作TCM空间(前面章节讲解的DMA2D,通用DMA和BDMA不支持操作TCM空间)。
    2.   对于本章节,重点要了解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  = 0; 
      hmdma->LastLinkedListNodeAddress   = 0; 
      hmdma->LinkedListNodeCounter  = 0;  
      
      /* 设置无错误 */
      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;    /* 每次传输128个字节 */
    
    MDMA_Handle.Init.SourceBlockAddressOffset  = 0; /* 用于block传输,地址偏移0 */
    MDMA_Handle.Init.DestBlockAddressOffset    = 0; /* 用于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 + 64*1024), 
                      64*1024, 
                      1);

    61.5 总结

    本章节就为大家讲解这么多,MDMA功能用到的地方还是比较多的,后面的章节会为大家做讲解。

  • 相关阅读:
    ASP.NET WebApi项目框架搭建(六):数据库ORM之Sqlsugar
    sqlsugar与数据库之间的相互操作
    C# SqlSugar框架的学习使用(一)SqlSugar简介及创建
    SqlSugar直接执行Sql
    在项目中迁移MS SQLServer到Mysql数据库,实现MySQL数据库的快速整合
    SqlSugar 简易操作数据库
    C# SqlSugar框架的学习使用(二) 类的生成及增删改查的应用
    使用开源框架Sqlsugar结合mysql开发一个小demo
    devops起源的各种ops概念
    STC8H开发(四): FwLib_STC8 封装库的介绍和注意事项
  • 原文地址:https://www.cnblogs.com/armfly/p/12371075.html
Copyright © 2011-2022 走看看