硬汉嵌入式论坛

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

[DMA] DMAMUX的定时器触+DMA控制任意IO做PWM和脉冲数控制

[复制链接]

2

主题

2

回帖

8

积分

新手上路

积分
8
发表于 2024-5-24 18:57:41 | 显示全部楼层 |阅读模式
请教坛主,我用了    第41章 STM32H7 的 BDMA 应用之控制任意 IO做 PWM 和脉冲数控制     这个例子在H723上,跑不起来,会进入传输错误中断。代码如下面。是什么原因?





LPTIM_HandleTypeDef  Lptim2Handle = {0};
static void LPTIM_Config(void)
{
    RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;


    /*##-1- 配置LPTIM2使用PCLK时钟 ##################################################*/
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM2;
    PeriphClkInitStruct.Lptim2ClockSelection = RCC_LPTIM2CLKSOURCE_D3PCLK1;
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);  


    /*##-2- 使能LPTIM2时钟并配置 ####################################################*/
    __HAL_RCC_LPTIM2_CLK_ENABLE();

    Lptim2Handle.Instance                           = LPTIM2;
    Lptim2Handle.Init.CounterSource                 = LPTIM_COUNTERSOURCE_INTERNAL;
    Lptim2Handle.Init.UpdateMode                    = LPTIM_UPDATE_ENDOFPERIOD;
    Lptim2Handle.Init.OutputPolarity                = LPTIM_OUTPUTPOLARITY_HIGH;
    Lptim2Handle.Init.Clock.Source                  = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
    Lptim2Handle.Init.Clock.Prescaler               = LPTIM_PRESCALER_DIV1;
    Lptim2Handle.Init.UltraLowPowerClock.Polarity   = LPTIM_CLOCKPOLARITY_RISING;
    Lptim2Handle.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION;
    Lptim2Handle.Init.Trigger.Source                = LPTIM_TRIGSOURCE_SOFTWARE;
    Lptim2Handle.Init.Trigger.ActiveEdge            = LPTIM_ACTIVEEDGE_RISING;
    Lptim2Handle.Init.Trigger.SampleTime            = LPTIM_TRIGSAMPLETIME_DIRECTTRANSITION;

    /*##-3- 初始化LPTIM2 ##########################################################*/
    if(HAL_LPTIM_Init(&Lptim2Handle) != HAL_OK)
    {
        Error_Handler(__FILE__, __LINE__);
    }

    /*##-4- 启动LPTIM2的PWM模式,但使用输出引脚,仅用于DMAMUX的触发 ##############*/
    /* LPTIM2的时钟主频是100MHz,这里配置触发是100MHz / (10000 - 1 + 1) = 10KHz */
                                /*输出10KHz方波,占空比50% */
    if (HAL_LPTIM_PWM_Start(&Lptim2Handle, 10000-1, 5000 - 1) != HAL_OK)
    {
        Error_Handler(__FILE__, __LINE__);
    }  
}

/*
*********************************************************************************************************
*        函 数 名: bsp_InitTimBDMA
*        功能说明: 配置DMAMUX的定时器触+DMA控制任意IO做PWM和脉冲数控制
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitTimBDMA(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    DMA_HandleTypeDef DMA_Handle = {0};
    HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams ={0};


     /*##-1- 配置Pc11用于PWM输出######################################*/
    __HAL_RCC_GPIOC_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);


    /*##-2- 配置DMA ##################################################*/
    __HAL_RCC_BDMA_CLK_ENABLE();

    DMA_Handle.Instance                 = BDMA_Channel0;           /* 使用的BDMA通道0 */
    DMA_Handle.Init.Request             = BDMA_REQUEST_GENERATOR0; /* 请求类型采用的DMAMUX请求发生器通道0 */  
    DMA_Handle.Init.Direction           = DMA_MEMORY_TO_PERIPH;    /* 传输方向是从存储器到外设 */  
    DMA_Handle.Init.PeriphInc           = DMA_PINC_DISABLE;        /* 外设地址自增禁止 */  
    DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;         /* 存储器地址自增使能 */  
    DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;     /* 外设数据传输位宽选择字,即32bit */     
    DMA_Handle.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;     /* 存储器数据传输位宽选择字,即32bit */   
    DMA_Handle.Init.Mode                = DMA_CIRCULAR;            /* 循环模式 */   
    DMA_Handle.Init.Priority            = DMA_PRIORITY_LOW;        /* 优先级低 */  
    DMA_Handle.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;    /* BDMA不支持FIFO */
    DMA_Handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL; /* BDMA不支持FIFO阀值设置 */
    DMA_Handle.Init.MemBurst            = DMA_MBURST_SINGLE;       /* BDMA不支持存储器突发 */
    DMA_Handle.Init.PeriphBurst         = DMA_PBURST_SINGLE;       /* BDMA不支持外设突发 */

    HAL_DMA_Init(&DMA_Handle);

    /* 开启BDMA Channel0的中断 */
    HAL_NVIC_SetPriority(BDMA_Channel0_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn);

    /*##-3- 配置DMAMUX #########################################################*/
    dmamux_ReqGenParams.SignalID  = HAL_DMAMUX2_REQ_GEN_LPTIM2_OUT;         /* 请求触发器选择LPTIM2_OUT */
    dmamux_ReqGenParams.Polarity  = HAL_DMAMUX_REQ_GEN_RISING_FALLING;      /* LPTIM2输出的上升沿和下降沿均可触发  */
    dmamux_ReqGenParams.RequestNumber = 1;                                  /* 触发后,传输进行1次DMA传输 */

    HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handle, &dmamux_ReqGenParams); /* 配置DMAMUX */

    HAL_DMAEx_EnableMuxRequestGenerator (&DMA_Handle);                      /* 使能DMAMUX请求发生器 */        

    /*##-4- 启动DMA传输 ################################################*/
    HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)IO_Toggle, (uint32_t)&GPIOC->BSRR, 8);

    /*
       默认情况下,用户通过注册回调函数DMA_Handle.XferHalfCpltCallback,然后函数HAL_DMA_Init会开启半传输完成中断,
       由于这里没有使用HAL库默认的中断管理函数HAL_DMA_IRQHandler,直接手动开启。
    */
    BDMA_Channel0->CCR |= BDMA_CCR_HTIE;                               
    BDMA_Channel0->CCR |= BDMA_CCR_TCIE;
               
    LPTIM_Config(); /* 配置LPTIM触发DMAMUX */
}

/*
*********************************************************************************************************
*        函 数 名: BDMA_Channel0_IRQHandler
*        功能说明: BDMA通道0
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void BDMA_Channel0_IRQHandler(void)
{
    /* 传输完成中断 */
    if((BDMA->ISR & BDMA_FLAG_TC0) != RESET)
    {
      BDMA->IFCR = BDMA_FLAG_TC0;

        /*
           1、传输完成开始使用DMA缓冲区的前半部分,此时可以动态修改后半部分数据
              比如缓冲区大小是IO_Toggle[0] 到 IO_Toggle[7]
              那么此时可以修改IO_Toggle[4] 到 IO_Toggle[7]
           2、变量所在的SRAM区已经通过MPU配置为WT模式,更新变量IO_Toggle会立即写入。
           3、不配置MPU的话,也可以通过Cahce的函数SCB_CleanDCache_by_Addr做Clean操作。
        */
    }

    /* 半传输完成中断 */   
    if((BDMA->ISR & BDMA_FLAG_HT0) != RESET)
    {
        BDMA->IFCR = BDMA_FLAG_HT0;

        /*
           1、半传输完成开始使用DMA缓冲区的后半部分,此时可以动态修改前半部分数据
              比如缓冲区大小是IO_Toggle[0] 到 IO_Toggle[7]
              那么此时可以修改IO_Toggle[0] 到 IO_Toggle[3]
           2、变量所在的SRAM区已经通过MPU配置为WT模式,更新变量IO_Toggle会立即写入。
           3、不配置MPU的话,也可以通过Cahce的函数SCB_CleanDCache_by_Addr做Clean操作。
        */
    }

    /* 传输错误中断 */
    if((BDMA->ISR & BDMA_FLAG_TE0) != RESET)
    {
        BDMA->IFCR = BDMA_FLAG_TE0;
    }
}

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117564
QQ
发表于 2024-5-25 07:38:38 | 显示全部楼层
注意DMA使用的RAM空间不要分配到TCM RAM上了,这个空间不支持通用DMA,你看下是不是这个问题。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-8-15 00:12 , Processed in 0.037461 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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