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

Просмотреть файл

@ -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
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,4 +1,4 @@
// +build avr nrf sam sifive stm32 k210
// +build avr nrf sam sifive stm32 k210 nxp
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
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
}

Просмотреть файл

@ -1,5 +0,0 @@
// +build nxp
package runtime
type timeUnit int64

Просмотреть файл

@ -35,53 +35,41 @@ import (
"device/arm"
"device/nxp"
"machine"
"runtime/volatile"
)
const (
WDOG_UNLOCK_SEQ1 = 0xC520
WDOG_UNLOCK_SEQ2 = 0xD928
watchdogUnlockSequence1 = 0xC520
watchdogUnlockSequence2 = 0xD928
DEFAULT_FTM_MOD = 61440 - 1
DEFAULT_FTM_PRESCALE = 1
_DEFAULT_FTM_MOD = 61440 - 1
_DEFAULT_FTM_PRESCALE = 1
)
var (
SIM_SOPT2_IRC48SEL = nxp.SIM_SOPT2_PLLFLLSEL(3)
SMC_PMCTRL_HSRUN = nxp.SMC_PMCTRL_RUNM(3)
SMC_PMSTAT_HSRUN = nxp.SMC_PMSTAT_PMSTAT(0x80)
const (
_SIM_SOPT2_IRC48SEL = 3 << nxp.SIM_SOPT2_PLLFLLSEL_Pos
_SMC_PMCTRL_HSRUN = 3 << nxp.SMC_PMCTRL_RUNM_Pos
_SMC_PMSTAT_HSRUN = 0x80 << nxp.SMC_PMSTAT_PMSTAT_Pos
)
var bootMsg = []byte("\r\n\r\nStartup complete, running main\r\n\r\n")
//go:section .resetHandler
//go:export Reset_Handler
func main() {
initSystem()
arm.Asm("CPSIE i")
initInternal()
startupLateHook()
initAll()
machine.UART1.Configure(machine.UARTConfig{BaudRate: 115200})
for _, c := range bootMsg {
for !machine.UART1.S1.HasBits(nxp.UART_S1_TDRE) {
}
machine.UART1.D.Set(c)
}
callMain()
run()
abort()
}
// ported ResetHandler from mk20dx128.c from teensy3 core libraries
//go:noinline
func initSystem() {
nxp.WDOG.UNLOCK.Set(WDOG_UNLOCK_SEQ1)
nxp.WDOG.UNLOCK.Set(WDOG_UNLOCK_SEQ2)
// from: ResetHandler
nxp.WDOG.UNLOCK.Set(watchdogUnlockSequence1)
nxp.WDOG.UNLOCK.Set(watchdogUnlockSequence2)
arm.Asm("nop")
arm.Asm("nop")
startupEarlyHook()
// TODO: hook for overriding? 'startupEarlyHook'
nxp.WDOG.STCTRLH.Set(nxp.WDOG_STCTRLH_ALLOWUPDATE)
// enable clocks to always-used peripherals
nxp.SIM.SCGC3.Set(nxp.SIM_SCGC3_ADC1 | nxp.SIM_SCGC3_FTM2 | nxp.SIM_SCGC3_FTM3)
@ -117,9 +105,9 @@ func initSystem() {
// enable capacitors for crystal
nxp.OSC.CR.Set(nxp.OSC_CR_SC8P | nxp.OSC_CR_SC2P | nxp.OSC_CR_ERCLKEN)
// enable osc, 8-32 MHz range, low power mode
nxp.MCG.C2.Set(uint8(nxp.MCG_C2_RANGE(2) | nxp.MCG_C2_EREFS))
nxp.MCG.C2.Set(uint8((2 << nxp.MCG_C2_RANGE_Pos) | nxp.MCG_C2_EREFS))
// switch to crystal as clock source, FLL input = 16 MHz / 512
nxp.MCG.C1.Set(uint8(nxp.MCG_C1_CLKS(2) | nxp.MCG_C1_FRDIV(4)))
nxp.MCG.C1.Set(uint8((2 << nxp.MCG_C1_CLKS_Pos) | (4 << nxp.MCG_C1_FRDIV_Pos)))
// wait for crystal oscillator to begin
for !nxp.MCG.S.HasBits(nxp.MCG_S_OSCINIT0) {
}
@ -127,7 +115,7 @@ func initSystem() {
for nxp.MCG.S.HasBits(nxp.MCG_S_IREFST) {
}
// wait for MCGOUT to use oscillator
for (nxp.MCG.S.Get() & nxp.MCG_S_CLKST_Msk) != nxp.MCG_S_CLKST(2) {
for (nxp.MCG.S.Get() & nxp.MCG_S_CLKST_Msk) != (2 << nxp.MCG_S_CLKST_Pos) {
}
// now in FBE mode
@ -137,11 +125,11 @@ func initSystem() {
// C6[PLLS] bit is written to 0
// C2[LP] is written to 0
// we need faster than the crystal, turn on the PLL (F_CPU > 120000000)
nxp.SMC.PMCTRL.Set(SMC_PMCTRL_HSRUN) // enter HSRUN mode
for nxp.SMC.PMSTAT.Get() != SMC_PMSTAT_HSRUN {
nxp.SMC.PMCTRL.Set(_SMC_PMCTRL_HSRUN) // enter HSRUN mode
for nxp.SMC.PMSTAT.Get() != _SMC_PMSTAT_HSRUN {
} // wait for HSRUN
nxp.MCG.C5.Set(nxp.MCG_C5_PRDIV(1))
nxp.MCG.C6.Set(nxp.MCG_C6_PLLS | nxp.MCG_C6_VDIV(29))
nxp.MCG.C5.Set((1 << nxp.MCG_C5_PRDIV_Pos))
nxp.MCG.C6.Set(nxp.MCG_C6_PLLS | (29 << nxp.MCG_C6_VDIV_Pos))
// wait for PLL to start using xtal as its input
for !nxp.MCG.S.HasBits(nxp.MCG_S_PLLST) {
@ -153,18 +141,18 @@ func initSystem() {
// now program the clock dividers
// config divisors: 180 MHz core, 60 MHz bus, 25.7 MHz flash, USB = IRC48M
nxp.SIM.CLKDIV1.Set(nxp.SIM_CLKDIV1_OUTDIV1(0) | nxp.SIM_CLKDIV1_OUTDIV2(2) | nxp.SIM_CLKDIV1_OUTDIV4(6))
nxp.SIM.CLKDIV2.Set(nxp.SIM_CLKDIV2_USBDIV(0))
nxp.SIM.CLKDIV1.Set((0 << nxp.SIM_CLKDIV1_OUTDIV1_Pos) | (2 << nxp.SIM_CLKDIV1_OUTDIV2_Pos) | (0 << nxp.SIM_CLKDIV1_OUTDIV1_Pos) | (6 << nxp.SIM_CLKDIV1_OUTDIV4_Pos))
nxp.SIM.CLKDIV2.Set((0 << nxp.SIM_CLKDIV2_USBDIV_Pos))
// switch to PLL as clock source, FLL input = 16 MHz / 512
nxp.MCG.C1.Set(nxp.MCG_C1_CLKS(0) | nxp.MCG_C1_FRDIV(4))
nxp.MCG.C1.Set((0 << nxp.MCG_C1_CLKS_Pos) | (4 << nxp.MCG_C1_FRDIV_Pos))
// wait for PLL clock to be used
for (nxp.MCG.S.Get() & nxp.MCG_S_CLKST_Msk) != nxp.MCG_S_CLKST(3) {
for (nxp.MCG.S.Get() & nxp.MCG_S_CLKST_Msk) != (3 << nxp.MCG_S_CLKST_Pos) {
}
// now we're in PEE mode
// trace is CPU clock, CLKOUT=OSCERCLK0
// USB uses IRC48
nxp.SIM.SOPT2.Set(nxp.SIM_SOPT2_USBSRC | SIM_SOPT2_IRC48SEL | nxp.SIM_SOPT2_TRACECLKSEL | nxp.SIM_SOPT2_CLKOUTSEL(6))
nxp.SIM.SOPT2.Set(nxp.SIM_SOPT2_USBSRC | _SIM_SOPT2_IRC48SEL | nxp.SIM_SOPT2_TRACECLKSEL | (6 << nxp.SIM_SOPT2_CLKOUTSEL_Pos))
// If the RTC oscillator isn't enabled, get it started. For Teensy 3.6
// we don't do this early. See comment above about slow rising power.
@ -174,23 +162,19 @@ func initSystem() {
}
// initialize the SysTick counter
nxp.SysTick.RVR.Set((machine.CPUFrequency() / 1000) - 1)
nxp.SysTick.CVR.Set(0)
nxp.SysTick.CSR.Set(nxp.SysTick_CSR_CLKSOURCE | nxp.SysTick_CSR_TICKINT | nxp.SysTick_CSR_ENABLE)
nxp.SystemControl.SHPR3.Set(0x20200000) // Systick = priority 32
initSysTick()
}
// ported _init_Teensyduino_internal_ from pins_teensy.c from teensy3 core libraries
//go:noinline
func initInternal() {
arm.EnableIRQ(nxp.IRQ_PORTA)
arm.EnableIRQ(nxp.IRQ_PORTB)
arm.EnableIRQ(nxp.IRQ_PORTC)
arm.EnableIRQ(nxp.IRQ_PORTD)
arm.EnableIRQ(nxp.IRQ_PORTE)
// from: _init_Teensyduino_internal_
// arm.EnableIRQ(nxp.IRQ_PORTA)
// arm.EnableIRQ(nxp.IRQ_PORTB)
// arm.EnableIRQ(nxp.IRQ_PORTC)
// arm.EnableIRQ(nxp.IRQ_PORTD)
// arm.EnableIRQ(nxp.IRQ_PORTE)
nxp.FTM0.CNT.Set(0)
nxp.FTM0.MOD.Set(DEFAULT_FTM_MOD)
nxp.FTM0.MOD.Set(_DEFAULT_FTM_MOD)
nxp.FTM0.C0SC.Set(0x28) // MSnB:MSnA = 10, ELSnB:ELSnA = 10
nxp.FTM0.C1SC.Set(0x28)
nxp.FTM0.C2SC.Set(0x28)
@ -209,145 +193,45 @@ func initInternal() {
nxp.FTM3.C6SC.Set(0x28)
nxp.FTM3.C7SC.Set(0x28)
nxp.FTM0.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE))
nxp.FTM0.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos))
nxp.FTM1.CNT.Set(0)
nxp.FTM1.MOD.Set(DEFAULT_FTM_MOD)
nxp.FTM1.MOD.Set(_DEFAULT_FTM_MOD)
nxp.FTM1.C0SC.Set(0x28)
nxp.FTM1.C1SC.Set(0x28)
nxp.FTM1.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE))
nxp.FTM1.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos))
// causes a data bus error for unknown reasons
// nxp.FTM2.CNT.Set(0)
// nxp.FTM2.MOD.Set(DEFAULT_FTM_MOD)
// nxp.FTM2.MOD.Set(_DEFAULT_FTM_MOD)
// nxp.FTM2.C0SC.Set(0x28)
// nxp.FTM2.C1SC.Set(0x28)
// nxp.FTM2.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE))
// nxp.FTM2.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos))
nxp.FTM3.CNT.Set(0)
nxp.FTM3.MOD.Set(DEFAULT_FTM_MOD)
nxp.FTM3.MOD.Set(_DEFAULT_FTM_MOD)
nxp.FTM3.C0SC.Set(0x28)
nxp.FTM3.C1SC.Set(0x28)
nxp.FTM3.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE))
nxp.FTM3.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (_DEFAULT_FTM_PRESCALE << nxp.FTM_SC_PS_Pos))
nxp.SIM.SCGC2.SetBits(nxp.SIM_SCGC2_TPM1)
nxp.SIM.SOPT2.SetBits(nxp.SIM_SOPT2_TPMSRC(2))
nxp.SIM.SOPT2.SetBits((2 << nxp.SIM_SOPT2_TPMSRC_Pos))
nxp.TPM1.CNT.Set(0)
nxp.TPM1.MOD.Set(32767)
nxp.TPM1.C0SC.Set(0x28)
nxp.TPM1.C1SC.Set(0x28)
nxp.TPM1.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(0))
nxp.TPM1.SC.Set((1 << nxp.FTM_SC_CLKS_Pos) | (0 << nxp.FTM_SC_PS_Pos))
// configure the low-power timer
// nxp.LPTMR0.CSR.Set(nxp.LPTMR0_CSR_TIE)
// nxp.LPTMR0.PSR.Set(nxp.LPTMR0_PSR_PCS(3) | nxp.LPTMR0_PSR_PRESCALE(1)) // use main (external) clock, divided by 4
// arm.EnableIRQ(nxp.IRQ_LPTMR0)
// configure the sleep timer
initSleepTimer()
// analog_init();
// #if !defined(TEENSY_INIT_USB_DELAY_BEFORE)
// #if TEENSYDUINO >= 142
// #define TEENSY_INIT_USB_DELAY_BEFORE 25
// #else
// #define TEENSY_INIT_USB_DELAY_BEFORE 50
// #endif
// #endif
// #if !defined(TEENSY_INIT_USB_DELAY_AFTER)
// #if TEENSYDUINO >= 142
// #define TEENSY_INIT_USB_DELAY_AFTER 275
// #else
// #define TEENSY_INIT_USB_DELAY_AFTER 350
// #endif
// #endif
// // for background about this startup delay, please see these conversations
// // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
// // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
// delay(TEENSY_INIT_USB_DELAY_BEFORE);
// usb_init();
// delay(TEENSY_INIT_USB_DELAY_AFTER);
}
func startupEarlyHook() {
// TODO allow override
// > programs using the watchdog timer or needing to initialize hardware as
// > early as possible can implement startup_early_hook()
nxp.WDOG.STCTRLH.Set(nxp.WDOG_STCTRLH_ALLOWUPDATE)
}
func startupLateHook() {
// TODO allow override
}
func postinit() {}
func putchar(c byte) {
machine.UART1.WriteByte(c)
machine.PutcharUART(&machine.UART0, c)
}
// ???
const asyncScheduler = false
// microseconds per tick
const tickMicros = 1000
// number of ticks since boot
var tickMilliCount volatile.Register32
//go:export SysTick_Handler
func tickHandler() {
tickMilliCount.Set(tickMilliCount.Get() + 1)
}
// ticks are in microseconds
func ticks() timeUnit {
m := arm.DisableInterrupts()
current := nxp.SysTick.CVR.Get()
count := tickMilliCount.Get()
istatus := nxp.SystemControl.ICSR.Get()
arm.EnableInterrupts(m)
if istatus&nxp.SystemControl_ICSR_PENDSTSET != 0 && current > 50 {
count++
}
current = ((machine.CPUFrequency() / tickMicros) - 1) - current
return timeUnit(count*tickMicros + current/(machine.CPUFrequency()/1000000))
}
// sleepTicks spins for a number of microseconds
func sleepTicks(d timeUnit) {
// TODO actually sleep
if d <= 0 {
return
}
start := ticks()
ms := d / 1000
for {
for ticks()-start >= 1000 {
ms--
if ms <= 0 {
return
}
start += 1000
}
arm.Asm("wfi")
}
}
func Sleep(d int64) {
sleepTicks(timeUnit(d))
}
// func abort() {
// for {
// // keep polling some communication while in fault
// // mode, so we don't completely die.
// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_USBOTG) usb_isr();
// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_UART0) uart0_status_isr();
// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_UART1) uart1_status_isr();
// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_UART2) uart2_status_isr();
// }
// }

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 registerEnd = 0x40100000
const bitbandBase = 0x42000000
const ptrBytes = unsafe.Sizeof(uintptr(0))
//go:inline
func bitbandAddress(reg uintptr, bit uint8) uintptr {
if uintptr(bit) > ptrBytes*8 {
if uintptr(bit) > 32 {
panic("invalid bit position")
}
if reg < registerBase || reg >= registerEnd {
panic("register is out of range")
}
return (reg-registerBase)*ptrBytes*8 + uintptr(bit)*ptrBytes + bitbandBase
return (reg-registerBase)*32 + uintptr(bit)*4 + bitbandBase
}
// Special types that causes loads/stores to be volatile (necessary for

Просмотреть файл

@ -5,8 +5,8 @@ ENTRY(Reset_Handler)
/* define memory layout */
MEMORY
{
FLASH_TEXT (rx) : ORIGIN = 0x00000000, LENGTH = 1024K
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K
FLASH_TEXT (rx) : ORIGIN = 0x00000000, LENGTH = 1024K
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K
}
_stack_size = 2K;
@ -18,21 +18,18 @@ SECTIONS
.text :
{
/* vector table MUST start at 0x0 */
. = 0;
_vector_table = .;
. = 0;
KEEP(*(.isr_vector))
/* flash configuration MUST be at 0x400 */
. = 0x400;
_flash_config = .;
KEEP(*(.flash_config))
KEEP(*(.flash_config))
/* everything else */
*(.resetHandler)
*(.text)
*(.text*)
*(.text.*)
*(.rodata)
*(.rodata*)
*(.rodata.*)
. = ALIGN(4);
} >FLASH_TEXT = 0xFF
@ -50,7 +47,7 @@ SECTIONS
/* Start address (in flash) of .data, used by startup code. */
_sidata = LOADADDR(.data);
/* todo add .usbdescriptortable .dmabuffers .usbbuffers */
/* this is where Teensy's LD script places .usbdescriptortable .dmabuffers .usbbuffers */
/* Globals with initial value */
.data :
@ -58,7 +55,7 @@ SECTIONS
. = ALIGN(4);
_sdata = .; /* used by startup code */
*(.data)
*(.data*)
*(.data.*)
. = ALIGN(4);
_edata = .; /* used by startup code */
} >RAM AT>FLASH_TEXT
@ -69,7 +66,7 @@ SECTIONS
. = ALIGN(4);
_sbss = .; /* used by startup code */
*(.bss)
*(.bss*)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* used by startup code */
@ -79,11 +76,6 @@ SECTIONS
{
*(.ARM.exidx) /* causes 'no memory region specified' error in lld */
*(.ARM.exidx.*) /* causes spurious 'undefined reference' errors */
/* all this makes it much harder to debug via disassembly */
*(.debug*)
*(.ARM.*)
*(.comment*)
}
}

Просмотреть файл

@ -1,7 +1,8 @@
.section .flash_config
.global __flash_config
.byte 0xFF
__flash_config:
.byte 0xFF
.byte 0xFF
.byte 0xFF
.byte 0xFF
.byte 0xFF
@ -9,11 +10,10 @@
.byte 0xFF
.byte 0xFF
.byte 0xFF
.byte 0xFF
.byte 0xFF
.byte 0xFF
.byte 0xFF
.byte 0xDE
.byte 0xF9
.byte 0xFF
.byte 0xFF
.byte 0xFF