Skip to main content
Matthias Dübon
Associate II
January 26, 2017
Solved

output compare channel problems

  • January 26, 2017
  • 8 replies
  • 1890 views
Posted on January 26, 2017 at 10:35

Hello everyone,

I want to use timer output compare channels as internal timebase (no output pins used). I did generate the following code by CubeMx

/* TIM3 init function */

static void MX_TIM3_Init(void)

{

TIM_ClockConfigTypeDef sClockSourceConfig;

TIM_MasterConfigTypeDef sMasterConfig;

TIM_OC_InitTypeDef sConfigOC;

htim3.Instance = TIM3;

htim3.Init.Prescaler = 0;

htim3.Init.CounterMode = TIM_COUNTERMODE_UP;

htim3.Init.Period = 65535;

htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

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_OC_Init(&htim3) != 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_TIMING;

sConfigOC.Pulse = 0x1000;

sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;

sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;

if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)

{

Error_Handler();

}

sConfigOC.Pulse = 0x10000;

if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)

{

Error_Handler();

}

}

I am starting the channels with

HAL_TIM_OC_Start_IT(&htim3, TIM_CHANNEL_1);

HAL_TIM_OC_Start_IT(&htim3, TIM_CHANNEL_2);

I am also having an ISR for the Timer events

void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)

{

   if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)

   {

      XXX += 1;

   }

   else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)

   {

      YYY += 1;

   }

}

Now I am having the following behavior:

I see the XXX and YYY counters are incremented but with the same speed. The incrementation is only depending on the 'htim3.Init.Period' the 'sConfigOC.Pulse' configuration is not used at all. Might that be a bug in CubeMx? I am using CubeMx Version 4.18

Any help would be very appreciated

Matthias

    This topic has been closed for replies.
    Best answer by Tesla DeLorean
    Posted on January 26, 2017 at 19:34

    They will increase at the same frequency, the Pulse setting changes the PHASE. ie one interrupts at 1 O'CLOCK, the other at 10 O'CLOCK, and the vector keeps rotating, and this same sequence repeat for each cycle (Period)

    If you want different frequencies you'll need to advance the CCRx at each interrupt

    8 replies

    ST Technical Moderator
    January 26, 2017
    Posted on January 26, 2017 at 19:08

    Hello

    D_bon.Matthias

    ,

    Please provide more information: which device and firmware version are you using ?

    It will be better to shareyour .ioc in orderto have more detailsabout your configuration setting?

    Regards

    Imen

    In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Thanks
    Tesla DeLorean
    Tesla DeLoreanBest answer
    Guru
    January 26, 2017
    Posted on January 26, 2017 at 19:34

    They will increase at the same frequency, the Pulse setting changes the PHASE. ie one interrupts at 1 O'CLOCK, the other at 10 O'CLOCK, and the vector keeps rotating, and this same sequence repeat for each cycle (Period)

    If you want different frequencies you'll need to advance the CCRx at each interrupt

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    T J
    Senior III
    January 27, 2017
    Posted on January 27, 2017 at 02:14

    Hi,

    if you are using one timer, then Yes, they will increase at the same rate.

    when using output compare, the 'roll over rate' is identical on each channel and it will be Timer input source / 65535, only the phase of the rising edge will change depending on the OC(channel) value.

    If you truly want separate timers, then you must use separate timers.

    Currently you are using 1 timer with 2 channels.

    I know this is slightly off topic, but I hope to give you clues to address your issue.

    on the '091 there are 17 timers, so many to choose from.

    using one timer as a mS timer.

    I too used this one to initialize :

    Tim21C = HAL_TIMEx_OCN_Start(&htim2,TIM_CHANNEL_1); // no interrupt no call back, polled mode: check the OC(channel) flag.
    �?�?

    IMPORTANT note: in cubeMX I set the rollover time to 1mS on the CRO.

    I used this for implementation:

    extern 'C' void wait_ms(int mS){
    // read current timer 2, 
    // set OC1 to this time 
    // wait for OC1 to fire 
    // count mS 
    resetWaitCounter(&htim2,1);
     do {
     waitTim2Ch1Flag(&htim2,1);
     }while(--mS>0);
    }
    void resetWaitCounter(TIM_HandleTypeDef *htim, uint32_t channel){
     uint32_t tmp;
     tmp = htim->Instance->CNT; // get the current timer value // start of 1mS timer
     htim->Instance->CCR1 = tmp; // set OC to 1mS time
     htim->Instance->SR &= ! TIM_SR_CC1IF; // clear the flag
    }
    void waitTim2Ch1Flag(TIM_HandleTypeDef *htim, uint32_t channel){
     uint32_t tmp;
     tmp = 0;
     while( ! tmp ){
     checkBackgroundServices(); // check Rx Tx, on Usart1, on CANBUS and various DMAs
     tmp = htim->Instance->SR & TIM_SR_CC1IF; 
     }
     htim->Instance->SR &= ! TIM_SR_CC1IF; // clear the flag 
    }�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

    CUBE MX output:

    /* TIM2 init function */
    void MX_TIM2_Init(void)
    {
     TIM_ClockConfigTypeDef sClockSourceConfig;
     TIM_MasterConfigTypeDef sMasterConfig;
     TIM_OC_InitTypeDef sConfigOC;
     htim2.Instance = TIM2;
     htim2.Init.Prescaler = 7;
     htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
     htim2.Init.Period = 0x1770; // this is 1mS on the CRO;
     htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV2;
     htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
     if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
     { Error_Handler(); }
     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
     if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
     { Error_Handler(); }
     if (HAL_TIM_OC_Init(&htim2) != HAL_OK)
     { Error_Handler(); }
     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
     if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
     { Error_Handler(); }
     sConfigOC.OCMode = TIM_OCMODE_TIMING;
     sConfigOC.Pulse = 1;
     sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
     sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
     if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
     { Error_Handler(); }
    }�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

    Tesla DeLorean
    Guru
    January 27, 2017
    Posted on January 27, 2017 at 04:14

    This is very dangerous, don't do this

    htim->Instance->SR   &=  ! TIM_SR_CC1IF;  // clear the flag  

    Do this

    htim->Instance->SR   =  ! TIM_SR_CC1IF;  // clear the flag  

    The RMW is not atomic, the TIM SR can change between the read and write, and ANDing something with zero clears interrupts that may have asserted and which you will now never observe. Also don't use bit-banding on this register, as this causes the same hazard.

    The register was specifically designed to do an atomic/synchronous AND operation with just the WRITE operation.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    T J
    Senior III
    January 27, 2017
    Posted on January 27, 2017 at 04:54

    Hi,

    Yes great help for an unknown aberration of dysfunction (a bug) to appear later.

    recompiled and it still works.

    but I found more RMW instructions, are these ok ?

     ADC1->CR &= (uint32_t)(~ADC_CR_ADEN);
     GPIOA->ODR &= ! Lcd1_nSS_Pin; // pin down
     hcan->Instance->sTxMailBox[transmitmailbox].TIR &= CAN_TI0R_TXRQ; // make sure the request is not set already
     hcan->pTxMsg->DLC &= (uint8_t)0x0000000FU;
     CAN->FMR &=~ CAN_FMR_FINIT; // (10) Leave filter init
    �?�?�?�?�?�?

    and many ORs of course..

    this is another good reason the check the registers manual.

    where do we find the description of this SR register ?

    This is very dangerous, don't do this
     htim->Instance->SR &= ! TIM_SR_CC1IF; // clear the flag
    Do this
     htim->Instance->SR = ! TIM_SR_CC1IF; // clear the flag
    �?�?�?�?�?�?�?�?

    roseanne qiu
    Associate III
    June 25, 2018
    Posted on June 25, 2018 at 18:16

    Dear 

    Matthias and Clive(I also asked this question in another thread, not solve it yet)

    I use basically the same as what your codes are(I believe that you also get the codes from STM32CubeMX ). But I even could not get interrupt for output channel compare interrupts. I do not know why(I could get timer interrupt without output channel comparation) . I am wondering what's wrong with my codes:

    here are my codes (remember I could get timer interrupt if I do not use channel compare register)

    here are my codes( it is almost the same as yours).

    =======================================

    void TIM3_IRQHandler()

    {

    HAL_TIM_IRQHandler(&Tim3Handle);

    }

    .....................................

    __TIM3_CLK_ENABLE();

    Tim3Handle.Init.Prescaler = 16400;

    Tim3Handle.Init.CounterMode = TIM_COUNTERMODE_UP;

    Tim3Handle.Init.Period = 10000;

    Tim3Handle.Instance = TIM3;

    {

    Tim3Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

    if ( HAL_TIM_Base_Init(&Tim3Handle) != HAL_OK )

    {

    Error_Handler();

    }

    }

    sMasterConfig3.MasterOutputTrigger = TIM_TRGO_RESET;

    sMasterConfig3.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

    if (HAL_TIMEx_MasterConfigSynchronization(&Tim3Handle, &sMasterConfig3) != HAL_OK)

    {

    Error_Handler();

    }

    sConfigOC3.OCMode = TIM_OCMODE_TIMING;

    sConfigOC3.Pulse = 1000 ;// Tim3Handle.Init.Period for thermal

    sConfigOC3.OCPolarity = TIM_OCPOLARITY_HIGH;

    sConfigOC3.OCFastMode = TIM_OCFAST_DISABLE;

    if (HAL_TIM_OC_ConfigChannel(&Tim3Handle, &sConfigOC3, TIM_CHANNEL_1) != HAL_OK)

    {

    Error_Handler();

    }

    sConfigOC3.Pulse = 20;// Tim3Handle.Init.Period for heating

    if (HAL_TIM_OC_ConfigChannel(&Tim3Handle, &sConfigOC3, TIM_CHANNEL_2) != HAL_OK)

    {

    Error_Handler();

    }

    HAL_TIM_OC_Start_IT(&Tim3Handle, TIM_CHANNEL_1);

    HAL_TIM_OC_Start_IT(&Tim3Handle, TIM_CHANNEL_2);

    ....

    HAL_NVIC_SetPriority(TIM3_IRQn, 0, 1);

    HAL_NVIC_EnableIRQ(TIM3_IRQn);

    any thing wrong with the codes.  

    I dig to the hal source codes inside stm32f4xx_hal_tim.c, still not get it.

    would you please help for these?

    thanks

    roseanne