Skip to content

Commit f7a30a1

Browse files
committed
Display chip features and MAC address in board info output
1 parent 18a0f05 commit f7a30a1

File tree

6 files changed

+230
-5
lines changed

6 files changed

+230
-5
lines changed

espflash/src/chip/esp32/esp32.rs

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::ops::Range;
22

33
use super::Esp32Params;
44
use crate::{
5-
chip::{Chip, ChipType, ReadEFuse, SpiRegisters},
5+
chip::{bytes_to_mac_addr, Chip, ChipType, ReadEFuse, SpiRegisters},
66
connection::Connection,
77
elf::FirmwareImage,
88
image_format::{Esp32BootloaderFormat, ImageFormat, ImageFormatId},
@@ -54,6 +54,64 @@ impl ChipType for Esp32 {
5454
const SUPPORTED_TARGETS: &'static [&'static str] =
5555
&["xtensa-esp32-none-elf", "xtensa-esp32-espidf"];
5656

57+
fn chip_features(&self, connection: &mut Connection) -> Result<Vec<&str>, Error> {
58+
let word3 = self.read_efuse(connection, 3)?;
59+
let word4 = self.read_efuse(connection, 4)?;
60+
let word6 = self.read_efuse(connection, 6)?;
61+
62+
let mut features = vec!["WiFi"];
63+
64+
let chip_ver_dis_bt = word3 & 0x2;
65+
if chip_ver_dis_bt == 0 {
66+
features.push("BT");
67+
}
68+
69+
let chip_ver_dis_app_cpu = word3 & 0x1;
70+
if chip_ver_dis_app_cpu == 0 {
71+
features.push("Dual Core");
72+
} else {
73+
features.push("Single Core");
74+
}
75+
76+
let chip_cpu_freq_rated = word3 & (1 << 13);
77+
if chip_cpu_freq_rated != 0 {
78+
let chip_cpu_freq_low = word3 & (1 << 12);
79+
if chip_cpu_freq_low != 0 {
80+
features.push("160MHz");
81+
} else {
82+
features.push("240MHz");
83+
}
84+
}
85+
86+
let pkg_version = self.package_version(connection)?;
87+
if [2, 4, 5, 6].contains(&pkg_version) {
88+
features.push("Embedded Flash");
89+
}
90+
if pkg_version == 6 {
91+
features.push("Embedded PSRAM");
92+
}
93+
94+
let adc_vref = (word4 >> 8) & 0x1;
95+
if adc_vref != 0 {
96+
features.push("VRef calibration in efuse");
97+
}
98+
99+
let blk3_part_res = (word3 >> 14) & 0x1;
100+
if blk3_part_res != 0 {
101+
features.push("BLK3 partially reserved");
102+
}
103+
104+
let coding_scheme = word6 & 0x3;
105+
features.push(match coding_scheme {
106+
0 => "Coding Scheme None",
107+
1 => "Coding Scheme 3/4",
108+
2 => "Coding Scheme Repeat (UNSUPPORTED)",
109+
_ => "Coding Scheme Invalid",
110+
});
111+
112+
Ok(features)
113+
}
114+
57115
fn get_flash_segments<'a>(
58116
image: &'a FirmwareImage,
59117
bootloader: Option<Vec<u8>>,
@@ -74,6 +132,17 @@ impl ChipType for Esp32 {
74132
}
75133
}
76134

135+
fn mac_address(&self, connection: &mut Connection) -> Result<String, Error> {
136+
let word1 = self.read_efuse(connection, 1)?;
137+
let word2 = self.read_efuse(connection, 2)?;
138+
139+
let words = ((word2 as u64) << 32) | word1 as u64;
140+
let bytes = words.to_be_bytes();
141+
let bytes = &bytes[2..8];
142+
143+
Ok(bytes_to_mac_addr(bytes))
144+
}
145+
77146
fn supports_target(target: &str) -> bool {
78147
target.starts_with("xtensa-esp32-")
79148
}
@@ -103,6 +172,15 @@ impl Esp32 {
103172

104173
Ok(revision)
105174
}
175+
176+
fn package_version(&self, connection: &mut Connection) -> Result<u32, Error> {
177+
let word3 = self.read_efuse(connection, 3)?;
178+
179+
let pkg_version = (word3 >> 9) & 0x7;
180+
let pkg_version = pkg_version + (((word3 >> 2) & 0x1) << 3);
181+
182+
Ok(pkg_version)
183+
}
106184
}
107185

108186
#[test]

espflash/src/chip/esp32/esp32c3.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::ops::Range;
22

33
use super::Esp32Params;
44
use crate::{
5-
chip::{ChipType, ReadEFuse, SpiRegisters},
5+
chip::{bytes_to_mac_addr, ChipType, ReadEFuse, SpiRegisters},
66
connection::Connection,
77
elf::FirmwareImage,
88
image_format::{Esp32BootloaderFormat, ImageFormat, ImageFormatId},
@@ -56,6 +56,10 @@ impl ChipType for Esp32c3 {
5656
const SUPPORTED_TARGETS: &'static [&'static str] =
5757
&["riscv32imc-uknown-none-elf", "riscv32imc-esp-espidf"];
5858

59+
fn chip_features(&self, _connection: &mut Connection) -> Result<Vec<&str>, Error> {
60+
Ok(vec!["WiFi"])
61+
}
62+
5963
fn crystal_freq(&self, _connection: &mut Connection) -> Result<u32, Error> {
6064
// The ESP32-C3's XTAL has a fixed frequency of 40MHz.
6165
Ok(40)
@@ -81,6 +85,17 @@ impl ChipType for Esp32c3 {
8185
}
8286
}
8387

88+
fn mac_address(&self, connection: &mut Connection) -> Result<String, Error> {
89+
let word5 = self.read_efuse(connection, 5)?;
90+
let word6 = self.read_efuse(connection, 6)?;
91+
92+
let bytes = ((word6 as u64) << 32) | word5 as u64;
93+
let bytes = bytes.to_be_bytes();
94+
let bytes = &bytes[2..];
95+
96+
Ok(bytes_to_mac_addr(bytes))
97+
}
98+
8499
fn supports_target(target: &str) -> bool {
85100
target.starts_with("riscv32imc-")
86101
}

espflash/src/chip/esp32/esp32s2.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::ops::Range;
22

33
use super::Esp32Params;
44
use crate::{
5-
chip::{ChipType, ReadEFuse, SpiRegisters},
5+
chip::{bytes_to_mac_addr, ChipType, ReadEFuse, SpiRegisters},
66
connection::Connection,
77
elf::FirmwareImage,
88
image_format::{Esp32BootloaderFormat, ImageFormat, ImageFormatId},
@@ -54,6 +54,36 @@ impl ChipType for Esp32s2 {
5454
const SUPPORTED_TARGETS: &'static [&'static str] =
5555
&["xtensa-esp32s2-none-elf", "xtensa-esp32s2-espidf"];
5656

57+
fn chip_features(&self, connection: &mut Connection) -> Result<Vec<&str>, Error> {
58+
let mut features = vec!["WiFi"];
59+
60+
let flash_version = match self.get_flash_version(connection)? {
61+
0 => "No Embedded Flash",
62+
1 => "Embedded Flash 2MB",
63+
2 => "Embedded Flash 4MB",
64+
_ => "Unknown Embedded Flash",
65+
};
66+
features.push(flash_version);
67+
68+
let psram_version = match self.get_psram_version(connection)? {
69+
0 => "No Embedded PSRAM",
70+
1 => "Embedded PSRAM 2MB",
71+
2 => "Embedded PSRAM 4MB",
72+
_ => "Unknown Embedded PSRAM",
73+
};
74+
features.push(psram_version);
75+
76+
let block2_version = match self.get_block2_version(connection)? {
77+
0 => "No calibration in BLK2 of efuse",
78+
1 => "ADC and temperature sensor calibration in BLK2 of efuse V1",
79+
2 => "ADC and temperature sensor calibration in BLK2 of efuse V2",
80+
_ => "Unknown Calibration in BLK2",
81+
};
82+
features.push(block2_version);
83+
84+
Ok(features)
85+
}
86+
5787
fn crystal_freq(&self, _connection: &mut Connection) -> Result<u32, Error> {
5888
// The ESP32-S2's XTAL has a fixed frequency of 40MHz.
5989
Ok(40)
@@ -79,6 +109,17 @@ impl ChipType for Esp32s2 {
79109
}
80110
}
81111

112+
fn mac_address(&self, connection: &mut Connection) -> Result<String, Error> {
113+
let word5 = self.read_efuse(connection, 5)?;
114+
let word6 = self.read_efuse(connection, 6)?;
115+
116+
let bytes = ((word6 as u64) << 32) | word5 as u64;
117+
let bytes = bytes.to_be_bytes();
118+
let bytes = &bytes[2..];
119+
120+
Ok(bytes_to_mac_addr(bytes))
121+
}
122+
82123
fn supports_target(target: &str) -> bool {
83124
target.starts_with("xtensa-esp32s2-")
84125
}
@@ -87,3 +128,26 @@ impl ChipType for Esp32s2 {
87128
impl ReadEFuse for Esp32s2 {
88129
const EFUSE_REG_BASE: u32 = 0x3F41A030;
89130
}
131+
132+
impl Esp32s2 {
133+
fn get_flash_version(&self, connection: &mut Connection) -> Result<u32, Error> {
134+
let blk1_word3 = self.read_efuse(connection, 8)?;
135+
let flash_version = (blk1_word3 >> 21) & 0xf;
136+
137+
Ok(flash_version)
138+
}
139+
140+
fn get_psram_version(&self, connection: &mut Connection) -> Result<u32, Error> {
141+
let blk1_word3 = self.read_efuse(connection, 8)?;
142+
let psram_version = (blk1_word3 >> 28) & 0xf;
143+
144+
Ok(psram_version)
145+
}
146+
147+
fn get_block2_version(&self, connection: &mut Connection) -> Result<u32, Error> {
148+
let blk2_word4 = self.read_efuse(connection, 15)?;
149+
let block2_version = (blk2_word4 >> 4) & 0x7;
150+
151+
Ok(block2_version)
152+
}
153+
}

espflash/src/chip/esp8266.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::ops::Range;
22

3-
use super::ChipType;
3+
use super::{bytes_to_mac_addr, ChipType};
44
use crate::{
55
chip::{ReadEFuse, SpiRegisters},
6+
connection::Connection,
67
elf::FirmwareImage,
78
error::UnsupportedImageFormatError,
89
image_format::{Esp8266Format, ImageFormat, ImageFormatId},
@@ -37,6 +38,10 @@ impl ChipType for Esp8266 {
3738

3839
const SUPPORTED_TARGETS: &'static [&'static str] = &["xtensa-esp8266-none-elf"];
3940

41+
fn chip_features(&self, _connection: &mut Connection) -> Result<Vec<&str>, Error> {
42+
Ok(vec!["WiFi"])
43+
}
44+
4045
fn get_flash_segments<'a>(
4146
image: &'a FirmwareImage,
4247
_bootloader: Option<Vec<u8>>,
@@ -49,6 +54,32 @@ impl ChipType for Esp8266 {
4954
}
5055
}
5156

57+
fn mac_address(&self, connection: &mut Connection) -> Result<String, Error> {
58+
let word0 = self.read_efuse(connection, 0)?;
59+
let word1 = self.read_efuse(connection, 1)?;
60+
let word3 = self.read_efuse(connection, 3)?;
61+
62+
// First determine the OUI portion of the MAC address
63+
let mut bytes = if word3 != 0 {
64+
vec![
65+
((word3 >> 16) & 0xff) as u8,
66+
((word3 >> 8) & 0xff) as u8,
67+
(word3 & 0xff) as u8,
68+
]
69+
} else if ((word1 >> 16) & 0xff) == 0 {
70+
vec![0x18, 0xfe, 0x34]
71+
} else {
72+
vec![0xac, 0xd0, 0x74]
73+
};
74+
75+
// Add the remaining NIC portion of the MAC address
76+
bytes.push(((word1 >> 8) & 0xff) as u8);
77+
bytes.push((word1 & 0xff) as u8);
78+
bytes.push(((word0 >> 24) & 0xff) as u8);
79+
80+
Ok(bytes_to_mac_addr(&bytes))
81+
}
82+
5283
fn supports_target(target: &str) -> bool {
5384
target.starts_with("xtensa-esp8266-")
5485
}

espflash/src/chip/mod.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ pub trait ChipType {
3434

3535
const SUPPORTED_TARGETS: &'static [&'static str];
3636

37+
/// List the available features of the connected chip.
38+
fn chip_features(&self, connection: &mut Connection) -> Result<Vec<&str>, Error>;
39+
3740
/// Determine the frequency of the crytal on the connected chip.
3841
fn crystal_freq(&self, connection: &mut Connection) -> Result<u32, Error> {
3942
let uart_div = connection.read_reg(Self::UART_CLKDIV_REG)? & Self::UART_CLKDIV_MASK;
@@ -52,6 +55,9 @@ pub trait ChipType {
5255
image_format: ImageFormatId,
5356
) -> Result<Box<dyn ImageFormat<'a> + 'a>, Error>;
5457

58+
/// Read the MAC address of the connected chip.
59+
fn mac_address(&self, connection: &mut Connection) -> Result<String, Error>;
60+
5561
fn supports_target(target: &str) -> bool;
5662
}
5763

@@ -238,4 +244,30 @@ impl Chip {
238244

239245
Ok(rev)
240246
}
247+
248+
pub fn chip_features(&self, connection: &mut Connection) -> Result<Vec<&str>, Error> {
249+
match self {
250+
Chip::Esp32 => Esp32.chip_features(connection),
251+
Chip::Esp32c3 => Esp32c3.chip_features(connection),
252+
Chip::Esp32s2 => Esp32s2.chip_features(connection),
253+
Chip::Esp8266 => Esp8266.chip_features(connection),
254+
}
255+
}
256+
257+
pub fn mac_address(&self, connection: &mut Connection) -> Result<String, Error> {
258+
match self {
259+
Chip::Esp32 => Esp32.mac_address(connection),
260+
Chip::Esp32c3 => Esp32c3.mac_address(connection),
261+
Chip::Esp32s2 => Esp32s2.mac_address(connection),
262+
Chip::Esp8266 => Esp8266.mac_address(connection),
263+
}
264+
}
265+
}
266+
267+
pub(crate) fn bytes_to_mac_addr(bytes: &[u8]) -> String {
268+
bytes
269+
.iter()
270+
.map(|b| format!("{:02x}", b))
271+
.collect::<Vec<_>>()
272+
.join(":")
241273
}

espflash/src/flasher.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,9 +479,12 @@ impl Flasher {
479479
/// Read and print any information we can about the connected board
480480
pub fn board_info(&mut self) -> Result<(), Error> {
481481
let chip = self.chip();
482+
let size = self.flash_size();
483+
482484
let maybe_revision = chip.chip_revision(self.connection())?;
485+
let features = chip.chip_features(self.connection())?;
483486
let freq = chip.crystal_freq(self.connection())?;
484-
let size = self.flash_size();
487+
let mac = chip.mac_address(self.connection())?;
485488

486489
print!("Chip type: {}", chip);
487490
match maybe_revision {
@@ -490,6 +493,8 @@ impl Flasher {
490493
}
491494
println!("Crystal frequency: {}MHz", freq);
492495
println!("Flash size: {}", size);
496+
println!("Features: {}", features.join(", "));
497+
println!("MAC address: {}", mac);
493498

494499
Ok(())
495500
}

0 commit comments

Comments
 (0)