2022-07-12 07:36 AM
Hi,
I am trying to set up two timers so that they generate a PWM with the second timer being 1/4 phase past the first one. I am using an STM32F446.
I have the second set up as slave and triggered by the OCREF2 of timer 1, this should then generate a reset of timer 2. Below is my timer init by cube mx and I'll also post the registers.
static void MX_TIM1_Init(void)
{
/* USER CODE BEGIN TIM1_Init 0 */
/* USER CODE END TIM1_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/* USER CODE BEGIN TIM1_Init 1 */
/* USER CODE END TIM1_Init 1 */
htim1.Instance = TIM1;
htim1.Init.Prescaler = 99;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 63999;
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();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_OC_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC2REF;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 31999;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
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();
}
__HAL_TIM_DISABLE_OCxPRELOAD(&htim1, TIM_CHANNEL_1);
sConfigOC.OCMode = TIM_OCMODE_TOGGLE;
sConfigOC.Pulse = 15999;
if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
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.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM1_Init 2 */
/* USER CODE END TIM1_Init 2 */
HAL_TIM_MspPostInit(&htim1);
}
/**
* @brief TIM3 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM3_Init(void)
{
/* USER CODE BEGIN TIM3_Init 0 */
/* USER CODE END TIM3_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_SlaveConfigTypeDef sSlaveConfig = {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 = 99;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 63999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
sSlaveConfig.InputTrigger = TIM_TS_ITR0;
if (HAL_TIM_SlaveConfigSynchro(&htim3, &sSlaveConfig) != 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 = 31999;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
__HAL_TIM_DISABLE_OCxPRELOAD(&htim3, TIM_CHANNEL_4);
/* USER CODE BEGIN TIM3_Init 2 */
/* USER CODE END TIM3_Init 2 */
HAL_TIM_MspPostInit(&htim3);
}
The registers after initialization look as follows:
TIM1
TIM3
With this setup my signals are just in phase, with the second one just 40us behind, which you cannot see in this snap
Solved! Go to Solution.
2022-07-13 07:41 AM
Try to use PWM mode rather than toggle in the channel which is set as TRGO from master.
You should set TIMx_CR1.ARPE (i.e. enable ARR preload) if you are going to change ARR on the fly.
JW
2022-07-12 08:11 AM
You want them both to be set up completely, except for enabling the counter, i.e. you want both TIMx_CR.CEN=0. After that, enable only the master timer's counter.
I have no idea how to pull this out with Cube/HAL, I don't use it. It's way simpler to do it in registers.
JW
2022-07-12 08:20 AM
I worded that badly, the registers look like that after starting the counters, before that they are completely set up. The timers are then started with a call to HAL_TIM_PWM_Start(...) which does exactly what you described (omitting the enable for the triggerd counter). Still the waveforms are in phase
2022-07-12 09:04 AM
> I worded that badly, the registers look like that after starting the counters, before that they are completely set up.
Show.
JW
2022-07-12 09:15 AM
TIM1 after call to MX init
TIM3 after call to MX init
2022-07-12 09:18 AM
Add-on question:
My goal after getting the timers working is to adjust the period on the fly:
Will something like this work or is it not recommended to set the register values while the counter is working?
adc_val = ADC1->DR;
if(adc_val > 0x7ff)
{
arr = (adc_val - 0x800) << 5;
TIM1->ARR = arr;
TIM2->ARR = arr;
TIM1->CCR1 = arr / 2u;
TIM1->CCR3 = arr / 4u;
TIM2->CCR2 = arr / 2u;
}else
{
arr = (0x800 - adc_val) << 5;
TIM1->ARR = arr;
TIM2->ARR = arr;
TIM1->CCR1 = arr / 2u;
TIM1->CCR3 = 3u * arr / 4u;
TIM2->CCR2 = arr / 2u;
}
2022-07-13 07:41 AM
Try to use PWM mode rather than toggle in the channel which is set as TRGO from master.
You should set TIMx_CR1.ARPE (i.e. enable ARR preload) if you are going to change ARR on the fly.
JW
2022-07-14 12:22 AM
I accidentally set active high instead of PWM which seems to work as well. Also it seems to be important to first call HAL_TIM_PWM_Start(...) for the slave timer, before the master timer