From 9de76fb42e9bbb06d842e9673836f4eadf32ddae Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 20 Apr 2022 15:18:09 +0200 Subject: [PATCH] avr: simplify timer-based time Simplify the interrupt-based timer code in a few ways: - Do not recalibrate the timer every 100ms. Instead, rely on the fact that the machine package will calbrate the timer if necessary if it makes changes to Timer0. - Do not configure Timer0 and then set nanosecondsInTick based on that value. Instead, use a fixed value. These two changes together mean that in code that doesn't use PWM, nanosecondsInTick will be constant which makes the TIMER0_OVF interrupt handler a lot smaller. Together this reduces the code size of AVR binaries by about 1200 bytes, making it pretty close to the pre-timer code size (only about 250 bytes larger). It also somehow fixes a problem with tinygo.org/x/drivers/examples/ws2812 on the Arduino Uno. I'm not quite sure what was going wrong, but bisecting pointed towards the timer code (https://github.com/tinygo-org/tinygo/pull/2428) and with this simplification the bug appears to be gone. --- src/runtime/runtime_avr.go | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/runtime/runtime_avr.go b/src/runtime/runtime_avr.go index 34fd7083..10ce1dad 100644 --- a/src/runtime/runtime_avr.go +++ b/src/runtime/runtime_avr.go @@ -77,14 +77,6 @@ func nanosecondsToTicks(ns int64) timeUnit { // Sleep this number of ticks of nanoseconds. func sleepTicks(d timeUnit) { waitTill := ticks() + d - // recalibrate if we have some time (>100ms) and it was a while when we did it last time. - if d > 100000 { - now := waitTill - d - if nextTimerRecalibrate < now { - nextTimerRecalibrate = now + timerRecalibrateInterval - adjustMonotonicTimer() - } - } for { // wait for interrupt avr.Asm("sleep") @@ -120,18 +112,17 @@ func abort() { } } -var ticksCount int64 // nanoseconds since start -var nanosecondsInTick int64 // nanoseconds per each tick +var ticksCount int64 // nanoseconds since start +var nanosecondsInTick int64 = 16000 // nanoseconds per each tick func initMonotonicTimer() { - nanosecondsInTick = 0 ticksCount = 0 interrupt.New(avr.IRQ_TIMER0_OVF, func(i interrupt.Interrupt) { // use volatile - increment := volatile.LoadUint64((*uint64)(unsafe.Pointer(&nanosecondsInTick))) ticks := volatile.LoadUint64((*uint64)(unsafe.Pointer(&ticksCount))) - volatile.StoreUint64((*uint64)(unsafe.Pointer(&ticksCount)), ticks+increment) + ticks += uint64(nanosecondsInTick) + volatile.StoreUint64((*uint64)(unsafe.Pointer(&ticksCount)), ticks) }) // initial initialization of the Timer0 @@ -146,8 +137,6 @@ func initMonotonicTimer() { // - Set prescaler 1 avr.TCCR0B.Set(avr.TCCR0B_CS00) - adjustMonotonicTimer() - // - Unmask interrupt avr.TIMSK0.SetBits(avr.TIMSK0_TOIE0) } @@ -155,7 +144,9 @@ func initMonotonicTimer() { //go:linkname adjustMonotonicTimer machine.adjustMonotonicTimer func adjustMonotonicTimer() { // adjust the nanosecondsInTick using volatile + mask := interrupt.Disable() volatile.StoreUint64((*uint64)(unsafe.Pointer(&nanosecondsInTick)), uint64(currentNanosecondsInTick())) + interrupt.Restore(mask) } func currentNanosecondsInTick() int64 {