2017-01-26 01:35 AM
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
Solved! Go to Solution.
2017-01-26 10:34 AM
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
2017-01-26 10:08 AM
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
2017-01-26 10:34 AM
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
2017-01-26 05:14 PM
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(); }
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
2017-01-26 08:14 PM
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.
2017-01-26 08:54 PM
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
�?�?�?�?�?�?�?�?
2017-01-30 02:20 AM
Hi marsh.nick,
You may refer to your reference manual for more details about
SR register.
Imen
2017-02-01 10:06 AM
>>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
2018-06-25 09:16 AM
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