2018-11-23 12:22 AM
In my project, I want to implement a timeout feature. That is, the user sets the required time and then starts a process. The process then has to end after the set timeout value. Now, the problem is I am able to turn off the process after the set timeout value, but the time is not precise( verified with portable timer device). That is, if I set a timeout of 5 minutes, it sometimes reaches the set value by 4.40 mins or 5.10mins, randomly. What am I doing wrong here? How to prevent this to get close to precise time?
Details:
Device: STM32F051R8T6
Clock: 24 Mhz
Timer16 is configured to tick every 1 second(Prescaler = 24000, ARR = 999)
void Timer16_Init(void)
{
TIM_TimeBaseInitTypeDef Timer16_struct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM16,ENABLE);
Timer16_struct.TIM_Prescaler = 24000;
Timer16_struct.TIM_CounterMode = TIM_CounterMode_Up;
Timer16_struct.TIM_Period = 999;
Timer16_struct.TIM_ClockDivision = TIM_CKD_DIV1;
Timer16_struct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM16, &Timer16_struct);
// That last function caused the UIF flag to get set. Clear it.
TIM_ClearITPendingBit(TIM16, TIM_IT_Update);
// Configure so that the interrupt flag is only set upon overflow
TIM_UpdateRequestConfig(TIM16, TIM_UpdateSource_Regular);
TIM_Cmd(TIM16, ENABLE);
}
void EnableTimer16Interrupt(void)
{
nvicStructure.NVIC_IRQChannel = TIM16_IRQn;
nvicStructure.NVIC_IRQChannelPriority = 0;
nvicStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvicStructure);
NVIC_SetPriority(TIM16_IRQn,0);
NVIC_EnableIRQ(TIM16_IRQn);
TIM_ITConfig(TIM16, TIM_IT_Update, ENABLE);
}
2018-11-23 03:04 AM
Hello RV,
what you are currently having is interrupt on every update event, that is, every 1 second is interrupt.
To be precise, interrupt is triggered later than every 1s, because your prescaler should be set to 23999.
Timer_tick_frequency = timer_input_freq / (prescaler + 1)
With your prescaler, your tick frequency is 1000Hz and with period set to 999, you have interrupt each second.
To get 5 minutes timeout, you would need to tick for 300 interrupts. Can you show us this part?
Best regards,
Tilen
2018-11-23 04:45 AM
As Tilen indicates the Period and Prescaler value should be N-1 form
If you can't get the interrupt to count off a uniform/consistent number of seconds you've got serious problems elsewhere in your code.
You'd have to be blocking interrupts, or failing to properly count them.
2018-11-30 09:02 PM
To get 5 minute interrupt, I am incrementing a 16 bit variable every second, inside timer IRQ handler, hence, when the value reaches 299 I consider it as timeout(of 5 seconds). Is this method right? or is there any better way around?
// Timer16 used for interrupting every 1 second
void TIM16_IRQHandler(void)
{
if(TIM_GetITStatus(TIM16,TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM16,TIM_IT_Update);
if(bTimerBegin) // Flag to check if user initiated timeout
{
SecondsCounter++; // 16 bit unsigned variable
if(SecondsCounter > 299) // 1s x 300 = 5 minutes
{
cSecondsCounter1 = 0; //Variable reset
bTimeOut = 1; // Flag to indicate Timeout
bTimerBegin = 0;
}
}
}
}
2018-11-30 09:06 PM
"You'd have to be blocking interrupts, or failing to properly count them."
Please refer the interrupt handler part replied to Tilen, is the method correct?
Regarding blocking interrupts, this is a 1 second interrupt, far slower than other interrupts being used, how could I be still "blocking" the interrupt? By using the same priority or should I block other interrupts when ever this interrupt is generated to get precision? How do I prevent this?
2018-12-07 01:07 AM
@Tilen MAJERLE Is this the correct way ?