Display the newer 'v{major}.{minor}' chip revision format (#307)

This commit is contained in:
Jesse Braham
2022-11-30 10:10:44 -08:00
committed by GitHub
parent d555956c22
commit b25af06912
9 changed files with 150 additions and 78 deletions

View File

@@ -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,

View File

@@ -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,

View File

@@ -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>,

View File

@@ -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,

View File

@@ -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(

View File

@@ -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>,

View File

@@ -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,

View File

@@ -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>,

View File

@@ -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();