cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F412 Multiple PWM Control Inquiry

KOPRO
Associate III

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.

1 ACCEPTED SOLUTION

Accepted Solutions

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

View solution in original post

10 REPLIES 10
Hl_st
ST Employee

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.

> 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

KOPRO
Associate III

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.

Commented below.

KOPRO
Associate III

Commented below.!

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.

KOPRO
Associate III

 

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

 

#include "buzzer.h"

extern TIM_HandleTypeDef htim2;

Buzzer_HandleTypeDef hbuzzer;

 

KOPRO
Associate III

We set a break point and analyzed the case closely.
When it's normal

TIM_HandleTypeDef
TIM_TypeDef *Instance; in
CNT; /*!< TIM counter register,

The value is within the normal range, but when there is no sound, there is a large value as shown below.
If we are trying to solve this, how should we solve it?

normal sound buzzer img = cnt range 100~ , 200~ , etc...

KOPRO_1-1715220828743.png

error sound buzzer img = cnt range 7237947, 619114 etc..

KOPRO_0-1715220810969.png

 

 

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