2024-10-29 01:21 AM - edited 2024-10-29 12:22 PM
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();
....
Solved! Go to Solution.
2024-10-29 04:08 PM
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
}