cancel
Showing results for 
Search instead for 
Did you mean: 

output compare channel problems

Matthias  Dübon
Associate II
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

1 ACCEPTED SOLUTION

Accepted Solutions
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
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

8 REPLIES 8
Imen.D
ST Employee
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

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
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
Up vote any posts that you find helpful, it shows what's working..
T J
Lead
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(); }
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

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
Up vote any posts that you find helpful, it shows what's working..
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
�?�?�?�?�?�?�?�?

Posted on January 30, 2017 at 10:20

Hi marsh.nick,

You may refer to your reference manual for more details about 

SR register.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Posted on February 01, 2017 at 18:06

>>but I found more RMW instructions, are these ok ?

You'd have to check the reference manual, but probably, yes.

The TIM has a specific issue because the timer can clock faster than you can read/write to the peripheral. The status can change, and you have a race condition. The CPU cannot do things atomically on peripheral registers that change themselves.

The designer of the IC was specifically aware of this, which is why the write operates as a mask, which clears the bit(s) of interest synchronously with the timer. ie same clock edge your mask ANDs, any new interrupt is OR'd into the register.

If you read the SR register non-asserted bits will be zero, if you AND these with your mask it will likely be zero, clearing everything. ie 0x01 & 0xFE = 0x00

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
roseanne qiu
Associate II
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