1// +build nrf 2 3package runtime 4 5import ( 6 "device/arm" 7 "device/nrf" 8 "machine" 9 "runtime/interrupt" 10 "runtime/volatile" 11) 12 13type timeUnit int64 14 15//go:linkname systemInit SystemInit 16func systemInit() 17 18func postinit() {} 19 20//export Reset_Handler 21func main() { 22 systemInit() 23 preinit() 24 run() 25 abort() 26} 27 28func init() { 29 machine.UART0.Configure(machine.UARTConfig{}) 30 initLFCLK() 31 initRTC() 32} 33 34func initLFCLK() { 35 if machine.HasLowFrequencyCrystal { 36 nrf.CLOCK.LFCLKSRC.Set(nrf.CLOCK_LFCLKSTAT_SRC_Xtal) 37 } 38 nrf.CLOCK.TASKS_LFCLKSTART.Set(1) 39 for nrf.CLOCK.EVENTS_LFCLKSTARTED.Get() == 0 { 40 } 41 nrf.CLOCK.EVENTS_LFCLKSTARTED.Set(0) 42} 43 44func initRTC() { 45 nrf.RTC1.TASKS_START.Set(1) 46 intr := interrupt.New(nrf.IRQ_RTC1, func(intr interrupt.Interrupt) { 47 nrf.RTC1.INTENCLR.Set(nrf.RTC_INTENSET_COMPARE0) 48 nrf.RTC1.EVENTS_COMPARE[0].Set(0) 49 rtc_wakeup.Set(1) 50 }) 51 intr.SetPriority(0xc0) // low priority 52 intr.Enable() 53} 54 55func putchar(c byte) { 56 machine.UART0.WriteByte(c) 57} 58 59const asyncScheduler = false 60 61func sleepTicks(d timeUnit) { 62 for d != 0 { 63 ticks() // update timestamp 64 ticks := uint32(d) & 0x7fffff // 23 bits (to be on the safe side) 65 rtc_sleep(ticks) 66 d -= timeUnit(ticks) 67 } 68} 69 70var ( 71 timestamp timeUnit // nanoseconds since boottime 72 rtcLastCounter uint32 // 24 bits ticks 73) 74 75// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds. 76func ticksToNanoseconds(ticks timeUnit) int64 { 77 // The following calculation is actually the following, but with both sides 78 // reduced to reduce the risk of overflow: 79 // ticks * 1e9 / 32768 80 return int64(ticks) * 1953125 / 64 81} 82 83// nanosecondsToTicks converts nanoseconds to RTC ticks (running at 32768Hz). 84func nanosecondsToTicks(ns int64) timeUnit { 85 // The following calculation is actually the following, but with both sides 86 // reduced to reduce the risk of overflow: 87 // ns * 32768 / 1e9 88 return timeUnit(ns * 64 / 1953125) 89} 90 91// Monotonically increasing numer of ticks since start. 92// 93// Note: very long pauses between measurements (more than 8 minutes) may 94// overflow the counter, leading to incorrect results. This might be fixed by 95// handling the overflow event. 96func ticks() timeUnit { 97 rtcCounter := uint32(nrf.RTC1.COUNTER.Get()) 98 offset := (rtcCounter - rtcLastCounter) & 0xffffff // change since last measurement 99 rtcLastCounter = rtcCounter 100 timestamp += timeUnit(offset) 101 return timestamp 102} 103 104var rtc_wakeup volatile.Register8 105 106func rtc_sleep(ticks uint32) { 107 nrf.RTC1.INTENSET.Set(nrf.RTC_INTENSET_COMPARE0) 108 rtc_wakeup.Set(0) 109 if ticks == 1 { 110 // Race condition (even in hardware) at ticks == 1. 111 // TODO: fix this in a better way by detecting it, like the manual 112 // describes. 113 ticks = 2 114 } 115 nrf.RTC1.CC[0].Set((nrf.RTC1.COUNTER.Get() + ticks) & 0x00ffffff) 116 for rtc_wakeup.Get() == 0 { 117 arm.Asm("wfi") 118 } 119} 120