
Make sure every to-be-implemented GC can use the same interface. As a result, a 1MB chunk of RAM is allocated on Unix systems on init instead of allocating on demand.
122 строки
2,4 КиБ
Go
122 строки
2,4 КиБ
Go
// +build avr
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"device/avr"
|
|
"machine"
|
|
"unsafe"
|
|
)
|
|
|
|
const BOARD = "arduino"
|
|
|
|
type timeUnit uint32
|
|
|
|
var currentTime timeUnit
|
|
|
|
const tickMicros = 1024 * 16384
|
|
|
|
// Watchdog timer periods. These can be off by a large margin (hence the jump
|
|
// between 64ms and 125ms which is not an exact double), so don't rely on this
|
|
// for accurate time keeping.
|
|
const (
|
|
WDT_PERIOD_16MS = iota
|
|
WDT_PERIOD_32MS
|
|
WDT_PERIOD_64MS
|
|
WDT_PERIOD_125MS
|
|
WDT_PERIOD_250MS
|
|
WDT_PERIOD_500MS
|
|
WDT_PERIOD_1S
|
|
WDT_PERIOD_2S
|
|
)
|
|
|
|
//go:extern _sbss
|
|
var _sbss unsafe.Pointer
|
|
|
|
//go:extern _ebss
|
|
var _ebss unsafe.Pointer
|
|
|
|
//go:export main
|
|
func main() {
|
|
preinit()
|
|
initAll()
|
|
postinit()
|
|
mainWrapper()
|
|
abort()
|
|
}
|
|
|
|
func preinit() {
|
|
// Initialize .bss: zero-initialized global variables.
|
|
ptr := uintptr(unsafe.Pointer(&_sbss))
|
|
for ptr != uintptr(unsafe.Pointer(&_ebss)) {
|
|
*(*uint8)(unsafe.Pointer(ptr)) = 0
|
|
ptr += 1
|
|
}
|
|
}
|
|
|
|
func postinit() {
|
|
// Enable interrupts after initialization.
|
|
avr.Asm("sei")
|
|
}
|
|
|
|
func init() {
|
|
initUART()
|
|
}
|
|
|
|
func initUART() {
|
|
machine.UART0.Configure(machine.UARTConfig{})
|
|
}
|
|
|
|
func putchar(c byte) {
|
|
machine.UART0.WriteByte(c)
|
|
}
|
|
|
|
// Sleep this number of ticks of 16ms.
|
|
//
|
|
// TODO: not very accurate. Improve accuracy by calibrating on startup and every
|
|
// once in a while.
|
|
func sleepTicks(d timeUnit) {
|
|
currentTime += d
|
|
for d != 0 {
|
|
sleepWDT(WDT_PERIOD_16MS)
|
|
d -= 1
|
|
}
|
|
}
|
|
|
|
// Sleep for a given period. The period is defined by the WDT peripheral, and is
|
|
// on most chips (at least) 3 bits wide, in powers of two from 16ms to 2s
|
|
// (0=16ms, 1=32ms, 2=64ms...). Note that the WDT is not very accurate: it can
|
|
// be off by a large margin depending on temperature and supply voltage.
|
|
//
|
|
// TODO: disable more peripherals etc. to reduce sleep current.
|
|
func sleepWDT(period uint8) {
|
|
// Configure WDT
|
|
avr.Asm("cli")
|
|
avr.Asm("wdr")
|
|
// Start timed sequence.
|
|
*avr.WDTCSR |= avr.WDTCSR_WDCE | avr.WDTCSR_WDE
|
|
// Enable WDT and set new timeout (0.5s)
|
|
*avr.WDTCSR = avr.WDTCSR_WDIE | avr.RegValue(period)
|
|
avr.Asm("sei")
|
|
|
|
// Set sleep mode to idle and enable sleep mode.
|
|
// Note: when using something other than idle, the UART won't work
|
|
// correctly. This needs to be fixed, though, so we can truly sleep.
|
|
*avr.SMCR = (0 << 1) | avr.SMCR_SE
|
|
|
|
// go to sleep
|
|
avr.Asm("sleep")
|
|
|
|
// disable sleep
|
|
*avr.SMCR = 0
|
|
}
|
|
|
|
func ticks() timeUnit {
|
|
return currentTime
|
|
}
|
|
|
|
func abort() {
|
|
for {
|
|
sleepWDT(WDT_PERIOD_2S)
|
|
}
|
|
}
|