Skip to main content
Tobe
Senior III
October 29, 2024
Solved

My micros() function is not glitchfree?

  • October 29, 2024
  • 4 replies
  • 2234 views

Hi,

i have a micros() function, that i adapted from arduino library. It worked flawlessly so far, but i have made a discovery, that micros() did not work properly at one time. micros() returned a time, that had 772us less, than it should have returned. Seems to be a very very rare case, but i want it to be perfect, and dont have any problems at all in the future. I cant see, where there should be a problem.

These are the definitions

 

/*
 * 170 Mhz sysclock
 * APB2 1/4
 * x2
 * Timer prescaler 1
 * => 771us interval (must be beow 1ms!)
 */
#define TICS_PER_TIMER_OVERFLOW 0xFFFF // DO NOT CHANGE. Update is only generated on overflow. Capture 1 dont seem to be usable!
#define MICROS_PER_TIMER_OVERFLOW 771

// the fractional number of milliseconds per timer overflow.
#define FRACT_INC (MICROS_PER_TIMER_OVERFLOW % 1000)
#define FRACT_MAX (1000)

 

 

Timer setup:

 

void TK_init_TimeAndDelay(){
	__HAL_RCC_TIM16_CLK_ENABLE();
	TIM16->PSC = TIM16_PRESC - 1; 				// true prescaler 85 is value (85-1)
	TIM16->CR1 |= TIM_CR1_CEN | TIM_CR1_URS;					// Enable counter
	TIM16->ARR = TICS_PER_TIMER_OVERFLOW - 1;
	TIM16->DIER |= TIM_DIER_UIE;				// Comp 1 interrupt enable
}

 

 

Interrupt handler:

 

void TK_TIM1_UP_TIM16_IRQHandler(void){
	if(TIM16->SR & TIM_SR_UIF){
		TIM16->SR &= ~TIM_SR_UIF; // reset flag

		//t_millis += MILLIS_INC; is zero anyway
		millisFract += FRACT_INC;

		if (millisFract >= FRACT_MAX) {
			millisFract -= FRACT_MAX;
			t_millis++;
		}
		timer_overflow_count++;
	}
}

 

 

micros() function:

 

uint32_t micros(){
	uint32_t tovf;
	uint32_t cnt;
	NVIC_DisableIRQ(TIM1_UP_TIM16_IRQn);
	cnt = TIM16->CNT;
	tovf = timer_overflow_count;

	// If a counter overflow has happend, we need to add that extra value!
	if((TIM16->SR & TIM_SR_UIF)){
		tovf++;
		cnt = TIM16->CNT;//0xFFFF - cnt; // Might have been 0xFFF0 and is now 0, so add value (-9 -> +9)
	}

	NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
	return tovf * MICROS_PER_TIMER_OVERFLOW + cnt/85;	// divided through 85, to get to us, since 1 tic is ~11ns
}

 

 

Here the actual point int the code where micros returned the wrong time (772us less than it should):

 

void TIM1_CC_IRQHandler(){
	__disable_irq();

	// Hall external triggered
	if(TIM1->SR & TIM_SR_CC1IF){
		TIM1->SR = ~TIM_SR_CC1IF;

		//TEST_HALL_ON;
		if(mSTATE >= MOTOR_STARTED){
			TEST_HALL_ON
			__disable_irq();
			eStructs[eventIndex].timeMicros = micros();
			....

 

 

 

 

 

 

 

 

 

This topic has been closed for replies.
Best answer by Tobe

Thanks to waclawek.jan i found the issue:

It was a priority issue, micros() was executed, when the TIM16 interrupt was beeing executed.

4 replies

waclawek.jan
Super User
October 29, 2024

> Here the actual point int the code where the error happend

What error?

JW

Tobe
TobeAuthor
Senior III
October 29, 2024

micros() returned a time, that had 772us less, than it should have returned.

Tesla DeLorean
Guru
October 29, 2024

I don't understand the point of the overflow code

The TIM keeps chugging regardless of how much time you spend in the interupt handler(s), or off on other tasks/threads

Is there some chance you could use a 32-bit TIM? Or a 16-bit TIM clocking at 1 MHz or 10 MHz, having span of say 65.536 ms or 6.5536 ms

If you have delays longer this, should we be considering different delay strategies entirely?

Is your RTOS going to wander off the plot for several milliseconds?

What delays / precision are we hoping for here?

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
October 29, 2024

Why is the function which appears to be the TIM16 ISR called  TK_TIM1_UP_TIM16_IRQHandler()?

What is the relationship between TIM1_CC and TIM16 interrupt priorities?

JW

 

PS.

> TIM16->SR &= ~TIM_SR_UIF;

Don't RMW the status register; perform a direct write. Interestingly, you do so for TIM1...

 

Tobe
TobeAuthor
Senior III
October 29, 2024

To be honest, i cant remember why i added TK_ ... i think it was because i dont use HAL too much.

TIM1 has the higher priority.

I have RMV removed.

Tobe
TobeAuthorBest answer
Senior III
October 29, 2024

Thanks to waclawek.jan i found the issue:

It was a priority issue, micros() was executed, when the TIM16 interrupt was beeing executed.

Tobe
TobeAuthor
Senior III
October 29, 2024

I made this change (is it good or ugly?):

#define CHECK_AND_DISABLE_IRQ uint32_t pMask = __get_PRIMASK(); __disable_irq();
#define ENABLE_IRQ_IF if(!pMask) __enable_irq();

void TK_TIM1_UP_TIM16_IRQHandler(void){
	TEST_TIM16_INT_ON
	if(TIM16->SR & TIM_SR_UIF){
		CHECK_AND_DISABLE_IRQ
		TIM16->SR = ~TIM_SR_UIF; // reset flag
		millisFract += FRACT_INC;

		if (millisFract >= FRACT_MAX) {
			millisFract -= FRACT_MAX;
			t_millis++;
		}
		timer_overflow_count++;
		ENABLE_IRQ_IF
	}
	TEST_TIM16_INT_OFF
}