Skip to main content
Rogers.Gary
Senior II
February 20, 2018
Question

Timer 2,3 Offset

  • February 20, 2018
  • 5 replies
  • 2515 views
Posted on February 20, 2018 at 05:30

Here's my code to initialize timers 2 and 3. Keep in mind that right now, this code executes with no problem and there is a 100Hz output on PA5 (TIM2) and PA6 (TIM3)

My objective is to offset TIM3 by 180 degrees from TIM2. I am able to do this in SPL, but have had no success with LL after trying different things, including direct register writes to TIM2 and TIM3. The interrupt handlers are functioning OK for both timers.

What do I need to do to the code below to achieve this?

__STATIC_INLINE void  Configure_TIMPWMOutput(void)

{

  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

 

  /* GPIO TIM2_CH1 configuration */

  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_ALTERNATE);

  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_5, LL_GPIO_PULL_DOWN);

  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_5, LL_GPIO_SPEED_FREQ_HIGH);

  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_5, LL_GPIO_AF_1);

 

  /* GPIO TIM3_CH1 configuration */

  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_6, LL_GPIO_MODE_ALTERNATE);

  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_6, LL_GPIO_PULL_DOWN);

  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_6, LL_GPIO_SPEED_FREQ_HIGH);

  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_6, LL_GPIO_AF_2);  

 

  /***********************************************/

  /* Configure NVIC for TIM2 interrupt */

  /***********************************************/

  NVIC_SetPriority(TIM2_IRQn, 0);

  NVIC_SetPriority(TIM3_IRQn, 0);

    

  /******************************/

  /* Peripheral clocks enabling */

  /******************************/

  /* Enable timer 2 peripheral clock */

  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);

  /* Enable timer 3 peripheral clock */  

  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);   

 

  /***************************/

  /* Time base configuration */

  /***************************/

  /* Set the pre-scaler value to have TIM2 counter clock equal to 10 kHz */

  LL_TIM_SetPrescaler(TIM2, __LL_TIM_CALC_PSC(SystemCoreClock, 10000));

  LL_TIM_SetPrescaler(TIM3, __LL_TIM_CALC_PSC(SystemCoreClock, 10000));  

 

  /* Enable TIM2_ARR and TIM3_ARR register preload. */

  LL_TIM_EnableARRPreload(TIM2);

  LL_TIM_EnableARRPreload(TIM3);  

    

  /* Set the auto-reload value to have a counter frequency of 100 Hz */

  LL_TIM_SetAutoReload(TIM2, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM2), 100));

  LL_TIM_SetAutoReload(TIM3, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM3), 100));  

 

  /*********************************/

  /* Output waveform configuration */

  /*********************************/

  /* Set output mode */

  LL_TIM_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1);

  LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1);  

 

  /* Set output channel polarity */

  LL_TIM_OC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_OCPOLARITY_HIGH);

 

  /* Set compare value to half of the counter period (50% duty cycle ) */

  LL_TIM_OC_SetCompareCH1(TIM2, (LL_TIM_GetAutoReload(TIM2) / 2));

  LL_TIM_OC_SetCompareCH1(TIM3, (LL_TIM_GetAutoReload(TIM3) / 2));  

 

  /* Enable TIM2_CCR1 register preload.   */

  LL_TIM_OC_EnablePreload(TIM2, LL_TIM_CHANNEL_CH1);

  LL_TIM_OC_EnablePreload(TIM3, LL_TIM_CHANNEL_CH1);  

 

  /**************************/

  /* TIM2 and TIM3 interrupts set-up */

  /**************************/

  /* Enable the capture/compare interrupt for TIM2, TIM3 channel 1*/

  LL_TIM_EnableIT_CC1(TIM2);

  LL_TIM_EnableIT_CC1(TIM3);    

 

  /**********************************/

  /* Start output signal generation */

  /**********************************/

  /* Enable TIM2, TIM3 output channel 1 */

  LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1);

  LL_TIM_CC_EnableChannel(TIM3, LL_TIM_CHANNEL_CH1);  

 

  /* Enable counters */

  LL_TIM_EnableCounter(TIM2);

  LL_TIM_EnableCounter(TIM3);    

 

  /***********************************************/

  /* Enable TIM2 and TIM3 INT Handlers */

  /***********************************************/

  NVIC_EnableIRQ(TIM2_IRQn);

  NVIC_EnableIRQ(TIM3_IRQn);

 

  /* Force update generation */

  LL_TIM_GenerateEvent_UPDATE(TIM2);

  LL_TIM_GenerateEvent_UPDATE(TIM3);  

}
    This topic has been closed for replies.

    5 replies

    Jan Waclawek
    Visitor II
    February 20, 2018
    Posted on February 20, 2018 at 08:14

    Not this, your original code which worked.

    JW

    Rogers.Gary
    Senior II
    February 21, 2018
    Posted on February 21, 2018 at 05:05

    hi Jan,

    You asked if I could post my original code from SPL; please see the code I have posted. Can you suggest how I could set up the LL code I have posted to get a 180 shift/offset on timer 3? I'm essentially doing the same thing in LL as I am in SPL. Set up 2 timers, then perform an OC compare on the respective channels. No matter where I place the code to set TIM2/TIM3, it does not alter the signals - they are still in phase.

    Appreciate any help I can get....thanks

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

    Here is the code that works in SPL/CMSIS. I would like to get this to work with the LL implementation.

    I tried direct register set  and it did not appear to work.

    Thanks for looking at this.

    #define TIMER_BASE      (uint16_t)20000

    void PWM_TIMER_Configuration( void )

    {

        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

        TIM_OCInitTypeDef  TIM_OCInitStructure;

        NVIC_InitTypeDef NVIC_InitStructure;

        

        TIM_TimeBaseStructInit( &TIM_TimeBaseStructure );   

        

        // 20 KHz timebase, assumes APB1 H/4 TIMCLK4 H/2

        uint16_t Prescaler = ((SystemCoreClock / 2) / TIMER_BASE);

       

        /* Time base configuration */

        // set for 100Hz

        TIM_TimeBaseStructure.TIM_Period = (uint16_t)( TIMER_BASE / 100 );

        TIM_TimeBaseStructure.TIM_Prescaler = Prescaler - 1;

        TIM_TimeBaseStructure.TIM_ClockDivision = 0;

        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

        //set timer 3 & 4 to same frequency

        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

        

        //create pulse width for both channels the same

        float32_t dutyCycle = (float32_t) (( BPF / 100.0) + 0.25 );

        uint16_t onTime = (uint16_t) (TIM_TimeBaseStructure.TIM_Period * dutyCycle );        

        /* Output Compare PWM1 Mode configuration: Channel 1 */

        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

        TIM_OCInitStructure.TIM_Pulse = onTime;

        

        //Timer 4 is on channel 1

        TIM_OC1Init(TIM4, &TIM_OCInitStructure);    

        

        //Set TIM3 channel 2 preload cfg

        TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);          

        /* Output Compare PWM1 Mode configuration: Channel 2 */

        TIM_OC2Init(TIM3, &TIM_OCInitStructure);

           

        //set timer 3 immediately to timerPeriod offset/2 = 180 degrees shift

        TIM4->CNT = TIM3->CNT + ((uint16_t) (TIM_TimeBaseStructure.TIM_Period / 2 ));

        TIM_Cmd(TIM4, ENABLE);        

        TIM_Cmd(TIM3, ENABLE);        

     

        //Set up TIM3 interrrupt

        NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;

        // set for RTOS

        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_KERNEL_INTERRUPT_PRIORITY;        

        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

        NVIC_Init(&NVIC_InitStructure);    

        TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);  

    }
    John Craven
    Senior
    February 21, 2018
    Posted on February 21, 2018 at 06:24

    I am not an SPL guy, but looking at you setup, and the my HAL code from the other thread;

    https://community.st.com/0D50X00009XkhLaSAJ

    You set up both timers as simple PWM. I don't see the extra bit to do Oneshot mode on the slave timer.

    In the HAL init of the Oneshot slave, first there is PWM init, and then Oneshot init;

    if (HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }

    digging into the oneshot init, here is what it adds;

    /* Reset the OPM Bit */ htim->Instance->CR1 &= ~TIM_CR1_OPM;/* Configure the OPM Mode */ htim->Instance->CR1 |= OnePulseMode;

    I also don't see you set the slave polarity low for CH1. I think you will need to do this, because the oneshotacts inverted to typical PWM.

    John Craven
    Senior
    February 21, 2018
    Posted on February 21, 2018 at 23:06

    I also think this is wrong, your setting the counter

    TIM4->CNT = TIM3->CNT + ((uint16_t) (TIM_TimeBaseStructure.TIM_Period / 2 ));

    to set the period, it would be;

    TIM4->ARR= TIM3->ARR+ ((uint16_t) (TIM_TimeBaseStructure.TIM_Period / 2 ));

    i found a downloaded the F4 SPL;

    if you going to try do what i did in HAL with SPL, your going to need to call this on the slave timer;

    TIM_SelectOnePulseMode(TIM_TypeDef* TIMx, uint16_t TIM_OPMode) with TIM_OPMode_Single 

    henry.dick
    Associate II
    February 20, 2018
    Posted on February 20, 2018 at 18:16

    1. Keep the two timers off. Then set up the rest.

    2. Zero one timers counter and load up the others counter with an offset equal to 1/2 of the period. 

    3. Enable both timers.

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

    ok, thanks....I will give it a try!

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

    Still getting a result that is not working. I just do not see how to configure the LL system on how to accomplish this.

    Both timers will be the same period. Let's say that period is 10ms and the DC is 25%. Then, I need the second timer's output pulse to occur exactly 1/2 the period time. See the attached (hacked) image. Again, this I can presently do in CMSIS, but not in LL.

    If TIMx starts at t = 0, TIMy output will be at t + 5ms. Again - I have the code configured so that right now, a PWM is occurring on TIM2 (PA5), TIM3( PA6) and these 2 signals are in phase. The question is, with a TIM2 period = 10ms, how do I get timer 3 to trigger at TIM2 + 5ms ?

    Seems it should be easy....but after looking at the LL mechanisms, not obvious.

    Help?0690X00000604PsQAI.jpg

    waclawek.jan
    Super User
    February 25, 2018
    Posted on February 25, 2018 at 09:44

    In the LL code in opening post, this part from your original code is missing:

    //set timer 3 immediately to timerPeriod offset/2 = 180 degrees shift

    TIM4->CNT = TIM3->CNT + ((uint16_t) (TIM_TimeBaseStructure.TIM_Period / 2 ));

    That's the key one though - this is where you establish the phase shift.

    I don't Cube, so don't know the exact incantation to do this 'properly' in LL, but the direct write to to CNT just as in the original code will do just fine.

    John presented you a more complex but more flexible option using the internal master-slave linking

    https://community.st.com/0D50X00009XkhLYSAZ

    , but yours will do if you are OK too, if you don't intend to change the phase shift on the run.

    Ah, and you want also to move this

    /* Force update generation */

    LL_TIM_GenerateEvent_UPDATE(TIM2);

    LL_TIM_GenerateEvent_UPDATE(TIM3);

    to *before* you enable the timers.

    JW

    Rogers.Gary
    Senior II
    February 25, 2018
    Posted on February 25, 2018 at 16:15

    jan,

    I had the timer offset in my code, just did not post it above. It looked like this:

    TIM3->CNT = TIM2->CNT + ((uint16_t) (LL_TIM_GetAutoReload(TIM2) / 2 ));

    The issue all along was the placement of the code 'LL_TIM_GenerateEvent_UPDATE'

    Once I moved that as you suggested, it worked.Great!

    Thanks again to you and everyone else who provided help with this.

    Gary