Viable NXP/Teensy support
- Fix UART & putChar - Timer-based sleep - Enable systick in abort - Buffered, interrupt-based UART TX - Use the new interrupt API and fix sleepTicks - Make pins behave more like other boards - Use the MCU's UART numbering - Allow interrupts to wake the scheduler (#1214)
Этот коммит содержится в:
родитель
59218cd784
коммит
4750635a20
11 изменённых файлов: 728 добавлений и 456 удалений
|
@ -2,91 +2,100 @@
|
|||
|
||||
package machine
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
if canSched {
|
||||
u.Flush()
|
||||
} else {
|
||||
for u.Transmitting.Get() != 0 {
|
||||
// busy wait flush
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set the divisor
|
||||
|
@ -104,23 +164,27 @@ func (u *UART) Configure(config UARTConfig) {
|
|||
u.BDL.Set(uint8((divisor >> 5) & 0xFF))
|
||||
u.C4.Set(uint8(divisor & 0x1F))
|
||||
|
||||
if !en {
|
||||
if !u.Configured {
|
||||
u.Configured = true
|
||||
|
||||
u.C1.Set(nxp.UART_C1_ILT)
|
||||
|
||||
// configure TX and RX watermark
|
||||
u.TWFIFO.Set(2) // causes bit TDRE of S1 to set
|
||||
u.RWFIFO.Set(4) // causes bit RDRF of S1 to set
|
||||
|
||||
// enable FIFOs
|
||||
u.PFIFO.Set(nxp.UART_PFIFO_TXFE | nxp.UART_PFIFO_RXFE)
|
||||
u.C2.Set(uartC2TXInactive)
|
||||
|
||||
arm.SetPriority(u.IRQNumber, uartIRQPriority)
|
||||
arm.EnableIRQ(u.IRQNumber)
|
||||
// setup interrupts
|
||||
u.C2.Set(uartC2TXInactive)
|
||||
u.Interrupt.SetPriority(uartIRQPriority)
|
||||
u.Interrupt.Enable()
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UART) Disable() {
|
||||
// adapted from Teensy core's serial_end
|
||||
func (u UART) Disable() {
|
||||
// from: serial_end
|
||||
|
||||
// check if the device has been enabled already
|
||||
if !u.SCGC.HasBits(u.SCGCMask) {
|
||||
|
@ -129,27 +193,29 @@ func (u *UART) Disable() {
|
|||
|
||||
u.Flush()
|
||||
|
||||
arm.DisableIRQ(u.IRQNumber)
|
||||
u.Interrupt.Disable()
|
||||
u.C2.Set(0)
|
||||
|
||||
// reconfigure pin
|
||||
u.RXPCR.Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_MUX(1))
|
||||
u.TXPCR.Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_MUX(1))
|
||||
u.DefaultRX.Configure(PinConfig{Mode: PinInputPullUp})
|
||||
u.DefaultTX.Configure(PinConfig{Mode: PinInputPullUp})
|
||||
|
||||
// clear flags
|
||||
u.S1.Get()
|
||||
u.D.Get()
|
||||
u.RXBuffer.Clear()
|
||||
u.Buffer.Clear()
|
||||
}
|
||||
|
||||
func (u *UART) Flush() {
|
||||
func (u UART) Flush() {
|
||||
for u.Transmitting.Get() != 0 {
|
||||
// gosched()
|
||||
gosched()
|
||||
}
|
||||
}
|
||||
|
||||
// adapted from Teensy core's uart0_status_isr
|
||||
func (u *UART) handleStatusInterrupt() {
|
||||
func (u UART) handleStatusInterrupt(interrupt.Interrupt) {
|
||||
// from: uart0_status_isr
|
||||
|
||||
// receive
|
||||
if u.S1.HasBits(nxp.UART_S1_RDRF | nxp.UART_S1_IDLE) {
|
||||
intrs := arm.DisableInterrupts()
|
||||
avail := u.RCFIFO.Get()
|
||||
|
@ -177,7 +243,7 @@ func (u *UART) handleStatusInterrupt() {
|
|||
arm.EnableInterrupts(intrs)
|
||||
|
||||
for {
|
||||
u.RXBuffer.Put(u.D.Get())
|
||||
u.Buffer.Put(u.D.Get())
|
||||
avail--
|
||||
if avail <= 0 {
|
||||
break
|
||||
|
@ -186,66 +252,54 @@ func (u *UART) handleStatusInterrupt() {
|
|||
}
|
||||
}
|
||||
|
||||
c := u.C2.Get()
|
||||
if c&nxp.UART_C2_TIE != 0 && u.S1.HasBits(nxp.UART_S1_TDRE) {
|
||||
for {
|
||||
n, ok := u.TXBuffer.Get()
|
||||
if !ok {
|
||||
// transmit
|
||||
if u.C2.HasBits(nxp.UART_C2_TIE) && u.S1.HasBits(nxp.UART_S1_TDRE) {
|
||||
data := make([]byte, 0, uartTXFIFODepth)
|
||||
avail := uartTXFIFODepth - u.TCFIFO.Get()
|
||||
|
||||
// get avail bytes from ring buffer
|
||||
for len(data) < int(avail) {
|
||||
if b, ok := u.TXBuffer.Get(); ok {
|
||||
data = append(data, b)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 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(n)
|
||||
|
||||
if u.TCFIFO.Get() >= 8 {
|
||||
break
|
||||
}
|
||||
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
Обычный файл
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
|
|
@ -19,20 +19,17 @@ SECTIONS
|
|||
{
|
||||
/* vector table MUST start at 0x0 */
|
||||
. = 0;
|
||||
_vector_table = .;
|
||||
KEEP(*(.isr_vector))
|
||||
|
||||
/* flash configuration MUST be at 0x400 */
|
||||
. = 0x400;
|
||||
_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,6 +1,6 @@
|
|||
|
||||
.section .flash_config
|
||||
.global __flash_config
|
||||
__flash_config:
|
||||
.byte 0xFF
|
||||
.byte 0xFF
|
||||
.byte 0xFF
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче