1

I am trying to generate 3 channel center aligned PWM with complementary outputs and deadtime insertion on an STM32G474. To test functionality of the timers, I currently have the 6 outputs connected to 6 LEDS to hopefully see a visible time delay between the main outputs going low and the complementary outputs going high. This however isn't the case, and I can't see any delay between the toggling despite a calculated deadtime of around 98ms. There is no visible time where no LED is active

My timer initiation code is below

void TIM1_Init() {
    // Enable clocks for GPIOA, GPIOB and TIM1
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1);
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

    // Set relevant GPIO pins to AF mode
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_DOWN;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_6;

    GPIO_InitStruct.Pin = LL_GPIO_PIN_8;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_13;
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_14;
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_15;
    LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    LL_TIM_InitTypeDef TIM_InitStruct;
    LL_TIM_StructInit(&TIM_InitStruct);
    TIM_InitStruct.Prescaler = 0xFFFF;
    TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_CENTER_UP_DOWN;
    TIM_InitStruct.Autoreload = 244;
    TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;

    LL_TIM_Init(TIM1, &TIM_InitStruct);
    LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL);

    LL_TIM_OC_InitTypeDef TIM_OC_InitStruct;
    LL_TIM_OC_StructInit(&TIM_OC_InitStruct);
    TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM2;
    TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE;
    TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_ENABLE;
    TIM_OC_InitStruct.CompareValue = 244/2;
    //TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_LOW;
    //TIM_OC_InitStruct.OCNPolarity = LL_TIM_OCPOLARITY_LOW;
    TIM_OC_InitStruct.OCIdleState = LL_TIM_OCIDLESTATE_LOW;
    TIM_OC_InitStruct.OCNIdleState = LL_TIM_OCIDLESTATE_LOW;

    LL_TIM_OC_Init(TIM1, LL_TIM_CHANNEL_CH1, &TIM_OC_InitStruct);
    LL_TIM_OC_Init(TIM1, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct);
    LL_TIM_OC_Init(TIM1, LL_TIM_CHANNEL_CH3, &TIM_OC_InitStruct);

    LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH1);
    LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH2);
    LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH3);

    LL_TIM_BDTR_InitTypeDef bdtr = {0};
    bdtr.OSSRState = LL_TIM_OSSR_ENABLE;
    bdtr.OSSIState = LL_TIM_OSSI_ENABLE;
    bdtr.LockLevel = LL_TIM_LOCKLEVEL_OFF;
    bdtr.DeadTime = 24;  // Try max for visible LED effect
    bdtr.BreakState = LL_TIM_BREAK_DISABLE;
    bdtr.BreakPolarity = LL_TIM_BREAK_POLARITY_HIGH;
    bdtr.AutomaticOutput = LL_TIM_AUTOMATICOUTPUT_ENABLE;
    LL_TIM_BDTR_Init(TIM1, &bdtr);

    LL_TIM_EnableAllOutputs(TIM1);
    LL_TIM_EnableCounter(TIM1);
    LL_TIM_GenerateEvent_UPDATE(TIM1);
}

In the wider code, the main function simply runs this function only then does a simple LED blinking program for a separate LED. Nothing else is changed, including clock speed at 16MHz

I have tried many setups and configuration options and nothing is working, I appreciate all help.

2
  • How did you check the timing, with your eyes or with an oscilloscope? (Background: human eyes are too inert to see such small times.) Commented May 5 at 14:52
  • I used a video recording to make very sure. I don't have access to a scope. Not even a single frame of dead time Commented May 5 at 18:58

1 Answer 1

1

How did you calculate the dead time?

As far as I can tell you cannot achieve such a long dead time.
I assume you calculated it based on the timer clock frequency divided by the prescaler.

The dead time generator used Tdts, which is not derived from the prescaled tim_psc_ck, it is based on the kernel timer, tim_ker_ck.

The reference manual gives examples based on an 8MHz clock, and the maximum dead time that can be inserted with this method is 31750ns. There is a register to prescale the Tdts, but only with a maximum of 4. I don't think you will be able to see it with a camera. Maybe if you slow down the entire clock tree to some extreme values.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the answer. I was not aware that the pre-scaler wasn't taken into account in the dead time timer. By my calculations given tim_psc_ck was at a low frequency I would be able to see the dead time but I know that's incorrect now. I'm curious however, in my example, what I should expect the dead time to be.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.