cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L4 PWM Phase Delay

Rogers.Gary
Senior II
Posted on February 19, 2018 at 19:02

Hello:

Using the Nucleo STM32L476RG demo board.

On an STM32F4xx, using CMSIS, I am able to create 2 PWM pulses that have the same period. However, the 2nd pulse is delayed by: TIM4->CNT = TIM3->CNT + (timerPeriod /2 ); // =180 degrees

I want to do the same thing using HAL, but it looks like a few things have changed from CMSIS!

I have my code where I have 2 pulses being generated at the correct duty cycle and frequency, but spinning the wheels on how to get the second pulse delayed as shown above.

Can someone please provide some insight on how I could accomplish this? Has HAL made it easier than CMSIS? Or just different?

Thanks!

UPDATE.

Found: DM00405316

Note: this post was migrated and contained many threaded conversations, some content may be missing.
22 REPLIES 22
Rogers.Gary
Senior II
Posted on February 20, 2018 at 00:10

No answer....ok.

Can anyone provide some insight as to how I can convert my STM32F4xx code to equivalent HAL code, or something close? I need to perform the same timer functions in HAL as I have in my CMSIS code.

Anyone?

henry.dick
Senior II
Posted on February 20, 2018 at 03:09

Didn't see your code so hard to help.

You can just initialize the timers by 180 degrees.

It wouldn't be perfectly syncd but close enough.

Rogers.Gary
Senior II
Posted on February 20, 2018 at 03:20

Hi dHenry,

Thanks. Just updated my post. Found article DM00405316, with info on converting SPL to LL.

If HAL was the only choice I would be switching processors...don't want to be a beta tester for the obfuscation that is HAL. I cannot imagine why they would get rid of CMSIS/SPL. I have thousands of lines of code and having LL available makes it possible to 'more easily' move the code to a newer processor, i.e., L series.

Will see how it works out.

John Craven
Senior
Posted on February 20, 2018 at 05:27

Setup Master Timer (TIM2) as basic PWM on CH1, only thing extra is to Master Output to Update Event

/* TIM2 init function */
static void MX_TIM2_Init(void)
{
 TIM_ClockConfigTypeDef sClockSourceConfig;
 TIM_MasterConfigTypeDef sMasterConfig;
 TIM_OC_InitTypeDef sConfigOC;
 htim2.Instance = TIM2;
 htim2.Init.Prescaler = 71;
 htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
 htim2.Init.Period = 9999;
 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
 htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
 if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
 if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
 if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 sConfigOC.OCMode = TIM_OCMODE_PWM1;
 sConfigOC.Pulse = 1000;
 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
 if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }

 HAL_TIM_MspPostInit(&htim2);
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Set Slave Timer (TIM1) as follows, basic PWM on CH1 , with polarity LOW, Oneshot mode, and Triggered by ITR1

/* TIM1 init function */
static void MX_TIM1_Init(void)
{
 TIM_ClockConfigTypeDef sClockSourceConfig;
 TIM_SlaveConfigTypeDef sSlaveConfig;
 TIM_MasterConfigTypeDef sMasterConfig;
 TIM_OC_InitTypeDef sConfigOC;
 TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
 htim1.Instance = TIM1;
 htim1.Init.Prescaler = 71;
 htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
 htim1.Init.Period = 6000;
 htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
 htim1.Init.RepetitionCounter = 0;
 htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
 if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
 if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 if (HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
 sSlaveConfig.InputTrigger = TIM_TS_ITR1;
 if (HAL_TIM_SlaveConfigSynchronization(&htim1, &sSlaveConfig) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
 sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
 if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 sConfigOC.OCMode = TIM_OCMODE_PWM1;
 sConfigOC.Pulse = 5000;
 sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
 sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
 sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
 sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
 if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
 sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
 sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
 sBreakDeadTimeConfig.DeadTime = 0;
 sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
 sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
 sBreakDeadTimeConfig.BreakFilter = 0;
 sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
 sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
 sBreakDeadTimeConfig.Break2Filter = 0;
 sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
 if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 HAL_TIM_MspPostInit(&htim1);
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Code to start timers and manipulate pulse width and phase;

 MX_TIM2_Init();
 MX_TIM1_Init();
 uint32_t period = 10000;
 uint32_t t1 = 1000;
 uint32_t t2 = 1000;
 uint32_t offset = period/2;
 __HAL_TIM_SET_AUTORELOAD(&htim2, period); //set master period
 __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, t2); //set master pulse width
 __HAL_TIM_SET_AUTORELOAD(&htim1, offset + t2); //set slave period
 __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, offset); //set slave pulse width
 HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
 HAL_TIM_OnePulse_Start(&htim1, TIM_CHANNEL_1);
 HAL_Delay(100);
 t1 = 2000; //increase master pulse width
 __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, t1);
 HAL_Delay(100);
 t2 = 2000; //increase slave pulse width
 __HAL_TIM_SET_AUTORELOAD(&htim1, offset + t2);
 __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, offset);
 HAL_Delay(100);
 offset = period/4; //reduce slave offset
 __HAL_TIM_SET_AUTORELOAD(&htim1, offset + t2);
 __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, offset);�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Posted on February 20, 2018 at 15:39

Surprises me that this won't work under HAL, registers are all exposed and available

TIM4->CNT = TIM3->CNT + (timerPeriod /2 ); // =180 degrees

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
John Craven
Senior
Posted on February 20, 2018 at 15:42

The alternative, which is probably a little cleaner,(no math and single calls for each parameter change):

add PWM on CH2 to master timer, using this as master output pulse.

use PWM on CH1 on master as the phase shift.

change master TRGO to the Compare Pulse (OC1) event

Set Slave CH1 pulse width to 1 (delay before the pulse, must be > zero)

then start things with;

HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); HAL_TIM_OnePulse_Start(&htim1, TIM_CHANNEL_1);

use these to make changes to timing;

__HAL_TIM_SET_AUTORELOAD(&htim2, period); //set master period __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, tm); //set master pulse width __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, (offset-1)); //set slave pulse offset __HAL_TIM_SET_AUTORELOAD(&htim1, ts); //set slave pulse width    // change period with 180deg phase 

__HAL_TIM_SET_AUTORELOAD(&htim2, newperiod); //set master period __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, (

newperiod/2

-1)); //set slave pulse offset

 

John Craven
Senior
Posted on February 20, 2018 at 17:59

 For CubeMX users, this is the setup for the clean code alternative i posted.

0690X00000609kqQAA.png0690X00000609STQAY.png0690X00000609SUQAY.png
Rogers.Gary
Senior II
Posted on February 20, 2018 at 18:53

Very helpful...thanks, I will test it out a bit later today.

Posted on February 20, 2018 at 18:07

John,

Could you please express it also in terms of TIM registers content? It's enough to read them out in debugger.

Thanks,

JW