mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-05 03:27:48 +00:00
Add AVR support
This requires support in LLVM, as AVR support is still experimental. For example, in bindings/go/build.sh, add -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=AVR to cmake_flags.
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
|
||||
// +build avr
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"device/avr"
|
||||
)
|
||||
|
||||
const BOARD = "arduino"
|
||||
|
||||
const Microsecond = 1
|
||||
|
||||
var currentTime uint64
|
||||
|
||||
func init() {
|
||||
currentTime = 0
|
||||
}
|
||||
|
||||
// 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
|
||||
)
|
||||
|
||||
func init() {
|
||||
initUART()
|
||||
}
|
||||
|
||||
func initUART() {
|
||||
// Initialize UART at 115200 baud when running at 16MHz.
|
||||
avr.USART.UBRR0H = 0
|
||||
avr.USART.UBRR0L = 8
|
||||
avr.USART.UCSR0B = avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 // enable RX and TX
|
||||
avr.USART.UCSR0C = avr.UCSR0C_UCSZ0 // 8-bits data
|
||||
}
|
||||
|
||||
func putchar(c byte) {
|
||||
for (avr.USART.UCSR0A & avr.UCSR0A_UDRE0) == 0 {
|
||||
// Wait until previous char has been sent.
|
||||
}
|
||||
avr.USART.UDR0 = avr.RegValue(c) // send char
|
||||
}
|
||||
|
||||
// Sleep by the given amount.
|
||||
//
|
||||
// TODO: not very accurate. Improve accuracy by calibrating on startup and every
|
||||
// once in a while.
|
||||
func sleep(d Duration) {
|
||||
currentTime += uint64(d)
|
||||
d /= 16384 // about 16ms
|
||||
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.WDT.WDTCSR |= avr.WDTCSR_WDCE | avr.WDTCSR_WDE
|
||||
// Enable WDT and set new timeout (0.5s)
|
||||
avr.WDT.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.CPU.SMCR = (0 << 1) | avr.SMCR_SE
|
||||
|
||||
// go to sleep
|
||||
avr.Asm("sleep")
|
||||
|
||||
// disable sleep
|
||||
avr.CPU.SMCR = 0
|
||||
}
|
||||
|
||||
func monotime() uint64 {
|
||||
return currentTime
|
||||
}
|
||||
|
||||
func abort() {
|
||||
avr.Asm("cli")
|
||||
for {
|
||||
sleepWDT(WDT_PERIOD_2S)
|
||||
}
|
||||
}
|
||||
|
||||
// Align on a word boundary.
|
||||
func align(ptr uintptr) uintptr {
|
||||
// No alignment necessary on the AVR.
|
||||
return ptr
|
||||
}
|
||||
Reference in New Issue
Block a user