8000 feat: add initial support for ESP32-S3 (#3442) · tinygo-org/tinygo@9b45c6a · GitHub
[go: up one dir, main page]

Skip to content

Commit 9b45c6a

Browse files
committed
feat: add initial support for ESP32-S3 (#3442)
1 parent dc44988 commit 9b45c6a

File tree

7 files changed

+642
-2
lines changed

7 files changed

+642
-2
lines changed

lib/cmsis-svd

src/device/esp/esp32s3.S

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
2+
// The following definitions were copied from:
3+
// esp-idf/components/xtensa/include/xtensa/corebits.h
4+
#define PS_WOE_MASK 0x00040000
5+
#define PS_OWB_MASK 0x00000F00
6+
#define PS_CALLINC_MASK 0x00030000
7+
#define PS_WOE PS_WOE_MASK
8+
9+
// Only calling it call_start_cpu0 for consistency with ESP-IDF.
10+
.section .text.call_start_cpu0
11+
1:
12+
.long _stack_top
13+
.global call_start_cpu0
14+
call_start_cpu0:
15+
// We need to set the stack pointer to a different value. This is somewhat
16+
// complicated in the Xtensa architecture. The code below is a modified
17+
// version of the following code:
18+
// https://github.com/espressif/esp-idf/blob/c77c4ccf/components/xtensa/include/xt_instr_macros.h#L47
19+
20+
// Disable WOE.
21+
rsr.ps a2
22+
movi a3, ~(PS_WOE_MASK)
23+
and a2, a2, a3
24+
wsr.ps a2
25+
rsync
26+
27+
// Set WINDOWSTART to 1 << WINDOWBASE.
28+
rsr.windowbase a2
29+
ssl a2
30+
movi a2, 1
31+
sll a2, a2
32+
wsr.windowstart a2
33+
rsync
34+
35+
// Load new stack pointer.
36+
l32r sp, 1b
37+
38+
// Re-enable WOE.
39+
rsr.ps a2
40+
movi a3, PS_WOE
41+
or a2, a2, a3
42+
wsr.ps a2
43+
rsync
44+
45+
// Enable the FPU (coprocessor 0 so the lowest bit).
46+
movi a2, 1
47+
wsr.cpenable a2
48+
rsync
49+
50+
// Jump to the runtime start function written in Go.
51+
call4 main
52+
53+
.section .text.tinygo_scanCurrentStack
54+
.global tinygo_scanCurrentStack
55+
tinygo_scanCurrentStack:
56+
// TODO: save callee saved registers on the stack
57+
j tinygo_scanstack

src/internal/task/task_stack_esp32.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build scheduler.tasks && esp32
1+
//go:build scheduler.tasks && (esp32 || esp32s3)
22

33
package task
44

src/machine/machine_esp32s3.go

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
//go:build esp32s3
2+
3+
package machine
4+
5+
import (
6+
"device/esp"
7+
"errors"
8+
"runtime/volatile"
9+
"unsafe"
10+
)
11+
12+
const deviceName = esp.Device
13+
14+
const peripheralClock = 80000000 // 80MHz
15+
16+
// CPUFrequency returns the current CPU frequency of the chip.
17+
// Currently it is a fixed frequency but it may allow changing in the future.
18+
func CPUFrequency() uint32 {
19+
return 160e6 // 160MHz
20+
}
21+
22+
var (
23+
ErrInvalidSPIBus = errors.New("machine: invalid SPI bus")
24+
)
25+
26+
const (
27+
PinOutput PinMode = iota
28+
PinInput
29+
PinInputPullup
30+
PinInputPulldown
31+
)
32+
33+
// Hardware pin numbers
34+
const (
35+
GPIO0 Pin = 0
36+
GPIO1 Pin = 1
37+
GPIO2 Pin = 2
38+
GPIO3 Pin = 3
39+
GPIO4 Pin = 4
40+
GPIO5 Pin = 5
41+
GPIO6 Pin = 6
42+
GPIO7 Pin = 7
43+
GPIO8 Pin = 8
44+
GPIO9 Pin = 9
45+
GPIO10 Pin = 10
46+
GPIO11 Pin = 11
47+
GPIO12 Pin = 12
48+
GPIO13 Pin = 13
49+
GPIO14 Pin = 14
50+
GPIO15 Pin = 15
51+
GPIO16 Pin = 16
52+
GPIO17 Pin = 17
53+
GPIO18 Pin = 18
54+
GPIO19 Pin = 19
55+
GPIO21 Pin = 21
56+
GPIO22 Pin = 22
57+
GPIO23 Pin = 23
58+
GPIO25 Pin = 25
59+
GPIO26 Pin = 26
60+
GPIO27 Pin = 27
61+
GPIO32 Pin = 32
62+
GPIO33 Pin = 33
63+
GPIO34 Pin = 34
64+
GPIO35 Pin = 35
65+
GPIO36 Pin = 36
66+
GPIO37 Pin = 37
67+
GPIO38 Pin = 38
68+
GPIO39 Pin = 39
69+
GPIO40 Pin = 40
70+
GPIO41 Pin = 41
71+
GPIO42 Pin = 42
72+
GPIO43 Pin = 43
73+
GPIO44 Pin = 44
74+
)
75+
76+
// Configure this pin with the given configuration.
77+
func (p Pin) Configure(config PinConfig) {
78+
// Output function 256 is a special value reserved for use as a regular GPIO
79+
// pin. Peripherals (SPI etc) can set a custom output function by calling
80+
// lowercase configure() instead with a signal name.
81+
p.configure(config, 256)
82+
}
83+
84+
// configure is the same as Configure, but allows for setting a specific input
85+
// or output signal.
86+
// Signals are always routed through the GPIO matrix for simplicity. Output
87+
// signals are configured in FUNCx_OUT_SEL_CFG which selects a particular signal
88+
// to output on a given pin. Input signals are configured in FUNCy_IN_SEL_CFG,
89< 10000 /code>+
// which sets the pin to use for a particular input signal.
90+
func (p Pin) configure(config PinConfig, signal uint32) {
91+
if p == NoPin {
92+
// This simplifies pin configuration in peripherals such as SPI.
93+
return
94+
}
95+
96+
// TODO: Mux config
97+
}
98+
99+
// outFunc returns the FUNCx_OUT_SEL_CFG register used for configuring the
100+
// output function selection.
101+
func (p Pin) outFunc() *volatile.Register32 {
102+
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_OUT_SEL_CFG), uintptr(p)*4))
103+
}
104+
105+
// inFunc returns the FUNCy_IN_SEL_CFG register used for configuring the input
106+
// function selection.
107+
func inFunc(signal uint32) *volatile.Register32 {
108+
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_IN_SEL_CFG), uintptr(signal)*4))
109+
}
110+
111+
// Set the pin to high or low.
112+
// Warning: only use this on an output pin!
113+
func (p Pin) Set(value bool) {
114+
if value {
115+
reg, mask := p.portMaskSet()
116+
reg.Set(mask)
117+
} else {
118+
reg, mask := p.portMaskClear()
119+
reg.Set(mask)
120+
}
121+
}
122+
123+
// Return the register and mask to enable a given GPIO pin. This can be used to
124+
// implement bit-banged drivers.
125+
//
126+
// Warning: only use this on an output pin!
127+
func (p Pin) PortMaskSet() (*uint32, uint32) {
128+
reg, mask := p.portMaskSet()
129+
return &reg.Reg, mask
130+
}
131+
132+
// Return the register and mask to disable a given GPIO pin. This can be used to
133+
// implement bit-banged drivers.
134+
//
135+
// Warning: only use this on an output pin!
136+
func (p Pin) PortMaskClear() (*uint32, uint32) {
137+
reg, mask := p.portMaskClear()
138+
return &reg.Reg, mask
139+
}
140+
141+
func (p Pin) portMaskSet() (*volatile.Register32, uint32) {
142+
if p < 32 {
143+
return &esp.GPIO.OUT_W1TS, 1 << p
144+
} else {
145+
return &esp.GPIO.OUT1_W1TS, 1 << (p - 32)
146+
}
147+
}
148+
149+
func (p Pin) portMaskClear() (*volatile.Register32, uint32) {
150+
if p < 32 {
151+
return &esp.GPIO.OUT_W1TC, 1 << p
152+
} else {
153+
return &esp.GPIO.OUT1_W1TC, 1 << (p - 32)
154+
}
155+
}
156+
157+
// Get returns the current value of a GPIO pin when the pin is configured as an
158+
// input or as an output.
159+
func (p Pin) Get() bool {
160+
if p < 32 {
161+
return esp.GPIO.IN.Get()&(1<<p) != 0
162+
} else {
163+
return esp.GPIO.IN1.Get()&(1<<(p-32)) != 0
164+
}
165+
}
166+
167+
// TODO: Mux
168+
169+
var DefaultUART = UART0
170+
171+
var (
172+
UART0 = &_UART0
173+
_UART0 = UART{Bus: esp.UART1, Buffer: NewRingBuffer()}
174+
UART1 = &_UART1
175+
_UART1 = UART{Bus: esp.UART1, Buffer: NewRingBuffer()}
176+
UART2 = &_UART2
177+
_UART2 = UART{Bus: esp.UART2, Buffer: NewRingBuffer()}
178+
)
179+
180+
type UART struct {
181+
Bus *esp.UART_Type
182+
Buffer *RingBuffer
183+
}
184+
185+
func (uart *UART) Configure(config UARTConfig) {
186+
if config.BaudRate == 0 {
187+
config.BaudRate = 115200
188+
}
189+
uart.Bus.CLKDIV.Set(peripheralClock / config.BaudRate)
190+
}
191+
192+
func (uart *UART) writeByte(b byte) error {
193+
for (uart.Bus.STATUS.Get()>>16)&0xff >= 128 {
194+
// Read UART_TXFIFO_CNT from the status register, which indicates how
195+
// many bytes there are in the transmit buffer. Wait until there are
196+
// less than 128 bytes in this buffer (the default buffer size).
197+
}
198+
uart.Bus.FIFO.Set(uint32(b))
199+
return nil
200+
}
201+
202+
func (uart *UART) flush() {}
203+
204+
// TODO: SPI

0 commit comments

Comments
 (0)
0