硬汉嵌入式论坛

 找回密码
 立即注册
查看: 3699|回复: 6
收起左侧

[HAL学习笔记] HAL库源文件stm32h7xx_hal_dma_ex.c学习笔记(2018-08-10 V1.1)

[复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106826
QQ
发表于 2018-8-3 00:15:28 | 显示全部楼层 |阅读模式
2018-08-03
首发
2018-08-10
忘了写函数HAL_DMAEx_ConfigMuxRequestGenerator

说明:
1、此文件主要用于DMA双缓冲和DMAMUX的多路选择器配置。
2、特别注意,仅DMA1和DMA2支持双缓冲,BDMA是不支持双缓冲的。


==============================================================================
                                                                  ##### 如何使用此驱动  #####
==============================================================================  

1、有两个函数可用于启动多缓冲,一个是函数HAL_DMA_MultiBufferStart,用于查询方式。另一个是函数HAL_DMA_MultiBufferStart_IT用于中断方式。

2、函数HAL_DMAEx_ConfigMuxSync用于配置DMA_MUX Synchronization Block。
     函数HAL_DMAEx_ConfigMuxRequestGenerator用于配置DMA_MUX Request Generator Block 。
     函数HAL_DMAEx_EnableMuxRequestGenerator 和 HAL_DMAEx_DisableMuxRequestGenerator用于使能和禁止DMA_MUX Request Generator Block

通过下面框图可以对这个功能有个感性认识:
QQ截图20180802225531.png

3、为了管理DMAMUX1的中断服务程序DMAMUX1_OVR_IRQHandler和DMAMUX2的中断服务DMAMUX2_OVR_IRQHandler,可以调用函数HAL_DMAEx_MUX_IRQHandler实现。
看上面的框图,我们可以看出,DMAMUX只有一个中断线,但是有很多的触发源,所以就需要用户在中断服务程序里面通过函数HAL_DMAEx_MUX_IRQHandler的形参进行区分是那个触发源。
(1)存储器到存储器模式,不允许使用DMA双缓冲
(2)使能了DMA双缓冲后,默认的传输方式circular循环模式
(3)在双缓冲模式下,即使DMA Stream已经使能,也可以通过寄存器DMA_SxM0AR 和 DMA_SxM1AR修改缓冲地址。
(4)特别注意,仅DMA1和DMA2支持双缓冲,BDMA是不支持双缓冲的。


1、函数HAL_DMAEx_MultiBufferStart
启动DMA双缓冲,未开启中断

2、函数HAL_DMAEx_MultiBufferStart_IT
启动DMA双缓冲,开启中断

3、函数HAL_DMAEx_ChangeMemory
用于程序运行时,修改DMA双缓冲的地址。特别注意,使用缓冲1的时候,可以修改2,而使用缓冲2的时候,可以修改1.

4、函数HAL_DMAEx_ConfigMuxSync
用于配置DMAMUX的同步触发源

5、函数HAL_DMAEx_ConfigMuxRequestGenerator
用于配置DMA_MUX Request Generator Block

6、函数HAL_DMAEx_EnableMuxRequestGenerator和HAL_DMAEx_DisableMuxRequestGenerator
用于使能和禁止DMA_MUX Request Generator Block

7、函数HAL_DMAEx_MUX_IRQHandler
可供用户在中断服务程序DMAMUX1_OVR_IRQHandler和DMAMUX2_OVR_IRQHandler里面调用的中断处理函数。

8、函数DMA_MultiBufferSetConfig
此文件内部调用,用于配置源地址,目标地址和数据长度。
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
发表于 2019-1-26 00:52:31 | 显示全部楼层
最近准备用BDMA的双缓冲模式,发现STM32H7的Reference Manual上写了支持Double Buffer Mode,还描述了启用双缓冲的步骤,但是库文件和MDK的调试界面都不支持呢。奇怪!

捕获1.PNG
捕获.PNG
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106826
QQ
 楼主| 发表于 2019-1-26 01:03:23 | 显示全部楼层
阿光_R0O1i 发表于 2019-1-26 00:52
最近准备用BDMA的双缓冲模式,发现STM32H7的Reference Manual上写了支持Double Buffer Mode,还描述了启用 ...

是的,当前使用半传输完整中断和传输完成中断实现双缓冲也挺方便。

STM32H7的HAL库V1.3.0对BDMA双缓冲的支持确有问题,寄存器定义和API均有待升级
http://www.armbbs.cn/forum.php?m ... 1207&fromuid=58
(出处: 安富莱电子论坛)
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
发表于 2019-1-26 14:05:48 | 显示全部楼层
自己写了个BDMA双缓冲配置的函数,验证了一下,BDMA双缓冲还是可以用的。手册还是比较靠谱的

不想改动官方库,这样以后升级库也方便,以下代码放在单独的文件里。

#define BDMA_CCR_DBM_Pos        (15U)                                          
#define BDMA_CCR_DBM_Msk        (0x1U << BDMA_CCR_DBM_Pos)                      /*!< 0x00008000 */
#define BDMA_CCR_DBM            BDMA_CCR_DBM_Msk                                /*!< DBM bits(Double-Buffer Mode)*/

#define BDMA_CCR_CT_Pos         (16U)                                          
#define BDMA_CCR_CT_Msk         (0x1U << BDMA_CCR_CT_Pos)                      /*!< 0x00010000 */
#define BDMA_CCR_CT             BDMA_CCR_CT_Msk                                /*!< CT bits(Current Target Memory)*/


HAL_StatusTypeDef HAL_BDMAEx_MultiBufferStart_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength)
{
    HAL_StatusTypeDef status = HAL_OK;
    __IO uint32_t *ifcRegister_Base = NULL; /* DMA Stream Interrupt Clear register */

    /* Check the parameters */
    assert_param(IS_DMA_BUFFER_SIZE(DataLength));

    /* Memory-to-memory transfer not supported in double buffering mode */  
    if(hdma->Init.Direction == DMA_MEMORY_TO_MEMORY)
    {
        hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
        return HAL_ERROR;
    }

    /* Process locked */
    __HAL_LOCK(hdma);

    if(HAL_DMA_STATE_READY == hdma->State)
    {
        /* Change DMA peripheral state */
        hdma->State = HAL_DMA_STATE_BUSY;

        /* Initialize the error code */
        hdma->ErrorCode = HAL_DMA_ERROR_NONE;

        /* Enable the Double buffer mode */
        ((BDMA_Channel_TypeDef   *)hdma->Instance)->CCR |= (uint32_t)BDMA_CCR_DBM;

        /* Configure DMA Stream destination address */
        *((uint32_t*)(&((BDMA_Channel_TypeDef   *)hdma->Instance)->CMAR)+1) = SecondMemAddress;

        /* Configure the source, destination address and the data length */
        /* Configure DMA Stream data length */
        ((BDMA_Channel_TypeDef   *)hdma->Instance)->CNDTR = DataLength;

        /* Peripheral to Memory */
        if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
        {
            /* Configure DMA Stream destination address */
            ((BDMA_Channel_TypeDef   *)hdma->Instance)->CPAR = DstAddress;

            /* Configure DMA Stream source address */
            ((BDMA_Channel_TypeDef   *)hdma->Instance)->CMAR = SrcAddress;
        }

        /* Clear all flags */        
        BDMA->IFCR  |= (BDMA_ISR_GIF0 << hdma->StreamIndex);

        /* Clear the DMAMUX synchro overrun flag */
        hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask;

        if(hdma->DMAmuxRequestGen != 0U)
        {
            /* Clear the DMAMUX request generator overrun flag */
            hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask;
        }

        /* Enable Common interrupts*/
        MODIFY_REG(((BDMA_Channel_TypeDef   *)hdma->Instance)->CCR, (BDMA_CCR_TCIE | BDMA_CCR_HTIE | BDMA_CCR_TEIE), (BDMA_CCR_TCIE | BDMA_CCR_TEIE));        

        if(hdma->XferHalfCpltCallback != NULL)
        {
            /*Enable Half Transfer IT if corresponding Callback is set*/
            ((BDMA_Channel_TypeDef   *)hdma->Instance)->CCR  |= BDMA_CCR_HTIE;
        }

        /* Check if DMAMUX Synchronization is enabled*/
        if((hdma->DMAmuxChannel->CCR & DMAMUX_CxCR_SE) != 0)
        {
            /* Enable DMAMUX sync overrun IT*/
            hdma->DMAmuxChannel->CCR |= DMAMUX_CxCR_SOIE;
        }

        if(hdma->DMAmuxRequestGen != 0U)
        {
            /* if using DMAMUX request generator, enable the DMAMUX request generator overrun IT*/
            /* enable the request gen overrun IT*/
            hdma->DMAmuxRequestGen->RGCR |= DMAMUX_RGxCR_OIE;
        }

        /* Enable the peripheral */
        __HAL_DMA_ENABLE(hdma);
    }
    else
    {
        /* Set the error code to busy */
        hdma->ErrorCode = HAL_DMA_ERROR_BUSY;

        /* Return error status */
        status = HAL_ERROR;
    }
    return status;
}


另外需要注意的是,官方库的DMA中断处理中,没有针对BDMA双缓冲的处理,但是可以自己在DMA传输完成中断回调中判断当前使用的缓冲区自行处理。
static void HAL_TransferCplt(DMA_HandleTypeDef *hdma)
{      
    if((((BDMA_Channel_TypeDef   *)hdma->Instance)->CCR & BDMA_CCR_CT_Msk) != RESET) {        
        //...      
    } else {     
       //...
    }        
}


希望可以帮到需要用这个功能的人。
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
发表于 2019-1-26 14:07:40 | 显示全部楼层
再者需要注意的是MDK5的调试界面里是看不到DBM和CT位的值的变化的,容易误以为配置没有生效。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106826
QQ
 楼主| 发表于 2019-1-26 14:19:51 | 显示全部楼层
阿光_R0O1i 发表于 2019-1-26 14:05
自己写了个BDMA双缓冲配置的函数,验证了一下,BDMA双缓冲还是可以用的。手册还是比较靠谱的。

不想 ...

谢谢分享
回复

使用道具 举报

3

主题

35

回帖

44

积分

新手上路

积分
44
发表于 2019-1-28 20:46:23 | 显示全部楼层
谢谢分享宝贵经验!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-6 04:11 , Processed in 0.186132 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表