cancel
Showing results for 
Search instead for 
Did you mean: 

My micros() function is not glitchfree?

Tobe
Senior III

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();
			....

 

 

 

 

 

 

 

 

 

10 REPLIES 10
Tobe
Senior III

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
}