diff options
-rw-r--r-- | src/machine/board_teensy36.go | 175 | ||||
-rw-r--r-- | src/machine/machine_nxp.go | 33 | ||||
-rw-r--r-- | src/machine/machine_nxpmk66f18.go | 271 | ||||
-rw-r--r-- | src/machine/uart.go | 2 | ||||
-rw-r--r-- | src/machine/uart_nxpmk66f18.go | 240 | ||||
-rw-r--r-- | src/runtime/runtime_nxp.go | 5 | ||||
-rw-r--r-- | src/runtime/runtime_nxpmk66f18.go | 214 | ||||
-rw-r--r-- | src/runtime/time_nxpmk66f18.go | 163 | ||||
-rw-r--r-- | src/runtime/volatile/bitband_nxpmk66f18.go (renamed from src/runtime/volatile/register_nxpmk66f18.go) | 5 | ||||
-rw-r--r-- | targets/nxpmk66f18.ld | 26 | ||||
-rw-r--r-- | targets/teensy36.s | 8 |
11 files changed, 707 insertions, 435 deletions
diff --git a/src/machine/board_teensy36.go b/src/machine/board_teensy36.go index f7991af7b..f0eccecd3 100644 --- a/src/machine/board_teensy36.go +++ b/src/machine/board_teensy36.go @@ -2,91 +2,100 @@ package machine -import ( - "device/nxp" -) - -// //go:keep -// //go:section .flash_config -// var FlashControl = [16]byte{ -// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -// 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xF9, 0xFF, 0xFF, -// } +// CPUFrequency returns the frequency of the ARM core clock (180MHz) +func CPUFrequency() uint32 { return 180000000 } -func CPUFrequency() uint32 { - return 180000000 -} +// ClockFrequency returns the frequency of the external oscillator (16MHz) +func ClockFrequency() uint32 { return 16000000 } // LED on the Teensy -const LED Pin = 13 +const LED = PC05 + +// digital IO +const ( + D00 = PB16 + D01 = PB17 + D02 = PD00 + D03 = PA12 + D04 = PA13 + D05 = PD07 + D06 = PD04 + D07 = PD02 + D08 = PD03 + D09 = PC03 + D10 = PC04 + D11 = PC06 + D12 = PC07 + D13 = PC05 + D14 = PD01 + D15 = PC00 + D16 = PB00 + D17 = PB01 + D18 = PB03 + D19 = PB02 + D20 = PD05 + D21 = PD06 + D22 = PC01 + D23 = PC02 + D24 = PE26 + D25 = PA05 + D26 = PA14 + D27 = PA15 + D28 = PA16 + D29 = PB18 + D30 = PB19 + D31 = PB10 + D32 = PB11 + D33 = PE24 + D34 = PE25 + D35 = PC08 + D36 = PC09 + D37 = PC10 + D38 = PC11 + D39 = PA17 + D40 = PA28 + D41 = PA29 + D42 = PA26 + D43 = PB20 + D44 = PB22 + D45 = PB23 + D46 = PB21 + D47 = PD08 + D48 = PD09 + D49 = PB04 + D50 = PB05 + D51 = PD14 + D52 = PD13 + D53 = PD12 + D54 = PD15 + D55 = PD11 + D56 = PE10 + D57 = PE11 + D58 = PE00 + D59 = PE01 + D60 = PE02 + D61 = PE03 + D62 = PE04 + D63 = PE05 +) -var pins = []pin{ - // {bit, control register, gpio register bank} - 0: {16, &nxp.PORTB.PCR16, nxp.GPIOB}, - 1: {17, &nxp.PORTB.PCR17, nxp.GPIOB}, - 2: {0, &nxp.PORTD.PCR0, nxp.GPIOD}, - 3: {12, &nxp.PORTA.PCR12, nxp.GPIOA}, - 4: {13, &nxp.PORTA.PCR13, nxp.GPIOA}, - 5: {7, &nxp.PORTD.PCR7, nxp.GPIOD}, - 6: {4, &nxp.PORTD.PCR4, nxp.GPIOD}, - 7: {2, &nxp.PORTD.PCR2, nxp.GPIOD}, - 8: {3, &nxp.PORTD.PCR3, nxp.GPIOD}, - 9: {3, &nxp.PORTC.PCR3, nxp.GPIOC}, - 10: {4, &nxp.PORTC.PCR4, nxp.GPIOC}, - 11: {6, &nxp.PORTC.PCR6, nxp.GPIOC}, - 12: {7, &nxp.PORTC.PCR7, nxp.GPIOC}, - 13: {5, &nxp.PORTC.PCR5, nxp.GPIOC}, - 14: {1, &nxp.PORTD.PCR1, nxp.GPIOD}, - 15: {0, &nxp.PORTC.PCR0, nxp.GPIOC}, - 16: {0, &nxp.PORTB.PCR0, nxp.GPIOB}, - 17: {1, &nxp.PORTB.PCR1, nxp.GPIOB}, - 18: {3, &nxp.PORTB.PCR3, nxp.GPIOB}, - 19: {2, &nxp.PORTB.PCR2, nxp.GPIOB}, - 20: {5, &nxp.PORTD.PCR5, nxp.GPIOD}, - 21: {6, &nxp.PORTD.PCR6, nxp.GPIOD}, - 22: {1, &nxp.PORTC.PCR1, nxp.GPIOC}, - 23: {2, &nxp.PORTC.PCR2, nxp.GPIOC}, - 24: {26, &nxp.PORTE.PCR26, nxp.GPIOE}, - 25: {5, &nxp.PORTA.PCR5, nxp.GPIOA}, - 26: {14, &nxp.PORTA.PCR14, nxp.GPIOA}, - 27: {15, &nxp.PORTA.PCR15, nxp.GPIOA}, - 28: {16, &nxp.PORTA.PCR16, nxp.GPIOA}, - 29: {18, &nxp.PORTB.PCR18, nxp.GPIOB}, - 30: {19, &nxp.PORTB.PCR19, nxp.GPIOB}, - 31: {10, &nxp.PORTB.PCR10, nxp.GPIOB}, - 32: {11, &nxp.PORTB.PCR11, nxp.GPIOB}, - 33: {24, &nxp.PORTE.PCR24, nxp.GPIOE}, - 34: {25, &nxp.PORTE.PCR25, nxp.GPIOE}, - 35: {8, &nxp.PORTC.PCR8, nxp.GPIOC}, - 36: {9, &nxp.PORTC.PCR9, nxp.GPIOC}, - 37: {10, &nxp.PORTC.PCR10, nxp.GPIOC}, - 38: {11, &nxp.PORTC.PCR11, nxp.GPIOC}, - 39: {17, &nxp.PORTA.PCR17, nxp.GPIOA}, - 40: {28, &nxp.PORTA.PCR28, nxp.GPIOA}, - 41: {29, &nxp.PORTA.PCR29, nxp.GPIOA}, - 42: {26, &nxp.PORTA.PCR26, nxp.GPIOA}, - 43: {20, &nxp.PORTB.PCR20, nxp.GPIOB}, - 44: {22, &nxp.PORTB.PCR22, nxp.GPIOB}, - 45: {23, &nxp.PORTB.PCR23, nxp.GPIOB}, - 46: {21, &nxp.PORTB.PCR21, nxp.GPIOB}, - 47: {8, &nxp.PORTD.PCR8, nxp.GPIOD}, - 48: {9, &nxp.PORTD.PCR9, nxp.GPIOD}, - 49: {4, &nxp.PORTB.PCR4, nxp.GPIOB}, - 50: {5, &nxp.PORTB.PCR5, nxp.GPIOB}, - 51: {14, &nxp.PORTD.PCR14, nxp.GPIOD}, - 52: {13, &nxp.PORTD.PCR13, nxp.GPIOD}, - 53: {12, &nxp.PORTD.PCR12, nxp.GPIOD}, - 54: {15, &nxp.PORTD.PCR15, nxp.GPIOD}, - 55: {11, &nxp.PORTD.PCR11, nxp.GPIOD}, - 56: {10, &nxp.PORTE.PCR10, nxp.GPIOE}, - 57: {11, &nxp.PORTE.PCR11, nxp.GPIOE}, - 58: {0, &nxp.PORTE.PCR0, nxp.GPIOE}, - 59: {1, &nxp.PORTE.PCR1, nxp.GPIOE}, - 60: {2, &nxp.PORTE.PCR2, nxp.GPIOE}, - 61: {3, &nxp.PORTE.PCR3, nxp.GPIOE}, - 62: {4, &nxp.PORTE.PCR4, nxp.GPIOE}, - 63: {5, &nxp.PORTE.PCR5, nxp.GPIOE}, -} +var ( + TeensyUART1 = &UART0 + TeensyUART2 = &UART1 + TeensyUART3 = &UART2 + TeensyUART4 = &UART3 + TeensyUART5 = &UART4 +) -//go:inline -func (p Pin) reg() pin { return pins[p] } +const ( + defaultUART0RX = D00 + defaultUART0TX = D01 + defaultUART1RX = D09 + defaultUART1TX = D10 + defaultUART2RX = D07 + defaultUART2TX = D08 + defaultUART3RX = D31 + defaultUART3TX = D32 + defaultUART4RX = D34 + defaultUART4TX = D33 +) diff --git a/src/machine/machine_nxp.go b/src/machine/machine_nxp.go deleted file mode 100644 index b29d4328c..000000000 --- a/src/machine/machine_nxp.go +++ /dev/null @@ -1,33 +0,0 @@ -// +build nxp - -package machine - -import ( - "device/arm" - "device/nxp" -) - -type PinMode uint8 - -const ( - PinInput PinMode = iota - PinOutput -) - -// Stop enters STOP (deep sleep) mode -func Stop() { - // set SLEEPDEEP to enable deep sleep - nxp.SystemControl.SCR.SetBits(nxp.SystemControl_SCR_SLEEPDEEP) - - // enter STOP mode - arm.Asm("wfi") -} - -// Wait enters WAIT (sleep) mode -func Wait() { - // clear SLEEPDEEP bit to disable deep sleep - nxp.SystemControl.SCR.ClearBits(nxp.SystemControl_SCR_SLEEPDEEP) - - // enter WAIT mode - arm.Asm("wfi") -} diff --git a/src/machine/machine_nxpmk66f18.go b/src/machine/machine_nxpmk66f18.go index 291fe1db7..3804b67b3 100644 --- a/src/machine/machine_nxpmk66f18.go +++ b/src/machine/machine_nxpmk66f18.go @@ -1,3 +1,32 @@ +// 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 machine @@ -5,69 +34,249 @@ package machine import ( "device/nxp" "runtime/volatile" + "unsafe" ) -type FastPin struct { - PDOR *volatile.BitRegister - PSOR *volatile.BitRegister - PCOR *volatile.BitRegister - PTOR *volatile.BitRegister - PDIR *volatile.BitRegister - PDDR *volatile.BitRegister -} +type PinMode uint8 + +const ( + PinInput PinMode = iota + PinInputPullUp + PinInputPullDown + PinOutput + PinOutputOpenDrain + PinDisable +) + +const ( + PA00 Pin = iota + PA01 + PA02 + PA03 + PA04 + PA05 + PA06 + PA07 + PA08 + PA09 + PA10 + PA11 + PA12 + PA13 + PA14 + PA15 + PA16 + PA17 + PA18 + PA19 + PA20 + PA21 + PA22 + PA23 + PA24 + PA25 + PA26 + PA27 + PA28 + PA29 +) + +const ( + PB00 Pin = iota + 32 + PB01 + PB02 + PB03 + PB04 + PB05 + PB06 + PB07 + PB08 + PB09 + PB10 + PB11 + _ + _ + _ + _ + PB16 + PB17 + PB18 + PB19 + PB20 + PB21 + PB22 + PB23 +) + +const ( + PC00 Pin = iota + 64 + PC01 + PC02 + PC03 + PC04 + PC05 + PC06 + PC07 + PC08 + PC09 + PC10 + PC11 + PC12 + PC13 + PC14 + PC15 + PC16 + PC17 + PC18 + PC19 +) + +const ( + PD00 Pin = iota + 96 + PD01 + PD02 + PD03 + PD04 + PD05 + PD06 + PD07 + PD08 + PD09 + PD10 + PD11 + PD12 + PD13 + PD14 + PD15 +) + +const ( + PE00 Pin = iota + 128 + PE01 + PE02 + PE03 + PE04 + PE05 + PE06 + PE07 + PE08 + PE09 + PE10 + PE11 + PE12 + PE13 + PE14 + PE15 + PE16 + PE17 + PE18 + PE19 + PE20 + PE21 + PE22 + PE23 + PE24 + PE25 + PE26 + PE27 + PE28 +) -type pin struct { - Bit uint8 - PCR *volatile.Register32 - GPIO *nxp.GPIO_Type +//go:inline +func (p Pin) reg() (*nxp.GPIO_Type, *volatile.Register32, uint8) { + var gpio *nxp.GPIO_Type + var pcr *nxp.PORT_Type + + if p < 32 { + gpio, pcr = nxp.GPIOA, nxp.PORTA + } else if p < 64 { + gpio, pcr = nxp.GPIOB, nxp.PORTB + } else if p < 96 { + gpio, pcr = nxp.GPIOC, nxp.PORTC + } else if p < 128 { + gpio, pcr = nxp.GPIOD, nxp.PORTD + } else if p < 160 { + gpio, pcr = nxp.GPIOE, nxp.PORTE + } else { + panic("invalid pin number") + } + + return gpio, &(*[32]volatile.Register32)(unsafe.Pointer(pcr))[p%32], uint8(p % 32) } // Configure this pin with the given configuration. func (p Pin) Configure(config PinConfig) { + gpio, pcr, pos := p.reg() + switch config.Mode { + case PinOutput: + gpio.PDDR.SetBits(1 << pos) + pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos) | nxp.PORT_PCR0_SRE | nxp.PORT_PCR0_DSE) + + case PinOutputOpenDrain: + gpio.PDDR.SetBits(1 << pos) + pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos) | nxp.PORT_PCR0_SRE | nxp.PORT_PCR0_DSE | nxp.PORT_PCR0_ODE) + case PinInput: - panic("todo") + gpio.PDDR.ClearBits(1 << pos) + pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos)) - case PinOutput: - r := p.reg() - r.GPIO.PDDR.SetBits(1 << r.Bit) - r.PCR.SetBits(nxp.PORT_PCR0_SRE | nxp.PORT_PCR0_DSE | nxp.PORT_PCR0_MUX(1)) - r.PCR.ClearBits(nxp.PORT_PCR0_ODE) + case PinInputPullUp: + gpio.PDDR.ClearBits(1 << pos) + pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos) | nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS) + + case PinInputPullDown: + gpio.PDDR.ClearBits(1 << pos) + pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos) | nxp.PORT_PCR0_PE) + + case PinDisable: + gpio.PDDR.ClearBits(1 << pos) + pcr.Set((0 << nxp.PORT_PCR0_MUX_Pos)) } } // Set changes the value of the GPIO pin. The pin must be configured as output. func (p Pin) Set(value bool) { - r := p.reg() + gpio, _, pos := p.reg() if value { - r.GPIO.PSOR.Set(1 << r.Bit) + gpio.PSOR.Set(1 << pos) } else { - r.GPIO.PCOR.Set(1 << r.Bit) + gpio.PCOR.Set(1 << pos) } } // Get returns the current value of a GPIO pin. func (p Pin) Get() bool { - r := p.reg() - return r.GPIO.PDIR.HasBits(1 << r.Bit) + gpio, _, pos := p.reg() + return gpio.PDIR.HasBits(1 << pos) } func (p Pin) Control() *volatile.Register32 { - return p.reg().PCR + _, pcr, _ := p.reg() + return pcr } func (p Pin) Fast() FastPin { - r := p.reg() + gpio, _, pos := p.reg() return FastPin{ - PDOR: r.GPIO.PDOR.Bit(r.Bit), - PSOR: r.GPIO.PSOR.Bit(r.Bit), - PCOR: r.GPIO.PCOR.Bit(r.Bit), - PTOR: r.GPIO.PTOR.Bit(r.Bit), - PDIR: r.GPIO.PDIR.Bit(r.Bit), - PDDR: r.GPIO.PDDR.Bit(r.Bit), + PDOR: gpio.PDOR.Bit(pos), + PSOR: gpio.PSOR.Bit(pos), + PCOR: gpio.PCOR.Bit(pos), + PTOR: gpio.PTOR.Bit(pos), + PDIR: gpio.PDIR.Bit(pos), + PDDR: gpio.PDDR.Bit(pos), } } +type FastPin struct { + PDOR *volatile.BitRegister + PSOR *volatile.BitRegister + PCOR *volatile.BitRegister + PTOR *volatile.BitRegister + PDIR *volatile.BitRegister + PDDR *volatile.BitRegister +} + func (p FastPin) Set() { p.PSOR.Set(true) } func (p FastPin) Clear() { p.PCOR.Set(true) } func (p FastPin) Toggle() { p.PTOR.Set(true) } diff --git a/src/machine/uart.go b/src/machine/uart.go index f3f46a571..c68324b61 100644 --- a/src/machine/uart.go +++ b/src/machine/uart.go @@ -1,4 +1,4 @@ -// +build avr nrf sam sifive stm32 k210 +// +build avr nrf sam sifive stm32 k210 nxp package machine diff --git a/src/machine/uart_nxpmk66f18.go b/src/machine/uart_nxpmk66f18.go index f5cc0b182..3fb4d9496 100644 --- a/src/machine/uart_nxpmk66f18.go +++ b/src/machine/uart_nxpmk66f18.go @@ -1,3 +1,32 @@ +// 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 machine @@ -6,6 +35,7 @@ import ( "device/arm" "device/nxp" "errors" + "runtime/interrupt" "runtime/volatile" _ "unsafe" // for go:linkname @@ -18,6 +48,10 @@ const ( uartC2TXInactive = uartC2Enable uartIRQPriority = 64 + + // determined from UARTx_PFIFO + uartRXFIFODepth = 8 + uartTXFIFODepth = 8 ) var ( @@ -25,61 +59,81 @@ var ( ErrNotConfigured = errors.New("device has not been configured") ) -type UARTConfig struct { - BaudRate uint32 -} +//go:linkname gosched runtime.Gosched +func gosched() -type UART struct { - *nxp.UART_Type - RXPCR *volatile.Register32 - TXPCR *volatile.Register32 - SCGC *volatile.Register32 - SCGCMask uint32 - IRQNumber uint32 +// PutcharUART writes a byte to the UART synchronously, without using interrupts +// or calling the scheduler +func PutcharUART(u UART, c byte) { + // ensure the UART has been configured + if !u.SCGC.HasBits(u.SCGCMask) { + u.configure(UARTConfig{}, false) + } - // state - RXBuffer RingBuffer - TXBuffer RingBuffer - Transmitting volatile.Register8 + for u.TCFIFO.Get() > 0 { + // busy wait + } + u.D.Set(c) + u.C2.Set(uartC2TXActive) } -// 'UART0' in the K66 manual corresponds to 'UART1' on the Teensy's pinout -var UART1 = UART{UART_Type: nxp.UART0, RXPCR: pins[0].PCR, TXPCR: pins[1].PCR, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART0, IRQNumber: nxp.IRQ_UART0_RX_TX} -var UART2 = UART{UART_Type: nxp.UART1, RXPCR: pins[9].PCR, TXPCR: pins[10].PCR, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART1, IRQNumber: nxp.IRQ_UART1_RX_TX} -var UART3 = UART{UART_Type: nxp.UART2, RXPCR: pins[7].PCR, TXPCR: pins[8].PCR, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART2, IRQNumber: nxp.IRQ_UART2_RX_TX} -var UART4 = UART{UART_Type: nxp.UART3, RXPCR: pins[31].PCR, TXPCR: pins[32].PCR, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART3, IRQNumber: nxp.IRQ_UART3_RX_TX} -var UART5 = UART{UART_Type: nxp.UART4, RXPCR: pins[34].PCR, TXPCR: pins[33].PCR, SCGC: &nxp.SIM.SCGC1, SCGCMask: nxp.SIM_SCGC1_UART4, IRQNumber: nxp.IRQ_UART4_RX_TX} +// PollUART manually checks a UART status and calls the ISR. This should only be +// called by runtime.abort. +func PollUART(u UART) { + if u.SCGC.HasBits(u.SCGCMask) { + u.handleStatusInterrupt(u.Interrupt) + } +} -//go:export UART0_RX_TX_IRQHandler -func uart0StatusISR() { UART1.handleStatusInterrupt() } +type UART = *UARTData -//go:export UART1_RX_TX_IRQHandler -func uart1StatusISR() { UART2.handleStatusInterrupt() } +type UARTData struct { + *nxp.UART_Type + SCGC *volatile.Register32 + SCGCMask uint32 -//go:export UART2_RX_TX_IRQHandler -func uart2StatusISR() { UART3.handleStatusInterrupt() } + DefaultRX Pin + DefaultTX Pin -//go:export UART3_RX_TX_IRQHandler -func uart3StatusISR() { UART4.handleStatusInterrupt() } + // state + Buffer RingBuffer // RX Buffer + TXBuffer RingBuffer + Configured bool + Transmitting volatile.Register8 + Interrupt interrupt.Interrupt +} -//go:export UART4_RX_TX_IRQHandler -func uart4StatusISR() { UART5.handleStatusInterrupt() } +var UART0 = UARTData{UART_Type: nxp.UART0, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART0, DefaultRX: defaultUART0RX, DefaultTX: defaultUART0TX} +var UART1 = UARTData{UART_Type: nxp.UART1, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART1, DefaultRX: defaultUART1RX, DefaultTX: defaultUART1TX} +var UART2 = UARTData{UART_Type: nxp.UART2, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART2, DefaultRX: defaultUART2RX, DefaultTX: defaultUART2TX} +var UART3 = UARTData{UART_Type: nxp.UART3, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART3, DefaultRX: defaultUART3RX, DefaultTX: defaultUART3TX} +var UART4 = UARTData{UART_Type: nxp.UART4, SCGC: &nxp.SIM.SCGC1, SCGCMask: nxp.SIM_SCGC1_UART4, DefaultRX: defaultUART4RX, DefaultTX: defaultUART4TX} + +func init() { + UART0.Interrupt = interrupt.New(nxp.IRQ_UART0_RX_TX, UART0.handleStatusInterrupt) + UART1.Interrupt = interrupt.New(nxp.IRQ_UART1_RX_TX, UART1.handleStatusInterrupt) + UART2.Interrupt = interrupt.New(nxp.IRQ_UART2_RX_TX, UART2.handleStatusInterrupt) + UART3.Interrupt = interrupt.New(nxp.IRQ_UART3_RX_TX, UART3.handleStatusInterrupt) + UART4.Interrupt = interrupt.New(nxp.IRQ_UART4_RX_TX, UART4.handleStatusInterrupt) +} // Configure the UART. -func (u *UART) Configure(config UARTConfig) { - en := u.SCGC.HasBits(u.SCGCMask) +func (u UART) Configure(config UARTConfig) { + u.configure(config, true) +} - // adapted from Teensy core's serial_begin +func (u UART) configure(config UARTConfig, canSched bool) { + // from: serial_begin - if !en { + if !u.Configured { u.Transmitting.Set(0) // turn on the clock u.SCGC.Set(u.SCGCMask) // configure pins - u.RXPCR.Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_PFE | nxp.PORT_PCR0_MUX(3)) - u.TXPCR.Set(nxp.PORT_PCR0_DSE | nxp.PORT_PCR0_SRE | nxp.PORT_PCR0_MUX(3)) + u.DefaultRX.Control().Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_PFE | (3 << nxp.PORT_PCR0_MUX_Pos)) + u.DefaultTX.Control().Set(nxp.PORT_PCR0_DSE | nxp.PORT_PCR0_SRE | (3 << nxp.PORT_PCR0_MUX_Pos)) u.C1.Set(nxp.UART_C1_ILT) } @@ -89,14 +143,20 @@ func (u *UART) Configure(config UARTConfig) { } // copied from teensy core's BAUD2DIV macro - divisor := ((CPUFrequency() * 2) + ((config.BaudRate) >> 1)) / config.BaudRate + divisor := ((CPUFrequency() * 2) + (config.BaudRate >> 1)) / config.BaudRate if divisor < 32 { divisor = 32 } - if en { + if u.Configured { // don't change baud rate mid transmit - u.Flush() + if canSched { + u.Flush() + } else { + for u.Transmitting.Get() != 0 { + // busy wait flush + } + } } // set the divisor @@ -104,23 +164,27 @@ func (u *UART) Configure(config UARTConfig) { u.BDL.Set(uint8((divisor >> 5) & 0xFF)) u.C4.Set(uint8(divisor & 0x1F)) - if !en { + if !u.Configured { + u.Configured = true + u.C1.Set(nxp.UART_C1_ILT) // configure TX and RX watermark u.TWFIFO.Set(2) // causes bit TDRE of S1 to set u.RWFIFO.Set(4) // causes bit RDRF of S1 to set + // enable FIFOs u.PFIFO.Set(nxp.UART_PFIFO_TXFE | nxp.UART_PFIFO_RXFE) - u.C2.Set(uartC2TXInactive) - arm.SetPriority(u.IRQNumber, uartIRQPriority) - arm.EnableIRQ(u.IRQNumber) + // setup interrupts + u.C2.Set(uartC2TXInactive) + u.Interrupt.SetPriority(uartIRQPriority) + u.Interrupt.Enable() } } -func (u *UART) Disable() { - // adapted from Teensy core's serial_end +func (u UART) Disable() { + // from: serial_end // check if the device has been enabled already if !u.SCGC.HasBits(u.SCGCMask) { @@ -129,27 +193,29 @@ func (u *UART) Disable() { u.Flush() - arm.DisableIRQ(u.IRQNumber) + u.Interrupt.Disable() u.C2.Set(0) // reconfigure pin - u.RXPCR.Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_MUX(1)) - u.TXPCR.Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_MUX(1)) + u.DefaultRX.Configure(PinConfig{Mode: PinInputPullUp}) + u.DefaultTX.Configure(PinConfig{Mode: PinInputPullUp}) // clear flags u.S1.Get() u.D.Get() - u.RXBuffer.Clear() + u.Buffer.Clear() } -func (u *UART) Flush() { +func (u UART) Flush() { for u.Transmitting.Get() != 0 { - // gosched() + gosched() } } -// adapted from Teensy core's uart0_status_isr -func (u *UART) handleStatusInterrupt() { +func (u UART) handleStatusInterrupt(interrupt.Interrupt) { + // from: uart0_status_isr + + // receive if u.S1.HasBits(nxp.UART_S1_RDRF | nxp.UART_S1_IDLE) { intrs := arm.DisableInterrupts() avail := u.RCFIFO.Get() @@ -177,7 +243,7 @@ func (u *UART) handleStatusInterrupt() { arm.EnableInterrupts(intrs) for { - u.RXBuffer.Put(u.D.Get()) + u.Buffer.Put(u.D.Get()) avail-- if avail <= 0 { break @@ -186,66 +252,54 @@ func (u *UART) handleStatusInterrupt() { } } - c := u.C2.Get() - if c&nxp.UART_C2_TIE != 0 && u.S1.HasBits(nxp.UART_S1_TDRE) { - for { - n, ok := u.TXBuffer.Get() - if !ok { + // transmit + if u.C2.HasBits(nxp.UART_C2_TIE) && u.S1.HasBits(nxp.UART_S1_TDRE) { + data := make([]byte, 0, uartTXFIFODepth) + avail := uartTXFIFODepth - u.TCFIFO.Get() + + // get avail bytes from ring buffer + for len(data) < int(avail) { + if b, ok := u.TXBuffer.Get(); ok { + data = append(data, b) + } else { break } + } - u.S1.Get() - u.D.Set(n) - - if u.TCFIFO.Get() >= 8 { - break + // write data to FIFO + l := len(data) + for i, b := range data { + if i == l-1 { + // only clear TDRE on last write, per the manual + u.S1.Get() } + u.D.Set(b) } + // if FIFO still has room, disable TIE, enable TCIE if u.S1.HasBits(nxp.UART_S1_TDRE) { - u.Transmitting.Set(0) u.C2.Set(uartC2TXCompleting) } } - if c&nxp.UART_C2_TCIE != 0 && u.S1.HasBits(nxp.UART_S1_TC) { + // transmit complete + if u.C2.HasBits(nxp.UART_C2_TCIE) && u.S1.HasBits(nxp.UART_S1_TC) { + u.Transmitting.Set(0) u.C2.Set(uartC2TXInactive) } } -//go:linkname gosched runtime.Gosched -func gosched() - // WriteByte writes a byte of data to the UART. -func (u *UART) WriteByte(c byte) error { - if !u.SCGC.HasBits(u.SCGCMask) { +func (u UART) WriteByte(c byte) error { + if !u.Configured { return ErrNotConfigured } - for !u.S1.HasBits(nxp.UART_S1_TDRE) { + for !u.TXBuffer.Put(c) { gosched() } - u.D.Set(c) - // // wait for room on the buffer - // for !u.TXBuffer.Put(c) { - // gosched() - // } - - // var wrote bool - // for u.S1.HasBits(nxp.UART_S1_TDRE) { - // n, ok := u.TXBuffer.Get() - // if ok { - // u.D.Set(n) - // wrote = true - // } else { - // break - // } - // } - - // if wrote { - // u.Transmitting.Set(1) - // u.C2.Set(uartC2TXActive) - // } + u.Transmitting.Set(1) + u.C2.Set(uartC2TXActive) return nil } diff --git a/src/runtime/runtime_nxp.go b/src/runtime/runtime_nxp.go deleted file mode 100644 index 08f6635c4..000000000 --- a/src/runtime/runtime_nxp.go +++ /dev/null @@ -1,5 +0,0 @@ -// +build nxp - -package runtime - -type timeUnit int64 diff --git a/src/runtime/runtime_nxpmk66f18.go b/src/runtime/runtime_nxpmk66f18.go index fef738f42..b03e1257c 100644 --- a/src/runtime/runtime_nxpmk66f18.go +++ b/src/runtime/runtime_nxpmk66f18.go @@ -35,53 +35,41 @@ import ( "device/arm" "device/nxp" "machine" - "runtime/volatile" ) const ( - WDOG_UNLOCK_SEQ1 = 0xC520 - WDOG_UNLOCK_SEQ2 = 0xD928 + watchdogUnlockSequence1 = 0xC520 + watchdogUnlockSequence2 = 0xD928 - DEFAULT_FTM_MOD = 61440 - 1 - DEFAULT_FTM_PRESCALE = 1 + _DEFAULT_FTM_MOD = 61440 - 1 + _DEFAULT_FTM_PRESCALE = 1 ) -var ( - SIM_SOPT2_IRC48SEL = nxp.SIM_SOPT2_PLLFLLSEL(3) - SMC_PMCTRL_HSRUN = nxp.SMC_PMCTRL_RUNM(3) - SMC_PMSTAT_HSRUN = nxp.SMC_PMSTAT_PMSTAT(0x80) +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 ) -var bootMsg = []byte("\r\n\r\nStartup complete, running main\r\n\r\n") - -//go:section .resetHandler //go:export Reset_Handler func main() { initSystem() arm.Asm("CPSIE i") initInternal() - startupLateHook() - - initAll() - machine.UART1.Configure(machine.UARTConfig{BaudRate: 115200}) - for _, c := range bootMsg { - for !machine.UART1.S1.HasBits(nxp.UART_S1_TDRE) { - } - machine.UART1.D.Set(c) - } - callMain() + run() abort() } -// ported ResetHandler from mk20dx128.c from teensy3 core libraries -//go:noinline func initSystem() { - nxp.WDOG.UNLOCK.Set(WDOG_UNLOCK_SEQ1) - nxp.WDOG.UNLOCK.Set(WDOG_UNLOCK_SEQ2) + // from: ResetHandler + + nxp.WDOG.UNLOCK.Set(watchdogUnlockSequence1) + nxp.WDOG.UNLOCK.Set(watchdogUnlockSequence2) arm.Asm("nop") arm.Asm("nop") - startupEarlyHook() + // 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) @@ -117,9 +105,9 @@ func initSystem() { // 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(nxp.MCG_C2_RANGE(2) | nxp.MCG_C2_EREFS)) + 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(nxp.MCG_C1_CLKS(2) | nxp.MCG_C1_FRDIV(4))) + 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) { } @@ -127,7 +115,7 @@ func initSystem() { 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) != nxp.MCG_S_CLKST(2) { + for (nxp.MCG.S.Get() & nxp.MCG_S_CLKST_Msk) != (2 << nxp.MCG_S_CLKST_Pos) { } // now in FBE mode @@ -137,11 +125,11 @@ func initSystem() { // 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 { + 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(nxp.MCG_C5_PRDIV(1)) - nxp.MCG.C6.Set(nxp.MCG_C6_PLLS | nxp.MCG_C6_VDIV(29)) + 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) { @@ -153,18 +141,18 @@ func initSystem() { // now program the clock dividers // config divisors: 180 MHz core, 60 MHz bus, 25.7 MHz flash, USB = IRC48M - nxp.SIM.CLKDIV1.Set(nxp.SIM_CLKDIV1_OUTDIV1(0) | nxp.SIM_CLKDIV1_OUTDIV2(2) | nxp.SIM_CLKDIV1_OUTDIV4(6)) - nxp.SIM.CLKDIV2.Set(nxp.SIM_CLKDIV2_USBDIV(0)) + 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(nxp.MCG_C1_CLKS(0) | nxp.MCG_C1_FRDIV(4)) + 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) != nxp.MCG_S_CLKST(3) { + 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 | nxp.SIM_SOPT2_CLKOUTSEL(6)) + 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. @@ -174,23 +162,19 @@ func initSystem() { } // initialize the SysTick counter - nxp.SysTick.RVR.Set((machine.CPUFrequency() / 1000) - 1) - nxp.SysTick.CVR.Set(0) - nxp.SysTick.CSR.Set(nxp.SysTick_CSR_CLKSOURCE | nxp.SysTick_CSR_TICKINT | nxp.SysTick_CSR_ENABLE) - nxp.SystemControl.SHPR3.Set(0x20200000) // Systick = priority 32 + initSysTick() } -// ported _init_Teensyduino_internal_ from pins_teensy.c from teensy3 core libraries -//go:noinline func initInternal() { - 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) + // 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.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) @@ -209,145 +193,45 @@ func initInternal() { nxp.FTM3.C6SC.Set(0x28) nxp.FTM3.C7SC.Set(0x28) - nxp.FTM0.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE)) + 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.MOD.Set(_DEFAULT_FTM_MOD) nxp.FTM1.C0SC.Set(0x28) nxp.FTM1.C1SC.Set(0x28) - nxp.FTM1.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE)) + 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.MOD.Set(_DEFAULT_FTM_MOD) // nxp.FTM2.C0SC.Set(0x28) // nxp.FTM2.C1SC.Set(0x28) - // nxp.FTM2.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE)) + // 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.MOD.Set(_DEFAULT_FTM_MOD) nxp.FTM3.C0SC.Set(0x28) nxp.FTM3.C1SC.Set(0x28) - nxp.FTM3.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE)) + 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(nxp.SIM_SOPT2_TPMSRC(2)) + 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(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(0)) + nxp.TPM1.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (0 << nxp.FTM_SC_PS_Pos)) - // configure the low-power timer - // nxp.LPTMR0.CSR.Set(nxp.LPTMR0_CSR_TIE) - // nxp.LPTMR0.PSR.Set(nxp.LPTMR0_PSR_PCS(3) | nxp.LPTMR0_PSR_PRESCALE(1)) // use main (external) clock, divided by 4 - // arm.EnableIRQ(nxp.IRQ_LPTMR0) + // configure the sleep timer + initSleepTimer() // analog_init(); - - // #if !defined(TEENSY_INIT_USB_DELAY_BEFORE) - // #if TEENSYDUINO >= 142 - // #define TEENSY_INIT_USB_DELAY_BEFORE 25 - // #else - // #define TEENSY_INIT_USB_DELAY_BEFORE 50 - // #endif - // #endif - - // #if !defined(TEENSY_INIT_USB_DELAY_AFTER) - // #if TEENSYDUINO >= 142 - // #define TEENSY_INIT_USB_DELAY_AFTER 275 - // #else - // #define TEENSY_INIT_USB_DELAY_AFTER 350 - // #endif - // #endif - - // // for background about this startup delay, please see these conversations - // // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980 - // // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273 - - // delay(TEENSY_INIT_USB_DELAY_BEFORE); - // usb_init(); - // delay(TEENSY_INIT_USB_DELAY_AFTER); } -func startupEarlyHook() { - // TODO allow override - // > programs using the watchdog timer or needing to initialize hardware as - // > early as possible can implement startup_early_hook() - - nxp.WDOG.STCTRLH.Set(nxp.WDOG_STCTRLH_ALLOWUPDATE) -} - -func startupLateHook() { - // TODO allow override -} +func postinit() {} func putchar(c byte) { - machine.UART1.WriteByte(c) + machine.PutcharUART(&machine.UART0, c) } // ??? const asyncScheduler = false - -// microseconds per tick -const tickMicros = 1000 - -// number of ticks since boot -var tickMilliCount volatile.Register32 - -//go:export SysTick_Handler -func tickHandler() { - tickMilliCount.Set(tickMilliCount.Get() + 1) -} - -// ticks are in microseconds -func ticks() timeUnit { - m := arm.DisableInterrupts() - current := nxp.SysTick.CVR.Get() - count := tickMilliCount.Get() - istatus := nxp.SystemControl.ICSR.Get() - arm.EnableInterrupts(m) - - if istatus&nxp.SystemControl_ICSR_PENDSTSET != 0 && current > 50 { - count++ - } - - current = ((machine.CPUFrequency() / tickMicros) - 1) - current - return timeUnit(count*tickMicros + current/(machine.CPUFrequency()/1000000)) -} - -// sleepTicks spins for a number of microseconds -func sleepTicks(d timeUnit) { - // TODO actually sleep - - if d <= 0 { - return - } - - start := ticks() - ms := d / 1000 - - for { - for ticks()-start >= 1000 { - ms-- - if ms <= 0 { - return - } - start += 1000 - } - arm.Asm("wfi") - } -} - -func Sleep(d int64) { - sleepTicks(timeUnit(d)) -} - -// func abort() { -// for { -// // keep polling some communication while in fault -// // mode, so we don't completely die. -// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_USBOTG) usb_isr(); -// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_UART0) uart0_status_isr(); -// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_UART1) uart1_status_isr(); -// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_UART2) uart2_status_isr(); -// } -// } diff --git a/src/runtime/time_nxpmk66f18.go b/src/runtime/time_nxpmk66f18.go new file mode 100644 index 000000000..3836fc39a --- /dev/null +++ b/src/runtime/time_nxpmk66f18.go @@ -0,0 +1,163 @@ +// 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" + "runtime/interrupt" + "runtime/volatile" +) + +type timeUnit int64 + +func ticksToNanoseconds(ticks timeUnit) int64 { + return int64(ticks) * 1000 +} + +func nanosecondsToTicks(ns int64) timeUnit { + return timeUnit(ns / 1000) +} + +// cyclesPerMilli-1 is used for the systick reset value +// the systick current value will be decremented on every clock cycle +// an interrupt is generated when the current value reaches 0 +// a value of freq/1000 generates a tick (irq) every millisecond (1/1000 s) +var cyclesPerMilli = machine.CPUFrequency() / 1000 + +// number of systick irqs (milliseconds) since boot +var systickCount volatile.Register64 + +func millisSinceBoot() uint64 { + return systickCount.Get() +} + +func initSysTick() { + nxp.SysTick.RVR.Set(cyclesPerMilli - 1) + nxp.SysTick.CVR.Set(0) + nxp.SysTick.CSR.Set(nxp.SysTick_CSR_CLKSOURCE | nxp.SysTick_CSR_TICKINT | nxp.SysTick_CSR_ENABLE) + 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 +} + +func initSleepTimer() { + nxp.SIM.SCGC5.SetBits(nxp.SIM_SCGC5_LPTMR) + nxp.LPTMR0.CSR.Set(nxp.LPTMR0_CSR_TIE) + + timerInterrupt = interrupt.New(nxp.IRQ_LPTMR0, timerWake) + timerInterrupt.Enable() +} + +//go:export SysTick_Handler +func tick() { + systickCount.Set(systickCount.Get() + 1) +} + +// ticks are in microseconds +func ticks() timeUnit { + mask := arm.DisableInterrupts() + current := nxp.SysTick.CVR.Get() // current value of the systick counter + count := millisSinceBoot() // number of milliseconds since boot + istatus := nxp.SystemControl.ICSR.Get() // interrupt status register + arm.EnableInterrupts(mask) + + micros := timeUnit(count * 1000) // a tick (1ms) = 1000 us + + // if the systick counter was about to reset and ICSR indicates a pending systick irq, increment count + if istatus&nxp.SystemControl_ICSR_PENDSTSET != 0 && current > 50 { + micros += 1000 + } else { + cycles := cyclesPerMilli - 1 - current // number of cycles since last 1ms tick + cyclesPerMicro := machine.CPUFrequency() / 1000000 + micros += timeUnit(cycles / cyclesPerMicro) + } + + return micros +} + +// sleepTicks spins for a number of microseconds +func sleepTicks(duration timeUnit) { + now := ticks() + end := duration + now + cyclesPerMicro := machine.ClockFrequency() / 1000000 + + if duration <= 0 { + return + } + + nxp.LPTMR0.PSR.Set((3 << nxp.LPTMR0_PSR_PCS_Pos) | nxp.LPTMR0_PSR_PBYP) // use 16MHz clock, undivided + + for now < end { + count := uint32(end-now) / cyclesPerMicro + if count > 65535 { + count = 65535 + } + + if !timerSleep(count) { + // return early due to interrupt + return + } + + now = ticks() + } +} + +var timerInterrupt interrupt.Interrupt +var timerActive volatile.Register32 + +func timerSleep(count uint32) bool { + timerActive.Set(1) + nxp.LPTMR0.CMR.Set(count) // set count + nxp.LPTMR0.CSR.SetBits(nxp.LPTMR0_CSR_TEN) // enable + + for { + arm.Asm("wfi") + if timerActive.Get() == 0 { + return true + } + + if hasScheduler { + // bail out, as the interrupt may have awoken a goroutine + break + } + + // if there is no scheduler, block for the entire count + } + + timerWake(timerInterrupt) + return false +} + +func timerWake(interrupt.Interrupt) { + timerActive.Set(0) + nxp.LPTMR0.CSR.Set(nxp.LPTMR0.CSR.Get()&^nxp.LPTMR0_CSR_TEN | nxp.LPTMR0_CSR_TCF) // clear flag and disable +} diff --git a/src/runtime/volatile/register_nxpmk66f18.go b/src/runtime/volatile/bitband_nxpmk66f18.go index 0f9b4cb80..0a4904db2 100644 --- a/src/runtime/volatile/register_nxpmk66f18.go +++ b/src/runtime/volatile/bitband_nxpmk66f18.go @@ -7,17 +7,16 @@ import "unsafe" const registerBase = 0x40000000 const registerEnd = 0x40100000 const bitbandBase = 0x42000000 -const ptrBytes = unsafe.Sizeof(uintptr(0)) //go:inline func bitbandAddress(reg uintptr, bit uint8) uintptr { - if uintptr(bit) > ptrBytes*8 { + if uintptr(bit) > 32 { panic("invalid bit position") } if reg < registerBase || reg >= registerEnd { panic("register is out of range") } - return (reg-registerBase)*ptrBytes*8 + uintptr(bit)*ptrBytes + bitbandBase + return (reg-registerBase)*32 + uintptr(bit)*4 + bitbandBase } // Special types that causes loads/stores to be volatile (necessary for diff --git a/targets/nxpmk66f18.ld b/targets/nxpmk66f18.ld index 3487264e6..470a5b384 100644 --- a/targets/nxpmk66f18.ld +++ b/targets/nxpmk66f18.ld @@ -5,8 +5,8 @@ ENTRY(Reset_Handler) /* define memory layout */ MEMORY { - FLASH_TEXT (rx) : ORIGIN = 0x00000000, LENGTH = 1024K - RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K + FLASH_TEXT (rx) : ORIGIN = 0x00000000, LENGTH = 1024K + RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K } _stack_size = 2K; @@ -18,21 +18,18 @@ SECTIONS .text : { /* vector table MUST start at 0x0 */ - . = 0; - _vector_table = .; + . = 0; KEEP(*(.isr_vector)) /* flash configuration MUST be at 0x400 */ . = 0x400; - _flash_config = .; - KEEP(*(.flash_config)) + KEEP(*(.flash_config)) /* everything else */ - *(.resetHandler) *(.text) - *(.text*) + *(.text.*) *(.rodata) - *(.rodata*) + *(.rodata.*) . = ALIGN(4); } >FLASH_TEXT = 0xFF @@ -50,7 +47,7 @@ SECTIONS /* Start address (in flash) of .data, used by startup code. */ _sidata = LOADADDR(.data); - /* todo add .usbdescriptortable .dmabuffers .usbbuffers */ + /* this is where Teensy's LD script places .usbdescriptortable .dmabuffers .usbbuffers */ /* Globals with initial value */ .data : @@ -58,7 +55,7 @@ SECTIONS . = ALIGN(4); _sdata = .; /* used by startup code */ *(.data) - *(.data*) + *(.data.*) . = ALIGN(4); _edata = .; /* used by startup code */ } >RAM AT>FLASH_TEXT @@ -69,7 +66,7 @@ SECTIONS . = ALIGN(4); _sbss = .; /* used by startup code */ *(.bss) - *(.bss*) + *(.bss.*) *(COMMON) . = ALIGN(4); _ebss = .; /* used by startup code */ @@ -79,11 +76,6 @@ SECTIONS { *(.ARM.exidx) /* causes 'no memory region specified' error in lld */ *(.ARM.exidx.*) /* causes spurious 'undefined reference' errors */ - - /* all this makes it much harder to debug via disassembly */ - *(.debug*) - *(.ARM.*) - *(.comment*) } } diff --git a/targets/teensy36.s b/targets/teensy36.s index 4e17e7c9d..ebfaac387 100644 --- a/targets/teensy36.s +++ b/targets/teensy36.s @@ -1,7 +1,8 @@ - .section .flash_config .global __flash_config - .byte 0xFF +__flash_config: + .byte 0xFF + .byte 0xFF .byte 0xFF .byte 0xFF .byte 0xFF @@ -9,11 +10,10 @@ .byte 0xFF .byte 0xFF .byte 0xFF - .byte 0xFF .byte 0xFF .byte 0xFF .byte 0xFF .byte 0xDE .byte 0xF9 .byte 0xFF - .byte 0xFF
\ No newline at end of file + .byte 0xFF |