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)
This commit is contained in:
Ethan Reesor
2020-02-23 20:09:44 -06:00
committed by Ron Evans
parent 59218cd784
commit 4750635a20
11 changed files with 728 additions and 456 deletions
+92 -83
View File
@@ -2,91 +2,100 @@
package machine
import (
"device/nxp"
)
// CPUFrequency returns the frequency of the ARM core clock (180MHz)
func CPUFrequency() uint32 { return 180000000 }
// //go:keep
// //go:section .flash_config
// var FlashControl = [16]byte{
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xF9, 0xFF, 0xFF,
// }
func CPUFrequency() uint32 {
return 180000000
}
// ClockFrequency returns the frequency of the external oscillator (16MHz)
func ClockFrequency() uint32 { return 16000000 }
// LED on the Teensy
const LED Pin = 13
const LED = PC05
var pins = []pin{
// {bit, control register, gpio register bank}
0: {16, &nxp.PORTB.PCR16, nxp.GPIOB},
1: {17, &nxp.PORTB.PCR17, nxp.GPIOB},
2: {0, &nxp.PORTD.PCR0, nxp.GPIOD},
3: {12, &nxp.PORTA.PCR12, nxp.GPIOA},
4: {13, &nxp.PORTA.PCR13, nxp.GPIOA},
5: {7, &nxp.PORTD.PCR7, nxp.GPIOD},
6: {4, &nxp.PORTD.PCR4, nxp.GPIOD},
7: {2, &nxp.PORTD.PCR2, nxp.GPIOD},
8: {3, &nxp.PORTD.PCR3, nxp.GPIOD},
9: {3, &nxp.PORTC.PCR3, nxp.GPIOC},
10: {4, &nxp.PORTC.PCR4, nxp.GPIOC},
11: {6, &nxp.PORTC.PCR6, nxp.GPIOC},
12: {7, &nxp.PORTC.PCR7, nxp.GPIOC},
13: {5, &nxp.PORTC.PCR5, nxp.GPIOC},
14: {1, &nxp.PORTD.PCR1, nxp.GPIOD},
15: {0, &nxp.PORTC.PCR0, nxp.GPIOC},
16: {0, &nxp.PORTB.PCR0, nxp.GPIOB},
17: {1, &nxp.PORTB.PCR1, nxp.GPIOB},
18: {3, &nxp.PORTB.PCR3, nxp.GPIOB},
19: {2, &nxp.PORTB.PCR2, nxp.GPIOB},
20: {5, &nxp.PORTD.PCR5, nxp.GPIOD},
21: {6, &nxp.PORTD.PCR6, nxp.GPIOD},
22: {1, &nxp.PORTC.PCR1, nxp.GPIOC},
23: {2, &nxp.PORTC.PCR2, nxp.GPIOC},
24: {26, &nxp.PORTE.PCR26, nxp.GPIOE},
25: {5, &nxp.PORTA.PCR5, nxp.GPIOA},
26: {14, &nxp.PORTA.PCR14, nxp.GPIOA},
27: {15, &nxp.PORTA.PCR15, nxp.GPIOA},
28: {16, &nxp.PORTA.PCR16, nxp.GPIOA},
29: {18, &nxp.PORTB.PCR18, nxp.GPIOB},
30: {19, &nxp.PORTB.PCR19, nxp.GPIOB},
31: {10, &nxp.PORTB.PCR10, nxp.GPIOB},
32: {11, &nxp.PORTB.PCR11, nxp.GPIOB},
33: {24, &nxp.PORTE.PCR24, nxp.GPIOE},
34: {25, &nxp.PORTE.PCR25, nxp.GPIOE},
35: {8, &nxp.PORTC.PCR8, nxp.GPIOC},
36: {9, &nxp.PORTC.PCR9, nxp.GPIOC},
37: {10, &nxp.PORTC.PCR10, nxp.GPIOC},
38: {11, &nxp.PORTC.PCR11, nxp.GPIOC},
39: {17, &nxp.PORTA.PCR17, nxp.GPIOA},
40: {28, &nxp.PORTA.PCR28, nxp.GPIOA},
41: {29, &nxp.PORTA.PCR29, nxp.GPIOA},
42: {26, &nxp.PORTA.PCR26, nxp.GPIOA},
43: {20, &nxp.PORTB.PCR20, nxp.GPIOB},
44: {22, &nxp.PORTB.PCR22, nxp.GPIOB},
45: {23, &nxp.PORTB.PCR23, nxp.GPIOB},
46: {21, &nxp.PORTB.PCR21, nxp.GPIOB},
47: {8, &nxp.PORTD.PCR8, nxp.GPIOD},
48: {9, &nxp.PORTD.PCR9, nxp.GPIOD},
49: {4, &nxp.PORTB.PCR4, nxp.GPIOB},
50: {5, &nxp.PORTB.PCR5, nxp.GPIOB},
51: {14, &nxp.PORTD.PCR14, nxp.GPIOD},
52: {13, &nxp.PORTD.PCR13, nxp.GPIOD},
53: {12, &nxp.PORTD.PCR12, nxp.GPIOD},
54: {15, &nxp.PORTD.PCR15, nxp.GPIOD},
55: {11, &nxp.PORTD.PCR11, nxp.GPIOD},
56: {10, &nxp.PORTE.PCR10, nxp.GPIOE},
57: {11, &nxp.PORTE.PCR11, nxp.GPIOE},
58: {0, &nxp.PORTE.PCR0, nxp.GPIOE},
59: {1, &nxp.PORTE.PCR1, nxp.GPIOE},
60: {2, &nxp.PORTE.PCR2, nxp.GPIOE},
61: {3, &nxp.PORTE.PCR3, nxp.GPIOE},
62: {4, &nxp.PORTE.PCR4, nxp.GPIOE},
63: {5, &nxp.PORTE.PCR5, nxp.GPIOE},
}
// digital IO
const (
D00 = PB16
D01 = PB17
D02 = PD00
D03 = PA12
D04 = PA13
D05 = PD07
D06 = PD04
D07 = PD02
D08 = PD03
D09 = PC03
D10 = PC04
D11 = PC06
D12 = PC07
D13 = PC05
D14 = PD01
D15 = PC00
D16 = PB00
D17 = PB01
D18 = PB03
D19 = PB02
D20 = PD05
D21 = PD06
D22 = PC01
D23 = PC02
D24 = PE26
D25 = PA05
D26 = PA14
D27 = PA15
D28 = PA16
D29 = PB18
D30 = PB19
D31 = PB10
D32 = PB11
D33 = PE24
D34 = PE25
D35 = PC08
D36 = PC09
D37 = PC10
D38 = PC11
D39 = PA17
D40 = PA28
D41 = PA29
D42 = PA26
D43 = PB20
D44 = PB22
D45 = PB23
D46 = PB21
D47 = PD08
D48 = PD09
D49 = PB04
D50 = PB05
D51 = PD14
D52 = PD13
D53 = PD12
D54 = PD15
D55 = PD11
D56 = PE10
D57 = PE11
D58 = PE00
D59 = PE01
D60 = PE02
D61 = PE03
D62 = PE04
D63 = PE05
)
//go:inline
func (p Pin) reg() pin { return pins[p] }
var (
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
)
-33
View File
@@ -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")
}
+261 -52
View File
@@ -1,3 +1,32 @@
// Derivative work of Teensyduino Core Library
// http://www.pjrc.com/teensy/
// Copyright (c) 2017 PJRC.COM, LLC.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// 1. The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// 2. If the Software is incorporated into a build system that allows
// selection among a list of target devices, then similar target
// devices manufactured by PJRC.COM must be included in the list of
// target devices and selectable in the same manner.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// +build nxp,mk66f18
package machine
@@ -5,8 +34,240 @@ package machine
import (
"device/nxp"
"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 {
PDOR *volatile.BitRegister
PSOR *volatile.BitRegister
@@ -16,58 +277,6 @@ type FastPin struct {
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) Clear() { p.PCOR.Set(true) }
func (p FastPin) Toggle() { p.PTOR.Set(true) }
+1 -1
View File
@@ -1,4 +1,4 @@
// +build avr nrf sam sifive stm32 k210
// +build avr nrf sam sifive stm32 k210 nxp
package machine
+147 -93
View File
@@ -1,3 +1,32 @@
// Derivative work of Teensyduino Core Library
// http://www.pjrc.com/teensy/
// Copyright (c) 2017 PJRC.COM, LLC.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// 1. The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// 2. If the Software is incorporated into a build system that allows
// selection among a list of target devices, then similar target
// devices manufactured by PJRC.COM must be included in the list of
// target devices and selectable in the same manner.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// +build nxp,mk66f18
package machine
@@ -6,6 +35,7 @@ import (
"device/arm"
"device/nxp"
"errors"
"runtime/interrupt"
"runtime/volatile"
_ "unsafe" // for go:linkname
@@ -18,6 +48,10 @@ const (
uartC2TXInactive = uartC2Enable
uartIRQPriority = 64
// determined from UARTx_PFIFO
uartRXFIFODepth = 8
uartTXFIFODepth = 8
)
var (
@@ -25,61 +59,81 @@ var (
ErrNotConfigured = errors.New("device has not been configured")
)
type UARTConfig struct {
BaudRate uint32
//go:linkname gosched runtime.Gosched
func gosched()
// 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
RXPCR *volatile.Register32
TXPCR *volatile.Register32
SCGC *volatile.Register32
SCGCMask uint32
IRQNumber uint32
SCGC *volatile.Register32
SCGCMask uint32
DefaultRX Pin
DefaultTX Pin
// state
RXBuffer RingBuffer
Buffer RingBuffer // RX Buffer
TXBuffer RingBuffer
Configured bool
Transmitting volatile.Register8
Interrupt interrupt.Interrupt
}
// 'UART0' in the K66 manual corresponds to 'UART1' on the Teensy's pinout
var UART1 = UART{UART_Type: nxp.UART0, RXPCR: pins[0].PCR, TXPCR: pins[1].PCR, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART0, IRQNumber: nxp.IRQ_UART0_RX_TX}
var UART2 = UART{UART_Type: nxp.UART1, RXPCR: pins[9].PCR, TXPCR: pins[10].PCR, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART1, IRQNumber: nxp.IRQ_UART1_RX_TX}
var UART3 = UART{UART_Type: nxp.UART2, RXPCR: pins[7].PCR, TXPCR: pins[8].PCR, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART2, IRQNumber: nxp.IRQ_UART2_RX_TX}
var UART4 = UART{UART_Type: nxp.UART3, RXPCR: pins[31].PCR, TXPCR: pins[32].PCR, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART3, IRQNumber: nxp.IRQ_UART3_RX_TX}
var UART5 = UART{UART_Type: nxp.UART4, RXPCR: pins[34].PCR, TXPCR: pins[33].PCR, SCGC: &nxp.SIM.SCGC1, SCGCMask: nxp.SIM_SCGC1_UART4, IRQNumber: nxp.IRQ_UART4_RX_TX}
var UART0 = UARTData{UART_Type: nxp.UART0, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART0, DefaultRX: defaultUART0RX, DefaultTX: defaultUART0TX}
var UART1 = UARTData{UART_Type: nxp.UART1, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART1, DefaultRX: defaultUART1RX, DefaultTX: defaultUART1TX}
var UART2 = UARTData{UART_Type: nxp.UART2, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART2, DefaultRX: defaultUART2RX, DefaultTX: defaultUART2TX}
var UART3 = UARTData{UART_Type: nxp.UART3, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART3, DefaultRX: defaultUART3RX, DefaultTX: defaultUART3TX}
var UART4 = UARTData{UART_Type: nxp.UART4, SCGC: &nxp.SIM.SCGC1, SCGCMask: nxp.SIM_SCGC1_UART4, DefaultRX: defaultUART4RX, DefaultTX: defaultUART4TX}
//go:export UART0_RX_TX_IRQHandler
func uart0StatusISR() { UART1.handleStatusInterrupt() }
//go:export UART1_RX_TX_IRQHandler
func uart1StatusISR() { UART2.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() }
func init() {
UART0.Interrupt = interrupt.New(nxp.IRQ_UART0_RX_TX, UART0.handleStatusInterrupt)
UART1.Interrupt = interrupt.New(nxp.IRQ_UART1_RX_TX, UART1.handleStatusInterrupt)
UART2.Interrupt = interrupt.New(nxp.IRQ_UART2_RX_TX, UART2.handleStatusInterrupt)
UART3.Interrupt = interrupt.New(nxp.IRQ_UART3_RX_TX, UART3.handleStatusInterrupt)
UART4.Interrupt = interrupt.New(nxp.IRQ_UART4_RX_TX, UART4.handleStatusInterrupt)
}
// Configure the UART.
func (u *UART) Configure(config UARTConfig) {
en := u.SCGC.HasBits(u.SCGCMask)
func (u UART) Configure(config UARTConfig) {
u.configure(config, true)
}
// adapted from Teensy core's serial_begin
func (u UART) configure(config UARTConfig, canSched bool) {
// from: serial_begin
if !en {
if !u.Configured {
u.Transmitting.Set(0)
// turn on the clock
u.SCGC.Set(u.SCGCMask)
// configure pins
u.RXPCR.Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_PFE | nxp.PORT_PCR0_MUX(3))
u.TXPCR.Set(nxp.PORT_PCR0_DSE | nxp.PORT_PCR0_SRE | nxp.PORT_PCR0_MUX(3))
u.DefaultRX.Control().Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_PFE | (3 << nxp.PORT_PCR0_MUX_Pos))
u.DefaultTX.Control().Set(nxp.PORT_PCR0_DSE | nxp.PORT_PCR0_SRE | (3 << nxp.PORT_PCR0_MUX_Pos))
u.C1.Set(nxp.UART_C1_ILT)
}
@@ -89,14 +143,20 @@ func (u *UART) Configure(config UARTConfig) {
}
// copied from teensy core's BAUD2DIV macro
divisor := ((CPUFrequency() * 2) + ((config.BaudRate) >> 1)) / config.BaudRate
divisor := ((CPUFrequency() * 2) + (config.BaudRate >> 1)) / config.BaudRate
if divisor < 32 {
divisor = 32
}
if en {
if u.Configured {
// don't change baud rate mid transmit
u.Flush()
if canSched {
u.Flush()
} else {
for u.Transmitting.Get() != 0 {
// busy wait flush
}
}
}
// set the divisor
@@ -104,23 +164,27 @@ func (u *UART) Configure(config UARTConfig) {
u.BDL.Set(uint8((divisor >> 5) & 0xFF))
u.C4.Set(uint8(divisor & 0x1F))
if !en {
if !u.Configured {
u.Configured = true
u.C1.Set(nxp.UART_C1_ILT)
// configure TX and RX watermark
u.TWFIFO.Set(2) // causes bit TDRE of S1 to set
u.RWFIFO.Set(4) // causes bit RDRF of S1 to set
// enable FIFOs
u.PFIFO.Set(nxp.UART_PFIFO_TXFE | nxp.UART_PFIFO_RXFE)
u.C2.Set(uartC2TXInactive)
arm.SetPriority(u.IRQNumber, uartIRQPriority)
arm.EnableIRQ(u.IRQNumber)
// setup interrupts
u.C2.Set(uartC2TXInactive)
u.Interrupt.SetPriority(uartIRQPriority)
u.Interrupt.Enable()
}
}
func (u *UART) Disable() {
// adapted from Teensy core's serial_end
func (u UART) Disable() {
// from: serial_end
// check if the device has been enabled already
if !u.SCGC.HasBits(u.SCGCMask) {
@@ -129,27 +193,29 @@ func (u *UART) Disable() {
u.Flush()
arm.DisableIRQ(u.IRQNumber)
u.Interrupt.Disable()
u.C2.Set(0)
// reconfigure pin
u.RXPCR.Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_MUX(1))
u.TXPCR.Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_MUX(1))
u.DefaultRX.Configure(PinConfig{Mode: PinInputPullUp})
u.DefaultTX.Configure(PinConfig{Mode: PinInputPullUp})
// clear flags
u.S1.Get()
u.D.Get()
u.RXBuffer.Clear()
u.Buffer.Clear()
}
func (u *UART) Flush() {
func (u UART) Flush() {
for u.Transmitting.Get() != 0 {
// gosched()
gosched()
}
}
// adapted from Teensy core's uart0_status_isr
func (u *UART) handleStatusInterrupt() {
func (u UART) handleStatusInterrupt(interrupt.Interrupt) {
// from: uart0_status_isr
// receive
if u.S1.HasBits(nxp.UART_S1_RDRF | nxp.UART_S1_IDLE) {
intrs := arm.DisableInterrupts()
avail := u.RCFIFO.Get()
@@ -177,7 +243,7 @@ func (u *UART) handleStatusInterrupt() {
arm.EnableInterrupts(intrs)
for {
u.RXBuffer.Put(u.D.Get())
u.Buffer.Put(u.D.Get())
avail--
if avail <= 0 {
break
@@ -186,66 +252,54 @@ func (u *UART) handleStatusInterrupt() {
}
}
c := u.C2.Get()
if c&nxp.UART_C2_TIE != 0 && u.S1.HasBits(nxp.UART_S1_TDRE) {
for {
n, ok := u.TXBuffer.Get()
if !ok {
break
}
// transmit
if u.C2.HasBits(nxp.UART_C2_TIE) && u.S1.HasBits(nxp.UART_S1_TDRE) {
data := make([]byte, 0, uartTXFIFODepth)
avail := uartTXFIFODepth - u.TCFIFO.Get()
u.S1.Get()
u.D.Set(n)
if u.TCFIFO.Get() >= 8 {
// get avail bytes from ring buffer
for len(data) < int(avail) {
if b, ok := u.TXBuffer.Get(); ok {
data = append(data, b)
} else {
break
}
}
// write data to FIFO
l := len(data)
for i, b := range data {
if i == l-1 {
// only clear TDRE on last write, per the manual
u.S1.Get()
}
u.D.Set(b)
}
// if FIFO still has room, disable TIE, enable TCIE
if u.S1.HasBits(nxp.UART_S1_TDRE) {
u.Transmitting.Set(0)
u.C2.Set(uartC2TXCompleting)
}
}
if c&nxp.UART_C2_TCIE != 0 && u.S1.HasBits(nxp.UART_S1_TC) {
// transmit complete
if u.C2.HasBits(nxp.UART_C2_TCIE) && u.S1.HasBits(nxp.UART_S1_TC) {
u.Transmitting.Set(0)
u.C2.Set(uartC2TXInactive)
}
}
//go:linkname gosched runtime.Gosched
func gosched()
// WriteByte writes a byte of data to the UART.
func (u *UART) WriteByte(c byte) error {
if !u.SCGC.HasBits(u.SCGCMask) {
func (u UART) WriteByte(c byte) error {
if !u.Configured {
return ErrNotConfigured
}
for !u.S1.HasBits(nxp.UART_S1_TDRE) {
for !u.TXBuffer.Put(c) {
gosched()
}
u.D.Set(c)
// // wait for room on the buffer
// for !u.TXBuffer.Put(c) {
// gosched()
// }
// var wrote bool
// for u.S1.HasBits(nxp.UART_S1_TDRE) {
// n, ok := u.TXBuffer.Get()
// if ok {
// u.D.Set(n)
// wrote = true
// } else {
// break
// }
// }
// if wrote {
// u.Transmitting.Set(1)
// u.C2.Set(uartC2TXActive)
// }
u.Transmitting.Set(1)
u.C2.Set(uartC2TXActive)
return nil
}