【STM32H7教程】第41章 STM32H7的BDMA应用之控制任意IO做PWM和脉冲数控制

2023-04-13  

41.1 初学者重要提示

  1. 学习本章节前,务必优先学习第39章和40章,需要对DMAMUX,BDMA的基础知识和HAL库的几个常用API有个认识。

  2. 使用半传输完成中断和传输完成中断实现的双缓冲效果跟BDMA本身支持的双缓冲模式实现的效果是一样的。只是最大传输个数只能达到32767次。

  3. 相比定时器本身支持的PWM,这种方式更加灵活,可以让任意IO都可以输出PWM,而且方便运行中动态修改输出状态。

41.2 定时器触发BDMA驱动设计

定时器触发DMAMUX,控制BDMA让GPIO输出PWM的实现思路框图如下:

下面将程序设计中的相关问题逐一为大家做个说明。

41.2.1 定时器选择

使用BDMA的话,请求信号都是来自DMAMUX2,而控制DMA做周期性传输的话,可以使用定时器触发,这样的话就可以使用DMAMUX的请求发生器功能,支持如下几种触发:

#define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH0_EVT   0U   

#define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH1_EVT   1U   

#define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH2_EVT   2U   

#define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH3_EVT   3U   

#define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH4_EVT   4U   

#define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH5_EVT   5U  

#define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH6_EVT   6U   

#define HAL_DMAMUX2_REQ_GEN_LPUART1_RX_WKUP   7U   

#define HAL_DMAMUX2_REQ_GEN_LPUART1_TX_WKUP   8U   

#define HAL_DMAMUX2_REQ_GEN_LPTIM2_WKUP       9U   

#define HAL_DMAMUX2_REQ_GEN_LPTIM2_OUT       10U  

#define HAL_DMAMUX2_REQ_GEN_LPTIM3_WKUP      11U   

#define HAL_DMAMUX2_REQ_GEN_LPTIM3_OUT       12U  

#define HAL_DMAMUX2_REQ_GEN_LPTIM4_WKUP      13U   

#define HAL_DMAMUX2_REQ_GEN_LPTIM5_WKUP      14U   

#define HAL_DMAMUX2_REQ_GEN_I2C4_WKUP        15U   

#define HAL_DMAMUX2_REQ_GEN_SPI6_WKUP        16U   

#define HAL_DMAMUX2_REQ_GEN_COMP1_OUT        17U   

#define HAL_DMAMUX2_REQ_GEN_COMP2_OUT        18U   

#define HAL_DMAMUX2_REQ_GEN_RTC_WKUP         19U   

#define HAL_DMAMUX2_REQ_GEN_EXTI0            20U  

#define HAL_DMAMUX2_REQ_GEN_EXTI2            21U   

#define HAL_DMAMUX2_REQ_GEN_I2C4_IT_EVT      22U  

#define HAL_DMAMUX2_REQ_GEN_SPI6_IT          23U  

#define HAL_DMAMUX2_REQ_GEN_LPUART1_TX_IT    24U  

#define HAL_DMAMUX2_REQ_GEN_LPUART1_RX_IT    25U   

#define HAL_DMAMUX2_REQ_GEN_ADC3_IT          26U   

#define HAL_DMAMUX2_REQ_GEN_ADC3_AWD1_OUT    27U  

#define HAL_DMAMUX2_REQ_GEN_BDMA_CH0_IT      28U  

#define HAL_DMAMUX2_REQ_GEN_BDMA_CH1_IT      29U   

我们这里使用的是LPTIM2_OUT,因为BDMA,LPTIM2和GPIO都在D3域。


接下来就是LPTIM的时钟配置问题,由前面的LPTIM章节,我们知道LPTIM2的时钟可以由LSE,LSI,APB或者外部输入时钟提供。使用LSE,LSI或者外部输入的好处是停机状态下,LPTIM1也可以正常工作。


V7开发板使用的LSE晶振是32768Hz。

STM32H743的LSI频率约32KHz。

LPTIM1 – LPTIM5的频率都是100MHz。

System Clock source       = PLL (HSE)

SYSCLK(Hz)                = 400000000 (CPU Clock)

HCLK(Hz)                  = 200000000 (AXI and AHBs Clock)

AHB Prescaler             = 2

D1 APB3 Prescaler         = 2 (APB3 Clock  100MHz)

D2 APB1 Prescaler         = 2 (APB1 Clock  100MHz)

D2 APB2 Prescaler         = 2 (APB2 Clock  100MHz)

D3 APB4 Prescaler         = 2 (APB4 Clock  100MHz)


因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = APB1 x 2 = 200MHz; 不含这个总线下的LPTIM1

因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = APB2 x 2 = 200MHz;


APB4上面的TIMxCLK没有分频,所以就是100MHz;


APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14,LPTIM1

APB2 定时器有 TIM1, TIM8 , TIM15, TIM16,TIM17


APB4 定时器有 LPTIM2,LPTIM3,LPTIM4,LPTIM5

如果选择APB时钟的话,配置如下:


RCC_PeriphCLKInitTypeDef   RCC_PeriphCLKInitStruct = {0};


RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM2;

RCC_PeriphCLKInitStruct.Lptim2ClockSelection = RCC_LPTIM2CLKSOURCE_D3PCLK1;

HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct);

使用APB作为LPTIM系统时钟注意以下两点:


LPTIM1 – LPTIM5的最高主频都是100MHz。

注意参数RCC_LPTIM2CLKSOURCE_D3PCLK1。

LPTIM1使用的RCC_LPTIM1CLKSOURCE_D2PCLK1。


LPTIM2使用的RCC_LPTIM2CLKSOURCE_D3PCLK1。


LPTIM3-LPTIM5使用的RCC_LPTIM345CLKSOURCE_D3PCLK1。


LPTIM2的配置代码如下:


1.    /*

2.    ******************************************************************************************************

3.    *    函 数 名: LPTIM_Config

4.    *    功能说明: 配置LPTIM,用于触发DMAMUX的请求发生器

5.    *    形    参: 无

6.    *    返 回 值: 无

7.    ******************************************************************************************************

8.    */

9.    void LPTIM_Config(void)

10.    {

11.        

12.        RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;

13.    

14.        

15.        /*##-1- 配置LPTIM2使用PCLK时钟 ##################################################*/

16.        PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM2;

17.        PeriphClkInitStruct.Lptim2ClockSelection = RCC_LPTIM2CLKSOURCE_D3PCLK1;

18.        HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);  

19.    

20.    

21.        /*##-2- 使能LPTIM2时钟并配置 ####################################################*/

22.        __HAL_RCC_LPTIM2_CLK_ENABLE();

23.    

24.        LptimHandle.Instance                           = LPTIM2;

25.        LptimHandle.Init.CounterSource                 = LPTIM_COUNTERSOURCE_INTERNAL;

26.        LptimHandle.Init.UpdateMode                    = LPTIM_UPDATE_ENDOFPERIOD;

27.        LptimHandle.Init.OutputPolarity                = LPTIM_OUTPUTPOLARITY_HIGH;

28.        LptimHandle.Init.Clock.Source                  = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;

29.        LptimHandle.Init.Clock.Prescaler               = LPTIM_PRESCALER_DIV1;

30.        LptimHandle.Init.UltraLowPowerClock.Polarity   = LPTIM_CLOCKPOLARITY_RISING;

31.        LptimHandle.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION;

32.        LptimHandle.Init.Trigger.Source                = LPTIM_TRIGSOURCE_SOFTWARE;

33.        LptimHandle.Init.Trigger.ActiveEdge            = LPTIM_ACTIVEEDGE_RISING;

34.        LptimHandle.Init.Trigger.SampleTime            = LPTIM_TRIGSAMPLETIME_DIRECTTRANSITION;

35.    

36.        /*##-3- 初始化LPTIM2 ##########################################################*/

37.        if(HAL_LPTIM_Init(&LptimHandle) != HAL_OK)

38.        {

39.            Error_Handler(__FILE__, __LINE__);

40.        }

41.    

42.        /*##-4- 启动LPTIM2的PWM模式,但使用输出引脚,仅用于DMAMUX的触发 ##############*/

43.        /* LPTIM2的时钟主频是100MHz,这里配置触发是100MHz / (10000 - 1 + 1) = 10KHz */

44.        if (HAL_LPTIM_PWM_Start(&LptimHandle, 10000-1, 5000 - 1) != HAL_OK)

45.        {

46.            Error_Handler(__FILE__, __LINE__);

47.        }  

48.    }

这里把几个关键的地方阐释下:


第16 – 18行,配置LPTIM2使用APB时钟。

第22 – 40行, 配置LPTIM2的相关参数,具体每个参数代表的含义可以看前面LPTIM章节的讲解。

第44 – 47行,配置LPTIM2工作在PWM模式,频率10KHz,占空比50%。这里仅仅是用到LPTIM2_OUT的输出信号作为DMAMUX的请求发生器触发源,所以用不到PWM的输出引脚。

41.2.2 DMMUX和BDMA配置

完整配置如下:


1.    /*

2.    ******************************************************************************************************

3.    *    函 数 名: bsp_InitTimBDMA

4.    *    功能说明: 配置DMAMUX的定时器触+DMA控制任意IO做PWM和脉冲数控制

5.    *    形    参: 无

6.    *    返 回 值: 无

7.    ******************************************************************************************************

8.    */

9.    void bsp_InitTimBDMA(void)

10.    {

11.        GPIO_InitTypeDef  GPIO_InitStruct;

12.        DMA_HandleTypeDef DMA_Handle = {0};

13.        HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams ={0};

14.    

15.        

16.         /*##-1-  ##################################################*/ 

17.        __HAL_RCC_GPIOB_CLK_ENABLE();

18.          

19.        GPIO_InitStruct.Pin = GPIO_PIN_1;

20.        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

21.        GPIO_InitStruct.Pull = GPIO_NOPULL;

22.        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

23.        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

24.        

25.      

26.        /*##-2- Configure the DMA ##################################################*/

27.        __HAL_RCC_BDMA_CLK_ENABLE();

28.    

29.        DMA_Handle.Instance            = BDMA_Channel0;           /* 使用的BDMA通道0 */

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。