diff --git a/hardware/arduino/sam/cores/arduino/wiring.c b/hardware/arduino/sam/cores/arduino/wiring.c index a934c50f5..02fd04aac 100644 --- a/hardware/arduino/sam/cores/arduino/wiring.c +++ b/hardware/arduino/sam/cores/arduino/wiring.c @@ -28,20 +28,50 @@ uint32_t millis( void ) return GetTickCount() ; } +// Interrupt-compatible version of micros +// Theory: repeatedly take readings of SysTick counter, millis counter and SysTick interrupt pending flag. +// When it appears that millis counter and pending is stable and SysTick hasn't rolled over, use these +// values to calculate micros. If there is a pending SysTick, add one to the millis counter in the calculation. uint32_t micros( void ) { - uint32_t ticks ; - uint32_t count ; + uint32_t ticks, ticks2; + uint32_t pend, pend2; + uint32_t count, count2; + + ticks2 = SysTick->VAL; + pend2 = !!((SCB->ICSR & SCB_ICSR_PENDSTSET_Msk)||((SCB->SHCSR & SCB_SHCSR_SYSTICKACT_Msk))) ; + count2 = GetTickCount(); - SysTick->CTRL; do { - ticks = SysTick->VAL; - count = GetTickCount(); - } while (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk); + ticks=ticks2; + pend=pend2; + count=count2; + ticks2 = SysTick->VAL; + pend2 = !!((SCB->ICSR & SCB_ICSR_PENDSTSET_Msk)||((SCB->SHCSR & SCB_SHCSR_SYSTICKACT_Msk))) ; + count2 = GetTickCount(); + } while ((pend != pend2) || (count != count2) || (ticks < ticks2)); - return count * 1000 + (SysTick->LOAD + 1 - ticks) / (SystemCoreClock/1000000) ; + return ((count+pend) * 1000) + (((SysTick->LOAD - ticks)*(1048576/(F_CPU/1000000)))>>20) ; + // this is an optimization to turn a runtime division into two compile-time divisions and + // a runtime multiplication and shift, saving a few cycles } +// original function: +// uint32_t micros( void ) +// { +// uint32_t ticks ; +// uint32_t count ; +// +// SysTick->CTRL; +// do { +// ticks = SysTick->VAL; +// count = GetTickCount(); +// } while (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk); +// +// return count * 1000 + (SysTick->LOAD + 1 - ticks) / (SystemCoreClock/1000000) ; +// } + + void delay( uint32_t ms ) { uint32_t end = GetTickCount() + ms;