【STM32H7教程】第43章 STM32H7的DMA应用之双缓冲控制任意IO和脉冲数控制

2023-04-13  

43.1 初学者重要提示

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

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

43.2 定时器触发DMA驱动设计

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

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

43.2.1 定时器选择

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

#define HAL_DMAMUX1_REQ_GEN_DMAMUX1_CH0_EVT   0U   

#define HAL_DMAMUX1_REQ_GEN_DMAMUX1_CH1_EVT   1U   

#define HAL_DMAMUX1_REQ_GEN_DMAMUX1_CH2_EVT   2U   

#define HAL_DMAMUX1_REQ_GEN_LPTIM1_OUT        3U   

#define HAL_DMAMUX1_REQ_GEN_LPTIM2_OUT        4U   

#define HAL_DMAMUX1_REQ_GEN_LPTIM3_OUT        5U   

#define HAL_DMAMUX1_REQ_GEN_EXTI0             6U   

#define HAL_DMAMUX1_REQ_GEN_TIM12_TRGO        7U  

我们这里使用的是TIM12_TRGO。


接下来就是TIM12的时钟配置问题,代码如下:


1.    /*

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

3.    *    函 数 名: TIM12_Config

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

5.    *    形    参: _Mode 

6.    *             0 配置为100KHz触发频率,如果DMAMUX配置为单边沿触发,那么输出PWM频率是50KHz,双边沿是

7.                    100KHz。

8.    *             1 配置为10KHz触发频率,如果DMAMUX配置为单边沿触发,那么输出PWM频率是5KHz,双边沿是10KHz。

9.    *    返 回 值: 无

10.    ******************************************************************************************************

11.    */

12.    void TIM12_Config(uint8_t _Mode)

13.    {

14.        TIM_HandleTypeDef  htim ={0};

15.        TIM_MasterConfigTypeDef sMasterConfig = {0};

16.        TIM_OC_InitTypeDef sConfig = {0};

17.        uint32_t Period[2] = {1999, 19999};

18.        uint32_t Pulse[2]  = {1000, 10000};

19.    

20.          /* 使能时钟 */  

21.          __HAL_RCC_TIM12_CLK_ENABLE();

22.          

23.        /*-----------------------------------------------------------------------

24.            bsp.c 文件中 void SystemClock_Config(void) 函数对时钟的配置如下: 

25.    

26.            System Clock source       = PLL (HSE)

27.            SYSCLK(Hz)                = 400000000 (CPU Clock)

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

29.            AHB Prescaler             = 2

30.            D1 APB3 Prescaler         = 2 (APB3 Clock  100MHz)

31.            D2 APB1 Prescaler         = 2 (APB1 Clock  100MHz)

32.            D2 APB2 Prescaler         = 2 (APB2 Clock  100MHz)

33.            D3 APB4 Prescaler         = 2 (APB4 Clock  100MHz)

34.    

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

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

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

38.    

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

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

41.    

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

43.    

44.        TIM12CLK = 200MHz/(Period + 1) / (Prescaler + 1)

45.        函数bsp_InitTimDMA1中DMAMUX1选择的是单边沿触发,每个时钟可以触发两次。

46.        ----------------------------------------------------------------------- */  

47.        HAL_TIM_Base_DeInit(&htim);

48.        

49.        htim.Instance = TIM12;

50.        htim.Init.Period            = Period[_Mode];

51.        htim.Init.Prescaler         = 0;

52.        htim.Init.ClockDivision     = 0;

53.        htim.Init.CounterMode       = TIM_COUNTERMODE_UP;

54.        htim.Init.RepetitionCounter = 0;

55.        HAL_TIM_Base_Init(&htim);

56.        

57.        sConfig.OCMode     = TIM_OCMODE_PWM1;

58.        sConfig.OCPolarity = TIM_OCPOLARITY_LOW;

59.    

60.        /* 占空比50% */

61.        sConfig.Pulse = Pulse[_Mode];  

62.        if(HAL_TIM_OC_ConfigChannel(&htim, &sConfig, TIM_CHANNEL_1) != HAL_OK)

63.        {

64.            Error_Handler(__FILE__, __LINE__);

65.        }

66.    

67.        /* 启动OC1 */

68.        if(HAL_TIM_OC_Start(&htim, TIM_CHANNEL_1) != HAL_OK)

69.        {

70.            Error_Handler(__FILE__, __LINE__);

71.        }

72.        

73.        /* TIM12的TRGO用于触发DMAMUX的请求发生器 */

74.        sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC1REF;

75.        sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;

76.        sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

77.    

78.        HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig);

79.    }

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


第14 – 16行,对作为局部变量的HAL库结构体做初始化,防止不确定值配置时出问题。

第17 – 18行,定义了两组周期变量和占空比变量,用来设置TIM12。

第20 – 71行,注释已经比较详细。

当选择第1组配置时,


TIM12CLK = 200MHz / (Period + 1) / (Prescaler + 1) = 200MHz/(1999+1) = 100KHz


占空比 = Pulse / (Period + 1) = 1000 / (1999+1)= 50%


当选择第2组配置时,


TIM12CLK = 200MHz / (Period + 1) / (Prescaler + 1) = 200MHz/(19999+1) = 10KHz


占空比 = Pulse / (Period + 1) = 10000 /(19999+1)= 50%


第22 – 40行, TIM12的TRGO用于触发DMAMUX的请求发生器。

这些知识点在前面的定时器章节有更详细的说明。


43.2.2 DMAMUX和DMA配置

完整配置如下:


1.    /*

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

3.    *    函 数 名: bsp_InitTimDMA

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

5.    *    形    参: 无

6.    *    返 回 值: 无

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

8.    */

9.    void bsp_InitTimDMA(void)

10.    {

11.        GPIO_InitTypeDef  GPIO_InitStruct;

12.        DMA_HandleTypeDef DMA_Handle = {0};

13.        HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams = {0};

14.    

15.        /*##-1- 配置PB1用于PWM输出 ##################################################*/

16.        __HAL_RCC_GPIOB_CLK_ENABLE();

17.        GPIO_InitStruct.Pin = GPIO_PIN_1;

18.        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

19.        GPIO_InitStruct.Pull = GPIO_NOPULL;

20.        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

21.        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

22.      

23.        /*##-2- 使能DMA1时钟并配置 ##################################################*/

24.        __HAL_RCC_DMA1_CLK_ENABLE();

25.        DMA_Handle.Instance          = DMA1_Stream1;            /* 使用的DMA1 Stream1 */

26.        DMA_Handle.Init.Request      = DMA_REQUEST_GENERATOR0;  /* 请求类型采用的DMAMUX请求发生器通道0 */  

27.        DMA_Handle.Init.Direction           = DMA_MEMORY_TO_PERIPH;/* 传输方向是从存储器到外设 */  

28.        DMA_Handle.Init.PeriphInc           = DMA_PINC_DISABLE;    /* 外设地址自增禁止 */ 

29.        DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;     /* 存储器地址自增使能 */  

30.        DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; /* 外设数据传输位宽选择字,即32bit */     

31.        DMA_Handle.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;  /* 存储器数据传输位宽选择字,即32bit */    

32.        DMA_Handle.Init.Mode                = DMA_CIRCULAR;        /* 循环模式 */   

33.        DMA_Handle.Init.Priority            = DMA_PRIORITY_LOW;    /* 优先级低 */  

34.        DMA_Handle.Init.FIFOMode     = DMA_FIFOMODE_DISABLE;     /* 禁止FIFO*/

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