github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/runtime_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 ) 39 40 const ( 41 watchdogUnlockSequence1 = 0xC520 42 watchdogUnlockSequence2 = 0xD928 43 44 _DEFAULT_FTM_MOD = 61440 - 1 45 _DEFAULT_FTM_PRESCALE = 1 46 ) 47 48 const ( 49 _SIM_SOPT2_IRC48SEL = 3 << nxp.SIM_SOPT2_PLLFLLSEL_Pos 50 _SMC_PMCTRL_HSRUN = 3 << nxp.SMC_PMCTRL_RUNM_Pos 51 _SMC_PMSTAT_HSRUN = 0x80 << nxp.SMC_PMSTAT_PMSTAT_Pos 52 ) 53 54 //go:export Reset_Handler 55 func main() { 56 initSystem() 57 arm.Asm("CPSIE i") 58 initInternal() 59 60 run() 61 exit(0) 62 } 63 64 func initSystem() { 65 // from: ResetHandler 66 67 nxp.WDOG.UNLOCK.Set(watchdogUnlockSequence1) 68 nxp.WDOG.UNLOCK.Set(watchdogUnlockSequence2) 69 arm.Asm("nop") 70 arm.Asm("nop") 71 // TODO: hook for overriding? 'startupEarlyHook' 72 nxp.WDOG.STCTRLH.Set(nxp.WDOG_STCTRLH_ALLOWUPDATE) 73 74 // enable clocks to always-used peripherals 75 nxp.SIM.SCGC3.Set(nxp.SIM_SCGC3_ADC1 | nxp.SIM_SCGC3_FTM2 | nxp.SIM_SCGC3_FTM3) 76 nxp.SIM.SCGC5.Set(0x00043F82) // clocks active to all GPIO 77 nxp.SIM.SCGC6.Set(nxp.SIM_SCGC6_RTC | nxp.SIM_SCGC6_FTM0 | nxp.SIM_SCGC6_FTM1 | nxp.SIM_SCGC6_ADC0 | nxp.SIM_SCGC6_FTF) 78 nxp.LMEM.PCCCR.Set(0x85000003) 79 80 // release I/O pins hold, if we woke up from VLLS mode 81 if nxp.PMC.REGSC.HasBits(nxp.PMC_REGSC_ACKISO) { 82 nxp.PMC.REGSC.SetBits(nxp.PMC_REGSC_ACKISO) 83 } 84 85 // since this is a write once register, make it visible to all F_CPU's 86 // so we can into other sleep modes in the future at any speed 87 nxp.SMC.PMPROT.Set(nxp.SMC_PMPROT_AHSRUN | nxp.SMC_PMPROT_AVLP | nxp.SMC_PMPROT_ALLS | nxp.SMC_PMPROT_AVLLS) 88 89 preinit() 90 91 // copy the vector table to RAM default all interrupts to medium priority level 92 // for (i=0; i < NVIC_NUM_INTERRUPTS + 16; i++) _VectorsRam[i] = _VectorsFlash[i]; 93 for i := uint32(0); i <= nxp.IRQ_max; i++ { 94 arm.SetPriority(i, 128) 95 } 96 // SCB_VTOR = (uint32_t)_VectorsRam; // use vector table in RAM 97 98 // hardware always starts in FEI mode 99 // C1[CLKS] bits are written to 00 100 // C1[IREFS] bit is written to 1 101 // C6[PLLS] bit is written to 0 102 // MCG_SC[FCDIV] defaults to divide by two for internal ref clock 103 // I tried changing MSG_SC to divide by 1, it didn't work for me 104 // enable capacitors for crystal 105 nxp.OSC.CR.Set(nxp.OSC_CR_SC8P | nxp.OSC_CR_SC2P | nxp.OSC_CR_ERCLKEN) 106 // enable osc, 8-32 MHz range, low power mode 107 nxp.MCG.C2.Set(uint8((2 << nxp.MCG_C2_RANGE_Pos) | nxp.MCG_C2_EREFS)) 108 // switch to crystal as clock source, FLL input = 16 MHz / 512 109 nxp.MCG.C1.Set(uint8((2 << nxp.MCG_C1_CLKS_Pos) | (4 << nxp.MCG_C1_FRDIV_Pos))) 110 // wait for crystal oscillator to begin 111 for !nxp.MCG.S.HasBits(nxp.MCG_S_OSCINIT0) { 112 } 113 // wait for FLL to use oscillator 114 for nxp.MCG.S.HasBits(nxp.MCG_S_IREFST) { 115 } 116 // wait for MCGOUT to use oscillator 117 for (nxp.MCG.S.Get() & nxp.MCG_S_CLKST_Msk) != (2 << nxp.MCG_S_CLKST_Pos) { 118 } 119 120 // now in FBE mode 121 // C1[CLKS] bits are written to 10 122 // C1[IREFS] bit is written to 0 123 // C1[FRDIV] must be written to divide xtal to 31.25-39 kHz 124 // C6[PLLS] bit is written to 0 125 // C2[LP] is written to 0 126 // we need faster than the crystal, turn on the PLL (F_CPU > 120000000) 127 nxp.SMC.PMCTRL.Set(_SMC_PMCTRL_HSRUN) // enter HSRUN mode 128 for nxp.SMC.PMSTAT.Get() != _SMC_PMSTAT_HSRUN { 129 } // wait for HSRUN 130 nxp.MCG.C5.Set((1 << nxp.MCG_C5_PRDIV_Pos)) 131 nxp.MCG.C6.Set(nxp.MCG_C6_PLLS | (29 << nxp.MCG_C6_VDIV_Pos)) 132 133 // wait for PLL to start using xtal as its input 134 for !nxp.MCG.S.HasBits(nxp.MCG_S_PLLST) { 135 } 136 // wait for PLL to lock 137 for !nxp.MCG.S.HasBits(nxp.MCG_S_LOCK0) { 138 } 139 // now we're in PBE mode 140 141 // now program the clock dividers 142 // config divisors: 180 MHz core, 60 MHz bus, 25.7 MHz flash, USB = IRC48M 143 nxp.SIM.CLKDIV1.Set((0 << nxp.SIM_CLKDIV1_OUTDIV1_Pos) | (2 << nxp.SIM_CLKDIV1_OUTDIV2_Pos) | (0 << nxp.SIM_CLKDIV1_OUTDIV3_Pos) | (6 << nxp.SIM_CLKDIV1_OUTDIV4_Pos)) 144 nxp.SIM.CLKDIV2.Set((0 << nxp.SIM_CLKDIV2_USBDIV_Pos)) 145 146 // switch to PLL as clock source, FLL input = 16 MHz / 512 147 nxp.MCG.C1.Set((0 << nxp.MCG_C1_CLKS_Pos) | (4 << nxp.MCG_C1_FRDIV_Pos)) 148 // wait for PLL clock to be used 149 for (nxp.MCG.S.Get() & nxp.MCG_S_CLKST_Msk) != (3 << nxp.MCG_S_CLKST_Pos) { 150 } 151 // now we're in PEE mode 152 // trace is CPU clock, CLKOUT=OSCERCLK0 153 // USB uses IRC48 154 nxp.SIM.SOPT2.Set(nxp.SIM_SOPT2_USBSRC | _SIM_SOPT2_IRC48SEL | nxp.SIM_SOPT2_TRACECLKSEL | (6 << nxp.SIM_SOPT2_CLKOUTSEL_Pos)) 155 156 // If the RTC oscillator isn't enabled, get it started. For Teensy 3.6 157 // we don't do this early. See comment above about slow rising power. 158 if !nxp.RTC.CR.HasBits(nxp.RTC_CR_OSCE) { 159 nxp.RTC.SR.Set(0) 160 nxp.RTC.CR.Set(nxp.RTC_CR_SC16P | nxp.RTC_CR_SC4P | nxp.RTC_CR_OSCE) 161 } 162 163 // initialize the SysTick counter 164 initSysTick() 165 } 166 167 func initInternal() { 168 // from: _init_Teensyduino_internal_ 169 // arm.EnableIRQ(nxp.IRQ_PORTA) 170 // arm.EnableIRQ(nxp.IRQ_PORTB) 171 // arm.EnableIRQ(nxp.IRQ_PORTC) 172 // arm.EnableIRQ(nxp.IRQ_PORTD) 173 // arm.EnableIRQ(nxp.IRQ_PORTE) 174 175 nxp.FTM0.CNT.Set(0) 176 nxp.FTM0.MOD.Set(_DEFAULT_FTM_MOD) 177 nxp.FTM0.C0SC.Set(0x28) // MSnB:MSnA = 10, ELSnB:ELSnA = 10 178 nxp.FTM0.C1SC.Set(0x28) 179 nxp.FTM0.C2SC.Set(0x28) 180 nxp.FTM0.C3SC.Set(0x28) 181 nxp.FTM0.C4SC.Set(0x28) 182 nxp.FTM0.C5SC.Set(0x28) 183 nxp.FTM0.C6SC.Set(0x28) 184 nxp.FTM0.C7SC.Set(0x28) 185 186 nxp.FTM3.C0SC.Set(0x28) 187 nxp.FTM3.C1SC.Set(0x28) 188 nxp.FTM3.C2SC.Set(0x28) 189 nxp.FTM3.C3SC.Set(0x28) 190 nxp.FTM3.C4SC.Set(0x28) 191 nxp.FTM3.C5SC.Set(0x28) 192 nxp.FTM3.C6SC.Set(0x28) 193 nxp.FTM3.C7SC.Set(0x28) 194 195 nxp.FTM0.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos)) 196 nxp.FTM1.CNT.Set(0) 197 nxp.FTM1.MOD.Set(_DEFAULT_FTM_MOD) 198 nxp.FTM1.C0SC.Set(0x28) 199 nxp.FTM1.C1SC.Set(0x28) 200 nxp.FTM1.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos)) 201 202 // causes a data bus error for unknown reasons 203 // nxp.FTM2.CNT.Set(0) 204 // nxp.FTM2.MOD.Set(_DEFAULT_FTM_MOD) 205 // nxp.FTM2.C0SC.Set(0x28) 206 // nxp.FTM2.C1SC.Set(0x28) 207 // nxp.FTM2.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos)) 208 209 nxp.FTM3.CNT.Set(0) 210 nxp.FTM3.MOD.Set(_DEFAULT_FTM_MOD) 211 nxp.FTM3.C0SC.Set(0x28) 212 nxp.FTM3.C1SC.Set(0x28) 213 nxp.FTM3.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos)) 214 215 nxp.SIM.SCGC2.SetBits(nxp.SIM_SCGC2_TPM1) 216 nxp.SIM.SOPT2.SetBits((2 << nxp.SIM_SOPT2_TPMSRC_Pos)) 217 nxp.TPM1.CNT.Set(0) 218 nxp.TPM1.MOD.Set(32767) 219 nxp.TPM1.C0SC.Set(0x28) 220 nxp.TPM1.C1SC.Set(0x28) 221 nxp.TPM1.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (0 << nxp.FTM_SC_PS_Pos)) 222 223 // configure the sleep timer 224 initSleepTimer() 225 226 // analog_init(); 227 } 228 229 func putchar(c byte) { 230 machine.PutcharUART(machine.UART0, c) 231 } 232 233 func getchar() byte { 234 // dummy, TODO 235 return 0 236 } 237 238 func buffered() int { 239 // dummy, TODO 240 return 0 241 } 242 243 func exit(code int) { 244 abort() 245 } 246 247 func abort() { 248 println("!!! ABORT !!!") 249 250 m := arm.DisableInterrupts() 251 arm.Asm("mov r12, #1") 252 arm.Asm("msr basepri, r12") // only execute interrupts of priority 0 253 nxp.SystemControl.SHPR3.ClearBits(nxp.SystemControl_SHPR3_PRI_15_Msk) // set systick to priority 0 254 arm.EnableInterrupts(m) 255 256 machine.LED.Configure(machine.PinConfig{Mode: machine.PinOutput}) 257 258 var v bool 259 for { 260 machine.LED.Set(v) 261 v = !v 262 263 t := millisSinceBoot() 264 for millisSinceBoot()-t < 60 { 265 arm.Asm("wfi") 266 } 267 268 // keep polling some communication while in fault 269 // mode, so we don't completely die. 270 // machine.PollUSB(&machine.USB0) 271 machine.PollUART(machine.UART0) 272 machine.PollUART(machine.UART1) 273 machine.PollUART(machine.UART2) 274 } 275 } 276 277 func waitForEvents() { 278 arm.Asm("wfe") 279 }