Skip to main content
Graduate
April 23, 2024
Solved

STM32F412 Multiple PWM Control Inquiry

  • April 23, 2024
  • 4 replies
  • 2795 views

I am developing a product using the STM32F412REFxLQFP64 chip, and I want to implement multi-PWM control.

 

For TIM2 buzzer control: TIM_HandleTypeDef TIM2 PB10 ------> TIM2_CH3

 

TIM3 is used to generate a 1kHz waveform: TIM_HandleTypeDef TIM3 Channel 4 PB1 ------> TIM3_CH4

void buzzerInit(void)
{
	Buzzer_InitTypeDef buzzerConfig;
	buzzerConfig.channel = TIM_CHANNEL_3;
	buzzerConfig.timer = &htim2;
	buzzerConfig.timerClockFreqHz = HAL_RCC_GetPCLK2Freq(); // NOTE: this should be freq of timer, not frequency of peripheral clock
	hbuzzer.Init = buzzerConfig;
}
void buzzer(BUZZER_StateTypeDef mode){
	buzzerStart(&hbuzzer);
	size_t songSize;
	switch(mode){
		case BUZZER_REGISTER:{
			songSize = sizeof(buzzer_register_theme) / sizeof(buzzer_register_theme[0]);
			for (size_t i = 0; i < songSize; i++) {
				buzzerNote(&hbuzzer, buzzer_register_theme[i].pitch);
				HAL_Delay(buzzer_register_theme[i].duration * 15);
			}
			break;
		}
		case BUZZER_START:{
			songSize = sizeof(buzzer_start_theme) / sizeof(buzzer_start_theme[0]);
			for (size_t i = 0; i < songSize; i++) {
				buzzerNote(&hbuzzer, buzzer_start_theme[i].pitch);
				HAL_Delay(buzzer_start_theme[i].duration * 15);
			}
			break;
		}
		case BUZZER_END:{
			songSize = sizeof(buzzer_end_theme) / sizeof(buzzer_end_theme[0]);
			for (size_t i = 0; i < songSize; i++) {
				buzzerNote(&hbuzzer, buzzer_end_theme[i].pitch);
				HAL_Delay(buzzer_end_theme[i].duration * 15);
			}
			break;
		}
		default :{
			break;
		}
	}
	buzzerStop(&hbuzzer);
	return;
}
void ctrl_pwm_1hz(char _flg)
{
	if(pwm_status == _flg)
		return;
	pwm_status = _flg;
	if(_flg == 0)
	{
		HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_4);
	}
	else
	{
		HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);
	}

}

When I control the buzzer and the 1kHz signal individually,

 

there are no issues. However, when I try to control them simultaneously,

 

the buzzer does not sound.

 

How can I solve this issue?

 

Thank you.

    This topic has been closed for replies.
    Best answer by waclawek.jan

    If you change TIMx_ARR in running timer (or stop timer for the TIMx_ARR change but don't clear TIMx_CNT) , use the ARR preload, i.e. set TIMx_CR1.ARPE.

     

    JW

    4 replies

    ST Employee
    April 23, 2024

    Hello,

    can you also send the code of these functions: 

    buzzerStart(&hbuzzer);
    buzzerNote(&hbuzzer, buzzer_register_theme[i].pitch);
    buzzerStop(&hbuzzer);

     

    KOPROAuthor
    Graduate
    April 26, 2024

    Commented below.!

    Super User
    April 23, 2024

    > However, when I try to control them simultaneously, the buzzer does not sound.

    Read out and check/compare-to-working/post TIM registers content, for working/non-working setup.

    JW

    KOPROAuthor
    Graduate
    April 26, 2024

    Commented below.

    KOPROAuthor
    Graduate
    April 23, 2024

    Hello there.

     

    this is buzzer code

    #include "buzzer.h"
    
    Buzzer_HandleTypeDef hbuzzer;
    
    note_t buzzer_register_theme[] =
    {
    	{NOTE_E7, 12},
    	{0, 12},
    	{NOTE_E7, 12},
    	{0, 12},
    	{NOTE_E7, 12},
    	{0, 12},
    	{NOTE_C7, 12},
    	{NOTE_C7, 12}
    };
    
    note_t buzzer_start_theme[] =
    {
    	{NOTE_E7, 12},
    	{NOTE_F7, 12},
    	{NOTE_FS7, 12},
    	{NOTE_G7, 12},
    	{NOTE_GS7, 12},
    	{NOTE_A7, 12}
    };
    
    void buzzerInit(void)
    {
    	Buzzer_InitTypeDef buzzerConfig;
    	buzzerConfig.channel = TIM_CHANNEL_3;
    	buzzerConfig.timer = &htim2;
    	buzzerConfig.timerClockFreqHz = HAL_RCC_GetPCLK2Freq(); // NOTE: this should be freq of timer, not frequency of peripheral clock
    	hbuzzer.Init = buzzerConfig;
    }
    
    void buzzerNote(Buzzer_HandleTypeDef* handle, uint32_t noteFreq) {
    	if(noteFreq > 0) {
    		handle->Init.timer->Instance->ARR=handle->Init.timerClockFreqHz/(handle->Init.timer->Init.Prescaler+1)/noteFreq;
    		__HAL_TIM_SET_COMPARE(handle->Init.timer, handle->Init.channel, handle->Init.timer->Instance->ARR/2);
    	} else
    		__HAL_TIM_SET_COMPARE(handle->Init.timer, handle->Init.channel, 0);
    }
    void buzzerNoNote(Buzzer_HandleTypeDef* handle) {
    	buzzerNote(handle,0);
    }
    void buzzerStart(Buzzer_HandleTypeDef* handle) {
    	buzzerNoNote(handle);
    	HAL_TIM_PWM_Start(handle->Init.timer, handle->Init.channel);
    }
    void buzzerStop(Buzzer_HandleTypeDef* handle){
    	buzzerNote(&hbuzzer, 0);
    	HAL_TIM_PWM_Stop(handle->Init.timer, handle->Init.channel);
    }
    
    void buzzer(BUZZER_StateTypeDef mode){
    	buzzerStart(&hbuzzer);
    	size_t songSize;
    	switch(mode){
    		case BUZZER_REGISTER:{
    			songSize = sizeof(buzzer_register_theme) / sizeof(buzzer_register_theme[0]);
    			for (size_t i = 0; i < songSize; i++) {
    				buzzerNote(&hbuzzer, buzzer_register_theme[i].pitch);
    				HAL_Delay(buzzer_register_theme[i].duration * 15);
    			}
    			break;
    		}
    		case BUZZER_START:{
    			songSize = sizeof(buzzer_start_theme) / sizeof(buzzer_start_theme[0]);
    			for (size_t i = 0; i < songSize; i++) {
    				buzzerNote(&hbuzzer, buzzer_start_theme[i].pitch);
    				HAL_Delay(buzzer_start_theme[i].duration * 15);
    			}
    			break;
    		}
    		case BUZZER_END:{
    			songSize = sizeof(buzzer_end_theme) / sizeof(buzzer_end_theme[0]);
    			for (size_t i = 0; i < songSize; i++) {
    				buzzerNote(&hbuzzer, buzzer_end_theme[i].pitch);
    				HAL_Delay(buzzer_end_theme[i].duration * 15);
    			}
    			break;
    		}
    		default :{
    			break;
    		}
    	}
    	buzzerStop(&hbuzzer);
    	return;
    }

     This is TIM code

    /* USER CODE BEGIN Header */
    /**
     ******************************************************************************
     * @file tim.c
     * @brief This file provides code for the configuration
     * of the TIM instances.
     ******************************************************************************
     * @attention
     *
     * Copyright (c) 2023 STMicroelectronics.
     * All rights reserved.
     *
     * This software is licensed under terms that can be found in the LICENSE file
     * in the root directory of this software component.
     * If no LICENSE file comes with this software, it is provided AS-IS.
     *
     ******************************************************************************
     */
    /* USER CODE END Header */
    /* Includes ------------------------------------------------------------------*/
    #include "tim.h"
    
    /* USER CODE BEGIN 0 */
    
    /* USER CODE END 0 */
    //PWM TM2 CH3 = PB10, BUZZER
    //PWM TM3 CH4 = PB1, Voltage Level Control
    TIM_HandleTypeDef htim2;
    TIM_HandleTypeDef htim3;
    
    /* TIM2 init function */
    void MX_TIM2_Init(void)
    {
    
     /* USER CODE BEGIN TIM2_Init 0 */
    
     /* USER CODE END TIM2_Init 0 */
    
     TIM_MasterConfigTypeDef sMasterConfig = {0};
     TIM_OC_InitTypeDef sConfigOC = {0};
    
     /* USER CODE BEGIN TIM2_Init 1 */
    
     /* USER CODE END TIM2_Init 1 */
     htim2.Instance = TIM2;
     htim2.Init.Prescaler = 8-1;
     htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
     htim2.Init.Period = 0xFFFF;
     htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
     htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
     if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
     {
     Error_Handler();
     }
     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
     if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
     {
     Error_Handler();
     }
     sConfigOC.OCMode = TIM_OCMODE_PWM1;
     sConfigOC.Pulse = 0;
     sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
     sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
     if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
     {
     Error_Handler();
     }
     /* USER CODE BEGIN TIM2_Init 2 */
    
     /* USER CODE END TIM2_Init 2 */
     HAL_TIM_MspPostInit(&htim2);
    
    }
    /* TIM3 init function */
    void MX_TIM3_Init(void)
    {
    
     /* USER CODE BEGIN TIM3_Init 0 */
    
     /* USER CODE END TIM3_Init 0 */
    
     TIM_MasterConfigTypeDef sMasterConfig = {0};
     TIM_OC_InitTypeDef sConfigOC = {0};
    
     /* USER CODE BEGIN TIM3_Init 1 */
    
     /* USER CODE END TIM3_Init 1 */
     htim3.Instance = TIM3;
     htim3.Init.Prescaler = 32;
     htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
     htim3.Init.Period = 999;
     htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
     htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
     if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
     {
     Error_Handler();
     }
     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
     if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
     {
     Error_Handler();
     }
     sConfigOC.OCMode = TIM_OCMODE_PWM1;
     sConfigOC.Pulse = 499;
     sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
     sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
     if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
     {
     Error_Handler();
     }
     /* USER CODE BEGIN TIM3_Init 2 */
    
     /* USER CODE END TIM3_Init 2 */
     HAL_TIM_MspPostInit(&htim3);
    
    }
    
    void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle)
    {
    
     if(tim_pwmHandle->Instance==TIM2)
     {
     /* USER CODE BEGIN TIM2_MspInit 0 */
    
     /* USER CODE END TIM2_MspInit 0 */
     /* TIM2 clock enable */
     __HAL_RCC_TIM2_CLK_ENABLE();
     /* USER CODE BEGIN TIM2_MspInit 1 */
    
     /* USER CODE END TIM2_MspInit 1 */
     }
     else if(tim_pwmHandle->Instance==TIM3)
     {
     /* USER CODE BEGIN TIM3_MspInit 0 */
    
     /* USER CODE END TIM3_MspInit 0 */
     /* TIM3 clock enable */
     __HAL_RCC_TIM3_CLK_ENABLE();
     /* USER CODE BEGIN TIM3_MspInit 1 */
    
     /* USER CODE END TIM3_MspInit 1 */
     }
    }
    void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
    {
    
     GPIO_InitTypeDef GPIO_InitStruct = {0};
     if(timHandle->Instance==TIM2)
     {
     /* USER CODE BEGIN TIM2_MspPostInit 0 */
    
     /* USER CODE END TIM2_MspPostInit 0 */
    
     __HAL_RCC_GPIOB_CLK_ENABLE();
     /**TIM2 GPIO Configuration
     PB10 ------> TIM2_CH3
     */
     GPIO_InitStruct.Pin = GPIO_PIN_10;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
     /* USER CODE BEGIN TIM2_MspPostInit 1 */
    
     /* USER CODE END TIM2_MspPostInit 1 */
     }
     else if(timHandle->Instance==TIM3)
     {
     /* USER CODE BEGIN TIM3_MspPostInit 0 */
    
     /* USER CODE END TIM3_MspPostInit 0 */
    
     __HAL_RCC_GPIOB_CLK_ENABLE();
     /**TIM3 GPIO Configuration
     PB1 ------> TIM3_CH4
     */
     GPIO_InitStruct.Pin = GPIO_PIN_1;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
     /* USER CODE BEGIN TIM3_MspPostInit 1 */
    
     /* USER CODE END TIM3_MspPostInit 1 */
     }
    
    }
    
    void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* tim_pwmHandle)
    {
    
     if(tim_pwmHandle->Instance==TIM2)
     {
     /* USER CODE BEGIN TIM2_MspDeInit 0 */
    
     /* USER CODE END TIM2_MspDeInit 0 */
     /* Peripheral clock disable */
     __HAL_RCC_TIM2_CLK_DISABLE();
     /* USER CODE BEGIN TIM2_MspDeInit 1 */
    
     /* USER CODE END TIM2_MspDeInit 1 */
     }
     else if(tim_pwmHandle->Instance==TIM3)
     {
     /* USER CODE BEGIN TIM3_MspDeInit 0 */
    
     /* USER CODE END TIM3_MspDeInit 0 */
     /* Peripheral clock disable */
     __HAL_RCC_TIM3_CLK_DISABLE();
     /* USER CODE BEGIN TIM3_MspDeInit 1 */
    
     /* USER CODE END TIM3_MspDeInit 1 */
     }
    }
    
    /* USER CODE BEGIN 1 */
    
    /* USER CODE END 1 */

     note_t buzzer_end_theme[] =
    {
    {NOTE_C7, 12},
    {0, 12},
    {NOTE_C7, 12},
    {0, 12},
    {NOTE_C7, 12},
    {0, 12}
    };

    sorry this code inside buzzer.c

    This is PWM code

    extern TIM_HandleTypeDef htim3;
    char pwm_status = 0;
    
    void ctrl_pwm_1hz(char _flg)
    {
    	if(pwm_status == _flg)
    		return;
    	pwm_status = _flg;
    	if(_flg == 0)
    	{
    		HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_4);
    	}
    	else
    	{
    		HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);
    	}
    
    }

     

    this is main code

    buzzer(BUZZER_START);
    osDelay(500);
    pwm_flag = true;
    ctrl_pwm_1hz(pwm_flag);

    When you first call the function, the buzzer and PWM operate normally,

    But when you call the function the next time,

    The buzzer does not operate normally and only the PWM operates normally.

    ST Employee
    April 29, 2024

    It seems that the definition of htim2 in buzzer code is missing so try to add:

    extern TIM_HandleTypeDef htim2;

    into buzzer code.

    KOPROAuthor
    Graduate
    May 8, 2024

     

    I put the code into the buzzer, but it doesn't work.

     

    #include "buzzer.h"
    
    extern TIM_HandleTypeDef htim2;
    
    Buzzer_HandleTypeDef hbuzzer;

     

    Super User
    May 9, 2024

    If you change TIMx_ARR in running timer (or stop timer for the TIMx_ARR change but don't clear TIMx_CNT) , use the ARR preload, i.e. set TIMx_CR1.ARPE.

     

    JW

    KOPROAuthor
    Graduate
    May 16, 2024

     

    Thank you

    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;

    I changed this source for activation and it works normally.