Skip to content

Commit 591e092

Browse files
authored
Merge pull request #47 from jessebraham/esp32s2
Add support for flashing the ESP32-S2
2 parents e1cf007 + af518bc commit 591e092

File tree

3 files changed

+190
-4
lines changed

3 files changed

+190
-4
lines changed
20.2 KB
Binary file not shown.

espflash/src/chip/esp32s2.rs

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

espflash/src/chip/mod.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,22 @@ use strum_macros::Display;
33

44
use crate::{
55
elf::{update_checksum, CodeSegment, FirmwareImage, RomSegment},
6-
flasher::FlashSize,
6+
error::{ChipDetectError, FlashDetectError},
7+
flash_target::{Esp32Target, Esp8266Target, FlashTarget, RamTarget},
8+
flasher::{FlashSize, SpiAttachParams},
79
Error, PartitionTable,
810
};
911

1012
use std::io::Write;
1113

12-
use crate::error::{ChipDetectError, FlashDetectError};
13-
use crate::flash_target::{Esp32Target, Esp8266Target, FlashTarget, RamTarget};
14-
use crate::flasher::SpiAttachParams;
1514
pub use esp32::Esp32;
1615
pub use esp32c3::Esp32c3;
16+
pub use esp32s2::Esp32s2;
1717
pub use esp8266::Esp8266;
1818

1919
mod esp32;
2020
mod esp32c3;
21+
mod esp32s2;
2122
mod esp8266;
2223

2324
const ESP_MAGIC: u8 = 0xE9;
@@ -98,6 +99,8 @@ pub enum Chip {
9899
Esp32,
99100
#[strum(serialize = "ESP32-C3")]
100101
Esp32c3,
102+
#[strum(serialize = "ESP32-S2")]
103+
Esp32s2,
101104
#[strum(serialize = "ESP8266")]
102105
Esp8266,
103106
}
@@ -109,6 +112,7 @@ impl Chip {
109112
Esp32c3::CHIP_DETECT_MAGIC_VALUE | Esp32c3::CHIP_DETECT_MAGIC_VALUE2 => {
110113
Ok(Chip::Esp32c3)
111114
}
115+
Esp32s2::CHIP_DETECT_MAGIC_VALUE => Ok(Chip::Esp32s2),
112116
Esp8266::CHIP_DETECT_MAGIC_VALUE => Ok(Chip::Esp8266),
113117
_ => Err(ChipDetectError::from(magic)),
114118
}
@@ -123,6 +127,7 @@ impl Chip {
123127
match self {
124128
Chip::Esp32 => Esp32::get_flash_segments(image, bootloader, partition_table),
125129
Chip::Esp32c3 => Esp32c3::get_flash_segments(image, bootloader, partition_table),
130+
Chip::Esp32s2 => Esp32s2::get_flash_segments(image, bootloader, partition_table),
126131
Chip::Esp8266 => Esp8266::get_flash_segments(image, None, None),
127132
}
128133
}
@@ -131,6 +136,7 @@ impl Chip {
131136
match self {
132137
Chip::Esp32 => Esp32::addr_is_flash(addr),
133138
Chip::Esp32c3 => Esp32c3::addr_is_flash(addr),
139+
Chip::Esp32s2 => Esp32s2::addr_is_flash(addr),
134140
Chip::Esp8266 => Esp8266::addr_is_flash(addr),
135141
}
136142
}
@@ -139,6 +145,7 @@ impl Chip {
139145
match self {
140146
Chip::Esp32 => Esp32::SPI_REGISTERS,
141147
Chip::Esp32c3 => Esp32c3::SPI_REGISTERS,
148+
Chip::Esp32s2 => Esp32s2::SPI_REGISTERS,
142149
Chip::Esp8266 => Esp8266::SPI_REGISTERS,
143150
}
144151
}

0 commit comments

Comments
 (0)