Browse Source

move AVR interrupt related code to runtime

move AVR interrupt related code to runtime
address formatting
add volatile to access counters
pull/2564/head
Dmitriy Zakharkin 3 years ago
committed by Ron Evans
parent
commit
50401c05e8
  1. 4
      src/machine/machine_atmega1280.go
  2. 4
      src/machine/machine_atmega328p.go
  3. 77
      src/machine/machine_avr.go
  4. 88
      src/runtime/runtime_avr.go

4
src/machine/machine_atmega1280.go

@ -181,7 +181,7 @@ func (pwm PWM) Configure(config PWMConfig) error {
avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01) avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01)
// monotonic timer is using the same time as PWM:0 // monotonic timer is using the same time as PWM:0
// we must adust internal settings of monotonic timer when PWM:0 settings changed // we must adust internal settings of monotonic timer when PWM:0 settings changed
AdjustMonotonicTimer() adjustMonotonicTimer()
} else { } else {
avr.TCCR2B.Set(prescaler) avr.TCCR2B.Set(prescaler)
// Set the PWM mode to fast PWM (mode = 3). // Set the PWM mode to fast PWM (mode = 3).
@ -719,7 +719,7 @@ func (pwm PWM) Set(channel uint8, value uint32) {
} }
// monotonic timer is using the same time as PWM:0 // monotonic timer is using the same time as PWM:0
// we must adust internal settings of monotonic timer when PWM:0 settings changed // we must adust internal settings of monotonic timer when PWM:0 settings changed
AdjustMonotonicTimer() adjustMonotonicTimer()
case 1: case 1:
mask := interrupt.Disable() mask := interrupt.Disable()
switch channel { switch channel {

4
src/machine/machine_atmega328p.go

@ -71,7 +71,7 @@ func (pwm PWM) Configure(config PWMConfig) error {
avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01) avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01)
// monotonic timer is using the same time as PWM:0 // monotonic timer is using the same time as PWM:0
// we must adust internal settings of monotonic timer when PWM:0 settings changed // we must adust internal settings of monotonic timer when PWM:0 settings changed
AdjustMonotonicTimer() adjustMonotonicTimer()
} else { } else {
avr.TCCR2B.Set(prescaler) avr.TCCR2B.Set(prescaler)
// Set the PWM mode to fast PWM (mode = 3). // Set the PWM mode to fast PWM (mode = 3).
@ -400,7 +400,7 @@ func (pwm PWM) Set(channel uint8, value uint32) {
} }
// monotonic timer is using the same time as PWM:0 // monotonic timer is using the same time as PWM:0
// we must adust internal settings of monotonic timer when PWM:0 settings changed // we must adust internal settings of monotonic timer when PWM:0 settings changed
AdjustMonotonicTimer() adjustMonotonicTimer()
case 1: case 1:
mask := interrupt.Disable() mask := interrupt.Disable()
switch channel { switch channel {

77
src/machine/machine_avr.go

@ -1,10 +1,10 @@
//go:build avr
// +build avr // +build avr
package machine package machine
import ( import (
"device/avr" "device/avr"
"runtime/interrupt"
"runtime/volatile" "runtime/volatile"
"unsafe" "unsafe"
) )
@ -144,75 +144,8 @@ func (a ADC) Get() uint16 {
return uint16(avr.ADCL.Get()) | uint16(avr.ADCH.Get())<<8 return uint16(avr.ADCL.Get()) | uint16(avr.ADCH.Get())<<8
} }
var Ticks int64 // nanoseconds since start // linked from runtime.adjustMonotonicTimer
var tickNanos int64 // nanoseconds per each tick func adjustMonotonicTimer()
func InitMonotonicTimer() { // linked from runtime.initMonotonicTimer
tickNanos = 0 func initMonotonicTimer()
Ticks = 0
interrupt.New(avr.IRQ_TIMER0_OVF, func(i interrupt.Interrupt) {
Ticks += tickNanos
})
// initial initialization of the Timer0
// - Mask interrupt
avr.TIMSK0.ClearBits(avr.TIMSK0_TOIE0 | avr.TIMSK0_OCIE0A | avr.TIMSK0_OCIE0B)
// - Write new values to TCNT2, OCR2x, and TCCR2x.
avr.TCNT0.Set(0)
avr.OCR0A.Set(0xff)
// - Set mode 3
avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01)
// - Set prescaler 1
avr.TCCR0B.Set(avr.TCCR0B_CS00)
AdjustMonotonicTimer()
// - Unmask interrupt
avr.TIMSK0.SetBits(avr.TIMSK0_TOIE0)
}
func AdjustMonotonicTimer() {
// adjust the tickNanos
tickNanos = currentTickNanos()
}
func currentTickNanos() int64 {
// this time depends on clk_IO, prescale, mode and OCR0A
// assuming the clock source is CPU clock
prescaler := int64(avr.TCCR0B.Get() & 0x7)
clock := (int64(1e12) / prescaler) / int64(CPUFrequency())
mode := avr.TCCR0A.Get() & 0x7
/*
Mode WGM02 WGM01 WGM00 Timer/Counter TOP Update of TOV Flag
Mode of Operation OCRx at Set on
0 0 0 0 Normal 0xFF Immediate MAX
1 0 0 1 PWM, Phase Correct 0xFF TOP BOTTOM
2 0 1 0 CTC OCRA Immediate MAX
3 0 1 1 Fast PWM 0xFF BOTTOM MAX
5 1 0 1 PWM, Phase Correct OCRA TOP BOTTOM
7 1 1 1 Fast PWM OCRA BOTTOM TOP
*/
switch mode {
case 0, 3:
// normal & fast PWM
// TOV0 Interrupt when moving from MAX (0xff) to 0x00
return clock * 256 / 1000
case 1:
// Phase Correct PWM
// TOV0 Interrupt when moving from MAX (0xff) to 0x00
return clock * 256 * 2 / 1000
case 2, 7:
// CTC & fast PWM
// TOV0 Interrupt when moving from MAX (OCRA) to 0x00
return clock * int64(avr.OCR0A.Get()) / 1000
case 5:
// Phase Correct PWM
// TOV0 Interrupt when moving from MAX (OCRA) to 0x00
return clock * int64(avr.OCR0A.Get()) * 2 / 1000
}
return clock / 1000 // for unknown
}

88
src/runtime/runtime_avr.go

@ -7,6 +7,7 @@ import (
"device/avr" "device/avr"
"machine" "machine"
"runtime/interrupt" "runtime/interrupt"
"runtime/volatile"
"unsafe" "unsafe"
) )
@ -58,7 +59,7 @@ func preinit() {
func initHardware() { func initHardware() {
initUART() initUART()
machine.InitMonotonicTimer() initMonotonicTimer()
nextTimerRecalibrate = ticks() + timerRecalibrateInterval nextTimerRecalibrate = ticks() + timerRecalibrateInterval
// Enable interrupts after initialization. // Enable interrupts after initialization.
@ -81,7 +82,7 @@ func sleepTicks(d timeUnit) {
now := waitTill - d now := waitTill - d
if nextTimerRecalibrate < now { if nextTimerRecalibrate < now {
nextTimerRecalibrate = now + timerRecalibrateInterval nextTimerRecalibrate = now + timerRecalibrateInterval
machine.AdjustMonotonicTimer() adjustMonotonicTimer()
} }
} }
for { for {
@ -98,10 +99,10 @@ func sleepTicks(d timeUnit) {
} }
} }
// ticks return time since start in nanoseconds func ticks() (ticksReturn timeUnit) {
func ticks() (ticks timeUnit) {
state := interrupt.Disable() state := interrupt.Disable()
ticks = timeUnit(machine.Ticks) // use volatile since ticksCount can be changed when running on multi-core boards.
ticksReturn = timeUnit(volatile.LoadUint64((*uint64)(unsafe.Pointer(&ticksCount))))
interrupt.Restore(state) interrupt.Restore(state)
return return
} }
@ -118,3 +119,80 @@ func abort() {
avr.Asm("sleep") avr.Asm("sleep")
} }
} }
var ticksCount int64 // nanoseconds since start
var nanosecondsInTick int64 // 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)
})
// initial initialization of the Timer0
// - Mask interrupt
avr.TIMSK0.ClearBits(avr.TIMSK0_TOIE0 | avr.TIMSK0_OCIE0A | avr.TIMSK0_OCIE0B)
// - Write new values to TCNT2, OCR2x, and TCCR2x.
avr.TCNT0.Set(0)
avr.OCR0A.Set(0xff)
// - Set mode 3
avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01)
// - Set prescaler 1
avr.TCCR0B.Set(avr.TCCR0B_CS00)
adjustMonotonicTimer()
// - Unmask interrupt
avr.TIMSK0.SetBits(avr.TIMSK0_TOIE0)
}
//go:linkname adjustMonotonicTimer machine.adjustMonotonicTimer
func adjustMonotonicTimer() {
// adjust the nanosecondsInTick using volatile
volatile.StoreUint64((*uint64)(unsafe.Pointer(&nanosecondsInTick)), uint64(currentNanosecondsInTick()))
}
func currentNanosecondsInTick() int64 {
// this time depends on clk_IO, prescale, mode and OCR0A
// assuming the clock source is CPU clock
prescaler := int64(avr.TCCR0B.Get() & 0x7)
clock := (int64(1e12) / prescaler) / int64(machine.CPUFrequency())
mode := avr.TCCR0A.Get() & 0x7
/*
Mode WGM02 WGM01 WGM00 Timer/Counter TOP Update of TOV Flag
Mode of Operation OCRx at Set on
0 0 0 0 Normal 0xFF Immediate MAX
1 0 0 1 PWM, Phase Correct 0xFF TOP BOTTOM
2 0 1 0 CTC OCRA Immediate MAX
3 0 1 1 Fast PWM 0xFF BOTTOM MAX
5 1 0 1 PWM, Phase Correct OCRA TOP BOTTOM
7 1 1 1 Fast PWM OCRA BOTTOM TOP
*/
switch mode {
case 0, 3:
// normal & fast PWM
// TOV0 Interrupt when moving from MAX (0xff) to 0x00
return clock * 256 / 1000
case 1:
// Phase Correct PWM
// TOV0 Interrupt when moving from MAX (0xff) to 0x00
return clock * 256 * 2 / 1000
case 2, 7:
// CTC & fast PWM
// TOV0 Interrupt when moving from MAX (OCRA) to 0x00
return clock * int64(avr.OCR0A.Get()) / 1000
case 5:
// Phase Correct PWM
// TOV0 Interrupt when moving from MAX (OCRA) to 0x00
return clock * int64(avr.OCR0A.Get()) * 2 / 1000
}
return clock / 1000 // for unknown
}

Loading…
Cancel
Save