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

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