
This is one step towards removing unnecessary special casts in most cases. It is also part of removing as much magic as possible from the compiler (the pragma is explicit, the special name is not).
109 строки
2,3 КиБ
Go
109 строки
2,3 КиБ
Go
// +build nrf
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"device/arm"
|
|
"device/nrf"
|
|
)
|
|
|
|
type timeUnit int64
|
|
|
|
const tickMicros = 1024 * 32
|
|
|
|
//go:linkname systemInit SystemInit
|
|
func systemInit()
|
|
|
|
//go:export Reset_Handler
|
|
func handleReset() {
|
|
systemInit()
|
|
main()
|
|
}
|
|
|
|
func init() {
|
|
initUART()
|
|
initLFCLK()
|
|
initRTC()
|
|
}
|
|
|
|
func initUART() {
|
|
nrf.UART0.ENABLE = nrf.UART_ENABLE_ENABLE_Enabled
|
|
nrf.UART0.BAUDRATE = nrf.UART_BAUDRATE_BAUDRATE_Baud115200
|
|
nrf.UART0.TASKS_STARTTX = 1
|
|
nrf.UART0.PSELTXD = 6 // pin 6 for NRF52840-DK
|
|
}
|
|
|
|
func initLFCLK() {
|
|
nrf.CLOCK.LFCLKSRC = nrf.CLOCK_LFCLKSTAT_SRC_Xtal
|
|
nrf.CLOCK.TASKS_LFCLKSTART = 1
|
|
for nrf.CLOCK.EVENTS_LFCLKSTARTED == 0 {
|
|
}
|
|
nrf.CLOCK.EVENTS_LFCLKSTARTED = 0
|
|
}
|
|
|
|
func initRTC() {
|
|
nrf.RTC0.TASKS_START = 1
|
|
// TODO: set priority
|
|
arm.EnableIRQ(nrf.IRQ_RTC0)
|
|
}
|
|
|
|
func putchar(c byte) {
|
|
nrf.UART0.TXD = nrf.RegValue(c)
|
|
for nrf.UART0.EVENTS_TXDRDY == 0 {
|
|
}
|
|
nrf.UART0.EVENTS_TXDRDY = 0
|
|
}
|
|
|
|
func sleepTicks(d timeUnit) {
|
|
for d != 0 {
|
|
ticks() // update timestamp
|
|
ticks := uint32(d) & 0x7fffff // 23 bits (to be on the safe side)
|
|
rtc_sleep(ticks) // TODO: not accurate (must be d / 30.5175...)
|
|
d -= timeUnit(ticks)
|
|
}
|
|
}
|
|
|
|
var (
|
|
timestamp timeUnit // nanoseconds since boottime
|
|
rtcLastCounter uint32 // 24 bits ticks
|
|
)
|
|
|
|
// Monotonically increasing numer of ticks since start.
|
|
//
|
|
// Note: very long pauses between measurements (more than 8 minutes) may
|
|
// overflow the counter, leading to incorrect results. This might be fixed by
|
|
// handling the overflow event.
|
|
func ticks() timeUnit {
|
|
rtcCounter := uint32(nrf.RTC0.COUNTER)
|
|
offset := (rtcCounter - rtcLastCounter) % 0xffffff // change since last measurement
|
|
rtcLastCounter = rtcCounter
|
|
timestamp += timeUnit(offset) // TODO: not precise
|
|
return timestamp
|
|
}
|
|
|
|
//go:volatile
|
|
type isrFlag bool
|
|
|
|
var rtc_wakeup isrFlag
|
|
|
|
func rtc_sleep(ticks uint32) {
|
|
nrf.RTC0.INTENSET = nrf.RTC_INTENSET_COMPARE0
|
|
rtc_wakeup = false
|
|
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.RTC0.CC[0] = (nrf.RTC0.COUNTER + nrf.RegValue(ticks)) & 0x00ffffff
|
|
for !rtc_wakeup {
|
|
arm.Asm("wfi")
|
|
}
|
|
}
|
|
|
|
//go:export RTC0_IRQHandler
|
|
func handleRTC0() {
|
|
nrf.RTC0.INTENCLR = nrf.RTC_INTENSET_COMPARE0
|
|
nrf.RTC0.EVENTS_COMPARE[0] = 0
|
|
rtc_wakeup = true
|
|
}
|