mirror of
https://github.com/esp-rs/espflash.git
synced 2026-04-09 16:15:20 +00:00
Merge pull request #69 from jessebraham/feature/more-board-info
Display chip features and MAC address in board info output
This commit is contained in:
@@ -2,7 +2,7 @@ use std::ops::Range;
|
||||
|
||||
use super::Esp32Params;
|
||||
use crate::{
|
||||
chip::{Chip, ChipType, ReadEFuse, SpiRegisters},
|
||||
chip::{bytes_to_mac_addr, Chip, ChipType, ReadEFuse, SpiRegisters},
|
||||
connection::Connection,
|
||||
elf::FirmwareImage,
|
||||
image_format::{Esp32BootloaderFormat, ImageFormat, ImageFormatId},
|
||||
@@ -54,6 +54,64 @@ impl ChipType for Esp32 {
|
||||
const SUPPORTED_TARGETS: &'static [&'static str] =
|
||||
&["xtensa-esp32-none-elf", "xtensa-esp32-espidf"];
|
||||
|
||||
fn chip_features(&self, connection: &mut Connection) -> Result<Vec<&str>, Error> {
|
||||
let word3 = self.read_efuse(connection, 3)?;
|
||||
let word4 = self.read_efuse(connection, 4)?;
|
||||
let word6 = self.read_efuse(connection, 6)?;
|
||||
|
||||
let mut features = vec!["WiFi"];
|
||||
|
||||
let chip_ver_dis_bt = word3 & 0x2;
|
||||
if chip_ver_dis_bt == 0 {
|
||||
features.push("BT");
|
||||
}
|
||||
|
||||
let chip_ver_dis_app_cpu = word3 & 0x1;
|
||||
if chip_ver_dis_app_cpu == 0 {
|
||||
features.push("Dual Core");
|
||||
} else {
|
||||
features.push("Single Core");
|
||||
}
|
||||
|
||||
let chip_cpu_freq_rated = word3 & (1 << 13);
|
||||
if chip_cpu_freq_rated != 0 {
|
||||
let chip_cpu_freq_low = word3 & (1 << 12);
|
||||
if chip_cpu_freq_low != 0 {
|
||||
features.push("160MHz");
|
||||
} else {
|
||||
features.push("240MHz");
|
||||
}
|
||||
}
|
||||
|
||||
let pkg_version = self.package_version(connection)?;
|
||||
if [2, 4, 5, 6].contains(&pkg_version) {
|
||||
features.push("Embedded Flash");
|
||||
}
|
||||
if pkg_version == 6 {
|
||||
features.push("Embedded PSRAM");
|
||||
}
|
||||
|
||||
let adc_vref = (word4 >> 8) & 0x1;
|
||||
if adc_vref != 0 {
|
||||
features.push("VRef calibration in efuse");
|
||||
}
|
||||
|
||||
let blk3_part_res = (word3 >> 14) & 0x1;
|
||||
if blk3_part_res != 0 {
|
||||
features.push("BLK3 partially reserved");
|
||||
}
|
||||
|
||||
let coding_scheme = word6 & 0x3;
|
||||
features.push(match coding_scheme {
|
||||
0 => "Coding Scheme None",
|
||||
1 => "Coding Scheme 3/4",
|
||||
2 => "Coding Scheme Repeat (UNSUPPORTED)",
|
||||
_ => "Coding Scheme Invalid",
|
||||
});
|
||||
|
||||
Ok(features)
|
||||
}
|
||||
|
||||
fn get_flash_segments<'a>(
|
||||
image: &'a FirmwareImage,
|
||||
bootloader: Option<Vec<u8>>,
|
||||
@@ -74,6 +132,17 @@ impl ChipType for Esp32 {
|
||||
}
|
||||
}
|
||||
|
||||
fn mac_address(&self, connection: &mut Connection) -> Result<String, Error> {
|
||||
let word1 = self.read_efuse(connection, 1)?;
|
||||
let word2 = self.read_efuse(connection, 2)?;
|
||||
|
||||
let words = ((word2 as u64) << 32) | word1 as u64;
|
||||
let bytes = words.to_be_bytes();
|
||||
let bytes = &bytes[2..8];
|
||||
|
||||
Ok(bytes_to_mac_addr(bytes))
|
||||
}
|
||||
|
||||
fn supports_target(target: &str) -> bool {
|
||||
target.starts_with("xtensa-esp32-")
|
||||
}
|
||||
@@ -103,6 +172,15 @@ impl Esp32 {
|
||||
|
||||
Ok(revision)
|
||||
}
|
||||
|
||||
fn package_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let word3 = self.read_efuse(connection, 3)?;
|
||||
|
||||
let pkg_version = (word3 >> 9) & 0x7;
|
||||
let pkg_version = pkg_version + (((word3 >> 2) & 0x1) << 3);
|
||||
|
||||
Ok(pkg_version)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::ops::Range;
|
||||
|
||||
use super::Esp32Params;
|
||||
use crate::{
|
||||
chip::{ChipType, ReadEFuse, SpiRegisters},
|
||||
chip::{bytes_to_mac_addr, ChipType, ReadEFuse, SpiRegisters},
|
||||
connection::Connection,
|
||||
elf::FirmwareImage,
|
||||
image_format::{Esp32BootloaderFormat, ImageFormat, ImageFormatId},
|
||||
@@ -56,6 +56,10 @@ impl ChipType for Esp32c3 {
|
||||
const SUPPORTED_TARGETS: &'static [&'static str] =
|
||||
&["riscv32imc-uknown-none-elf", "riscv32imc-esp-espidf"];
|
||||
|
||||
fn chip_features(&self, _connection: &mut Connection) -> Result<Vec<&str>, Error> {
|
||||
Ok(vec!["WiFi"])
|
||||
}
|
||||
|
||||
fn crystal_freq(&self, _connection: &mut Connection) -> Result<u32, Error> {
|
||||
// The ESP32-C3's XTAL has a fixed frequency of 40MHz.
|
||||
Ok(40)
|
||||
@@ -81,6 +85,17 @@ impl ChipType for Esp32c3 {
|
||||
}
|
||||
}
|
||||
|
||||
fn mac_address(&self, connection: &mut Connection) -> Result<String, Error> {
|
||||
let word5 = self.read_efuse(connection, 5)?;
|
||||
let word6 = self.read_efuse(connection, 6)?;
|
||||
|
||||
let bytes = ((word6 as u64) << 32) | word5 as u64;
|
||||
let bytes = bytes.to_be_bytes();
|
||||
let bytes = &bytes[2..];
|
||||
|
||||
Ok(bytes_to_mac_addr(bytes))
|
||||
}
|
||||
|
||||
fn supports_target(target: &str) -> bool {
|
||||
target.starts_with("riscv32imc-")
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::ops::Range;
|
||||
|
||||
use super::Esp32Params;
|
||||
use crate::{
|
||||
chip::{ChipType, ReadEFuse, SpiRegisters},
|
||||
chip::{bytes_to_mac_addr, ChipType, ReadEFuse, SpiRegisters},
|
||||
connection::Connection,
|
||||
elf::FirmwareImage,
|
||||
image_format::{Esp32BootloaderFormat, ImageFormat, ImageFormatId},
|
||||
@@ -54,6 +54,36 @@ impl ChipType for Esp32s2 {
|
||||
const SUPPORTED_TARGETS: &'static [&'static str] =
|
||||
&["xtensa-esp32s2-none-elf", "xtensa-esp32s2-espidf"];
|
||||
|
||||
fn chip_features(&self, connection: &mut Connection) -> Result<Vec<&str>, Error> {
|
||||
let mut features = vec!["WiFi"];
|
||||
|
||||
let flash_version = match self.get_flash_version(connection)? {
|
||||
0 => "No Embedded Flash",
|
||||
1 => "Embedded Flash 2MB",
|
||||
2 => "Embedded Flash 4MB",
|
||||
_ => "Unknown Embedded Flash",
|
||||
};
|
||||
features.push(flash_version);
|
||||
|
||||
let psram_version = match self.get_psram_version(connection)? {
|
||||
0 => "No Embedded PSRAM",
|
||||
1 => "Embedded PSRAM 2MB",
|
||||
2 => "Embedded PSRAM 4MB",
|
||||
_ => "Unknown Embedded PSRAM",
|
||||
};
|
||||
features.push(psram_version);
|
||||
|
||||
let block2_version = match self.get_block2_version(connection)? {
|
||||
0 => "No calibration in BLK2 of efuse",
|
||||
1 => "ADC and temperature sensor calibration in BLK2 of efuse V1",
|
||||
2 => "ADC and temperature sensor calibration in BLK2 of efuse V2",
|
||||
_ => "Unknown Calibration in BLK2",
|
||||
};
|
||||
features.push(block2_version);
|
||||
|
||||
Ok(features)
|
||||
}
|
||||
|
||||
fn crystal_freq(&self, _connection: &mut Connection) -> Result<u32, Error> {
|
||||
// The ESP32-S2's XTAL has a fixed frequency of 40MHz.
|
||||
Ok(40)
|
||||
@@ -79,6 +109,17 @@ impl ChipType for Esp32s2 {
|
||||
}
|
||||
}
|
||||
|
||||
fn mac_address(&self, connection: &mut Connection) -> Result<String, Error> {
|
||||
let word5 = self.read_efuse(connection, 5)?;
|
||||
let word6 = self.read_efuse(connection, 6)?;
|
||||
|
||||
let bytes = ((word6 as u64) << 32) | word5 as u64;
|
||||
let bytes = bytes.to_be_bytes();
|
||||
let bytes = &bytes[2..];
|
||||
|
||||
Ok(bytes_to_mac_addr(bytes))
|
||||
}
|
||||
|
||||
fn supports_target(target: &str) -> bool {
|
||||
target.starts_with("xtensa-esp32s2-")
|
||||
}
|
||||
@@ -87,3 +128,26 @@ impl ChipType for Esp32s2 {
|
||||
impl ReadEFuse for Esp32s2 {
|
||||
const EFUSE_REG_BASE: u32 = 0x3F41A030;
|
||||
}
|
||||
|
||||
impl Esp32s2 {
|
||||
fn get_flash_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let blk1_word3 = self.read_efuse(connection, 8)?;
|
||||
let flash_version = (blk1_word3 >> 21) & 0xf;
|
||||
|
||||
Ok(flash_version)
|
||||
}
|
||||
|
||||
fn get_psram_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let blk1_word3 = self.read_efuse(connection, 8)?;
|
||||
let psram_version = (blk1_word3 >> 28) & 0xf;
|
||||
|
||||
Ok(psram_version)
|
||||
}
|
||||
|
||||
fn get_block2_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let blk2_word4 = self.read_efuse(connection, 15)?;
|
||||
let block2_version = (blk2_word4 >> 4) & 0x7;
|
||||
|
||||
Ok(block2_version)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use super::ChipType;
|
||||
use super::{bytes_to_mac_addr, ChipType};
|
||||
use crate::{
|
||||
chip::{ReadEFuse, SpiRegisters},
|
||||
connection::Connection,
|
||||
elf::FirmwareImage,
|
||||
error::UnsupportedImageFormatError,
|
||||
image_format::{Esp8266Format, ImageFormat, ImageFormatId},
|
||||
@@ -37,6 +38,10 @@ impl ChipType for Esp8266 {
|
||||
|
||||
const SUPPORTED_TARGETS: &'static [&'static str] = &["xtensa-esp8266-none-elf"];
|
||||
|
||||
fn chip_features(&self, _connection: &mut Connection) -> Result<Vec<&str>, Error> {
|
||||
Ok(vec!["WiFi"])
|
||||
}
|
||||
|
||||
fn get_flash_segments<'a>(
|
||||
image: &'a FirmwareImage,
|
||||
_bootloader: Option<Vec<u8>>,
|
||||
@@ -49,6 +54,32 @@ impl ChipType for Esp8266 {
|
||||
}
|
||||
}
|
||||
|
||||
fn mac_address(&self, connection: &mut Connection) -> Result<String, Error> {
|
||||
let word0 = self.read_efuse(connection, 0)?;
|
||||
let word1 = self.read_efuse(connection, 1)?;
|
||||
let word3 = self.read_efuse(connection, 3)?;
|
||||
|
||||
// First determine the OUI portion of the MAC address
|
||||
let mut bytes = if word3 != 0 {
|
||||
vec![
|
||||
((word3 >> 16) & 0xff) as u8,
|
||||
((word3 >> 8) & 0xff) as u8,
|
||||
(word3 & 0xff) as u8,
|
||||
]
|
||||
} else if ((word1 >> 16) & 0xff) == 0 {
|
||||
vec![0x18, 0xfe, 0x34]
|
||||
} else {
|
||||
vec![0xac, 0xd0, 0x74]
|
||||
};
|
||||
|
||||
// Add the remaining NIC portion of the MAC address
|
||||
bytes.push(((word1 >> 8) & 0xff) as u8);
|
||||
bytes.push((word1 & 0xff) as u8);
|
||||
bytes.push(((word0 >> 24) & 0xff) as u8);
|
||||
|
||||
Ok(bytes_to_mac_addr(&bytes))
|
||||
}
|
||||
|
||||
fn supports_target(target: &str) -> bool {
|
||||
target.starts_with("xtensa-esp8266-")
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ pub trait ChipType {
|
||||
|
||||
const SUPPORTED_TARGETS: &'static [&'static str];
|
||||
|
||||
/// List the available features of the connected chip.
|
||||
fn chip_features(&self, connection: &mut Connection) -> Result<Vec<&str>, Error>;
|
||||
|
||||
/// Determine the frequency of the crytal on the connected chip.
|
||||
fn crystal_freq(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let uart_div = connection.read_reg(Self::UART_CLKDIV_REG)? & Self::UART_CLKDIV_MASK;
|
||||
@@ -52,6 +55,9 @@ pub trait ChipType {
|
||||
image_format: ImageFormatId,
|
||||
) -> Result<Box<dyn ImageFormat<'a> + 'a>, Error>;
|
||||
|
||||
/// Read the MAC address of the connected chip.
|
||||
fn mac_address(&self, connection: &mut Connection) -> Result<String, Error>;
|
||||
|
||||
fn supports_target(target: &str) -> bool;
|
||||
}
|
||||
|
||||
@@ -238,4 +244,30 @@ impl Chip {
|
||||
|
||||
Ok(rev)
|
||||
}
|
||||
|
||||
pub fn chip_features(&self, connection: &mut Connection) -> Result<Vec<&str>, Error> {
|
||||
match self {
|
||||
Chip::Esp32 => Esp32.chip_features(connection),
|
||||
Chip::Esp32c3 => Esp32c3.chip_features(connection),
|
||||
Chip::Esp32s2 => Esp32s2.chip_features(connection),
|
||||
Chip::Esp8266 => Esp8266.chip_features(connection),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mac_address(&self, connection: &mut Connection) -> Result<String, Error> {
|
||||
match self {
|
||||
Chip::Esp32 => Esp32.mac_address(connection),
|
||||
Chip::Esp32c3 => Esp32c3.mac_address(connection),
|
||||
Chip::Esp32s2 => Esp32s2.mac_address(connection),
|
||||
Chip::Esp8266 => Esp8266.mac_address(connection),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn bytes_to_mac_addr(bytes: &[u8]) -> String {
|
||||
bytes
|
||||
.iter()
|
||||
.map(|b| format!("{:02x}", b))
|
||||
.collect::<Vec<_>>()
|
||||
.join(":")
|
||||
}
|
||||
|
||||
@@ -479,10 +479,13 @@ impl Flasher {
|
||||
/// Read and print any information we can about the connected board
|
||||
pub fn board_info(&mut self) -> Result<(), Error> {
|
||||
let chip = self.chip();
|
||||
let maybe_revision = chip.chip_revision(self.connection())?;
|
||||
let freq = chip.crystal_freq(self.connection())?;
|
||||
let size = self.flash_size();
|
||||
|
||||
let maybe_revision = chip.chip_revision(self.connection())?;
|
||||
let features = chip.chip_features(self.connection())?;
|
||||
let freq = chip.crystal_freq(self.connection())?;
|
||||
let mac = chip.mac_address(self.connection())?;
|
||||
|
||||
print!("Chip type: {}", chip);
|
||||
match maybe_revision {
|
||||
Some(revision) => println!(" (revision {})", revision),
|
||||
@@ -490,6 +493,8 @@ impl Flasher {
|
||||
}
|
||||
println!("Crystal frequency: {}MHz", freq);
|
||||
println!("Flash size: {}", size);
|
||||
println!("Features: {}", features.join(", "));
|
||||
println!("MAC address: {}", mac);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user