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  }