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 }