Skip to content

Commit 2174374

Browse files
authored
Add support for flashing the ESP32-C2 (aka ESP8684) (#204)
* No longer try to detect chip from target, as we will have multiple RISC-V chips * Reduce the repetition required to define a chip * Add support for per-chip flash frequency encodings * Add support for flashing the ESP32-C2 (aka ESP8684)
1 parent d458b77 commit 2174374

File tree

20 files changed

+420
-258
lines changed

20 files changed

+420
-258
lines changed

Cargo.lock

Lines changed: 10 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cargo-espflash/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@ clap = { version = "3.1", features = ["derive"] }
3636
espflash = { version = "=1.5.2-dev", path = "../espflash" }
3737
miette = { version = "4.7", features = ["fancy"] }
3838
serde = { version = "1.0", features = ["derive"] }
39+
strum = "0.24"
3940
thiserror = "1.0"
4041
toml = "0.5"

cargo-espflash/src/error.rs

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
use std::{
2+
fmt::{Display, Formatter},
3+
iter::once,
4+
};
5+
16
use espflash::Chip;
27
use miette::{Diagnostic, LabeledSpan, SourceCode, SourceOffset};
3-
use std::fmt::{Display, Formatter};
4-
use std::iter::once;
58
use thiserror::Error;
69

710
#[derive(Error, Debug, Diagnostic)]
@@ -48,24 +51,6 @@ pub enum Error {
4851
#[error(transparent)]
4952
#[diagnostic(transparent)]
5053
NoTarget(#[from] NoTargetError),
51-
#[error("Failed to detect chip for target {0}")]
52-
#[diagnostic(
53-
code(cargo_espflash::unknown_target),
54-
help(
55-
"The following targets are recognized:
56-
- ESP32: {}
57-
- ESP32-C3: {}
58-
- ESP32-S2: {}
59-
- ESP32-S3: {}
60-
- ESP8266: {}",
61-
Chip::Esp32.supported_targets().join(", "),
62-
Chip::Esp32c3.supported_targets().join(", "),
63-
Chip::Esp32s2.supported_targets().join(", "),
64-
Chip::Esp32s3.supported_targets().join(", "),
65-
Chip::Esp8266.supported_targets().join(", "),
66-
)
67-
)]
68-
UnknownTarget(String),
6954
}
7055

7156
#[derive(Debug)]

cargo-espflash/src/main.rs

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use espflash::{
1515
Chip, Config, ImageFormatId,
1616
};
1717
use miette::{IntoDiagnostic, Result, WrapErr};
18+
use strum::VariantNames;
1819

1920
use crate::{
2021
cargo_config::{parse_cargo_config, CargoConfig},
@@ -100,6 +101,9 @@ pub struct BuildOpts {
100101
pub struct SaveImageOpts {
101102
#[clap(flatten)]
102103
pub build_opts: BuildOpts,
104+
/// Chip to create an image for
105+
#[clap(possible_values = Chip::VARIANTS)]
106+
pub chip: Chip,
103107
/// File name to save the generated image to
104108
pub file: PathBuf,
105109
/// Boolean flag to merge binaries into single binary
@@ -150,7 +154,7 @@ fn flash(
150154
) -> Result<()> {
151155
let mut flasher = connect(&opts.connect_opts, &config)?;
152156

153-
let build_ctx = build(&opts.build_opts, &cargo_config, Some(flasher.chip()))
157+
let build_ctx = build(&opts.build_opts, &cargo_config, flasher.chip())
154158
.wrap_err("Failed to build project")?;
155159

156160
// Print the board information once the project has successfully built. We do
@@ -209,26 +213,16 @@ fn flash(
209213
fn build(
210214
build_options: &BuildOpts,
211215
cargo_config: &CargoConfig,
212-
chip: Option<Chip>,
216+
chip: Chip,
213217
) -> Result<BuildContext> {
214218
let target = build_options
215219
.target
216220
.as_deref()
217221
.or_else(|| cargo_config.target())
218-
.ok_or_else(|| NoTargetError::new(chip))?;
222+
.ok_or_else(|| NoTargetError::new(Some(chip)))?;
219223

220-
let chip = if chip.is_some() {
221-
chip
222-
} else {
223-
Chip::from_target(target)
224-
};
225-
226-
if let Some(chip) = chip {
227-
if !chip.supports_target(target) {
228-
return Err(Error::UnsupportedTarget(UnsupportedTargetError::new(target, chip)).into());
229-
}
230-
} else {
231-
return Err(Error::UnknownTarget(target.to_string()).into());
224+
if !chip.supports_target(target) {
225+
return Err(Error::UnsupportedTarget(UnsupportedTargetError::new(target, chip)).into());
232226
}
233227

234228
// The 'build-std' unstable cargo feature is required to enable
@@ -369,17 +363,7 @@ fn save_image(
369363
metadata: CargoEspFlashMeta,
370364
cargo_config: CargoConfig,
371365
) -> Result<()> {
372-
let target = opts
373-
.build_opts
374-
.target
375-
.as_deref()
376-
.or_else(|| cargo_config.target())
377-
.ok_or_else(|| NoTargetError::new(None))
378-
.into_diagnostic()?;
379-
380-
let chip = Chip::from_target(target).ok_or_else(|| Error::UnknownTarget(target.into()))?;
381-
382-
let build_ctx = build(&opts.build_opts, &cargo_config, Some(chip))?;
366+
let build_ctx = build(&opts.build_opts, &cargo_config, opts.chip)?;
383367
let elf_data = fs::read(build_ctx.artifact_path).into_diagnostic()?;
384368

385369
let bootloader = opts
@@ -405,7 +389,7 @@ fn save_image(
405389
.or(metadata.format);
406390

407391
save_elf_as_image(
408-
chip,
392+
opts.chip,
409393
&elf_data,
410394
opts.file,
411395
image_format,

espflash/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ crossterm = "0.24"
4141
csv = "1.1"
4242
dialoguer = "0.10"
4343
directories-next = "2.0"
44-
espmonitor = "0.9"
44+
espmonitor = "0.10"
4545
flate2 = "1.0"
4646
indicatif = "0.16"
47+
maplit = "1.0"
4748
md5 = "0.7"
4849
miette = { version = "4.7", features = ["fancy"] }
4950
parse_int = "0.6"
18.2 KB
Binary file not shown.

espflash/src/chip/esp32/esp32.rs

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,28 @@
11
use std::ops::Range;
22

33
use super::Esp32Params;
4-
use crate::error::UnsupportedImageFormatError;
54
use crate::{
65
chip::{bytes_to_mac_addr, Chip, ChipType, ReadEFuse, SpiRegisters},
76
connection::Connection,
87
elf::{FirmwareImage, FlashFrequency, FlashMode},
8+
error::UnsupportedImageFormatError,
99
flasher::FlashSize,
1010
image_format::{Esp32BootloaderFormat, ImageFormat, ImageFormatId},
1111
Error, PartitionTable,
1212
};
1313

1414
pub struct Esp32;
1515

16-
const IROM_MAP_START: u32 = 0x400d0000;
17-
const IROM_MAP_END: u32 = 0x40400000;
18-
19-
const DROM_MAP_START: u32 = 0x3F400000;
20-
const DROM_MAP_END: u32 = 0x3F800000;
21-
22-
pub const PARAMS: Esp32Params = Esp32Params {
23-
boot_addr: 0x1000,
24-
partition_addr: 0x8000,
25-
nvs_addr: 0x9000,
26-
nvs_size: 0x6000,
27-
phy_init_data_addr: 0xf000,
28-
phy_init_data_size: 0x1000,
29-
app_addr: 0x10000,
30-
app_size: 0x3f0000,
31-
chip_id: 0,
32-
default_bootloader: include_bytes!("../../../bootloader/esp32-bootloader.bin"),
33-
};
16+
pub const PARAMS: Esp32Params = Esp32Params::new(
17+
0x1000,
18+
0x10000,
19+
0x3f0000,
20+
0,
21+
include_bytes!("../../../bootloader/esp32-bootloader.bin"),
22+
);
3423

3524
impl ChipType for Esp32 {
36-
const CHIP_DETECT_MAGIC_VALUE: u32 = 0x00f01d83;
25+
const CHIP_DETECT_MAGIC_VALUES: &'static [u32] = &[0x00f01d83];
3726

3827
const UART_CLKDIV_REG: u32 = 0x3ff40014;
3928

@@ -47,11 +36,10 @@ impl ChipType for Esp32 {
4736
miso_length_offset: Some(0x2c),
4837
};
4938

50-
const FLASH_RANGES: &'static [Range<u32>] =
51-
&[IROM_MAP_START..IROM_MAP_END, DROM_MAP_START..DROM_MAP_END];
52-
53-
const DEFAULT_IMAGE_FORMAT: ImageFormatId = ImageFormatId::Bootloader;
54-
const SUPPORTED_IMAGE_FORMATS: &'static [ImageFormatId] = &[ImageFormatId::Bootloader];
39+
const FLASH_RANGES: &'static [Range<u32>] = &[
40+
0x400d0000..0x40400000, // IROM
41+
0x3F400000..0x3F800000, // DROM
42+
];
5543

5644
const SUPPORTED_TARGETS: &'static [&'static str] =
5745
&["xtensa-esp32-none-elf", "xtensa-esp32-espidf"];

espflash/src/chip/esp32/esp32c2.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use std::{collections::HashMap, ops::Range};
2+
3+
use maplit::hashmap;
4+
5+
use super::Esp32Params;
6+
use crate::{
7+
chip::{ChipType, ReadEFuse, SpiRegisters},
8+
connection::Connection,
9+
elf::{FirmwareImage, FlashFrequency, FlashMode},
10+
flasher::FlashSize,
11+
image_format::{Esp32BootloaderFormat, Esp32DirectBootFormat, ImageFormat, ImageFormatId},
12+
Chip, Error, PartitionTable,
13+
};
14+
15+
pub struct Esp32c2;
16+
17+
pub const PARAMS: Esp32Params = Esp32Params::new(
18+
0x0,
19+
0x10000,
20+
0x1f0000,
21+
12,
22+
include_bytes!("../../../bootloader/esp32c2-bootloader.bin"),
23+
);
24+
25+
impl ChipType for Esp32c2 {
26+
const CHIP_DETECT_MAGIC_VALUES: &'static [u32] = &[
27+
0x6F51306F, // ECO0
28+
0x7C41A06F, // ECO1
29+
];
30+
31+
const UART_CLKDIV_REG: u32 = 0x3ff40014;
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+
const FLASH_RANGES: &'static [Range<u32>] = &[
44+
0x42000000..0x42400000, // IROM
45+
0x3C000000..0x3C400000, // DROM
46+
];
47+
48+
const SUPPORTED_IMAGE_FORMATS: &'static [ImageFormatId] =
49+
&[ImageFormatId::Bootloader, ImageFormatId::DirectBoot];
50+
51+
const SUPPORTED_TARGETS: &'static [&'static str] = &[
52+
"riscv32imac-unknown-none-elf",
53+
"riscv32imc-esp-espidf",
54+
"riscv32imc-unknown-none-elf",
55+
];
56+
57+
fn chip_features(&self, _connection: &mut Connection) -> Result<Vec<&str>, Error> {
58+
Ok(vec!["WiFi"])
59+
}
60+
61+
fn crystal_freq(&self, _connection: &mut Connection) -> Result<u32, Error> {
62+
// The ESP32-C2's XTAL has a fixed frequency of 40MHz.
63+
Ok(40)
64+
}
65+
66+
fn get_flash_segments<'a>(
67+
image: &'a dyn FirmwareImage<'a>,
68+
bootloader: Option<Vec<u8>>,
69+
partition_table: Option<PartitionTable>,
70+
image_format: ImageFormatId,
71+
_chip_revision: Option<u32>,
72+
flash_mode: Option<FlashMode>,
73+
flash_size: Option<FlashSize>,
74+
flash_freq: Option<FlashFrequency>,
75+
) -> Result<Box<dyn ImageFormat<'a> + 'a>, Error> {
76+
match image_format {
77+
ImageFormatId::Bootloader => Ok(Box::new(Esp32BootloaderFormat::new(
78+
image,
79+
Chip::Esp32c2,
80+
PARAMS,
81+
partition_table,
82+
bootloader,
83+
flash_mode,
84+
flash_size,
85+
flash_freq,
86+
)?)),
87+
ImageFormatId::DirectBoot => Ok(Box::new(Esp32DirectBootFormat::new(image)?)),
88+
}
89+
}
90+
91+
fn flash_frequency_encodings() -> HashMap<FlashFrequency, u8> {
92+
use FlashFrequency::*;
93+
94+
hashmap! {
95+
Flash15M => 0x2,
96+
Flash20M => 0x1,
97+
Flash30M => 0x0,
98+
Flash60M => 0xF,
99+
}
100+
}
101+
}
102+
103+
impl ReadEFuse for Esp32c2 {
104+
const EFUSE_REG_BASE: u32 = 0x60008800;
105+
}
106+
107+
impl Esp32c2 {
108+
pub fn chip_revision(&self, connection: &mut Connection) -> Result<u32, Error> {
109+
let block1_addr = Self::EFUSE_REG_BASE + 0x44;
110+
let num_word = 3;
111+
let pos = 18;
112+
113+
let value = connection.read_reg(block1_addr + (num_word * 0x4))?;
114+
let value = (value & (0x7 << pos)) >> pos;
115+
116+
Ok(value)
117+
}
118+
}

0 commit comments

Comments
 (0)