- 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)
Этот коммит содержится в:
Ethan Reesor 2020-02-23 20:09:44 -06:00 коммит произвёл Ron Evans
родитель 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 Обычный файл
Просмотреть файл

@ -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