Skip to main content
Associate II
December 30, 2023
Solved

Changing PWM Mode during runtime

Hello, I am trying to write a routine, that takes an array of structures as input and sets the timer 1 parameters. This function is called after each overflow of timer 1. I turn off the respective channels, then set the parameters, as seen in the following ISR:

 

void TIM1_UP_TIM16_IRQHandler(void)

{

htim1.Instance->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1NE | TIM_CCER_CC2E | TIM_CCER_CC2NE | TIM_CCER_CC3E | TIM_CCER_CC3NE);

HAL_GPIO_WritePin(TIM1_UP_GPIO_Port, TIM1_UP_Pin, GPIO_PIN_SET);

HAL_TIM_IRQHandler(&htim1);

HAL_GPIO_WritePin(TIM1_UP_GPIO_Port, TIM1_UP_Pin, GPIO_PIN_RESET);

 

if (currentPattern < NUM_PATTERNS) {

setconfig(&durations[currentPattern]);

currentPattern++;

}

 

The setconfig function looks as follows:

:

void setconfig(TIM_SU const* const timersetup) {

// Function that takes a pointer to a TIM_SU structure as an argument

htim2.Instance->ARR = timersetup->tim2_period;

 

// Period of timer 1, i.e. the duration of the second pulse

htim1.Instance->ARR = timersetup->tim1_period;

 

// Duration of the first pulse (positive or negative)

htim1.Instance->CCR1 = timersetup->tim1_channel1_pwm_duration;

htim1.Instance->CCR2 = timersetup->tim1_channel2_pwm_duration;

htim1.Instance->CCR3 = timersetup->tim1_channel3_pwm_duration;

 

// Dead time, sets only the lower 8 bits (see page 1280)

htim1.Instance->BDTR &= ~TIM_BDTR_DTG; // Mask to clear the DTG bits

htim1.Instance->BDTR |= (uint32_t)(timersetup->dead_time & 0xFF);

 

htim1.Instance->CCMR1 &= ~TIM_CCMR1_OC1M; //channel 1 clearing

htim1.Instance->CCMR1 &= ~TIM_CCMR1_OC2M; //channel 2 clearing

htim1.Instance->CCMR2 &= ~TIM_CCMR2_OC3M; //channel 3 clearing

 

switch (timersetup->tim1_channel1_pwm_mode) {

case PWM_MODE_1:

TIM1->CCMR1 |= (TIM_OCMODE_PWM1 << TIM_CCMR1_OC1M_Pos);

break;

case PWM_MODE_2:

TIM1->CCMR1 |= (TIM_OCMODE_PWM2 << TIM_CCMR1_OC1M_Pos);

}

switch (timersetup->tim1_channel2_pwm_mode) {

case PWM_MODE_1:

TIM1->CCMR1 |= (TIM_OCMODE_PWM1 << TIM_CCMR1_OC2M_Pos);

break;

case PWM_MODE_2:

TIM1->CCMR1 |= (TIM_OCMODE_PWM2 << TIM_CCMR1_OC2M_Pos);

}

switch (timersetup->tim1_channel3_pwm_mode) {

case PWM_MODE_1:

TIM1->CCMR2 |= (TIM_OCMODE_PWM1 << TIM_CCMR2_OC3M_Pos);;

break;

case PWM_MODE_2:

TIM1->CCMR2 |= (TIM_OCMODE_PWM2 << TIM_CCMR2_OC3M_Pos);

}

}

Just as an example, one structure of the "durations" array:

 

TIM_SU durations[NUM_PATTERNS]= {

// Array of TIM_SU structures. NUM_PATTERNS defines the number of patterns. Each element is initialized with specific settings.

 

{

.tim2_period = 50000-1,

.tim1_channel1_pwm_duration =8000-1,

.tim1_channel2_pwm_duration =8000-1,

.tim1_channel3_pwm_duration =8000-1,

.tim1_period = 30000-1,

.dead_time = 200,

 

.tim1_channel1_pwm_mode = PWM_MODE_1,

.tim1_channel2_pwm_mode = PWM_MODE_1,

.tim1_channel3_pwm_mode = PWM_MODE_1,

 

},....

However, I am not able to change the PWM during runtime. I can change every other parameter with this code, the PWM Mode for each channel remains unchanged.

Is there any obvious reason I am missing? I turn the channels of, clear the respective bit-field and set it according to the desired PWM mode...

 

Thank you in advance for your help!

 

Ruan!

This topic has been closed for replies.
TDK
TDKBest answer
December 30, 2023

> TIM1->CCMR1 |= (TIM_OCMODE_PWM1 << TIM_CCMR1_OC1M_Pos);

TIM_OCMODE_PWM1 is already shifted to the appropriate bits for the OC1M field within CCMR1. You're shifting it more, so other bits are being modified instead of what you want.

Definition:

 

#define TIM_OCMODE_PWM1 (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1) /*!< PWM mode 1 */

 

https://github.com/STMicroelectronics/stm32l4xx_hal_driver/blob/675fb52ad4d5e2b0ddd294487da6fb6d185f9868/Inc/stm32l4xx_hal_tim.h#L996

 

For channels 2 and 4, you will need to left-shift it by (TIM_CCMR1_OC2M_Pos - TIM_CCMR1_OC1M_Pos) bits.

"If you feel a post has answered your question, please click ""Accept as Solution""."

3 replies

Associate II
December 30, 2023

I am using the STM32L433 Nucleo Board!

TDK
TDKBest answer
December 30, 2023

> TIM1->CCMR1 |= (TIM_OCMODE_PWM1 << TIM_CCMR1_OC1M_Pos);

TIM_OCMODE_PWM1 is already shifted to the appropriate bits for the OC1M field within CCMR1. You're shifting it more, so other bits are being modified instead of what you want.

Definition:

 

#define TIM_OCMODE_PWM1 (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1) /*!< PWM mode 1 */

 

https://github.com/STMicroelectronics/stm32l4xx_hal_driver/blob/675fb52ad4d5e2b0ddd294487da6fb6d185f9868/Inc/stm32l4xx_hal_tim.h#L996

 

For channels 2 and 4, you will need to left-shift it by (TIM_CCMR1_OC2M_Pos - TIM_CCMR1_OC1M_Pos) bits.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Associate II
December 31, 2023

Right, that did the trick!

 

Thank you TDK! :)