Skip to content

Commit fbbaa5e

Browse files
cjpetersondenysvitaliofauchon
authored
Add ESP32-S3 support (#5091)
* feat: add initial support for ESP32-S3 (#3442) * feat: add initial support for esp32-s3 * esp32s3: fix merge errors * esp32s3: Fix Watchdog registers bad names * esp32s3: fix linker relocation errors and support for ESP binary * esp32s3: fix memory section overlap * esp32s3: correct clock frequencies * esp32s3: more stable cpu * esp32s3: enable basic gpio support * esp32s3: simplify loading and check extensions * esp32s3: synchronize cpu features with clang * esp32s3: correct iram origin --------- Co-authored-by: Denys Vitali <denys@denv.it> Co-authored-by: Olivier Fauchon <ofauchon2204@gmail.com>
1 parent 97a2cb4 commit fbbaa5e

File tree

9 files changed

+714
-3
lines changed

9 files changed

+714
-3
lines changed

builder/build.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1042,7 +1042,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
10421042
if err != nil {
10431043
return result, err
10441044
}
1045-
case "esp32", "esp32-img", "esp32c3", "esp8266":
1045+
case "esp32", "esp32-img", "esp32c3", "esp32s3", "esp8266":
10461046
// Special format for the ESP family of chips (parsed by the ROM
10471047
// bootloader).
10481048
result.Binary = filepath.Join(tmpdir, "main"+outext)

builder/builder_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func TestClangAttributes(t *testing.T) {
2828
"cortex-m4",
2929
"cortex-m7",
3030
"esp32c3",
31+
"esp32s3",
3132
"fe310",
3233
"gameboy-advance",
3334
"k210",

builder/esp.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,12 @@ func makeESPFirmwareImage(infile, outfile, format string) error {
100100
chip_id := map[string]uint16{
101101
"esp32": 0x0000,
102102
"esp32c3": 0x0005,
103+
"esp32s3": 0x0009,
103104
}[chip]
104105

105106
// Image header.
106107
switch chip {
107-
case "esp32", "esp32c3":
108+
case "esp32", "esp32c3", "esp32s3":
108109
// Header format:
109110
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
110111
// Note: not adding a SHA256 hash as the binary is modified by

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: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
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 xtalClock = 40_000000 // 40MHz
15+
const apbClock = 80_000000 // 80MHz
16+
const cryptoPWMClock = 160_000000 // 160MHz
17+
18+
// GetCPUFrequency returns the current CPU frequency of the chip.
19+
func GetCPUFrequency() (uint32, error) {
20+
switch esp.SYSTEM.GetSYSCLK_CONF_SOC_CLK_SEL() {
21+
case 0:
22+
return xtalClock / (esp.SYSTEM.GetSYSCLK_CONF_PRE_DIV_CNT() + 1), nil
23+
case 1:
24+
switch esp.SYSTEM.GetCPU_PER_CONF_CPUPERIOD_SEL() {
25+
case 0:
26+
return 80e6, nil
27+
case 1:
28+
return 160e6, nil
29+
case 2:
30+
// If esp.SYSTEM.GetCPU_PER_CONF_PLL_FREQ_SEL() == 1, this is undefined
31+
return 240e6, nil
32+
}
33+
case 2:
34+
//RC Fast Clock
35+
return (175e5) / (esp.SYSTEM.GetSYSCLK_CONF_PRE_DIV_CNT() + 1), nil
36+
}
37+
return 0, errors.New("machine: Unable to determine current cpu frequency")
38+
}
39+
40+
// SetCPUFrequency sets the frequency of the CPU to one of several targets
41+
func SetCPUFrequency(frequency uint32) error {
42+
// Always assume we are on PLL. Lower frequencies can be set with a different
43+
// clock source, but this will change the behavior of APB clock and Crypto PWM
44+
// clock
45+
//esp.SYSTEM.SetSYSCLK_CONF_SOC_CLK_SEL(1)
46+
47+
switch frequency {
48+
case 80_000000:
49+
esp.SYSTEM.SetCPU_PER_CONF_CPUPERIOD_SEL(0)
50+
esp.SYSTEM.SetCPU_PER_CONF_PLL_FREQ_SEL(0) // Reduce PLL freq when possible
51+
return nil
52+
case 160_000000:
53+
esp.SYSTEM.SetCPU_PER_CONF_CPUPERIOD_SEL(1)
54+
esp.SYSTEM.SetCPU_PER_CONF_PLL_FREQ_SEL(0)
55+
return nil
56+
case 240_000000:
57+
esp.SYSTEM.SetCPU_PER_CONF_PLL_FREQ_SEL(1) // Increase PLL freq when needed
58+
esp.SYSTEM.SetCPU_PER_CONF_CPUPERIOD_SEL(2)
59+
return nil
60+
}
61+
return errors.New("machine: Unsupported CPU frequency selected. Supported: 80, 160, 240 MHz")
62+
}
63+
64+
var (
65+
ErrInvalidSPIBus = errors.New("machine: invalid SPI bus")
66+
)
67+
68+
const (
69+
PinOutput PinMode = iota
70+
PinInput
71+
PinInputPullup
72+
PinInputPulldown
73+
)
74+
75+
// Hardware pin numbers
76+
const (
77+
GPIO0 Pin = 0
78+
GPIO1 Pin = 1
79+
GPIO2 Pin = 2
80+
GPIO3 Pin = 3
81+
GPIO4 Pin = 4
82+
GPIO5 Pin = 5
83+
GPIO6 Pin = 6
84+
GPIO7 Pin = 7
85+
GPIO8 Pin = 8
86+
GPIO9 Pin = 9
87+
GPIO10 Pin = 10
88+
GPIO11 Pin = 11
89+
GPIO12 Pin = 12
90+
GPIO13 Pin = 13
91+
GPIO14 Pin = 14
92+
GPIO15 Pin = 15
93+
GPIO16 Pin = 16
94+
GPIO17 Pin = 17
95+
GPIO18 Pin = 18
96+
GPIO19 Pin = 19
97+
GPIO20 Pin = 20
98+
GPIO21 Pin = 21
99+
GPIO26 Pin = 26
100+
GPIO27 Pin = 27
101+
GPIO28 Pin = 28
102+
GPIO29 Pin = 29
103+
GPIO30 Pin = 30
104+
GPIO31 Pin = 31
105+
GPIO32 Pin = 32
106+
GPIO33 Pin = 33
107+
GPIO34 Pin = 34
108+
GPIO35 Pin = 35
109+
GPIO36 Pin = 36
110+
GPIO37 Pin = 37
111+
GPIO38 Pin = 38
112+
GPIO39 Pin = 39
113+
GPIO40 Pin = 40
114+
GPIO41 Pin = 41
115+
GPIO42 Pin = 42
116+
GPIO43 Pin = 43
117+
GPIO44 Pin = 44
118+
GPIO45 Pin = 45
119+
GPIO46 Pin = 46
120+
GPIO47 Pin = 47
121+
GPIO48 Pin = 48
122+
)
123+
124+
// Configure this pin with the given configuration.
125+
func (p Pin) Configure(config PinConfig) {
126+
// Output function 256 is a special value reserved for use as a regular GPIO
127+
// pin. Peripherals (SPI etc) can set a custom output function by calling
128+
// lowercase configure() instead with a signal name.
129+
p.configure(config, 256)
130+
}
131+
132+
// configure is the same as Configure, but allows for setting a specific input
133+
// or output signal.
134+
// Signals are always routed through the GPIO matrix for simplicity. Output
135+
// signals are configured in FUNCx_OUT_SEL_CFG which selects a particular signal
136+
// to output on a given pin. Input signals are configured in FUNCy_IN_SEL_CFG,
137+
// which sets the pin to use for a particular input signal.
138+
func (p Pin) configure(config PinConfig, signal uint32) {
139+
if p == NoPin {
140+
// This simplifies pin configuration in peripherals such as SPI.
141+
return
142+
}
143+
144+
ioConfig := uint32(0)
145+
146+
// MCU_SEL: Function 1 is always GPIO
147+
ioConfig |= (1 << esp.IO_MUX_GPIO_MCU_SEL_Pos)
148+
149+
// FUN_IE: Make this pin an input pin (always set for GPIO operation)
150+
ioConfig |= esp.IO_MUX_GPIO_FUN_IE
151+
152+
// DRV: Set drive strength to 20 mA as a default. Pins 17 and 18 are special
153+
var drive uint32
154+
if p == GPIO17 || p == GPIO18 {
155+
drive = 1 // 20 mA
156+
} else {
157+
drive = 2 // 20 mA
158+
}
159+
ioConfig |= (drive << esp.IO_MUX_GPIO_FUN_DRV_Pos)
160+
161+
// WPU/WPD: Select pull mode.
162+
if config.Mode == PinInputPullup {
163+
ioConfig |= esp.IO_MUX_GPIO_FUN_WPU
164+
} else if config.Mode == PinInputPulldown {
165+
ioConfig |= esp.IO_MUX_GPIO_FUN_WPD
166+
}
167+
168+
// Set configuration
169+
ioRegister := p.ioMuxReg()
170+
ioRegister.Set(ioConfig)
171+
172+
switch config.Mode {
173+
case PinOutput:
174+
// Set the 'output enable' bit.
175+
if p < 32 {
176+
esp.GPIO.ENABLE_W1TS.Set(1 << p)
177+
} else {
178+
esp.GPIO.ENABLE1_W1TS.Set(1 << (p - 32))
179+
}
180+
// Set the signal to read the output value from. It can be a peripheral
181+
// output signal, or the special value 256 which indicates regular GPIO
182+
// usage.
183+
p.outFunc().Set(signal)
184+
case PinInput, PinInputPullup, PinInputPulldown:
185+
// Clear the 'output enable' bit.
186+
if p < 32 {
187+
esp.GPIO.ENABLE_W1TC.Set(1 << p)
188+
} else {
189+
esp.GPIO.ENABLE1_W1TC.Set(1 << (p - 32))
190+
}
191+
if signal != 256 {
192+
// Signal is a peripheral function (not a simple GPIO). Connect this
193+
// signal to the pin.
194+
// Note that outFunc and inFunc work in the opposite direction.
195+
// outFunc configures a pin to use a given output signal, while
196+
// inFunc specifies a pin to use to read the signal from.
197+
inFunc(signal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(p)<<esp.GPIO_FUNC_IN_SEL_CFG_IN_SEL_Pos)
198+
}
199+
}
200+
}
201+
202+
// ioMuxReg returns the IO_MUX_n_REG register used for configuring the io mux for
203+
// this pin
204+
func (p Pin) ioMuxReg() *volatile.Register32 {
205+
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.IO_MUX.GPIO0), uintptr(p)*4))
206+
}
207+
208+
// outFunc returns the FUNCx_OUT_SEL_CFG register used for configuring the
209+
// output function selection.
210+
func (p Pin) outFunc() *volatile.Register32 {
211+
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_OUT_SEL_CFG), uintptr(p)*4))
212+
}
213+
214+
// inFunc returns the FUNCy_IN_SEL_CFG register used for configuring the input
215+
// function selection.
216+
func inFunc(signal uint32) *volatile.Register32 {
217+
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_IN_SEL_CFG), uintptr(signal)*4))
218+
}
219+
220+
// Set the pin to high or low.
221+
// Warning: only use this on an output pin!
222+
func (p Pin) Set(value bool) {
223+
if value {
224+
reg, mask := p.portMaskSet()
225+
reg.Set(mask)
226+
} else {
227+
reg, mask := p.portMaskClear()
228+
reg.Set(mask)
229+
}
230+
}
231+
232+
// Return the register and mask to enable a given GPIO pin. This can be used to
233+
// implement bit-banged drivers.
234+
//
235+
// Warning: only use this on an output pin!
236+
func (p Pin) PortMaskSet() (*uint32, uint32) {
237+
reg, mask := p.portMaskSet()
238+
return &reg.Reg, mask
239+
}
240+
241+
// Return the register and mask to disable a given GPIO pin. This can be used to
242+
// implement bit-banged drivers.
243+
//
244+
// Warning: only use this on an output pin!
245+
func (p Pin) PortMaskClear() (*uint32, uint32) {
246+
reg, mask := p.portMaskClear()
247+
return &reg.Reg, mask
248+
}
249+
250+
func (p Pin) portMaskSet() (*volatile.Register32, uint32) {
251+
if p < 32 {
252+
return &esp.GPIO.OUT_W1TS, 1 << p
253+
} else {
254+
return &esp.GPIO.OUT1_W1TS, 1 << (p - 32)
255+
}
256+
}
257+
258+
func (p Pin) portMaskClear() (*volatile.Register32, uint32) {
259+
if p < 32 {
260+
return &esp.GPIO.OUT_W1TC, 1 << p
261+
} else {
262+
return &esp.GPIO.OUT1_W1TC, 1 << (p - 32)
263+
}
264+
}
265+
266+
// Get returns the current value of a GPIO pin when the pin is configured as an
267+
// input or as an output.
268+
func (p Pin) Get() bool {
269+
if p < 32 {
270+
return esp.GPIO.IN.Get()&(1<<p) != 0
271+
} else {
272+
return esp.GPIO.IN1.Get()&(1<<(p-32)) != 0
273+
}
274+
}
275+
276+
var DefaultUART = UART0
277+
278+
var (
279+
UART0 = &_UART0
280+
_UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()}
281+
UART1 = &_UART1
282+
_UART1 = UART{Bus: esp.UART1, Buffer: NewRingBuffer()}
283+
UART2 = &_UART2
284+
_UART2 = UART{Bus: esp.UART2, Buffer: NewRingBuffer()}
285+
)
286+
287+
type UART struct {
288+
Bus *esp.UART_Type
289+
Buffer *RingBuffer
290+
}
291+
292+
func (uart *UART) Configure(config UARTConfig) {
293+
if config.BaudRate == 0 {
294+
config.BaudRate = 115200
295+
}
296+
// Crystal clock source is selected by default
297+
uart.Bus.CLKDIV.Set(xtalClock / config.BaudRate)
298+
}
299+
300+
func (uart *UART) writeByte(b byte) error {
301+
for (uart.Bus.STATUS.Get()>>16)&0xff >= 128 {
302+
// Read UART_TXFIFO_CNT from the status register, which indicates how
303+
// many bytes there are in the transmit buffer. Wait until there are
304+
// less than 128 bytes in this buffer (the default buffer size).
305+
}
306+
uart.Bus.FIFO.Set(uint32(b))
307+
return nil
308+
}
309+
310+
func (uart *UART) flush() {}
311+
312+
// TODO: SPI

0 commit comments

Comments
 (0)