Skip to content

Commit 4044f53

Browse files
committed
Add support for flashing the ESP32-C3
1 parent b61cce3 commit 4044f53

File tree

5 files changed

+173
-4
lines changed

5 files changed

+173
-4
lines changed

cargo-espflash/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ fn usage() -> Result<()> {
7676
[--ram] \
7777
[--release] \
7878
[--example EXAMPLE] \
79-
[--chip {{esp32,esp8266}}] \
79+
[--chip {{esp32,esp32c3,esp8266}}] \
8080
[--speed BAUD] \
8181
<serial>";
8282

19.4 KB
Binary file not shown.

espflash/src/chip/esp32c3.rs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
use bytemuck::bytes_of;
2+
use sha2::{Digest, Sha256};
3+
4+
use crate::{
5+
chip::{
6+
encode_flash_size, get_segment_padding, save_flash_segment, save_segment, Chip, ChipType,
7+
EspCommonHeader, ExtendedHeader, SegmentHeader, SpiRegisters, ESP_MAGIC, SEG_HEADER_LEN,
8+
WP_PIN_DISABLED,
9+
},
10+
elf::{FirmwareImage, RomSegment, ESP_CHECKSUM_MAGIC},
11+
partition_table::PartitionTable,
12+
Error,
13+
};
14+
15+
use std::{borrow::Cow, io::Write, iter::once};
16+
17+
pub struct Esp32c3;
18+
19+
const IROM_MAP_START: u32 = 0x42000000;
20+
const IROM_MAP_END: u32 = 0x42800000;
21+
22+
const DROM_MAP_START: u32 = 0x3c000000;
23+
const DROM_MAP_END: u32 = 0x3c800000;
24+
25+
const BOOT_ADDR: u32 = 0x0;
26+
const PARTITION_ADDR: u32 = 0x8000;
27+
const APP_ADDR: u32 = 0x10000;
28+
29+
impl ChipType for Esp32c3 {
30+
const CHIP_DETECT_MAGIC_VALUE: u32 = 0x6921506f;
31+
const CHIP_DETECT_MAGIC_VALUE2: u32 = 0x1b31506f;
32+
33+
const SPI_REGISTERS: SpiRegisters = SpiRegisters {
34+
base: 0x60002000,
35+
usr_offset: 0x18,
36+
usr1_offset: 0x1C,
37+
usr2_offset: 0x20,
38+
w0_offset: 0x58,
39+
mosi_length_offset: Some(0x24),
40+
miso_length_offset: Some(0x28),
41+
};
42+
43+
fn addr_is_flash(addr: u32) -> bool {
44+
(IROM_MAP_START..IROM_MAP_END).contains(&addr)
45+
|| (DROM_MAP_START..DROM_MAP_END).contains(&addr)
46+
}
47+
48+
fn get_flash_segments<'a>(
49+
image: &'a FirmwareImage,
50+
) -> Box<dyn Iterator<Item = Result<RomSegment<'a>, Error>> + 'a> {
51+
let bootloader = include_bytes!("../../bootloader/esp32c3-bootloader.bin");
52+
53+
let partition_table = PartitionTable::basic(0x10000, 0x3f0000).to_bytes();
54+
55+
fn get_data<'a>(image: &'a FirmwareImage) -> Result<RomSegment<'a>, Error> {
56+
let mut data = Vec::new();
57+
58+
let header = EspCommonHeader {
59+
magic: ESP_MAGIC,
60+
segment_count: 0,
61+
flash_mode: image.flash_mode as u8,
62+
flash_config: encode_flash_size(image.flash_size)? + image.flash_frequency as u8,
63+
entry: image.entry,
64+
};
65+
data.write_all(bytes_of(&header))?;
66+
67+
let extended_header = ExtendedHeader {
68+
wp_pin: WP_PIN_DISABLED,
69+
clk_q_drv: 0,
70+
d_cs_drv: 0,
71+
gd_wp_drv: 0,
72+
chip_id: 5,
73+
min_rev: 0,
74+
padding: [0; 8],
75+
append_digest: 1,
76+
};
77+
data.write_all(bytes_of(&extended_header))?;
78+
79+
let mut checksum = ESP_CHECKSUM_MAGIC;
80+
81+
let _ = image.segments().collect::<Vec<_>>();
82+
83+
let mut flash_segments: Vec<_> = image.rom_segments(Chip::Esp32c3).collect();
84+
flash_segments.sort();
85+
let mut ram_segments: Vec<_> = image.ram_segments(Chip::Esp32c3).collect();
86+
ram_segments.sort();
87+
let mut ram_segments = ram_segments.into_iter();
88+
89+
let mut segment_count = 0;
90+
91+
for segment in flash_segments {
92+
loop {
93+
let pad_len = get_segment_padding(data.len(), &segment);
94+
if pad_len > 0 {
95+
if pad_len > SEG_HEADER_LEN {
96+
if let Some(ram_segment) = ram_segments.next() {
97+
checksum = save_segment(&mut data, &ram_segment, checksum)?;
98+
segment_count += 1;
99+
continue;
100+
}
101+
}
102+
let pad_header = SegmentHeader {
103+
addr: 0,
104+
length: pad_len as u32,
105+
};
106+
data.write_all(bytes_of(&pad_header))?;
107+
for _ in 0..pad_len {
108+
data.write_all(&[0])?;
109+
}
110+
segment_count += 1;
111+
} else {
112+
break;
113+
}
114+
}
115+
checksum = save_flash_segment(&mut data, &segment, checksum)?;
116+
segment_count += 1;
117+
}
118+
119+
for segment in ram_segments {
120+
checksum = save_segment(&mut data, &segment, checksum)?;
121+
segment_count += 1;
122+
}
123+
124+
let padding = 15 - (data.len() % 16);
125+
let padding = &[0u8; 16][0..padding as usize];
126+
data.write_all(padding)?;
127+
128+
data.write_all(&[checksum])?;
129+
130+
// since we added some dummy segments, we need to patch the segment count
131+
data[1] = segment_count as u8;
132+
133+
let mut hasher = Sha256::new();
134+
hasher.update(&data);
135+
let hash = hasher.finalize();
136+
data.write_all(&hash)?;
137+
138+
Ok(RomSegment {
139+
addr: APP_ADDR,
140+
data: Cow::Owned(data),
141+
})
142+
}
143+
144+
Box::new(
145+
once(Ok(RomSegment {
146+
addr: BOOT_ADDR,
147+
data: Cow::Borrowed(bootloader),
148+
}))
149+
.chain(once(Ok(RomSegment {
150+
addr: PARTITION_ADDR,
151+
data: Cow::Owned(partition_table),
152+
})))
153+
.chain(once(get_data(image))),
154+
)
155+
}
156+
}

espflash/src/chip/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ use crate::{
99
use std::{io::Write, str::FromStr};
1010

1111
pub use esp32::Esp32;
12+
pub use esp32c3::Esp32c3;
1213
pub use esp8266::Esp8266;
1314

1415
mod esp32;
16+
mod esp32c3;
1517
mod esp8266;
1618

1719
const ESP_MAGIC: u8 = 0xE9;
@@ -87,13 +89,17 @@ struct ExtendedHeader {
8789
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
8890
pub enum Chip {
8991
Esp32,
92+
Esp32c3,
9093
Esp8266,
9194
}
9295

9396
impl Chip {
9497
pub fn from_magic(magic: u32) -> Option<Self> {
9598
match magic {
9699
Esp32::CHIP_DETECT_MAGIC_VALUE => Some(Chip::Esp32),
100+
Esp32c3::CHIP_DETECT_MAGIC_VALUE | Esp32c3::CHIP_DETECT_MAGIC_VALUE2 => {
101+
Some(Chip::Esp32c3)
102+
}
97103
Esp8266::CHIP_DETECT_MAGIC_VALUE => Some(Chip::Esp8266),
98104
_ => None,
99105
}
@@ -105,20 +111,23 @@ impl Chip {
105111
) -> Box<dyn Iterator<Item = Result<RomSegment<'a>, Error>> + 'a> {
106112
match self {
107113
Chip::Esp32 => Esp32::get_flash_segments(image),
114+
Chip::Esp32c3 => Esp32c3::get_flash_segments(image),
108115
Chip::Esp8266 => Esp8266::get_flash_segments(image),
109116
}
110117
}
111118

112119
pub fn addr_is_flash(&self, addr: u32) -> bool {
113120
match self {
114121
Chip::Esp32 => Esp32::addr_is_flash(addr),
122+
Chip::Esp32c3 => Esp32c3::addr_is_flash(addr),
115123
Chip::Esp8266 => Esp8266::addr_is_flash(addr),
116124
}
117125
}
118126

119127
pub fn spi_registers(&self) -> SpiRegisters {
120128
match self {
121129
Chip::Esp32 => Esp32::SPI_REGISTERS,
130+
Chip::Esp32c3 => Esp32c3::SPI_REGISTERS,
122131
Chip::Esp8266 => Esp8266::SPI_REGISTERS,
123132
}
124133
}
@@ -130,6 +139,7 @@ impl FromStr for Chip {
130139
fn from_str(s: &str) -> Result<Self, Self::Err> {
131140
match s {
132141
"esp32" => Ok(Chip::Esp32),
142+
"esp32c3" => Ok(Chip::Esp32c3),
133143
"esp8266" => Ok(Chip::Esp8266),
134144
_ => Err(Error::UnrecognizedChip),
135145
}
@@ -153,6 +163,8 @@ struct SegmentHeader {
153163
length: u32,
154164
}
155165

166+
// Note that this function ONLY applies to the ESP32 and variants; the ESP8266
167+
// has defined its own version rather than using this implementation.
156168
fn encode_flash_size(size: FlashSize) -> Result<u8, Error> {
157169
match size {
158170
FlashSize::Flash256Kb => Err(Error::UnsupportedFlash(size as u8)),

espflash/src/flasher.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ impl Flasher {
178178
if let Some(b) = speed {
179179
match flasher.chip {
180180
Chip::Esp8266 => (), /* Not available */
181-
Chip::Esp32 => {
181+
_ => {
182182
if b.speed() > BaudRate::Baud115200.speed() {
183183
println!("WARN setting baud rate higher than 115200 can cause issues.");
184184
flasher.change_baud(b)?;
@@ -357,7 +357,7 @@ impl Flasher {
357357
Chip::Esp8266 => {
358358
self.begin_command(Command::FlashBegin, 0, 0, FLASH_WRITE_SIZE as u32, 0)?;
359359
}
360-
Chip::Esp32 => {
360+
_ => {
361361
let spi_params = spi_attach_params.encode();
362362
self.connection
363363
.command(Command::SpiAttach as u8, spi_params.as_slice(), 0)?;
@@ -509,8 +509,8 @@ impl Flasher {
509509
let block_count = (segment.data.len() + FLASH_WRITE_SIZE - 1) / FLASH_WRITE_SIZE;
510510

511511
let erase_size = match self.chip {
512-
Chip::Esp32 => segment.data.len() as u32,
513512
Chip::Esp8266 => get_erase_size(addr as usize, segment.data.len()) as u32,
513+
_ => segment.data.len() as u32,
514514
};
515515

516516
self.begin_command(
@@ -538,6 +538,7 @@ impl Flasher {
538538
self.block_command(Command::FlashData, block, block_padding, 0xff, i as u32)?;
539539
pb_chunk.inc(1);
540540
}
541+
541542
pb_chunk.finish_with_message(format!("segment 0x{:X}", addr));
542543
}
543544

0 commit comments

Comments
 (0)