github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/runtime_nrf.go (about)

     1  //go:build nrf && !nrf52840
     2  
     3  package runtime
     4  
     5  import (
     6  	"device/arm"
     7  	"device/nrf"
     8  	"machine"
     9  	"runtime/interrupt"
    10  	"runtime/volatile"
    11  )
    12  
    13  type timeUnit int64
    14  
    15  //go:linkname systemInit SystemInit
    16  func systemInit()
    17  
    18  //export Reset_Handler
    19  func main() {
    20  	if nrf.FPUPresent {
    21  		arm.SCB.CPACR.Set(0) // disable FPU if it is enabled
    22  	}
    23  	systemInit()
    24  	preinit()
    25  	run()
    26  	exit(0)
    27  }
    28  
    29  func init() {
    30  	machine.InitSerial()
    31  	initLFCLK()
    32  	initRTC()
    33  }
    34  
    35  func initLFCLK() {
    36  	if machine.HasLowFrequencyCrystal {
    37  		nrf.CLOCK.LFCLKSRC.Set(nrf.CLOCK_LFCLKSTAT_SRC_Xtal)
    38  	}
    39  	nrf.CLOCK.TASKS_LFCLKSTART.Set(1)
    40  	for nrf.CLOCK.EVENTS_LFCLKSTARTED.Get() == 0 {
    41  	}
    42  	nrf.CLOCK.EVENTS_LFCLKSTARTED.Set(0)
    43  }
    44  
    45  func initRTC() {
    46  	nrf.RTC1.TASKS_START.Set(1)
    47  	intr := interrupt.New(nrf.IRQ_RTC1, func(intr interrupt.Interrupt) {
    48  		if nrf.RTC1.EVENTS_COMPARE[0].Get() != 0 {
    49  			nrf.RTC1.EVENTS_COMPARE[0].Set(0)
    50  			nrf.RTC1.INTENCLR.Set(nrf.RTC_INTENSET_COMPARE0)
    51  			nrf.RTC1.EVENTS_COMPARE[0].Set(0)
    52  			rtc_wakeup.Set(1)
    53  		}
    54  		if nrf.RTC1.EVENTS_OVRFLW.Get() != 0 {
    55  			nrf.RTC1.EVENTS_OVRFLW.Set(0)
    56  			rtcOverflows.Set(rtcOverflows.Get() + 1)
    57  		}
    58  	})
    59  	nrf.RTC1.INTENSET.Set(nrf.RTC_INTENSET_OVRFLW)
    60  	intr.SetPriority(0xc0) // low priority
    61  	intr.Enable()
    62  }
    63  
    64  func putchar(c byte) {
    65  	machine.Serial.WriteByte(c)
    66  }
    67  
    68  func getchar() byte {
    69  	for machine.Serial.Buffered() == 0 {
    70  		Gosched()
    71  	}
    72  	v, _ := machine.Serial.ReadByte()
    73  	return v
    74  }
    75  
    76  func buffered() int {
    77  	return machine.Serial.Buffered()
    78  }
    79  
    80  func sleepTicks(d timeUnit) {
    81  	for d != 0 {
    82  		ticks := uint32(d) & 0x7fffff // 23 bits (to be on the safe side)
    83  		rtc_sleep(ticks)
    84  		d -= timeUnit(ticks)
    85  	}
    86  }
    87  
    88  var rtcOverflows volatile.Register32 // number of times the RTC wrapped around
    89  
    90  // ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
    91  func ticksToNanoseconds(ticks timeUnit) int64 {
    92  	// The following calculation is actually the following, but with both sides
    93  	// reduced to reduce the risk of overflow:
    94  	//     ticks * 1e9 / 32768
    95  	return int64(ticks) * 1953125 / 64
    96  }
    97  
    98  // nanosecondsToTicks converts nanoseconds to RTC ticks (running at 32768Hz).
    99  func nanosecondsToTicks(ns int64) timeUnit {
   100  	// The following calculation is actually the following, but with both sides
   101  	// reduced to reduce the risk of overflow:
   102  	//     ns * 32768 / 1e9
   103  	return timeUnit(ns * 64 / 1953125)
   104  }
   105  
   106  // Monotonically increasing numer of ticks since start.
   107  func ticks() timeUnit {
   108  	// For some ways of capturing the time atomically, see this thread:
   109  	// https://www.eevblog.com/forum/microcontrollers/correct-timing-by-timer-overflow-count/msg749617/#msg749617
   110  	// Here, instead of re-reading the counter register if an overflow has been
   111  	// detected, we simply try again because that results in (slightly) smaller
   112  	// code and is perhaps easier to prove correct.
   113  	for {
   114  		mask := interrupt.Disable()
   115  		counter := uint32(nrf.RTC1.COUNTER.Get())
   116  		overflows := rtcOverflows.Get()
   117  		hasOverflow := nrf.RTC1.EVENTS_OVRFLW.Get() != 0
   118  		interrupt.Restore(mask)
   119  
   120  		if hasOverflow {
   121  			// There was an overflow. Try again.
   122  			continue
   123  		}
   124  
   125  		// The counter is 24 bits in size, so the number of overflows form the
   126  		// upper 32 bits (together 56 bits, which covers 71493 years at
   127  		// 32768kHz: I'd argue good enough for most purposes).
   128  		return timeUnit(overflows)<<24 + timeUnit(counter)
   129  	}
   130  }
   131  
   132  var rtc_wakeup volatile.Register8
   133  
   134  func rtc_sleep(ticks uint32) {
   135  	nrf.RTC1.INTENSET.Set(nrf.RTC_INTENSET_COMPARE0)
   136  	rtc_wakeup.Set(0)
   137  	if ticks == 1 {
   138  		// Race condition (even in hardware) at ticks == 1.
   139  		// TODO: fix this in a better way by detecting it, like the manual
   140  		// describes.
   141  		ticks = 2
   142  	}
   143  	nrf.RTC1.CC[0].Set((nrf.RTC1.COUNTER.Get() + ticks) & 0x00ffffff)
   144  	for rtc_wakeup.Get() == 0 {
   145  		waitForEvents()
   146  	}
   147  }