Viable NXP/Teensy support
- Fix UART & putChar - Timer-based sleep - Enable systick in abort - Buffered, interrupt-based UART TX - Use the new interrupt API and fix sleepTicks - Make pins behave more like other boards - Use the MCU's UART numbering - Allow interrupts to wake the scheduler (#1214)
Этот коммит содержится в:
родитель
59218cd784
коммит
4750635a20
11 изменённых файлов: 728 добавлений и 456 удалений
|
@ -2,91 +2,100 @@
|
||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
// CPUFrequency returns the frequency of the ARM core clock (180MHz)
|
||||||
"device/nxp"
|
func CPUFrequency() uint32 { return 180000000 }
|
||||||
)
|
|
||||||
|
|
||||||
// //go:keep
|
// ClockFrequency returns the frequency of the external oscillator (16MHz)
|
||||||
// //go:section .flash_config
|
func ClockFrequency() uint32 { return 16000000 }
|
||||||
// var FlashControl = [16]byte{
|
|
||||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xF9, 0xFF, 0xFF,
|
|
||||||
// }
|
|
||||||
|
|
||||||
func CPUFrequency() uint32 {
|
|
||||||
return 180000000
|
|
||||||
}
|
|
||||||
|
|
||||||
// LED on the Teensy
|
// LED on the Teensy
|
||||||
const LED Pin = 13
|
const LED = PC05
|
||||||
|
|
||||||
var pins = []pin{
|
// digital IO
|
||||||
// {bit, control register, gpio register bank}
|
const (
|
||||||
0: {16, &nxp.PORTB.PCR16, nxp.GPIOB},
|
D00 = PB16
|
||||||
1: {17, &nxp.PORTB.PCR17, nxp.GPIOB},
|
D01 = PB17
|
||||||
2: {0, &nxp.PORTD.PCR0, nxp.GPIOD},
|
D02 = PD00
|
||||||
3: {12, &nxp.PORTA.PCR12, nxp.GPIOA},
|
D03 = PA12
|
||||||
4: {13, &nxp.PORTA.PCR13, nxp.GPIOA},
|
D04 = PA13
|
||||||
5: {7, &nxp.PORTD.PCR7, nxp.GPIOD},
|
D05 = PD07
|
||||||
6: {4, &nxp.PORTD.PCR4, nxp.GPIOD},
|
D06 = PD04
|
||||||
7: {2, &nxp.PORTD.PCR2, nxp.GPIOD},
|
D07 = PD02
|
||||||
8: {3, &nxp.PORTD.PCR3, nxp.GPIOD},
|
D08 = PD03
|
||||||
9: {3, &nxp.PORTC.PCR3, nxp.GPIOC},
|
D09 = PC03
|
||||||
10: {4, &nxp.PORTC.PCR4, nxp.GPIOC},
|
D10 = PC04
|
||||||
11: {6, &nxp.PORTC.PCR6, nxp.GPIOC},
|
D11 = PC06
|
||||||
12: {7, &nxp.PORTC.PCR7, nxp.GPIOC},
|
D12 = PC07
|
||||||
13: {5, &nxp.PORTC.PCR5, nxp.GPIOC},
|
D13 = PC05
|
||||||
14: {1, &nxp.PORTD.PCR1, nxp.GPIOD},
|
D14 = PD01
|
||||||
15: {0, &nxp.PORTC.PCR0, nxp.GPIOC},
|
D15 = PC00
|
||||||
16: {0, &nxp.PORTB.PCR0, nxp.GPIOB},
|
D16 = PB00
|
||||||
17: {1, &nxp.PORTB.PCR1, nxp.GPIOB},
|
D17 = PB01
|
||||||
18: {3, &nxp.PORTB.PCR3, nxp.GPIOB},
|
D18 = PB03
|
||||||
19: {2, &nxp.PORTB.PCR2, nxp.GPIOB},
|
D19 = PB02
|
||||||
20: {5, &nxp.PORTD.PCR5, nxp.GPIOD},
|
D20 = PD05
|
||||||
21: {6, &nxp.PORTD.PCR6, nxp.GPIOD},
|
D21 = PD06
|
||||||
22: {1, &nxp.PORTC.PCR1, nxp.GPIOC},
|
D22 = PC01
|
||||||
23: {2, &nxp.PORTC.PCR2, nxp.GPIOC},
|
D23 = PC02
|
||||||
24: {26, &nxp.PORTE.PCR26, nxp.GPIOE},
|
D24 = PE26
|
||||||
25: {5, &nxp.PORTA.PCR5, nxp.GPIOA},
|
D25 = PA05
|
||||||
26: {14, &nxp.PORTA.PCR14, nxp.GPIOA},
|
D26 = PA14
|
||||||
27: {15, &nxp.PORTA.PCR15, nxp.GPIOA},
|
D27 = PA15
|
||||||
28: {16, &nxp.PORTA.PCR16, nxp.GPIOA},
|
D28 = PA16
|
||||||
29: {18, &nxp.PORTB.PCR18, nxp.GPIOB},
|
D29 = PB18
|
||||||
30: {19, &nxp.PORTB.PCR19, nxp.GPIOB},
|
D30 = PB19
|
||||||
31: {10, &nxp.PORTB.PCR10, nxp.GPIOB},
|
D31 = PB10
|
||||||
32: {11, &nxp.PORTB.PCR11, nxp.GPIOB},
|
D32 = PB11
|
||||||
33: {24, &nxp.PORTE.PCR24, nxp.GPIOE},
|
D33 = PE24
|
||||||
34: {25, &nxp.PORTE.PCR25, nxp.GPIOE},
|
D34 = PE25
|
||||||
35: {8, &nxp.PORTC.PCR8, nxp.GPIOC},
|
D35 = PC08
|
||||||
36: {9, &nxp.PORTC.PCR9, nxp.GPIOC},
|
D36 = PC09
|
||||||
37: {10, &nxp.PORTC.PCR10, nxp.GPIOC},
|
D37 = PC10
|
||||||
38: {11, &nxp.PORTC.PCR11, nxp.GPIOC},
|
D38 = PC11
|
||||||
39: {17, &nxp.PORTA.PCR17, nxp.GPIOA},
|
D39 = PA17
|
||||||
40: {28, &nxp.PORTA.PCR28, nxp.GPIOA},
|
D40 = PA28
|
||||||
41: {29, &nxp.PORTA.PCR29, nxp.GPIOA},
|
D41 = PA29
|
||||||
42: {26, &nxp.PORTA.PCR26, nxp.GPIOA},
|
D42 = PA26
|
||||||
43: {20, &nxp.PORTB.PCR20, nxp.GPIOB},
|
D43 = PB20
|
||||||
44: {22, &nxp.PORTB.PCR22, nxp.GPIOB},
|
D44 = PB22
|
||||||
45: {23, &nxp.PORTB.PCR23, nxp.GPIOB},
|
D45 = PB23
|
||||||
46: {21, &nxp.PORTB.PCR21, nxp.GPIOB},
|
D46 = PB21
|
||||||
47: {8, &nxp.PORTD.PCR8, nxp.GPIOD},
|
D47 = PD08
|
||||||
48: {9, &nxp.PORTD.PCR9, nxp.GPIOD},
|
D48 = PD09
|
||||||
49: {4, &nxp.PORTB.PCR4, nxp.GPIOB},
|
D49 = PB04
|
||||||
50: {5, &nxp.PORTB.PCR5, nxp.GPIOB},
|
D50 = PB05
|
||||||
51: {14, &nxp.PORTD.PCR14, nxp.GPIOD},
|
D51 = PD14
|
||||||
52: {13, &nxp.PORTD.PCR13, nxp.GPIOD},
|
D52 = PD13
|
||||||
53: {12, &nxp.PORTD.PCR12, nxp.GPIOD},
|
D53 = PD12
|
||||||
54: {15, &nxp.PORTD.PCR15, nxp.GPIOD},
|
D54 = PD15
|
||||||
55: {11, &nxp.PORTD.PCR11, nxp.GPIOD},
|
D55 = PD11
|
||||||
56: {10, &nxp.PORTE.PCR10, nxp.GPIOE},
|
D56 = PE10
|
||||||
57: {11, &nxp.PORTE.PCR11, nxp.GPIOE},
|
D57 = PE11
|
||||||
58: {0, &nxp.PORTE.PCR0, nxp.GPIOE},
|
D58 = PE00
|
||||||
59: {1, &nxp.PORTE.PCR1, nxp.GPIOE},
|
D59 = PE01
|
||||||
60: {2, &nxp.PORTE.PCR2, nxp.GPIOE},
|
D60 = PE02
|
||||||
61: {3, &nxp.PORTE.PCR3, nxp.GPIOE},
|
D61 = PE03
|
||||||
62: {4, &nxp.PORTE.PCR4, nxp.GPIOE},
|
D62 = PE04
|
||||||
63: {5, &nxp.PORTE.PCR5, nxp.GPIOE},
|
D63 = PE05
|
||||||
}
|
)
|
||||||
|
|
||||||
//go:inline
|
var (
|
||||||
func (p Pin) reg() pin { return pins[p] }
|
TeensyUART1 = &UART0
|
||||||
|
TeensyUART2 = &UART1
|
||||||
|
TeensyUART3 = &UART2
|
||||||
|
TeensyUART4 = &UART3
|
||||||
|
TeensyUART5 = &UART4
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultUART0RX = D00
|
||||||
|
defaultUART0TX = D01
|
||||||
|
defaultUART1RX = D09
|
||||||
|
defaultUART1TX = D10
|
||||||
|
defaultUART2RX = D07
|
||||||
|
defaultUART2TX = D08
|
||||||
|
defaultUART3RX = D31
|
||||||
|
defaultUART3TX = D32
|
||||||
|
defaultUART4RX = D34
|
||||||
|
defaultUART4TX = D33
|
||||||
|
)
|
||||||
|
|
|
@ -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")
|
|
||||||
}
|
|
|
@ -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
|
// +build nxp,mk66f18
|
||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
@ -5,8 +34,240 @@ package machine
|
||||||
import (
|
import (
|
||||||
"device/nxp"
|
"device/nxp"
|
||||||
"runtime/volatile"
|
"runtime/volatile"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
//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:
|
||||||
|
gpio.PDDR.ClearBits(1 << pos)
|
||||||
|
pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos))
|
||||||
|
|
||||||
|
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) {
|
||||||
|
gpio, _, pos := p.reg()
|
||||||
|
if value {
|
||||||
|
gpio.PSOR.Set(1 << pos)
|
||||||
|
} else {
|
||||||
|
gpio.PCOR.Set(1 << pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the current value of a GPIO pin.
|
||||||
|
func (p Pin) Get() bool {
|
||||||
|
gpio, _, pos := p.reg()
|
||||||
|
return gpio.PDIR.HasBits(1 << pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Pin) Control() *volatile.Register32 {
|
||||||
|
_, pcr, _ := p.reg()
|
||||||
|
return pcr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Pin) Fast() FastPin {
|
||||||
|
gpio, _, pos := p.reg()
|
||||||
|
return FastPin{
|
||||||
|
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 {
|
type FastPin struct {
|
||||||
PDOR *volatile.BitRegister
|
PDOR *volatile.BitRegister
|
||||||
PSOR *volatile.BitRegister
|
PSOR *volatile.BitRegister
|
||||||
|
@ -16,58 +277,6 @@ type FastPin struct {
|
||||||
PDDR *volatile.BitRegister
|
PDDR *volatile.BitRegister
|
||||||
}
|
}
|
||||||
|
|
||||||
type pin struct {
|
|
||||||
Bit uint8
|
|
||||||
PCR *volatile.Register32
|
|
||||||
GPIO *nxp.GPIO_Type
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure this pin with the given configuration.
|
|
||||||
func (p Pin) Configure(config PinConfig) {
|
|
||||||
switch config.Mode {
|
|
||||||
case PinInput:
|
|
||||||
panic("todo")
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set changes the value of the GPIO pin. The pin must be configured as output.
|
|
||||||
func (p Pin) Set(value bool) {
|
|
||||||
r := p.reg()
|
|
||||||
if value {
|
|
||||||
r.GPIO.PSOR.Set(1 << r.Bit)
|
|
||||||
} else {
|
|
||||||
r.GPIO.PCOR.Set(1 << r.Bit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Pin) Control() *volatile.Register32 {
|
|
||||||
return p.reg().PCR
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Pin) Fast() FastPin {
|
|
||||||
r := 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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p FastPin) Set() { p.PSOR.Set(true) }
|
func (p FastPin) Set() { p.PSOR.Set(true) }
|
||||||
func (p FastPin) Clear() { p.PCOR.Set(true) }
|
func (p FastPin) Clear() { p.PCOR.Set(true) }
|
||||||
func (p FastPin) Toggle() { p.PTOR.Set(true) }
|
func (p FastPin) Toggle() { p.PTOR.Set(true) }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// +build avr nrf sam sifive stm32 k210
|
// +build avr nrf sam sifive stm32 k210 nxp
|
||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
|
|
|
@ -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
|
// +build nxp,mk66f18
|
||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
@ -6,6 +35,7 @@ import (
|
||||||
"device/arm"
|
"device/arm"
|
||||||
"device/nxp"
|
"device/nxp"
|
||||||
"errors"
|
"errors"
|
||||||
|
"runtime/interrupt"
|
||||||
"runtime/volatile"
|
"runtime/volatile"
|
||||||
|
|
||||||
_ "unsafe" // for go:linkname
|
_ "unsafe" // for go:linkname
|
||||||
|
@ -18,6 +48,10 @@ const (
|
||||||
uartC2TXInactive = uartC2Enable
|
uartC2TXInactive = uartC2Enable
|
||||||
|
|
||||||
uartIRQPriority = 64
|
uartIRQPriority = 64
|
||||||
|
|
||||||
|
// determined from UARTx_PFIFO
|
||||||
|
uartRXFIFODepth = 8
|
||||||
|
uartTXFIFODepth = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -25,61 +59,81 @@ var (
|
||||||
ErrNotConfigured = errors.New("device has not been configured")
|
ErrNotConfigured = errors.New("device has not been configured")
|
||||||
)
|
)
|
||||||
|
|
||||||
type UARTConfig struct {
|
//go:linkname gosched runtime.Gosched
|
||||||
BaudRate uint32
|
func gosched()
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
for u.TCFIFO.Get() > 0 {
|
||||||
|
// busy wait
|
||||||
|
}
|
||||||
|
u.D.Set(c)
|
||||||
|
u.C2.Set(uartC2TXActive)
|
||||||
}
|
}
|
||||||
|
|
||||||
type UART struct {
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UART = *UARTData
|
||||||
|
|
||||||
|
type UARTData struct {
|
||||||
*nxp.UART_Type
|
*nxp.UART_Type
|
||||||
RXPCR *volatile.Register32
|
SCGC *volatile.Register32
|
||||||
TXPCR *volatile.Register32
|
SCGCMask uint32
|
||||||
SCGC *volatile.Register32
|
|
||||||
SCGCMask uint32
|
DefaultRX Pin
|
||||||
IRQNumber uint32
|
DefaultTX Pin
|
||||||
|
|
||||||
// state
|
// state
|
||||||
RXBuffer RingBuffer
|
Buffer RingBuffer // RX Buffer
|
||||||
TXBuffer RingBuffer
|
TXBuffer RingBuffer
|
||||||
|
Configured bool
|
||||||
Transmitting volatile.Register8
|
Transmitting volatile.Register8
|
||||||
|
Interrupt interrupt.Interrupt
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'UART0' in the K66 manual corresponds to 'UART1' on the Teensy's pinout
|
var UART0 = UARTData{UART_Type: nxp.UART0, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART0, DefaultRX: defaultUART0RX, DefaultTX: defaultUART0TX}
|
||||||
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 UART1 = UARTData{UART_Type: nxp.UART1, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART1, DefaultRX: defaultUART1RX, DefaultTX: defaultUART1TX}
|
||||||
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 UART2 = UARTData{UART_Type: nxp.UART2, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART2, DefaultRX: defaultUART2RX, DefaultTX: defaultUART2TX}
|
||||||
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 UART3 = UARTData{UART_Type: nxp.UART3, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART3, DefaultRX: defaultUART3RX, DefaultTX: defaultUART3TX}
|
||||||
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 UART4 = UARTData{UART_Type: nxp.UART4, SCGC: &nxp.SIM.SCGC1, SCGCMask: nxp.SIM_SCGC1_UART4, DefaultRX: defaultUART4RX, DefaultTX: defaultUART4TX}
|
||||||
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}
|
|
||||||
|
|
||||||
//go:export UART0_RX_TX_IRQHandler
|
func init() {
|
||||||
func uart0StatusISR() { UART1.handleStatusInterrupt() }
|
UART0.Interrupt = interrupt.New(nxp.IRQ_UART0_RX_TX, UART0.handleStatusInterrupt)
|
||||||
|
UART1.Interrupt = interrupt.New(nxp.IRQ_UART1_RX_TX, UART1.handleStatusInterrupt)
|
||||||
//go:export UART1_RX_TX_IRQHandler
|
UART2.Interrupt = interrupt.New(nxp.IRQ_UART2_RX_TX, UART2.handleStatusInterrupt)
|
||||||
func uart1StatusISR() { UART2.handleStatusInterrupt() }
|
UART3.Interrupt = interrupt.New(nxp.IRQ_UART3_RX_TX, UART3.handleStatusInterrupt)
|
||||||
|
UART4.Interrupt = interrupt.New(nxp.IRQ_UART4_RX_TX, UART4.handleStatusInterrupt)
|
||||||
//go:export UART2_RX_TX_IRQHandler
|
}
|
||||||
func uart2StatusISR() { UART3.handleStatusInterrupt() }
|
|
||||||
|
|
||||||
//go:export UART3_RX_TX_IRQHandler
|
|
||||||
func uart3StatusISR() { UART4.handleStatusInterrupt() }
|
|
||||||
|
|
||||||
//go:export UART4_RX_TX_IRQHandler
|
|
||||||
func uart4StatusISR() { UART5.handleStatusInterrupt() }
|
|
||||||
|
|
||||||
// Configure the UART.
|
// Configure the UART.
|
||||||
func (u *UART) Configure(config UARTConfig) {
|
func (u UART) Configure(config UARTConfig) {
|
||||||
en := u.SCGC.HasBits(u.SCGCMask)
|
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)
|
u.Transmitting.Set(0)
|
||||||
|
|
||||||
// turn on the clock
|
// turn on the clock
|
||||||
u.SCGC.Set(u.SCGCMask)
|
u.SCGC.Set(u.SCGCMask)
|
||||||
|
|
||||||
// configure pins
|
// configure pins
|
||||||
u.RXPCR.Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_PFE | 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.TXPCR.Set(nxp.PORT_PCR0_DSE | nxp.PORT_PCR0_SRE | nxp.PORT_PCR0_MUX(3))
|
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)
|
u.C1.Set(nxp.UART_C1_ILT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,14 +143,20 @@ func (u *UART) Configure(config UARTConfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// copied from teensy core's BAUD2DIV macro
|
// 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 {
|
if divisor < 32 {
|
||||||
divisor = 32
|
divisor = 32
|
||||||
}
|
}
|
||||||
|
|
||||||
if en {
|
if u.Configured {
|
||||||
// don't change baud rate mid transmit
|
// 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
|
// set the divisor
|
||||||
|
@ -104,23 +164,27 @@ func (u *UART) Configure(config UARTConfig) {
|
||||||
u.BDL.Set(uint8((divisor >> 5) & 0xFF))
|
u.BDL.Set(uint8((divisor >> 5) & 0xFF))
|
||||||
u.C4.Set(uint8(divisor & 0x1F))
|
u.C4.Set(uint8(divisor & 0x1F))
|
||||||
|
|
||||||
if !en {
|
if !u.Configured {
|
||||||
|
u.Configured = true
|
||||||
|
|
||||||
u.C1.Set(nxp.UART_C1_ILT)
|
u.C1.Set(nxp.UART_C1_ILT)
|
||||||
|
|
||||||
// configure TX and RX watermark
|
// configure TX and RX watermark
|
||||||
u.TWFIFO.Set(2) // causes bit TDRE of S1 to set
|
u.TWFIFO.Set(2) // causes bit TDRE of S1 to set
|
||||||
u.RWFIFO.Set(4) // causes bit RDRF 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.PFIFO.Set(nxp.UART_PFIFO_TXFE | nxp.UART_PFIFO_RXFE)
|
||||||
u.C2.Set(uartC2TXInactive)
|
|
||||||
|
|
||||||
arm.SetPriority(u.IRQNumber, uartIRQPriority)
|
// setup interrupts
|
||||||
arm.EnableIRQ(u.IRQNumber)
|
u.C2.Set(uartC2TXInactive)
|
||||||
|
u.Interrupt.SetPriority(uartIRQPriority)
|
||||||
|
u.Interrupt.Enable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UART) Disable() {
|
func (u UART) Disable() {
|
||||||
// adapted from Teensy core's serial_end
|
// from: serial_end
|
||||||
|
|
||||||
// check if the device has been enabled already
|
// check if the device has been enabled already
|
||||||
if !u.SCGC.HasBits(u.SCGCMask) {
|
if !u.SCGC.HasBits(u.SCGCMask) {
|
||||||
|
@ -129,27 +193,29 @@ func (u *UART) Disable() {
|
||||||
|
|
||||||
u.Flush()
|
u.Flush()
|
||||||
|
|
||||||
arm.DisableIRQ(u.IRQNumber)
|
u.Interrupt.Disable()
|
||||||
u.C2.Set(0)
|
u.C2.Set(0)
|
||||||
|
|
||||||
// reconfigure pin
|
// reconfigure pin
|
||||||
u.RXPCR.Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_MUX(1))
|
u.DefaultRX.Configure(PinConfig{Mode: PinInputPullUp})
|
||||||
u.TXPCR.Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_MUX(1))
|
u.DefaultTX.Configure(PinConfig{Mode: PinInputPullUp})
|
||||||
|
|
||||||
// clear flags
|
// clear flags
|
||||||
u.S1.Get()
|
u.S1.Get()
|
||||||
u.D.Get()
|
u.D.Get()
|
||||||
u.RXBuffer.Clear()
|
u.Buffer.Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UART) Flush() {
|
func (u UART) Flush() {
|
||||||
for u.Transmitting.Get() != 0 {
|
for u.Transmitting.Get() != 0 {
|
||||||
// gosched()
|
gosched()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// adapted from Teensy core's uart0_status_isr
|
func (u UART) handleStatusInterrupt(interrupt.Interrupt) {
|
||||||
func (u *UART) handleStatusInterrupt() {
|
// from: uart0_status_isr
|
||||||
|
|
||||||
|
// receive
|
||||||
if u.S1.HasBits(nxp.UART_S1_RDRF | nxp.UART_S1_IDLE) {
|
if u.S1.HasBits(nxp.UART_S1_RDRF | nxp.UART_S1_IDLE) {
|
||||||
intrs := arm.DisableInterrupts()
|
intrs := arm.DisableInterrupts()
|
||||||
avail := u.RCFIFO.Get()
|
avail := u.RCFIFO.Get()
|
||||||
|
@ -177,7 +243,7 @@ func (u *UART) handleStatusInterrupt() {
|
||||||
arm.EnableInterrupts(intrs)
|
arm.EnableInterrupts(intrs)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
u.RXBuffer.Put(u.D.Get())
|
u.Buffer.Put(u.D.Get())
|
||||||
avail--
|
avail--
|
||||||
if avail <= 0 {
|
if avail <= 0 {
|
||||||
break
|
break
|
||||||
|
@ -186,66 +252,54 @@ func (u *UART) handleStatusInterrupt() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c := u.C2.Get()
|
// transmit
|
||||||
if c&nxp.UART_C2_TIE != 0 && u.S1.HasBits(nxp.UART_S1_TDRE) {
|
if u.C2.HasBits(nxp.UART_C2_TIE) && u.S1.HasBits(nxp.UART_S1_TDRE) {
|
||||||
for {
|
data := make([]byte, 0, uartTXFIFODepth)
|
||||||
n, ok := u.TXBuffer.Get()
|
avail := uartTXFIFODepth - u.TCFIFO.Get()
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
u.S1.Get()
|
// get avail bytes from ring buffer
|
||||||
u.D.Set(n)
|
for len(data) < int(avail) {
|
||||||
|
if b, ok := u.TXBuffer.Get(); ok {
|
||||||
if u.TCFIFO.Get() >= 8 {
|
data = append(data, b)
|
||||||
|
} else {
|
||||||
break
|
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) {
|
if u.S1.HasBits(nxp.UART_S1_TDRE) {
|
||||||
u.Transmitting.Set(0)
|
|
||||||
u.C2.Set(uartC2TXCompleting)
|
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)
|
u.C2.Set(uartC2TXInactive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname gosched runtime.Gosched
|
|
||||||
func gosched()
|
|
||||||
|
|
||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (u *UART) WriteByte(c byte) error {
|
func (u UART) WriteByte(c byte) error {
|
||||||
if !u.SCGC.HasBits(u.SCGCMask) {
|
if !u.Configured {
|
||||||
return ErrNotConfigured
|
return ErrNotConfigured
|
||||||
}
|
}
|
||||||
|
|
||||||
for !u.S1.HasBits(nxp.UART_S1_TDRE) {
|
for !u.TXBuffer.Put(c) {
|
||||||
gosched()
|
gosched()
|
||||||
}
|
}
|
||||||
u.D.Set(c)
|
|
||||||
|
|
||||||
// // wait for room on the buffer
|
u.Transmitting.Set(1)
|
||||||
// for !u.TXBuffer.Put(c) {
|
u.C2.Set(uartC2TXActive)
|
||||||
// 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)
|
|
||||||
// }
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
// +build nxp
|
|
||||||
|
|
||||||
package runtime
|
|
||||||
|
|
||||||
type timeUnit int64
|
|
|
@ -35,53 +35,41 @@ import (
|
||||||
"device/arm"
|
"device/arm"
|
||||||
"device/nxp"
|
"device/nxp"
|
||||||
"machine"
|
"machine"
|
||||||
"runtime/volatile"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
WDOG_UNLOCK_SEQ1 = 0xC520
|
watchdogUnlockSequence1 = 0xC520
|
||||||
WDOG_UNLOCK_SEQ2 = 0xD928
|
watchdogUnlockSequence2 = 0xD928
|
||||||
|
|
||||||
DEFAULT_FTM_MOD = 61440 - 1
|
_DEFAULT_FTM_MOD = 61440 - 1
|
||||||
DEFAULT_FTM_PRESCALE = 1
|
_DEFAULT_FTM_PRESCALE = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
SIM_SOPT2_IRC48SEL = nxp.SIM_SOPT2_PLLFLLSEL(3)
|
_SIM_SOPT2_IRC48SEL = 3 << nxp.SIM_SOPT2_PLLFLLSEL_Pos
|
||||||
SMC_PMCTRL_HSRUN = nxp.SMC_PMCTRL_RUNM(3)
|
_SMC_PMCTRL_HSRUN = 3 << nxp.SMC_PMCTRL_RUNM_Pos
|
||||||
SMC_PMSTAT_HSRUN = nxp.SMC_PMSTAT_PMSTAT(0x80)
|
_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
|
//go:export Reset_Handler
|
||||||
func main() {
|
func main() {
|
||||||
initSystem()
|
initSystem()
|
||||||
arm.Asm("CPSIE i")
|
arm.Asm("CPSIE i")
|
||||||
initInternal()
|
initInternal()
|
||||||
startupLateHook()
|
|
||||||
|
|
||||||
initAll()
|
run()
|
||||||
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()
|
|
||||||
abort()
|
abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ported ResetHandler from mk20dx128.c from teensy3 core libraries
|
|
||||||
//go:noinline
|
|
||||||
func initSystem() {
|
func initSystem() {
|
||||||
nxp.WDOG.UNLOCK.Set(WDOG_UNLOCK_SEQ1)
|
// from: ResetHandler
|
||||||
nxp.WDOG.UNLOCK.Set(WDOG_UNLOCK_SEQ2)
|
|
||||||
|
nxp.WDOG.UNLOCK.Set(watchdogUnlockSequence1)
|
||||||
|
nxp.WDOG.UNLOCK.Set(watchdogUnlockSequence2)
|
||||||
arm.Asm("nop")
|
arm.Asm("nop")
|
||||||
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
|
// enable clocks to always-used peripherals
|
||||||
nxp.SIM.SCGC3.Set(nxp.SIM_SCGC3_ADC1 | nxp.SIM_SCGC3_FTM2 | nxp.SIM_SCGC3_FTM3)
|
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
|
// enable capacitors for crystal
|
||||||
nxp.OSC.CR.Set(nxp.OSC_CR_SC8P | nxp.OSC_CR_SC2P | nxp.OSC_CR_ERCLKEN)
|
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
|
// 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
|
// 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
|
// wait for crystal oscillator to begin
|
||||||
for !nxp.MCG.S.HasBits(nxp.MCG_S_OSCINIT0) {
|
for !nxp.MCG.S.HasBits(nxp.MCG_S_OSCINIT0) {
|
||||||
}
|
}
|
||||||
|
@ -127,7 +115,7 @@ func initSystem() {
|
||||||
for nxp.MCG.S.HasBits(nxp.MCG_S_IREFST) {
|
for nxp.MCG.S.HasBits(nxp.MCG_S_IREFST) {
|
||||||
}
|
}
|
||||||
// wait for MCGOUT to use oscillator
|
// 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
|
// now in FBE mode
|
||||||
|
@ -137,11 +125,11 @@ func initSystem() {
|
||||||
// C6[PLLS] bit is written to 0
|
// C6[PLLS] bit is written to 0
|
||||||
// C2[LP] is written to 0
|
// C2[LP] is written to 0
|
||||||
// we need faster than the crystal, turn on the PLL (F_CPU > 120000000)
|
// we need faster than the crystal, turn on the PLL (F_CPU > 120000000)
|
||||||
nxp.SMC.PMCTRL.Set(SMC_PMCTRL_HSRUN) // enter HSRUN mode
|
nxp.SMC.PMCTRL.Set(_SMC_PMCTRL_HSRUN) // enter HSRUN mode
|
||||||
for nxp.SMC.PMSTAT.Get() != SMC_PMSTAT_HSRUN {
|
for nxp.SMC.PMSTAT.Get() != _SMC_PMSTAT_HSRUN {
|
||||||
} // wait for HSRUN
|
} // wait for HSRUN
|
||||||
nxp.MCG.C5.Set(nxp.MCG_C5_PRDIV(1))
|
nxp.MCG.C5.Set((1 << nxp.MCG_C5_PRDIV_Pos))
|
||||||
nxp.MCG.C6.Set(nxp.MCG_C6_PLLS | nxp.MCG_C6_VDIV(29))
|
nxp.MCG.C6.Set(nxp.MCG_C6_PLLS | (29 << nxp.MCG_C6_VDIV_Pos))
|
||||||
|
|
||||||
// wait for PLL to start using xtal as its input
|
// wait for PLL to start using xtal as its input
|
||||||
for !nxp.MCG.S.HasBits(nxp.MCG_S_PLLST) {
|
for !nxp.MCG.S.HasBits(nxp.MCG_S_PLLST) {
|
||||||
|
@ -153,18 +141,18 @@ func initSystem() {
|
||||||
|
|
||||||
// now program the clock dividers
|
// now program the clock dividers
|
||||||
// config divisors: 180 MHz core, 60 MHz bus, 25.7 MHz flash, USB = IRC48M
|
// 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.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(nxp.SIM_CLKDIV2_USBDIV(0))
|
nxp.SIM.CLKDIV2.Set((0 << nxp.SIM_CLKDIV2_USBDIV_Pos))
|
||||||
|
|
||||||
// switch to PLL as clock source, FLL input = 16 MHz / 512
|
// 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
|
// 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
|
// now we're in PEE mode
|
||||||
// trace is CPU clock, CLKOUT=OSCERCLK0
|
// trace is CPU clock, CLKOUT=OSCERCLK0
|
||||||
// USB uses IRC48
|
// 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
|
// 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.
|
// we don't do this early. See comment above about slow rising power.
|
||||||
|
@ -174,23 +162,19 @@ func initSystem() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the SysTick counter
|
// initialize the SysTick counter
|
||||||
nxp.SysTick.RVR.Set((machine.CPUFrequency() / 1000) - 1)
|
initSysTick()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ported _init_Teensyduino_internal_ from pins_teensy.c from teensy3 core libraries
|
|
||||||
//go:noinline
|
|
||||||
func initInternal() {
|
func initInternal() {
|
||||||
arm.EnableIRQ(nxp.IRQ_PORTA)
|
// from: _init_Teensyduino_internal_
|
||||||
arm.EnableIRQ(nxp.IRQ_PORTB)
|
// arm.EnableIRQ(nxp.IRQ_PORTA)
|
||||||
arm.EnableIRQ(nxp.IRQ_PORTC)
|
// arm.EnableIRQ(nxp.IRQ_PORTB)
|
||||||
arm.EnableIRQ(nxp.IRQ_PORTD)
|
// arm.EnableIRQ(nxp.IRQ_PORTC)
|
||||||
arm.EnableIRQ(nxp.IRQ_PORTE)
|
// arm.EnableIRQ(nxp.IRQ_PORTD)
|
||||||
|
// arm.EnableIRQ(nxp.IRQ_PORTE)
|
||||||
|
|
||||||
nxp.FTM0.CNT.Set(0)
|
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.C0SC.Set(0x28) // MSnB:MSnA = 10, ELSnB:ELSnA = 10
|
||||||
nxp.FTM0.C1SC.Set(0x28)
|
nxp.FTM0.C1SC.Set(0x28)
|
||||||
nxp.FTM0.C2SC.Set(0x28)
|
nxp.FTM0.C2SC.Set(0x28)
|
||||||
|
@ -209,145 +193,45 @@ func initInternal() {
|
||||||
nxp.FTM3.C6SC.Set(0x28)
|
nxp.FTM3.C6SC.Set(0x28)
|
||||||
nxp.FTM3.C7SC.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.CNT.Set(0)
|
||||||
nxp.FTM1.MOD.Set(DEFAULT_FTM_MOD)
|
nxp.FTM1.MOD.Set(_DEFAULT_FTM_MOD)
|
||||||
nxp.FTM1.C0SC.Set(0x28)
|
nxp.FTM1.C0SC.Set(0x28)
|
||||||
nxp.FTM1.C1SC.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.CNT.Set(0)
|
||||||
// nxp.FTM2.MOD.Set(DEFAULT_FTM_MOD)
|
// nxp.FTM2.MOD.Set(_DEFAULT_FTM_MOD)
|
||||||
// nxp.FTM2.C0SC.Set(0x28)
|
// nxp.FTM2.C0SC.Set(0x28)
|
||||||
// nxp.FTM2.C1SC.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.CNT.Set(0)
|
||||||
nxp.FTM3.MOD.Set(DEFAULT_FTM_MOD)
|
nxp.FTM3.MOD.Set(_DEFAULT_FTM_MOD)
|
||||||
nxp.FTM3.C0SC.Set(0x28)
|
nxp.FTM3.C0SC.Set(0x28)
|
||||||
nxp.FTM3.C1SC.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.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.CNT.Set(0)
|
||||||
nxp.TPM1.MOD.Set(32767)
|
nxp.TPM1.MOD.Set(32767)
|
||||||
nxp.TPM1.C0SC.Set(0x28)
|
nxp.TPM1.C0SC.Set(0x28)
|
||||||
nxp.TPM1.C1SC.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
|
// configure the sleep timer
|
||||||
// nxp.LPTMR0.CSR.Set(nxp.LPTMR0_CSR_TIE)
|
initSleepTimer()
|
||||||
// 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)
|
|
||||||
|
|
||||||
// analog_init();
|
// 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() {
|
func postinit() {}
|
||||||
// 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 putchar(c byte) {
|
func putchar(c byte) {
|
||||||
machine.UART1.WriteByte(c)
|
machine.PutcharUART(&machine.UART0, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ???
|
// ???
|
||||||
const asyncScheduler = false
|
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();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
163
src/runtime/time_nxpmk66f18.go
Обычный файл
163
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
|
||||||
|
}
|
|
@ -7,17 +7,16 @@ import "unsafe"
|
||||||
const registerBase = 0x40000000
|
const registerBase = 0x40000000
|
||||||
const registerEnd = 0x40100000
|
const registerEnd = 0x40100000
|
||||||
const bitbandBase = 0x42000000
|
const bitbandBase = 0x42000000
|
||||||
const ptrBytes = unsafe.Sizeof(uintptr(0))
|
|
||||||
|
|
||||||
//go:inline
|
//go:inline
|
||||||
func bitbandAddress(reg uintptr, bit uint8) uintptr {
|
func bitbandAddress(reg uintptr, bit uint8) uintptr {
|
||||||
if uintptr(bit) > ptrBytes*8 {
|
if uintptr(bit) > 32 {
|
||||||
panic("invalid bit position")
|
panic("invalid bit position")
|
||||||
}
|
}
|
||||||
if reg < registerBase || reg >= registerEnd {
|
if reg < registerBase || reg >= registerEnd {
|
||||||
panic("register is out of range")
|
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
|
// Special types that causes loads/stores to be volatile (necessary for
|
|
@ -5,8 +5,8 @@ ENTRY(Reset_Handler)
|
||||||
/* define memory layout */
|
/* define memory layout */
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
FLASH_TEXT (rx) : ORIGIN = 0x00000000, LENGTH = 1024K
|
FLASH_TEXT (rx) : ORIGIN = 0x00000000, LENGTH = 1024K
|
||||||
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K
|
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K
|
||||||
}
|
}
|
||||||
|
|
||||||
_stack_size = 2K;
|
_stack_size = 2K;
|
||||||
|
@ -18,21 +18,18 @@ SECTIONS
|
||||||
.text :
|
.text :
|
||||||
{
|
{
|
||||||
/* vector table MUST start at 0x0 */
|
/* vector table MUST start at 0x0 */
|
||||||
. = 0;
|
. = 0;
|
||||||
_vector_table = .;
|
|
||||||
KEEP(*(.isr_vector))
|
KEEP(*(.isr_vector))
|
||||||
|
|
||||||
/* flash configuration MUST be at 0x400 */
|
/* flash configuration MUST be at 0x400 */
|
||||||
. = 0x400;
|
. = 0x400;
|
||||||
_flash_config = .;
|
KEEP(*(.flash_config))
|
||||||
KEEP(*(.flash_config))
|
|
||||||
|
|
||||||
/* everything else */
|
/* everything else */
|
||||||
*(.resetHandler)
|
|
||||||
*(.text)
|
*(.text)
|
||||||
*(.text*)
|
*(.text.*)
|
||||||
*(.rodata)
|
*(.rodata)
|
||||||
*(.rodata*)
|
*(.rodata.*)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
|
||||||
} >FLASH_TEXT = 0xFF
|
} >FLASH_TEXT = 0xFF
|
||||||
|
@ -50,7 +47,7 @@ SECTIONS
|
||||||
/* Start address (in flash) of .data, used by startup code. */
|
/* Start address (in flash) of .data, used by startup code. */
|
||||||
_sidata = LOADADDR(.data);
|
_sidata = LOADADDR(.data);
|
||||||
|
|
||||||
/* todo add .usbdescriptortable .dmabuffers .usbbuffers */
|
/* this is where Teensy's LD script places .usbdescriptortable .dmabuffers .usbbuffers */
|
||||||
|
|
||||||
/* Globals with initial value */
|
/* Globals with initial value */
|
||||||
.data :
|
.data :
|
||||||
|
@ -58,7 +55,7 @@ SECTIONS
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_sdata = .; /* used by startup code */
|
_sdata = .; /* used by startup code */
|
||||||
*(.data)
|
*(.data)
|
||||||
*(.data*)
|
*(.data.*)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_edata = .; /* used by startup code */
|
_edata = .; /* used by startup code */
|
||||||
} >RAM AT>FLASH_TEXT
|
} >RAM AT>FLASH_TEXT
|
||||||
|
@ -69,7 +66,7 @@ SECTIONS
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_sbss = .; /* used by startup code */
|
_sbss = .; /* used by startup code */
|
||||||
*(.bss)
|
*(.bss)
|
||||||
*(.bss*)
|
*(.bss.*)
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_ebss = .; /* used by startup code */
|
_ebss = .; /* used by startup code */
|
||||||
|
@ -79,11 +76,6 @@ SECTIONS
|
||||||
{
|
{
|
||||||
*(.ARM.exidx) /* causes 'no memory region specified' error in lld */
|
*(.ARM.exidx) /* causes 'no memory region specified' error in lld */
|
||||||
*(.ARM.exidx.*) /* causes spurious 'undefined reference' errors */
|
*(.ARM.exidx.*) /* causes spurious 'undefined reference' errors */
|
||||||
|
|
||||||
/* all this makes it much harder to debug via disassembly */
|
|
||||||
*(.debug*)
|
|
||||||
*(.ARM.*)
|
|
||||||
*(.comment*)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
|
||||||
.section .flash_config
|
.section .flash_config
|
||||||
.global __flash_config
|
.global __flash_config
|
||||||
.byte 0xFF
|
__flash_config:
|
||||||
|
.byte 0xFF
|
||||||
|
.byte 0xFF
|
||||||
.byte 0xFF
|
.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 0xFF
|
.byte 0xFF
|
||||||
.byte 0xFF
|
.byte 0xFF
|
||||||
.byte 0xFF
|
.byte 0xFF
|
||||||
.byte 0xDE
|
.byte 0xDE
|
||||||
.byte 0xF9
|
.byte 0xF9
|
||||||
.byte 0xFF
|
.byte 0xFF
|
||||||
.byte 0xFF
|
.byte 0xFF
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче