aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/machine/board_teensy36.go175
-rw-r--r--src/machine/machine_nxp.go33
-rw-r--r--src/machine/machine_nxpmk66f18.go271
-rw-r--r--src/machine/uart.go2
-rw-r--r--src/machine/uart_nxpmk66f18.go240
-rw-r--r--src/runtime/runtime_nxp.go5
-rw-r--r--src/runtime/runtime_nxpmk66f18.go214
-rw-r--r--src/runtime/time_nxpmk66f18.go163
-rw-r--r--src/runtime/volatile/bitband_nxpmk66f18.go (renamed from src/runtime/volatile/register_nxpmk66f18.go)5
-rw-r--r--targets/nxpmk66f18.ld26
-rw-r--r--targets/teensy36.s8
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