mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-05 03:27:48 +00:00
b67351babe
Previously, the machine.UART0 object had two meanings:
- it was the first UART on the chip
- it was the default output for println
These two meanings conflict, and resulted in workarounds like:
- Defining UART0 to refer to the USB-CDC interface (atsamd21,
atsamd51, nrf52840), even though that clearly isn't an UART.
- Defining NRF_UART0 to avoid a conflict with UART0 (which was
redefined as a USB-CDC interface).
- Defining aliases like UART0 = UART1, which refer to the same
hardware peripheral (stm32).
This commit changes this to use a new machine.Serial object for the
default serial port. It might refer to the first or second UART
depending on the board, or even to the USB-CDC interface. Also, UART0
now really refers to the first UART on the chip, no longer to a USB-CDC
interface.
The changes in the runtime package are all just search+replace. The
changes in the machine package are a mixture of search+replace and
manual modifications.
This commit does not affect binary size, in fact it doesn't affect the
resulting binary at all.
138 lines
3.5 KiB
Go
138 lines
3.5 KiB
Go
// +build nrf
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"device/arm"
|
|
"device/nrf"
|
|
"machine"
|
|
"runtime/interrupt"
|
|
"runtime/volatile"
|
|
)
|
|
|
|
type timeUnit int64
|
|
|
|
//go:linkname systemInit SystemInit
|
|
func systemInit()
|
|
|
|
func postinit() {}
|
|
|
|
//export Reset_Handler
|
|
func main() {
|
|
if nrf.FPUPresent {
|
|
arm.SCB.CPACR.Set(0) // disable FPU if it is enabled
|
|
}
|
|
systemInit()
|
|
preinit()
|
|
run()
|
|
abort()
|
|
}
|
|
|
|
func init() {
|
|
machine.Serial.Configure(machine.UARTConfig{})
|
|
initLFCLK()
|
|
initRTC()
|
|
}
|
|
|
|
func initLFCLK() {
|
|
if machine.HasLowFrequencyCrystal {
|
|
nrf.CLOCK.LFCLKSRC.Set(nrf.CLOCK_LFCLKSTAT_SRC_Xtal)
|
|
}
|
|
nrf.CLOCK.TASKS_LFCLKSTART.Set(1)
|
|
for nrf.CLOCK.EVENTS_LFCLKSTARTED.Get() == 0 {
|
|
}
|
|
nrf.CLOCK.EVENTS_LFCLKSTARTED.Set(0)
|
|
}
|
|
|
|
func initRTC() {
|
|
nrf.RTC1.TASKS_START.Set(1)
|
|
intr := interrupt.New(nrf.IRQ_RTC1, func(intr interrupt.Interrupt) {
|
|
if nrf.RTC1.EVENTS_COMPARE[0].Get() != 0 {
|
|
nrf.RTC1.EVENTS_COMPARE[0].Set(0)
|
|
nrf.RTC1.INTENCLR.Set(nrf.RTC_INTENSET_COMPARE0)
|
|
nrf.RTC1.EVENTS_COMPARE[0].Set(0)
|
|
rtc_wakeup.Set(1)
|
|
}
|
|
if nrf.RTC1.EVENTS_OVRFLW.Get() != 0 {
|
|
nrf.RTC1.EVENTS_OVRFLW.Set(0)
|
|
rtcOverflows.Set(rtcOverflows.Get() + 1)
|
|
}
|
|
})
|
|
nrf.RTC1.INTENSET.Set(nrf.RTC_INTENSET_OVRFLW)
|
|
intr.SetPriority(0xc0) // low priority
|
|
intr.Enable()
|
|
}
|
|
|
|
func putchar(c byte) {
|
|
machine.Serial.WriteByte(c)
|
|
}
|
|
|
|
func sleepTicks(d timeUnit) {
|
|
for d != 0 {
|
|
ticks := uint32(d) & 0x7fffff // 23 bits (to be on the safe side)
|
|
rtc_sleep(ticks)
|
|
d -= timeUnit(ticks)
|
|
}
|
|
}
|
|
|
|
var rtcOverflows volatile.Register32 // number of times the RTC wrapped around
|
|
|
|
// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
|
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
|
// The following calculation is actually the following, but with both sides
|
|
// reduced to reduce the risk of overflow:
|
|
// ticks * 1e9 / 32768
|
|
return int64(ticks) * 1953125 / 64
|
|
}
|
|
|
|
// nanosecondsToTicks converts nanoseconds to RTC ticks (running at 32768Hz).
|
|
func nanosecondsToTicks(ns int64) timeUnit {
|
|
// The following calculation is actually the following, but with both sides
|
|
// reduced to reduce the risk of overflow:
|
|
// ns * 32768 / 1e9
|
|
return timeUnit(ns * 64 / 1953125)
|
|
}
|
|
|
|
// Monotonically increasing numer of ticks since start.
|
|
func ticks() timeUnit {
|
|
// For some ways of capturing the time atomically, see this thread:
|
|
// https://www.eevblog.com/forum/microcontrollers/correct-timing-by-timer-overflow-count/msg749617/#msg749617
|
|
// Here, instead of re-reading the counter register if an overflow has been
|
|
// detected, we simply try again because that results in (slightly) smaller
|
|
// code and is perhaps easier to prove correct.
|
|
for {
|
|
mask := interrupt.Disable()
|
|
counter := uint32(nrf.RTC1.COUNTER.Get())
|
|
overflows := rtcOverflows.Get()
|
|
hasOverflow := nrf.RTC1.EVENTS_OVRFLW.Get() != 0
|
|
interrupt.Restore(mask)
|
|
|
|
if hasOverflow {
|
|
// There was an overflow. Try again.
|
|
continue
|
|
}
|
|
|
|
// The counter is 24 bits in size, so the number of overflows form the
|
|
// upper 32 bits (together 56 bits, which covers 71493 years at
|
|
// 32768kHz: I'd argue good enough for most purposes).
|
|
return timeUnit(overflows)<<24 + timeUnit(counter)
|
|
}
|
|
}
|
|
|
|
var rtc_wakeup volatile.Register8
|
|
|
|
func rtc_sleep(ticks uint32) {
|
|
nrf.RTC1.INTENSET.Set(nrf.RTC_INTENSET_COMPARE0)
|
|
rtc_wakeup.Set(0)
|
|
if ticks == 1 {
|
|
// Race condition (even in hardware) at ticks == 1.
|
|
// TODO: fix this in a better way by detecting it, like the manual
|
|
// describes.
|
|
ticks = 2
|
|
}
|
|
nrf.RTC1.CC[0].Set((nrf.RTC1.COUNTER.Get() + ticks) & 0x00ffffff)
|
|
for rtc_wakeup.Get() == 0 {
|
|
waitForEvents()
|
|
}
|
|
}
|