2018-02-19 10:02 AM
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.2018-02-19 03:10 PM
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?
2018-02-19 06:09 PM
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.
2018-02-19 06:20 PM
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.
2018-02-19 08:27 PM
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);�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
2018-02-20 06:39 AM
Surprises me that this won't work under HAL, registers are all exposed and available
TIM4->CNT = TIM3->CNT + (timerPeriod /2 ); // =180 degrees
2018-02-20 06:42 AM
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 offset2018-02-20 08:59 AM
For CubeMX users, this is the setup for the clean code alternative i posted.
2018-02-20 09:53 AM
Very helpful...thanks, I will test it out a bit later today.
2018-02-20 10:07 AM
John,
Could you please express it also in terms of TIM registers content? It's enough to read them out in debugger.
Thanks,
JW