cancel
Showing results for 
Search instead for 
Did you mean: 

Timer synchronisation

Repwoc
Associate III

I am using a STM32G4 MCU and STM32CubeIDE. 

I want to synchronise two timers (TIM3 and TIM15) that are generating PWM signals so that they both start at the same time. 

TIM3 is set to 250 kHz and the PWM is modulated via DMA on channel 1.  The modulated signal is a 10 kHz sine wave.

TIM15 is set to 10 kHz and the PWM is a simple 50% duty cycle.

I need the timers to start together to ensure that the PW Modulated 10 kHz sine wave (TIM3) is synchronised to the 10 kHz PWM (TIM15).

I thought it would be straight forward enough. 

I have configured TIM15 as master.  In CubeMX I have set Master/Slave Mode (MSM bit) to "Enable (Trigger delayed for master/slaves simultaneous start)" and Trigger Event Selection to "Enable (CNT_EN)".

I have configured TIM3 as a slave.  In CubeMX I have set Slave Mode to "Trigger Mode" and Trigger Source to "ITR6" (per the reference manual).

To the CubeIDE generated code I have added:

  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_1, BDPos_CCRValue_Buffer, CCRValue_BufferSize);
  HAL_TIM_PWM_Start(&htim15, TIM_CHANNEL_1);

  /* USER CODE END 2 */

BDPos_CCRValue_Buffer and CCRValue_BufferSize are a pointer to the sine wave data buffer and the buffer size.

When I run the code the timers are not synchronised.  After debugging through the code I found that TIM3 starts immediately on executing HAL_TIM_PWM_Start_DMA and does not wait for TIM15 to be started.  TIM15 starts when this code is executed:

    /* Enable the Capture compare channel */
    TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
void TIM_CCxChannelCmd(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ChannelState)
{
  uint32_t tmp;

  /* Check the parameters */
  assert_param(IS_TIM_CC1_INSTANCE(TIMx));
  assert_param(IS_TIM_CHANNELS(Channel));

  tmp = TIM_CCER_CC1E << (Channel & 0x1FU); /* 0x1FU = 31 bits max shift */

  /* Reset the CCxE Bit */
  TIMx->CCER &= ~tmp;

  /* Set or reset the CCxE Bit */
  TIMx->CCER |= (uint32_t)(ChannelState << (Channel & 0x1FU)); /* 0x1FU = 31 bits max shift */
}

TIM15 starts when the last line is executed (ie after /* Set or reset the CCxE Bit */).

Is there a way to make TIM3 wait for TIM15 to start?

Thanks.

 

21 REPLIES 21
Repwoc
Associate III

So I changed the master Trigger Event Selection TRGO to "Update Event" instead of "Enable (CNT_EN)" so that TIM15 (slave) starts on the first update event of TIM3 (ie 4 uS after starting TIM3).  Now the 10 kHz signals align perfectly.

Thanks for your input chaps.  I think this is solved.  It only took me about three days :(

Repwoc
Associate III

In summary, when using CubeMX + HAL or LL:

1. To ensure that a slave timer starts when the master timer starts, the master timer must be initialised before the slave timer is initialised (ie MX_TIMmaster_Init() must run before MX_TIMslave_Init()) and the slave timer must be started before the master timer (eg with HAL_TIM_PWM_Start());

2. To align the 10 kHz PWM from TIM15 (slave) with the 10 kHz PW Modulated sine wave from TIM3 (master)  I set the TIM3 (master) Trigger Event Selection TRGO to "Update Event" to ensure that the slave timer started at the same time as the first DMA request to get sine wave data.