mirror of
https://github.com/esp-rs/espflash.git
synced 2026-03-24 00:00:22 +00:00
Display the newer 'v{major}.{minor}' chip revision format (#307)
This commit is contained in:
@@ -131,6 +131,9 @@ https://github.com/espressif/esp32c3-direct-boot-example"
|
||||
chip: Chip,
|
||||
frequency: FlashFrequency,
|
||||
},
|
||||
#[error("The {chip} does not support {feature}")]
|
||||
#[diagnostic(code(espflash::unsupported_feature))]
|
||||
UnsupportedFeature { chip: Chip, feature: String },
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Diagnostic)]
|
||||
@@ -449,7 +452,7 @@ impl From<u8> for FlashDetectError {
|
||||
pub struct UnsupportedImageFormatError {
|
||||
format: ImageFormatKind,
|
||||
chip: Chip,
|
||||
revision: Option<u32>,
|
||||
revision: Option<(u32, u32)>,
|
||||
}
|
||||
|
||||
impl Display for UnsupportedImageFormatError {
|
||||
@@ -459,9 +462,11 @@ impl Display for UnsupportedImageFormatError {
|
||||
"Image format {} is not supported by the {}",
|
||||
self.format, self.chip
|
||||
)?;
|
||||
if let Some(revision) = self.revision {
|
||||
write!(f, " revision {}", revision)?;
|
||||
|
||||
if let Some((major, minor)) = self.revision {
|
||||
write!(f, " revision v{major}.{minor}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -491,7 +496,7 @@ impl Diagnostic for UnsupportedImageFormatError {
|
||||
}
|
||||
|
||||
impl UnsupportedImageFormatError {
|
||||
pub fn new(format: ImageFormatKind, chip: Chip, revision: Option<u32>) -> Self {
|
||||
pub fn new(format: ImageFormatKind, chip: Chip, revision: Option<(u32, u32)>) -> Self {
|
||||
UnsupportedImageFormatError {
|
||||
format,
|
||||
chip,
|
||||
|
||||
@@ -608,22 +608,25 @@ 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 target = chip.into_target();
|
||||
let maybe_revision = target.chip_revision(self.connection())?;
|
||||
|
||||
let features = target.chip_features(self.connection())?;
|
||||
let freq = target.crystal_freq(self.connection())?;
|
||||
let mac = target.mac_address(self.connection())?;
|
||||
|
||||
print!("Chip type: {}", chip);
|
||||
match maybe_revision {
|
||||
Some(revision) => println!(" (revision {})", revision),
|
||||
None => println!(),
|
||||
// The ESP8266 does not have readable major/minor revision numbers, so we have
|
||||
// nothing to print if targeting it.
|
||||
print!("Chip type: {chip}");
|
||||
if chip != Chip::Esp8266 {
|
||||
let (major, minor) = target.chip_revision(self.connection())?;
|
||||
println!(" (revision v{major}.{minor})");
|
||||
} else {
|
||||
println!("");
|
||||
}
|
||||
println!("Crystal frequency: {}MHz", freq);
|
||||
println!("Crystal frequency: {freq}MHz");
|
||||
println!("Flash size: {}", self.flash_size);
|
||||
println!("Features: {}", features.join(", "));
|
||||
println!("MAC address: {}", mac);
|
||||
println!("MAC address: {mac}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -687,9 +690,11 @@ impl Flasher {
|
||||
bootloader,
|
||||
partition_table,
|
||||
image_format,
|
||||
self.chip
|
||||
.into_target()
|
||||
.chip_revision(&mut self.connection)?,
|
||||
Some(
|
||||
self.chip
|
||||
.into_target()
|
||||
.chip_revision(&mut self.connection)?,
|
||||
),
|
||||
flash_mode,
|
||||
flash_size.or(Some(self.flash_size)),
|
||||
flash_freq,
|
||||
|
||||
@@ -118,24 +118,25 @@ impl Target for Esp32 {
|
||||
Ok(features)
|
||||
}
|
||||
|
||||
fn chip_revision(&self, connection: &mut Connection) -> Result<Option<u32>, Error> {
|
||||
let word3 = self.read_efuse(connection, 3)?;
|
||||
let word5 = self.read_efuse(connection, 5)?;
|
||||
fn major_chip_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let apb_ctl_date = connection.read_reg(0x3FF6_607C)?;
|
||||
|
||||
let apb_ctrl_date = connection.read_reg(0x3ff6_607c)?;
|
||||
let rev_bit0 = (self.read_efuse(connection, 3)? >> 15) & 0x1;
|
||||
let rev_bit1 = (self.read_efuse(connection, 5)? >> 20) & 0x1;
|
||||
let rev_bit2 = (apb_ctl_date >> 31) & 0x1;
|
||||
|
||||
let rev_bit0 = (word3 >> 15) & 0x1 != 0;
|
||||
let rev_bit1 = (word5 >> 20) & 0x1 != 0;
|
||||
let rev_bit2 = (apb_ctrl_date >> 31) & 0x1 != 0;
|
||||
let combine_value = (rev_bit2 << 2) | (rev_bit1 << 1) | rev_bit0;
|
||||
|
||||
let revision = match (rev_bit0, rev_bit1, rev_bit2) {
|
||||
(true, true, true) => 3,
|
||||
(true, true, false) => 2,
|
||||
(true, false, _) => 1,
|
||||
(false, _, _) => 0,
|
||||
};
|
||||
match combine_value {
|
||||
1 => Ok(1),
|
||||
3 => Ok(2),
|
||||
7 => Ok(3),
|
||||
_ => Ok(0),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Some(revision))
|
||||
fn minor_chip_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
Ok((self.read_efuse(connection, 5)? >> 24) & 0x3)
|
||||
}
|
||||
|
||||
fn crystal_freq(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
@@ -152,7 +153,7 @@ impl Target for Esp32 {
|
||||
bootloader: Option<Vec<u8>>,
|
||||
partition_table: Option<PartitionTable>,
|
||||
image_format: Option<ImageFormatKind>,
|
||||
_chip_revision: Option<u32>,
|
||||
_chip_revision: Option<(u32, u32)>,
|
||||
flash_mode: Option<FlashMode>,
|
||||
flash_size: Option<FlashSize>,
|
||||
flash_freq: Option<FlashFrequency>,
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::{collections::HashMap, ops::Range};
|
||||
|
||||
use esp_idf_part::PartitionTable;
|
||||
|
||||
use super::{Chip, Esp32Params, ReadEFuse, SpiRegisters, Target};
|
||||
use super::{bytes_to_mac_addr, Chip, Esp32Params, ReadEFuse, SpiRegisters, Target};
|
||||
use crate::{
|
||||
connection::Connection,
|
||||
elf::FirmwareImage,
|
||||
@@ -50,18 +50,15 @@ impl Target for Esp32c2 {
|
||||
}
|
||||
|
||||
fn chip_features(&self, _connection: &mut Connection) -> Result<Vec<&str>, Error> {
|
||||
Ok(vec!["WiFi"])
|
||||
Ok(vec!["WiFi", "BLE"])
|
||||
}
|
||||
|
||||
fn chip_revision(&self, connection: &mut Connection) -> Result<Option<u32>, Error> {
|
||||
let block1_addr = self.efuse_reg() + 0x44;
|
||||
let num_word = 3;
|
||||
let pos = 18;
|
||||
fn major_chip_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
Ok(self.read_efuse(connection, 17)? >> 20 & 0x3)
|
||||
}
|
||||
|
||||
let value = connection.read_reg(block1_addr + (num_word * 0x4))?;
|
||||
let value = (value & (0x7 << pos)) >> pos;
|
||||
|
||||
Ok(Some(value))
|
||||
fn minor_chip_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
Ok(self.read_efuse(connection, 17)? >> 16 & 0xf)
|
||||
}
|
||||
|
||||
fn crystal_freq(&self, _connection: &mut Connection) -> Result<u32, Error> {
|
||||
@@ -88,7 +85,7 @@ impl Target for Esp32c2 {
|
||||
bootloader: Option<Vec<u8>>,
|
||||
partition_table: Option<PartitionTable>,
|
||||
image_format: Option<ImageFormatKind>,
|
||||
_chip_revision: Option<u32>,
|
||||
_chip_revision: Option<(u32, u32)>,
|
||||
flash_mode: Option<FlashMode>,
|
||||
flash_size: Option<FlashSize>,
|
||||
flash_freq: Option<FlashFrequency>,
|
||||
@@ -110,6 +107,18 @@ impl Target for Esp32c2 {
|
||||
}
|
||||
}
|
||||
|
||||
/// What is the MAC address?
|
||||
fn mac_address(&self, connection: &mut Connection) -> Result<String, Error> {
|
||||
let word5 = self.read_efuse(connection, 16)?;
|
||||
let word6 = self.read_efuse(connection, 17)?;
|
||||
|
||||
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 spi_registers(&self) -> SpiRegisters {
|
||||
SpiRegisters {
|
||||
base: 0x6000_2000,
|
||||
|
||||
@@ -40,7 +40,7 @@ impl Esp32c3 {
|
||||
|
||||
impl ReadEFuse for Esp32c3 {
|
||||
fn efuse_reg(&self) -> u32 {
|
||||
0x6000_8830
|
||||
0x6000_8800
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,18 +50,18 @@ impl Target for Esp32c3 {
|
||||
}
|
||||
|
||||
fn chip_features(&self, _connection: &mut Connection) -> Result<Vec<&str>, Error> {
|
||||
Ok(vec!["WiFi"])
|
||||
Ok(vec!["WiFi", "BLE"])
|
||||
}
|
||||
|
||||
fn chip_revision(&self, connection: &mut Connection) -> Result<Option<u32>, Error> {
|
||||
let block1_addr = self.efuse_reg() + 0x14;
|
||||
let num_word = 3;
|
||||
let pos = 18;
|
||||
fn major_chip_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
Ok(self.read_efuse(connection, 22)? >> 24 & 0x3)
|
||||
}
|
||||
|
||||
let value = connection.read_reg(block1_addr + (num_word * 0x4))?;
|
||||
let value = (value & (0x7 << pos)) >> pos;
|
||||
fn minor_chip_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let hi = self.read_efuse(connection, 22)? >> 23 & 0x1;
|
||||
let lo = self.read_efuse(connection, 20)? >> 18 & 0x7;
|
||||
|
||||
Ok(Some(value))
|
||||
Ok((hi << 3) + lo)
|
||||
}
|
||||
|
||||
fn crystal_freq(&self, _connection: &mut Connection) -> Result<u32, Error> {
|
||||
@@ -75,7 +75,7 @@ impl Target for Esp32c3 {
|
||||
bootloader: Option<Vec<u8>>,
|
||||
partition_table: Option<PartitionTable>,
|
||||
image_format: Option<ImageFormatKind>,
|
||||
chip_revision: Option<u32>,
|
||||
chip_revision: Option<(u32, u32)>,
|
||||
flash_mode: Option<FlashMode>,
|
||||
flash_size: Option<FlashSize>,
|
||||
flash_freq: Option<FlashFrequency>,
|
||||
@@ -93,7 +93,7 @@ impl Target for Esp32c3 {
|
||||
flash_size,
|
||||
flash_freq,
|
||||
)?)),
|
||||
(ImageFormatKind::DirectBoot, None | Some(3..)) => {
|
||||
(ImageFormatKind::DirectBoot, None | Some((3.., _))) => {
|
||||
Ok(Box::new(DirectBootFormat::new(image, 0)?))
|
||||
}
|
||||
_ => Err(
|
||||
|
||||
@@ -40,21 +40,21 @@ impl Esp32s2 {
|
||||
}
|
||||
|
||||
fn get_block2_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let blk2_word4 = self.read_efuse(connection, 15)?;
|
||||
let blk2_word4 = self.read_efuse(connection, 27)?;
|
||||
let block2_version = (blk2_word4 >> 4) & 0x7;
|
||||
|
||||
Ok(block2_version)
|
||||
}
|
||||
|
||||
fn get_flash_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let blk1_word3 = self.read_efuse(connection, 8)?;
|
||||
let blk1_word3 = self.read_efuse(connection, 20)?;
|
||||
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 blk1_word3 = self.read_efuse(connection, 20)?;
|
||||
let psram_version = (blk1_word3 >> 28) & 0xf;
|
||||
|
||||
Ok(psram_version)
|
||||
@@ -67,7 +67,7 @@ impl Esp32s2 {
|
||||
|
||||
impl ReadEFuse for Esp32s2 {
|
||||
fn efuse_reg(&self) -> u32 {
|
||||
0x3f41_a030
|
||||
0x3f41_a000
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,17 @@ impl Target for Esp32s2 {
|
||||
Ok(features)
|
||||
}
|
||||
|
||||
fn major_chip_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
Ok(self.read_efuse(connection, 20)? >> 18 & 0x3)
|
||||
}
|
||||
|
||||
fn minor_chip_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let hi = self.read_efuse(connection, 20)? >> 20 & 0x1;
|
||||
let lo = self.read_efuse(connection, 21)? >> 4 & 0x7;
|
||||
|
||||
Ok((hi << 3) + lo)
|
||||
}
|
||||
|
||||
fn crystal_freq(&self, _connection: &mut Connection) -> Result<u32, Error> {
|
||||
// The ESP32-S2's XTAL has a fixed frequency of 40MHz.
|
||||
Ok(40)
|
||||
@@ -125,7 +136,7 @@ impl Target for Esp32s2 {
|
||||
bootloader: Option<Vec<u8>>,
|
||||
partition_table: Option<PartitionTable>,
|
||||
image_format: Option<ImageFormatKind>,
|
||||
_chip_revision: Option<u32>,
|
||||
_chip_revision: Option<(u32, u32)>,
|
||||
flash_mode: Option<FlashMode>,
|
||||
flash_size: Option<FlashSize>,
|
||||
flash_freq: Option<FlashFrequency>,
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::ops::Range;
|
||||
|
||||
use esp_idf_part::PartitionTable;
|
||||
|
||||
use super::{bytes_to_mac_addr, Chip, Esp32Params, ReadEFuse, SpiRegisters, Target};
|
||||
use super::{Chip, Esp32Params, ReadEFuse, SpiRegisters, Target};
|
||||
use crate::{
|
||||
connection::Connection,
|
||||
elf::FirmwareImage,
|
||||
@@ -33,11 +33,19 @@ impl Esp32s3 {
|
||||
pub fn has_magic_value(value: u32) -> bool {
|
||||
CHIP_DETECT_MAGIC_VALUES.contains(&value)
|
||||
}
|
||||
|
||||
fn blk_version_major(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
Ok(self.read_efuse(connection, 96)? & 0x3)
|
||||
}
|
||||
|
||||
fn blk_version_minor(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
Ok(self.read_efuse(connection, 20)? >> 24 & 0x7)
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadEFuse for Esp32s3 {
|
||||
fn efuse_reg(&self) -> u32 {
|
||||
0x6000_7030
|
||||
0x6000_7000
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +58,29 @@ impl Target for Esp32s3 {
|
||||
Ok(vec!["WiFi", "BLE"])
|
||||
}
|
||||
|
||||
fn major_chip_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let major = self.read_efuse(connection, 22)? >> 24 & 0x3;
|
||||
|
||||
// Workaround: The major version field was allocated to other purposes when
|
||||
// block version is v1.1. Luckily only chip v0.0 have this kind of block version
|
||||
// and efuse usage.
|
||||
if self.minor_chip_version(connection)? == 0
|
||||
&& self.blk_version_major(connection)? == 1
|
||||
&& self.blk_version_minor(connection)? == 1
|
||||
{
|
||||
Ok(0)
|
||||
} else {
|
||||
Ok(major)
|
||||
}
|
||||
}
|
||||
|
||||
fn minor_chip_version(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let hi = self.read_efuse(connection, 22)? >> 23 & 0x1;
|
||||
let lo = self.read_efuse(connection, 20)? >> 18 & 0x7;
|
||||
|
||||
Ok((hi << 3) + lo)
|
||||
}
|
||||
|
||||
fn crystal_freq(&self, _connection: &mut Connection) -> Result<u32, Error> {
|
||||
// The ESP32-S3's XTAL has a fixed frequency of 40MHz.
|
||||
Ok(40)
|
||||
@@ -61,7 +92,7 @@ impl Target for Esp32s3 {
|
||||
bootloader: Option<Vec<u8>>,
|
||||
partition_table: Option<PartitionTable>,
|
||||
image_format: Option<ImageFormatKind>,
|
||||
_chip_revision: Option<u32>,
|
||||
_chip_revision: Option<(u32, u32)>,
|
||||
flash_mode: Option<FlashMode>,
|
||||
flash_size: Option<FlashSize>,
|
||||
flash_freq: Option<FlashFrequency>,
|
||||
@@ -83,17 +114,6 @@ impl Target for Esp32s3 {
|
||||
}
|
||||
}
|
||||
|
||||
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 spi_registers(&self) -> SpiRegisters {
|
||||
SpiRegisters {
|
||||
base: 0x6000_2000,
|
||||
|
||||
@@ -46,6 +46,20 @@ impl Target for Esp8266 {
|
||||
Ok(vec!["WiFi"])
|
||||
}
|
||||
|
||||
fn major_chip_version(&self, _connection: &mut Connection) -> Result<u32, Error> {
|
||||
Err(Error::UnsupportedFeature {
|
||||
chip: Chip::Esp8266,
|
||||
feature: "reading the major chip version".into(),
|
||||
})
|
||||
}
|
||||
|
||||
fn minor_chip_version(&self, _connection: &mut Connection) -> Result<u32, Error> {
|
||||
Err(Error::UnsupportedFeature {
|
||||
chip: Chip::Esp8266,
|
||||
feature: "reading the minor chip version".into(),
|
||||
})
|
||||
}
|
||||
|
||||
fn crystal_freq(&self, connection: &mut Connection) -> Result<u32, Error> {
|
||||
let uart_div = connection.read_reg(UART_CLKDIV_REG)? & UART_CLKDIV_MASK;
|
||||
let est_xtal = (connection.get_baud()? * uart_div) / 1_000_000 / XTAL_CLK_DIVIDER;
|
||||
@@ -60,7 +74,7 @@ impl Target for Esp8266 {
|
||||
_bootloader: Option<Vec<u8>>,
|
||||
_partition_table: Option<PartitionTable>,
|
||||
image_format: Option<ImageFormatKind>,
|
||||
_chip_revision: Option<u32>,
|
||||
_chip_revision: Option<(u32, u32)>,
|
||||
flash_mode: Option<FlashMode>,
|
||||
flash_size: Option<FlashSize>,
|
||||
flash_freq: Option<FlashFrequency>,
|
||||
|
||||
@@ -254,11 +254,18 @@ pub trait Target: ReadEFuse {
|
||||
/// Enumerate the chip's features, read from eFuse
|
||||
fn chip_features(&self, connection: &mut Connection) -> Result<Vec<&str>, Error>;
|
||||
|
||||
/// Deterimine the chip's revision number, if it has one
|
||||
fn chip_revision(&self, _connection: &mut Connection) -> Result<Option<u32>, Error> {
|
||||
Ok(None)
|
||||
/// Deterimine the chip's revision number
|
||||
fn chip_revision(&self, connection: &mut Connection) -> Result<(u32, u32), Error> {
|
||||
let major = self.major_chip_version(connection)?;
|
||||
let minor = self.minor_chip_version(connection)?;
|
||||
|
||||
Ok((major, minor))
|
||||
}
|
||||
|
||||
fn major_chip_version(&self, connection: &mut Connection) -> Result<u32, Error>;
|
||||
|
||||
fn minor_chip_version(&self, connection: &mut Connection) -> Result<u32, Error>;
|
||||
|
||||
/// What is the crystal frequency?
|
||||
fn crystal_freq(&self, connection: &mut Connection) -> Result<u32, Error>;
|
||||
|
||||
@@ -288,7 +295,7 @@ pub trait Target: ReadEFuse {
|
||||
bootloader: Option<Vec<u8>>,
|
||||
partition_table: Option<PartitionTable>,
|
||||
image_format: Option<ImageFormatKind>,
|
||||
chip_revision: Option<u32>,
|
||||
chip_revision: Option<(u32, u32)>,
|
||||
flash_mode: Option<FlashMode>,
|
||||
flash_size: Option<FlashSize>,
|
||||
flash_freq: Option<FlashFrequency>,
|
||||
@@ -296,8 +303,8 @@ pub trait Target: ReadEFuse {
|
||||
|
||||
/// What is the MAC address?
|
||||
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 word5 = self.read_efuse(connection, 17)?;
|
||||
let word6 = self.read_efuse(connection, 18)?;
|
||||
|
||||
let bytes = ((word6 as u64) << 32) | word5 as u64;
|
||||
let bytes = bytes.to_be_bytes();
|
||||
|
||||
Reference in New Issue
Block a user