Files
tinygo/src/runtime/runtime_nxpmk66f18.go
T
Ayke van Laethem 8cd2a462b9 runtime: remove the asyncScheduler constant
There is no reason to specialize this per chip as it is only ever used
for JavaScript. Not only that, it is causing confusion and is yet
another quirk to learn when porting the runtime to a new
microcontroller.
2021-05-08 23:08:12 +02:00

268 lines
8.6 KiB
Go

// Derivative work of Teensyduino Core Library
// http://www.pjrc.com/teensy/
// Copyright (c) 2017 PJRC.COM, LLC.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// 1. The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// 2. If the Software is incorporated into a build system that allows
// selection among a list of target devices, then similar target
// devices manufactured by PJRC.COM must be included in the list of
// target devices and selectable in the same manner.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// +build nxp,mk66f18
package runtime
import (
"device/arm"
"device/nxp"
"machine"
)
const (
watchdogUnlockSequence1 = 0xC520
watchdogUnlockSequence2 = 0xD928
_DEFAULT_FTM_MOD = 61440 - 1
_DEFAULT_FTM_PRESCALE = 1
)
const (
_SIM_SOPT2_IRC48SEL = 3 << nxp.SIM_SOPT2_PLLFLLSEL_Pos
_SMC_PMCTRL_HSRUN = 3 << nxp.SMC_PMCTRL_RUNM_Pos
_SMC_PMSTAT_HSRUN = 0x80 << nxp.SMC_PMSTAT_PMSTAT_Pos
)
//go:export Reset_Handler
func main() {
initSystem()
arm.Asm("CPSIE i")
initInternal()
run()
abort()
}
func initSystem() {
// from: ResetHandler
nxp.WDOG.UNLOCK.Set(watchdogUnlockSequence1)
nxp.WDOG.UNLOCK.Set(watchdogUnlockSequence2)
arm.Asm("nop")
arm.Asm("nop")
// TODO: hook for overriding? 'startupEarlyHook'
nxp.WDOG.STCTRLH.Set(nxp.WDOG_STCTRLH_ALLOWUPDATE)
// enable clocks to always-used peripherals
nxp.SIM.SCGC3.Set(nxp.SIM_SCGC3_ADC1 | nxp.SIM_SCGC3_FTM2 | nxp.SIM_SCGC3_FTM3)
nxp.SIM.SCGC5.Set(0x00043F82) // clocks active to all GPIO
nxp.SIM.SCGC6.Set(nxp.SIM_SCGC6_RTC | nxp.SIM_SCGC6_FTM0 | nxp.SIM_SCGC6_FTM1 | nxp.SIM_SCGC6_ADC0 | nxp.SIM_SCGC6_FTF)
nxp.LMEM.PCCCR.Set(0x85000003)
// release I/O pins hold, if we woke up from VLLS mode
if nxp.PMC.REGSC.HasBits(nxp.PMC_REGSC_ACKISO) {
nxp.PMC.REGSC.SetBits(nxp.PMC_REGSC_ACKISO)
}
// since this is a write once register, make it visible to all F_CPU's
// so we can into other sleep modes in the future at any speed
nxp.SMC.PMPROT.Set(nxp.SMC_PMPROT_AHSRUN | nxp.SMC_PMPROT_AVLP | nxp.SMC_PMPROT_ALLS | nxp.SMC_PMPROT_AVLLS)
preinit()
// copy the vector table to RAM default all interrupts to medium priority level
// for (i=0; i < NVIC_NUM_INTERRUPTS + 16; i++) _VectorsRam[i] = _VectorsFlash[i];
for i := uint32(0); i <= nxp.IRQ_max; i++ {
arm.SetPriority(i, 128)
}
// SCB_VTOR = (uint32_t)_VectorsRam; // use vector table in RAM
// hardware always starts in FEI mode
// C1[CLKS] bits are written to 00
// C1[IREFS] bit is written to 1
// C6[PLLS] bit is written to 0
// MCG_SC[FCDIV] defaults to divide by two for internal ref clock
// I tried changing MSG_SC to divide by 1, it didn't work for me
// enable capacitors for crystal
nxp.OSC.CR.Set(nxp.OSC_CR_SC8P | nxp.OSC_CR_SC2P | nxp.OSC_CR_ERCLKEN)
// enable osc, 8-32 MHz range, low power mode
nxp.MCG.C2.Set(uint8((2 << nxp.MCG_C2_RANGE_Pos) | nxp.MCG_C2_EREFS))
// switch to crystal as clock source, FLL input = 16 MHz / 512
nxp.MCG.C1.Set(uint8((2 << nxp.MCG_C1_CLKS_Pos) | (4 << nxp.MCG_C1_FRDIV_Pos)))
// wait for crystal oscillator to begin
for !nxp.MCG.S.HasBits(nxp.MCG_S_OSCINIT0) {
}
// wait for FLL to use oscillator
for nxp.MCG.S.HasBits(nxp.MCG_S_IREFST) {
}
// wait for MCGOUT to use oscillator
for (nxp.MCG.S.Get() & nxp.MCG_S_CLKST_Msk) != (2 << nxp.MCG_S_CLKST_Pos) {
}
// now in FBE mode
// C1[CLKS] bits are written to 10
// C1[IREFS] bit is written to 0
// C1[FRDIV] must be written to divide xtal to 31.25-39 kHz
// C6[PLLS] bit is written to 0
// C2[LP] is written to 0
// we need faster than the crystal, turn on the PLL (F_CPU > 120000000)
nxp.SMC.PMCTRL.Set(_SMC_PMCTRL_HSRUN) // enter HSRUN mode
for nxp.SMC.PMSTAT.Get() != _SMC_PMSTAT_HSRUN {
} // wait for HSRUN
nxp.MCG.C5.Set((1 << nxp.MCG_C5_PRDIV_Pos))
nxp.MCG.C6.Set(nxp.MCG_C6_PLLS | (29 << nxp.MCG_C6_VDIV_Pos))
// wait for PLL to start using xtal as its input
for !nxp.MCG.S.HasBits(nxp.MCG_S_PLLST) {
}
// wait for PLL to lock
for !nxp.MCG.S.HasBits(nxp.MCG_S_LOCK0) {
}
// now we're in PBE mode
// now program the clock dividers
// config divisors: 180 MHz core, 60 MHz bus, 25.7 MHz flash, USB = IRC48M
nxp.SIM.CLKDIV1.Set((0 << nxp.SIM_CLKDIV1_OUTDIV1_Pos) | (2 << nxp.SIM_CLKDIV1_OUTDIV2_Pos) | (0 << nxp.SIM_CLKDIV1_OUTDIV1_Pos) | (6 << nxp.SIM_CLKDIV1_OUTDIV4_Pos))
nxp.SIM.CLKDIV2.Set((0 << nxp.SIM_CLKDIV2_USBDIV_Pos))
// switch to PLL as clock source, FLL input = 16 MHz / 512
nxp.MCG.C1.Set((0 << nxp.MCG_C1_CLKS_Pos) | (4 << nxp.MCG_C1_FRDIV_Pos))
// wait for PLL clock to be used
for (nxp.MCG.S.Get() & nxp.MCG_S_CLKST_Msk) != (3 << nxp.MCG_S_CLKST_Pos) {
}
// now we're in PEE mode
// trace is CPU clock, CLKOUT=OSCERCLK0
// USB uses IRC48
nxp.SIM.SOPT2.Set(nxp.SIM_SOPT2_USBSRC | _SIM_SOPT2_IRC48SEL | nxp.SIM_SOPT2_TRACECLKSEL | (6 << nxp.SIM_SOPT2_CLKOUTSEL_Pos))
// If the RTC oscillator isn't enabled, get it started. For Teensy 3.6
// we don't do this early. See comment above about slow rising power.
if !nxp.RTC.CR.HasBits(nxp.RTC_CR_OSCE) {
nxp.RTC.SR.Set(0)
nxp.RTC.CR.Set(nxp.RTC_CR_SC16P | nxp.RTC_CR_SC4P | nxp.RTC_CR_OSCE)
}
// initialize the SysTick counter
initSysTick()
}
func initInternal() {
// from: _init_Teensyduino_internal_
// arm.EnableIRQ(nxp.IRQ_PORTA)
// arm.EnableIRQ(nxp.IRQ_PORTB)
// arm.EnableIRQ(nxp.IRQ_PORTC)
// arm.EnableIRQ(nxp.IRQ_PORTD)
// arm.EnableIRQ(nxp.IRQ_PORTE)
nxp.FTM0.CNT.Set(0)
nxp.FTM0.MOD.Set(_DEFAULT_FTM_MOD)
nxp.FTM0.C0SC.Set(0x28) // MSnB:MSnA = 10, ELSnB:ELSnA = 10
nxp.FTM0.C1SC.Set(0x28)
nxp.FTM0.C2SC.Set(0x28)
nxp.FTM0.C3SC.Set(0x28)
nxp.FTM0.C4SC.Set(0x28)
nxp.FTM0.C5SC.Set(0x28)
nxp.FTM0.C6SC.Set(0x28)
nxp.FTM0.C7SC.Set(0x28)
nxp.FTM3.C0SC.Set(0x28)
nxp.FTM3.C1SC.Set(0x28)
nxp.FTM3.C2SC.Set(0x28)
nxp.FTM3.C3SC.Set(0x28)
nxp.FTM3.C4SC.Set(0x28)
nxp.FTM3.C5SC.Set(0x28)
nxp.FTM3.C6SC.Set(0x28)
nxp.FTM3.C7SC.Set(0x28)
nxp.FTM0.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos))
nxp.FTM1.CNT.Set(0)
nxp.FTM1.MOD.Set(_DEFAULT_FTM_MOD)
nxp.FTM1.C0SC.Set(0x28)
nxp.FTM1.C1SC.Set(0x28)
nxp.FTM1.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos))
// causes a data bus error for unknown reasons
// nxp.FTM2.CNT.Set(0)
// nxp.FTM2.MOD.Set(_DEFAULT_FTM_MOD)
// nxp.FTM2.C0SC.Set(0x28)
// nxp.FTM2.C1SC.Set(0x28)
// nxp.FTM2.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos))
nxp.FTM3.CNT.Set(0)
nxp.FTM3.MOD.Set(_DEFAULT_FTM_MOD)
nxp.FTM3.C0SC.Set(0x28)
nxp.FTM3.C1SC.Set(0x28)
nxp.FTM3.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos))
nxp.SIM.SCGC2.SetBits(nxp.SIM_SCGC2_TPM1)
nxp.SIM.SOPT2.SetBits((2 << nxp.SIM_SOPT2_TPMSRC_Pos))
nxp.TPM1.CNT.Set(0)
nxp.TPM1.MOD.Set(32767)
nxp.TPM1.C0SC.Set(0x28)
nxp.TPM1.C1SC.Set(0x28)
nxp.TPM1.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (0 << nxp.FTM_SC_PS_Pos))
// configure the sleep timer
initSleepTimer()
// analog_init();
}
func postinit() {}
func putchar(c byte) {
machine.PutcharUART(&machine.UART0, c)
}
func abort() {
println("!!! ABORT !!!")
m := arm.DisableInterrupts()
arm.Asm("mov r12, #1")
arm.Asm("msr basepri, r12") // only execute interrupts of priority 0
nxp.SystemControl.SHPR3.ClearBits(nxp.SystemControl_SHPR3_PRI_15_Msk) // set systick to priority 0
arm.EnableInterrupts(m)
machine.LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
var v bool
for {
machine.LED.Set(v)
v = !v
t := millisSinceBoot()
for millisSinceBoot()-t < 60 {
arm.Asm("wfi")
}
// keep polling some communication while in fault
// mode, so we don't completely die.
// machine.PollUSB(&machine.USB0)
machine.PollUART(&machine.UART0)
machine.PollUART(&machine.UART1)
machine.PollUART(&machine.UART2)
}
}
func waitForEvents() {
arm.Asm("wfe")
}