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.
Этот коммит содержится в:
Ayke van Laethem 2022-04-20 15:18:09 +02:00 коммит произвёл Ron Evans
родитель 52c61de19f
коммит 9de76fb42e

Просмотреть файл

@ -77,14 +77,6 @@ func nanosecondsToTicks(ns int64) timeUnit {
// Sleep this number of ticks of nanoseconds. // Sleep this number of ticks of nanoseconds.
func sleepTicks(d timeUnit) { func sleepTicks(d timeUnit) {
waitTill := ticks() + d 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 { for {
// wait for interrupt // wait for interrupt
avr.Asm("sleep") avr.Asm("sleep")
@ -120,18 +112,17 @@ func abort() {
} }
} }
var ticksCount int64 // nanoseconds since start var ticksCount int64 // nanoseconds since start
var nanosecondsInTick int64 // nanoseconds per each tick var nanosecondsInTick int64 = 16000 // nanoseconds per each tick
func initMonotonicTimer() { func initMonotonicTimer() {
nanosecondsInTick = 0
ticksCount = 0 ticksCount = 0
interrupt.New(avr.IRQ_TIMER0_OVF, func(i interrupt.Interrupt) { interrupt.New(avr.IRQ_TIMER0_OVF, func(i interrupt.Interrupt) {
// use volatile // use volatile
increment := volatile.LoadUint64((*uint64)(unsafe.Pointer(&nanosecondsInTick)))
ticks := volatile.LoadUint64((*uint64)(unsafe.Pointer(&ticksCount))) 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 // initial initialization of the Timer0
@ -146,8 +137,6 @@ func initMonotonicTimer() {
// - Set prescaler 1 // - Set prescaler 1
avr.TCCR0B.Set(avr.TCCR0B_CS00) avr.TCCR0B.Set(avr.TCCR0B_CS00)
adjustMonotonicTimer()
// - Unmask interrupt // - Unmask interrupt
avr.TIMSK0.SetBits(avr.TIMSK0_TOIE0) avr.TIMSK0.SetBits(avr.TIMSK0_TOIE0)
} }
@ -155,7 +144,9 @@ func initMonotonicTimer() {
//go:linkname adjustMonotonicTimer machine.adjustMonotonicTimer //go:linkname adjustMonotonicTimer machine.adjustMonotonicTimer
func adjustMonotonicTimer() { func adjustMonotonicTimer() {
// adjust the nanosecondsInTick using volatile // adjust the nanosecondsInTick using volatile
mask := interrupt.Disable()
volatile.StoreUint64((*uint64)(unsafe.Pointer(&nanosecondsInTick)), uint64(currentNanosecondsInTick())) volatile.StoreUint64((*uint64)(unsafe.Pointer(&nanosecondsInTick)), uint64(currentNanosecondsInTick()))
interrupt.Restore(mask)
} }
func currentNanosecondsInTick() int64 { func currentNanosecondsInTick() int64 {