2014-05-07 02:04 PM
I am trying to build a scheduler on top of a 1MHz tim5 32 bit timer operating in one pulse mode:
void initMicrosecondTimer(void) { RCC ->APB1ENR |= RCC_APB1ENR_TIM5EN; // Enable TIM5 clock nvicEnableVector(HW_TIMER_IRQ, CORTEX_PRIORITY_MASK(HW_TIMER_PRIORITY)); TIM->DIER |= TIM_DIER_UIE; // Enable interrupt on update event TIM->CR1 |= TIM_CR1_OPM; // one pulse mode: count down ARR and stop TIM->CR1 &= ~TIM_CR1_ARPE; /* ARR register is NOT buffered, allows to update timer's period on-fly. */ TIM->PSC = 84 - 1; // 168MHz / 2 / 84 = 1MHz, each tick is a microsecond } /** * sets the alarm to the specified number of microseconds from now. * This function should be invoked under kernel lock which would disable interrupts. */ void setHardwareUsTimer(int timeUs) { TIM->ARR = timeUs - 1; TIM->EGR |= TIM_EGR_UG; // generate an update event to reload timer's counter value TIM->CR1 |= TIM_CR1_CEN; // restart timer lastSetTimerTime = getTimeNowUs(); isTimerPending = TRUE; timerRestartCounter++; } Full file: https://sourceforge.net/p/rusefi/code/HEAD/tree/trunk/firmware/hw_layer/microsecond_timer.c Problem: while everything works as expected in case of timeUs parameter above 300, I am not getting the expected callback for smaller timeUs parameter values like 5 or 11. Just for clarity: I am not even trying to constantly invoke 5us, 5us, 5us, 5us - even a single 5us between 300us invocations fails. Currently I am trying relatively low #define HW_TIMER_PRIORITY 12 but I was still expecting the callback to happen eventually? Please advice how can I get the callback to happen, even if it would be a bit late.2014-05-07 04:03 PM
What happens in getTimeNowUs(); ? Is it causing a race condition on the isTimerPending flag?
Here's a thought, why don't you just run TIM5 in maximal mode, and let it keep clocking at 1 MHz (1us), use that as your time base TIM5->CNT, not keep resetting it, and set TIM5->CCR1 = TIM5->CNT + us, and interrupt on the CC1?2014-05-07 06:37 PM
getTimeNowUs() is just a 64-bit counter based on CYCCNT, alone the lines of
int value = DWT_CYCCNT; if (value < currentValue) currentBase += 0x100000000LL; currentValue = value; return (currentBase + currentValue) / (CORE_CLOCK / 1000000); so while yes it is not perfect because of unguarded concurrent write to curentValue I do not see how it would be affecting the timer or the flag. I think I can try to implement your suggestion with channel #1 interrupt, it would be on the edge of my low-level skills but I would try. Still, curious why the resetting implementation does not work :(2014-05-08 04:36 AM
Yeah, I don't know why.
You might want to benchmark that 64-bit division code though. I don't see it taking 100's of microseconds