Skip to content

Commit 5f66260

Browse files
committed
machine,targets: add minimal esp32c6 implementation
This adds a minimal esp32c6 implementation, currently only supporting the examples/serial and examples/blinky1 programs. It does correctly output the expected "Hello, World" via the serial port, as well as blink the onboard LED. In addition, it adds support for the PLIC based IRQ handling as used on the ESP32C6 processor. Some parts of this code are loosely based on PR #5252 and #5248 Signed-off-by: deadprogram <ron@hybridgroup.com>
1 parent ba95eb3 commit 5f66260

14 files changed

Lines changed: 1616 additions & 5 deletions

GNUmakefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,9 @@ ifneq ($(XTENSA), 0)
960960
@$(MD5SUM) test.bin
961961
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
962962
@$(MD5SUM) test.bin
963+
# xiao-esp32c6
964+
$(TINYGO) build -size short -o test.bin -target=xiao-esp32c6 examples/blinky1
965+
@$(MD5SUM) test.bin
963966
# xiao-esp32s3
964967
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinky1
965968
@$(MD5SUM) test.bin

builder/build.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
10761076
if err != nil {
10771077
return result, err
10781078
}
1079-
case "esp32", "esp32-img", "esp32c3", "esp32s3", "esp8266":
1079+
case "esp32", "esp32-img", "esp32c3", "esp32s3", "esp32c6", "esp8266":
10801080
// Special format for the ESP family of chips (parsed by the ROM
10811081
// bootloader).
10821082
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+
"esp32c6",
3132
"esp32s3",
3233
"fe310",
3334
"gameboy-advance",

builder/esp.go

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

107+
// SPI flash speed/size byte (byte 3 of header):
108+
// Upper nibble = flash size, lower nibble = flash frequency.
109+
// The espflasher auto-detects and patches the flash size (upper nibble),
110+
// but the frequency (lower nibble) must be correct per chip.
111+
spiSpeedSize := map[string]uint8{
112+
"esp32": 0x1f, // 80MHz=0x0F, 2MB=0x10
113+
"esp32c3": 0x1f, // 80MHz=0x0F, 2MB=0x10
114+
"esp32c6": 0x10, // 80MHz=0x00, 2MB=0x10 (C6 uses different freq encoding)
115+
"esp32s3": 0x1f, // 80MHz=0x0F, 2MB=0x10
116+
}[chip]
117+
106118
// Image header.
107119
switch chip {
108-
case "esp32", "esp32c3", "esp32s3":
120+
case "esp32", "esp32c3", "esp32s3", "esp32c6":
109121
// Header format:
110122
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
111123
// Note: not adding a SHA256 hash as the binary is modified by
@@ -126,8 +138,8 @@ func makeESPFirmwareImage(infile, outfile, format string) error {
126138
}{
127139
magic: 0xE9,
128140
segment_count: byte(len(segments)),
129-
spi_mode: 2, // ESP_IMAGE_SPI_MODE_DIO
130-
spi_speed_size: 0x1f, // ESP_IMAGE_SPI_SPEED_80M, ESP_IMAGE_FLASH_SIZE_2MB
141+
spi_mode: 2, // ESP_IMAGE_SPI_MODE_DIO
142+
spi_speed_size: spiSpeedSize,
131143
entry_addr: uint32(inf.Entry),
132144
wp_pin: 0xEE, // disable WP pin
133145
chip_id: chip_id,

src/device/esp/esp32c6.S

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// This is a very minimal bootloader for the ESP32-C6. It only initializes the
2+
// flash and then continues with the generic RISC-V initialization code, which
3+
// in turn will call runtime.main.
4+
// It is written in assembly (and not in a higher level language) to make sure
5+
// it is entirely loaded into IRAM and doesn't accidentally call functions
6+
// stored in IROM.
7+
//
8+
// The ESP32-C6 has a unified IRAM/DRAM address space at 0x40800000, and
9+
// separate DROM (0x42800000) / IROM (0x42000000) flash-mapped regions.
10+
11+
.section .init
12+
.global call_start_cpu0
13+
.type call_start_cpu0,@function
14+
call_start_cpu0:
15+
// At this point:
16+
// - The ROM bootloader is finished and has jumped to here.
17+
// - We're running from IRAM: both IRAM and DRAM segments have been loaded
18+
// by the ROM bootloader.
19+
// - We have a usable stack (but not the one we would like to use).
20+
// - No flash mappings (MMU) are set up yet.
21+
22+
// Reset MMU, see bootloader_reset_mmu in the ESP-IDF.
23+
call Cache_Suspend_ICache
24+
mv s0, a0 // autoload value
25+
call Cache_Invalidate_ICache_All
26+
call Cache_MMU_Init
27+
28+
// Set up flash mapping (both IROM and DROM).
29+
// On ESP32-C6, Cache_Dbus_MMU_Set is replaced by Cache_MSPI_MMU_Set
30+
// which has an extra "sensitive" parameter.
31+
// C equivalent:
32+
// Cache_MSPI_MMU_Set(0, 0, 0x42000000, 0, 64, 256, 0)
33+
// Maps 16MB starting at 0x42000000, covering both IROM and DROM.
34+
li a0, 0 // sensitive: no flash encryption
35+
li a1, 0 // ext_ram: MMU_ACCESS_FLASH
36+
li a2, 0x42000000 // vaddr: start of flash-mapped region
37+
li a3, 0 // paddr: physical address in the flash chip
38+
li a4, 64 // psize: always 64 (kilobytes)
39+
li a5, 256 // num: pages (16MB / 64K = 256, covers IROM+DROM)
40+
li a6, 0 // fixed
41+
call Cache_MSPI_MMU_Set
42+
43+
// Enable the flash cache.
44+
mv a0, s0 // restore autoload value from Cache_Suspend_ICache call
45+
call Cache_Resume_ICache
46+
47+
// Jump to generic RISC-V initialization, which initializes the stack
48+
// pointer and globals register. It should not return.
49+
j _start
50+
51+
.section .text.exception_vectors
52+
.global _vector_table
53+
.type _vector_table,@function
54+
55+
_vector_table:
56+
57+
.option push
58+
.option norvc
59+
60+
.rept 32
61+
j handleInterruptASM /* interrupt handler */
62+
.endr
63+
64+
.option pop
65+
66+
.size _vector_table, .-_vector_table

src/machine/board_xiao-esp32c6.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//go:build xiao_esp32c6
2+
3+
// This file contains the pin mappings for the Seeed XIAO ESP32C6 board.
4+
//
5+
// Seeed Studio XIAO ESP32C6 is an IoT mini development board based on
6+
// the Espressif ESP32-C6 WiFi 6 / Bluetooth 5 / 802.15.4 chip.
7+
//
8+
// - https://www.seeedstudio.com/Seeed-Studio-XIAO-ESP32C6-p-5884.html
9+
// - https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/
10+
11+
package machine
12+
13+
// Digital Pins
14+
const (
15+
D0 = GPIO0
16+
D1 = GPIO1
17+
D2 = GPIO2
18+
D3 = GPIO21
19+
D4 = GPIO22
20+
D5 = GPIO23
21+
D6 = GPIO16
22+
D7 = GPIO17
23+
D8 = GPIO19
24+
D9 = GPIO20
25+
D10 = GPIO18
26+
)
27+
28+
// Analog pins
29+
const (
30+
A0 = GPIO0
31+
A1 = GPIO1
32+
A2 = GPIO2
33+
)
34+
35+
// UART pins
36+
const (
37+
UART_TX_PIN = GPIO16
38+
UART_RX_PIN = GPIO17
39+
)
40+
41+
// I2C pins
42+
const (
43+
SDA_PIN = GPIO22
44+
SCL_PIN = GPIO23
45+
)
46+
47+
// SPI pins
48+
const (
49+
SPI_SCK_PIN = GPIO19
50+
SPI_SDI_PIN = GPIO20
51+
SPI_SDO_PIN = GPIO18
52+
)
53+
54+
// Onboard LEDs
55+
const (
56+
LED = GPIO15
57+
)

0 commit comments

Comments
 (0)