github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/time_nxpmk66f18.go (about) 1 // Derivative work of Teensyduino Core Library 2 // http://www.pjrc.com/teensy/ 3 // Copyright (c) 2017 PJRC.COM, LLC. 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining 6 // a copy of this software and associated documentation files (the 7 // "Software"), to deal in the Software without restriction, including 8 // without limitation the rights to use, copy, modify, merge, publish, 9 // distribute, sublicense, and/or sell copies of the Software, and to 10 // permit persons to whom the Software is furnished to do so, subject to 11 // the following conditions: 12 // 13 // 1. The above copyright notice and this permission notice shall be 14 // included in all copies or substantial portions of the Software. 15 // 16 // 2. If the Software is incorporated into a build system that allows 17 // selection among a list of target devices, then similar target 18 // devices manufactured by PJRC.COM must be included in the list of 19 // target devices and selectable in the same manner. 20 // 21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 // SOFTWARE. 29 30 //go:build nxp && mk66f18 31 32 package runtime 33 34 import ( 35 "device/arm" 36 "device/nxp" 37 "machine" 38 "runtime/interrupt" 39 "runtime/volatile" 40 ) 41 42 type timeUnit int64 43 44 func ticksToNanoseconds(ticks timeUnit) int64 { 45 return int64(ticks) * 1000 46 } 47 48 func nanosecondsToTicks(ns int64) timeUnit { 49 return timeUnit(ns / 1000) 50 } 51 52 // cyclesPerMilli-1 is used for the systick reset value. 53 // The systick current value will be decremented on every clock cycle. 54 // An interrupt is generated when the current value reaches 0. 55 // A value of freq/1000 generates a tick (irq) every millisecond (1/1000 s). 56 var cyclesPerMilli = machine.CPUFrequency() / 1000 57 58 // number of systick irqs (milliseconds) since boot 59 var systickCount volatile.Register64 60 61 func millisSinceBoot() uint64 { 62 return systickCount.Get() 63 } 64 65 func initSysTick() { 66 nxp.SysTick.RVR.Set(cyclesPerMilli - 1) 67 nxp.SysTick.CVR.Set(0) 68 nxp.SysTick.CSR.Set(nxp.SysTick_CSR_CLKSOURCE | nxp.SysTick_CSR_TICKINT | nxp.SysTick_CSR_ENABLE) 69 nxp.SystemControl.SHPR3.Set((32 << nxp.SystemControl_SHPR3_PRI_15_Pos) | (32 << nxp.SystemControl_SHPR3_PRI_14_Pos)) // set systick and pendsv priority to 32 70 } 71 72 func initSleepTimer() { 73 nxp.SIM.SCGC5.SetBits(nxp.SIM_SCGC5_LPTMR) 74 nxp.LPTMR0.CSR.Set(nxp.LPTMR0_CSR_TIE) 75 76 timerInterrupt = interrupt.New(nxp.IRQ_LPTMR0, timerWake) 77 timerInterrupt.Enable() 78 } 79 80 //go:export SysTick_Handler 81 func tick() { 82 systickCount.Set(systickCount.Get() + 1) 83 } 84 85 // ticks are in microseconds 86 func ticks() timeUnit { 87 mask := arm.DisableInterrupts() 88 current := nxp.SysTick.CVR.Get() // current value of the systick counter 89 count := millisSinceBoot() // number of milliseconds since boot 90 istatus := nxp.SystemControl.ICSR.Get() // interrupt status register 91 arm.EnableInterrupts(mask) 92 93 micros := timeUnit(count * 1000) // a tick (1ms) = 1000 us 94 95 // if the systick counter was about to reset and ICSR indicates a pending systick irq, increment count 96 if istatus&nxp.SystemControl_ICSR_PENDSTSET != 0 && current > 50 { 97 micros += 1000 98 } else { 99 cycles := cyclesPerMilli - 1 - current // number of cycles since last 1ms tick 100 cyclesPerMicro := machine.CPUFrequency() / 1000000 101 micros += timeUnit(cycles / cyclesPerMicro) 102 } 103 104 return micros 105 } 106 107 // sleepTicks spins for a number of microseconds 108 func sleepTicks(duration timeUnit) { 109 now := ticks() 110 end := duration + now 111 cyclesPerMicro := machine.ClockFrequency() / 1000000 112 113 if duration <= 0 { 114 return 115 } 116 117 nxp.LPTMR0.PSR.Set((3 << nxp.LPTMR0_PSR_PCS_Pos) | nxp.LPTMR0_PSR_PBYP) // use 16MHz clock, undivided 118 119 for now < end { 120 count := uint32(end-now) / cyclesPerMicro 121 if count > 65535 { 122 count = 65535 123 } 124 125 if !timerSleep(count) { 126 // return early due to interrupt 127 return 128 } 129 130 now = ticks() 131 } 132 } 133 134 var timerInterrupt interrupt.Interrupt 135 var timerActive volatile.Register32 136 137 func timerSleep(count uint32) bool { 138 timerActive.Set(1) 139 nxp.LPTMR0.CMR.Set(count) // set count 140 nxp.LPTMR0.CSR.SetBits(nxp.LPTMR0_CSR_TEN) // enable 141 142 for { 143 arm.Asm("wfi") 144 if timerActive.Get() == 0 { 145 return true 146 } 147 148 if hasScheduler { 149 // bail out, as the interrupt may have awoken a goroutine 150 break 151 } 152 153 // if there is no scheduler, block for the entire count 154 } 155 156 timerWake(timerInterrupt) 157 return false 158 } 159 160 func timerWake(interrupt.Interrupt) { 161 timerActive.Set(0) 162 nxp.LPTMR0.CSR.Set(nxp.LPTMR0.CSR.Get()&^nxp.LPTMR0_CSR_TEN | nxp.LPTMR0_CSR_TCF) // clear flag and disable 163 }