Skip to main content
Associate II
April 23, 2024
Solved

STM32F412 Multiple PWM Control Inquiry

  • April 23, 2024
  • 10 replies
  • 2847 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

10 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);

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
KOPROAuthor
Associate II
April 26, 2024

Commented below.!

waclawek.jan
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
Associate II
April 26, 2024

Commented below.

KOPROAuthor
Associate II
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.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
KOPROAuthor
Associate II
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;

 

waclawek.jan
waclawek.janBest answer
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
Associate II
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.