Skip to content

Commit 9de76fb

Browse files
aykevldeadprogram
authored andcommitted
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 (#2428) and with this simplification the bug appears to be gone.
1 parent 52c61de commit 9de76fb

File tree

1 file changed

+6
-15
lines changed

1 file changed

+6
-15
lines changed

src/runtime/runtime_avr.go

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,6 @@ func nanosecondsToTicks(ns int64) timeUnit {
7777
// Sleep this number of ticks of nanoseconds.
7878
func sleepTicks(d timeUnit) {
7979
waitTill := ticks() + d
80-
// recalibrate if we have some time (>100ms) and it was a while when we did it last time.
81-
if d > 100000 {
82-
now := waitTill - d
83-
if nextTimerRecalibrate < now {
84-
nextTimerRecalibrate = now + timerRecalibrateInterval
85-
adjustMonotonicTimer()
86-
}
87-
}
8880
for {
8981
// wait for interrupt
9082
avr.Asm("sleep")
@@ -120,18 +112,17 @@ func abort() {
120112
}
121113
}
122114

123-
var ticksCount int64 // nanoseconds since start
124-
var nanosecondsInTick int64 // nanoseconds per each tick
115+
var ticksCount int64 // nanoseconds since start
116+
var nanosecondsInTick int64 = 16000 // nanoseconds per each tick
125117

126118
func initMonotonicTimer() {
127-
nanosecondsInTick = 0
128119
ticksCount = 0
129120

130121
interrupt.New(avr.IRQ_TIMER0_OVF, func(i interrupt.Interrupt) {
131122
// use volatile
132-
increment := volatile.LoadUint64((*uint64)(unsafe.Pointer(&nanosecondsInTick)))
133123
ticks := volatile.LoadUint64((*uint64)(unsafe.Pointer(&ticksCount)))
134-
volatile.StoreUint64((*uint64)(unsafe.Pointer(&ticksCount)), ticks+increment)
124+
ticks += uint64(nanosecondsInTick)
125+
volatile.StoreUint64((*uint64)(unsafe.Pointer(&ticksCount)), ticks)
135126
})
136127

137128
// initial initialization of the Timer0
@@ -146,16 +137,16 @@ func initMonotonicTimer() {
146137
// - Set prescaler 1
147138
avr.TCCR0B.Set(avr.TCCR0B_CS00)
148139

149-
adjustMonotonicTimer()
150-
151140
// - Unmask interrupt
152141
avr.TIMSK0.SetBits(avr.TIMSK0_TOIE0)
153142
}
154143

155144
//go:linkname adjustMonotonicTimer machine.adjustMonotonicTimer
156145
func adjustMonotonicTimer() {
157146
// adjust the nanosecondsInTick using volatile
147+
mask := interrupt.Disable()
158148
volatile.StoreUint64((*uint64)(unsafe.Pointer(&nanosecondsInTick)), uint64(currentNanosecondsInTick()))
149+
interrupt.Restore(mask)
159150
}
160151

161152
func currentNanosecondsInTick() int64 {

0 commit comments

Comments
 (0)