Skip to content

Commit e67cd28

Browse files
committed
Add methods for reading the crystal frequency and revision for applicable chips
1 parent 7025dd4 commit e67cd28

File tree

9 files changed

+133
-22
lines changed

9 files changed

+133
-22
lines changed

cargo-espflash/src/main.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
use crate::cargo_config::parse_cargo_config;
2-
use crate::error::UnsupportedTargetError;
1+
use std::{
2+
fs,
3+
path::PathBuf,
4+
process::{exit, Command, ExitStatus, Stdio},
5+
string::ToString,
6+
};
7+
38
use cargo_metadata::Message;
49
use clap::{App, Arg, SubCommand};
510
use error::Error;
@@ -8,12 +13,8 @@ use miette::{IntoDiagnostic, Result, WrapErr};
813
use monitor::monitor;
914
use package_metadata::CargoEspFlashMeta;
1015
use serial::{BaudRate, FlowControl, SerialPort};
11-
use std::{
12-
fs,
13-
path::PathBuf,
14-
process::{exit, Command, ExitStatus, Stdio},
15-
string::ToString,
16-
};
16+
17+
use crate::{cargo_config::parse_cargo_config, error::UnsupportedTargetError};
1718

1819
mod cargo_config;
1920
mod error;
@@ -23,6 +24,7 @@ mod package_metadata;
2324

2425
fn main() -> Result<()> {
2526
miette::set_panic_hook();
27+
2628
let mut app = App::new(env!("CARGO_PKG_NAME"))
2729
.bin_name("cargo")
2830
.subcommand(
@@ -143,7 +145,7 @@ fn main() -> Result<()> {
143145
// provided, display the board info and terminate the application.
144146
let mut flasher = Flasher::connect(serial, speed)?;
145147
if matches.is_present("board_info") {
146-
board_info(&flasher);
148+
board_info(&mut flasher)?;
147149
return Ok(());
148150
}
149151

@@ -200,9 +202,23 @@ fn main() -> Result<()> {
200202
Ok(())
201203
}
202204

203-
fn board_info(flasher: &Flasher) {
204-
println!("Chip type: {}", flasher.chip());
205-
println!("Flash size: {}", flasher.flash_size());
205+
fn board_info(flasher: &mut Flasher) -> Result<()> {
206+
let chip = flasher.chip();
207+
let revision = chip.chip_revision(flasher.connection())?;
208+
let freq = chip.crystal_freq(flasher.connection())?;
209+
210+
// Print the detected chip type, and if available the silicon revision.
211+
print!("Chip type: {}", chip);
212+
if let Some(revision) = revision {
213+
println!(" (revision {})", revision);
214+
} else {
215+
println!();
216+
}
217+
218+
println!("Crystal frequency: {}MHz", freq);
219+
println!("Flash size: {}", flasher.flash_size());
220+
221+
Ok(())
206222
}
207223

208224
fn build(

espflash/src/chip/esp32/esp32.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::ops::Range;
33
use super::Esp32Params;
44
use crate::{
55
chip::{Chip, ChipType, ReadEFuse, SpiRegisters},
6+
connection::Connection,
67
elf::FirmwareImage,
78
image_format::{Esp32BootloaderFormat, ImageFormat, ImageFormatId},
89
Error, PartitionTable,
@@ -32,6 +33,8 @@ pub const PARAMS: Esp32Params = Esp32Params {
3233
impl ChipType for Esp32 {
3334
const CHIP_DETECT_MAGIC_VALUE: u32 = 0x00f01d83;
3435

36+
const UART_CLKDIV_REG: u32 = 0x3ff40014;
37+
3538
const SPI_REGISTERS: SpiRegisters = SpiRegisters {
3639
base: 0x3ff42000,
3740
usr_offset: 0x1c,
@@ -80,6 +83,28 @@ impl ReadEFuse for Esp32 {
8083
const EFUSE_REG_BASE: u32 = 0x3ff5a000;
8184
}
8285

86+
impl Esp32 {
87+
pub fn chip_revision(&self, connection: &mut Connection) -> Result<u32, Error> {
88+
let word3 = self.read_efuse(connection, 3)?;
89+
let word5 = self.read_efuse(connection, 5)?;
90+
91+
let apb_ctrl_date = connection.read_reg(0x3FF6607C)?;
92+
93+
let rev_bit0 = (word3 >> 15) & 0x1 != 0;
94+
let rev_bit1 = (word5 >> 20) & 0x1 != 0;
95+
let rev_bit2 = (apb_ctrl_date >> 31) & 0x1 != 0;
96+
97+
let revision = match (rev_bit0, rev_bit1, rev_bit2) {
98+
(true, true, true) => 3,
99+
(true, true, false) => 2,
100+
(true, false, _) => 1,
101+
(false, _, _) => 0,
102+
};
103+
104+
Ok(revision)
105+
}
106+
}
107+
83108
#[test]
84109
fn test_esp32_rom() {
85110
use std::fs::read;

espflash/src/chip/esp32/esp32c3.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::ops::Range;
33
use super::Esp32Params;
44
use crate::{
55
chip::{ChipType, ReadEFuse, SpiRegisters},
6+
connection::Connection,
67
elf::FirmwareImage,
78
image_format::{Esp32BootloaderFormat, ImageFormat, ImageFormatId},
89
Chip, Error, PartitionTable,
@@ -33,6 +34,8 @@ impl ChipType for Esp32c3 {
3334
const CHIP_DETECT_MAGIC_VALUE: u32 = 0x6921506f;
3435
const CHIP_DETECT_MAGIC_VALUE2: u32 = 0x1b31506f;
3536

37+
const UART_CLKDIV_REG: u32 = 0x3ff40014;
38+
3639
const SPI_REGISTERS: SpiRegisters = SpiRegisters {
3740
base: 0x60002000,
3841
usr_offset: 0x18,
@@ -53,6 +56,11 @@ impl ChipType for Esp32c3 {
5356
const SUPPORTED_TARGETS: &'static [&'static str] =
5457
&["riscv32imc-uknown-none-elf", "riscv32imc-esp-espidf"];
5558

59+
fn crystal_freq(&self, _connection: &mut Connection) -> Result<u32, Error> {
60+
// The ESP32-C3's XTAL has a fixed frequency of 40MHz.
61+
Ok(40)
62+
}
63+
5664
fn get_flash_segments<'a>(
5765
image: &'a FirmwareImage,
5866
bootloader: Option<Vec<u8>>,
@@ -81,3 +89,16 @@ impl ChipType for Esp32c3 {
8189
impl ReadEFuse for Esp32c3 {
8290
const EFUSE_REG_BASE: u32 = 0x60008830;
8391
}
92+
93+
impl Esp32c3 {
94+
pub fn chip_revision(&self, connection: &mut Connection) -> Result<u32, Error> {
95+
let block1_addr = Self::EFUSE_REG_BASE + 0x14;
96+
let num_word = 3;
97+
let pos = 18;
98+
99+
let value = connection.read_reg(block1_addr + (num_word * 0x4))?;
100+
let value = (value & (0x7 << pos)) >> pos;
101+
102+
Ok(value)
103+
}
104+
}

espflash/src/chip/esp32/esp32s2.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::ops::Range;
33
use super::Esp32Params;
44
use crate::{
55
chip::{ChipType, ReadEFuse, SpiRegisters},
6+
connection::Connection,
67
elf::FirmwareImage,
78
image_format::{Esp32BootloaderFormat, ImageFormat, ImageFormatId},
89
Chip, Error, PartitionTable,
@@ -32,6 +33,8 @@ pub const PARAMS: Esp32Params = Esp32Params {
3233
impl ChipType for Esp32s2 {
3334
const CHIP_DETECT_MAGIC_VALUE: u32 = 0x000007c6;
3435

36+
const UART_CLKDIV_REG: u32 = 0x3f400014;
37+
3538
const SPI_REGISTERS: SpiRegisters = SpiRegisters {
3639
base: 0x3f402000,
3740
usr_offset: 0x18,
@@ -51,6 +54,11 @@ impl ChipType for Esp32s2 {
5154
const SUPPORTED_TARGETS: &'static [&'static str] =
5255
&["xtensa-esp32s2-none-elf", "xtensa-esp32s2-espidf"];
5356

57+
fn crystal_freq(&self, _connection: &mut Connection) -> Result<u32, Error> {
58+
// The ESP32-S2's XTAL has a fixed frequency of 40MHz.
59+
Ok(40)
60+
}
61+
5462
fn get_flash_segments<'a>(
5563
image: &'a FirmwareImage,
5664
bootloader: Option<Vec<u8>>,

espflash/src/chip/esp32/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::PartitionTable;
22

3+
#[allow(clippy::module_inception)]
34
mod esp32;
45
mod esp32c3;
56
mod esp32s2;

espflash/src/chip/esp8266.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ pub struct Esp8266;
1717
impl ChipType for Esp8266 {
1818
const CHIP_DETECT_MAGIC_VALUE: u32 = 0xfff0c101;
1919

20+
const UART_CLKDIV_REG: u32 = 0x60000014;
21+
const XTAL_CLK_DIVIDER: u32 = 2;
22+
2023
const SPI_REGISTERS: SpiRegisters = SpiRegisters {
2124
base: 0x60000200,
2225
usr_offset: 0x1c,

espflash/src/chip/mod.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ pub trait ChipType {
2222
const CHIP_DETECT_MAGIC_VALUE: u32;
2323
const CHIP_DETECT_MAGIC_VALUE2: u32 = 0x0; // give default value, as most chips don't only have one
2424

25+
const UART_CLKDIV_REG: u32;
26+
const UART_CLKDIV_MASK: u32 = 0xFFFFF;
27+
const XTAL_CLK_DIVIDER: u32 = 1;
28+
2529
const SPI_REGISTERS: SpiRegisters;
2630
const FLASH_RANGES: &'static [Range<u32>];
2731

@@ -30,6 +34,16 @@ pub trait ChipType {
3034

3135
const SUPPORTED_TARGETS: &'static [&'static str];
3236

37+
/// Determine the frequency of the crytal on the connected chip.
38+
fn crystal_freq(&self, connection: &mut Connection) -> Result<u32, Error> {
39+
let uart_div = connection.read_reg(Self::UART_CLKDIV_REG)? & Self::UART_CLKDIV_MASK;
40+
let est_xtal =
41+
(connection.get_baud().speed() as u32 * uart_div) / 1_000_000 / Self::XTAL_CLK_DIVIDER;
42+
let norm_xtal = if est_xtal > 33 { 40 } else { 26 };
43+
44+
Ok(norm_xtal)
45+
}
46+
3347
/// Get the firmware segments for writing an image to flash
3448
fn get_flash_segments<'a>(
3549
image: &'a FirmwareImage,
@@ -206,12 +220,22 @@ impl Chip {
206220
}
207221
}
208222

209-
pub fn read_efuse(&self, connection: &mut Connection, n: u32) -> Result<u32, Error> {
223+
pub fn crystal_freq(&self, connection: &mut Connection) -> Result<u32, Error> {
210224
match self {
211-
Chip::Esp32 => Esp32.read_efuse(connection, n),
212-
Chip::Esp32c3 => Esp32c3.read_efuse(connection, n),
213-
Chip::Esp32s2 => Esp32s2.read_efuse(connection, n),
214-
Chip::Esp8266 => Esp8266.read_efuse(connection, n),
225+
Chip::Esp32 => Esp32.crystal_freq(connection),
226+
Chip::Esp32c3 => Esp32c3.crystal_freq(connection),
227+
Chip::Esp32s2 => Esp32s2.crystal_freq(connection),
228+
Chip::Esp8266 => Esp8266.crystal_freq(connection),
215229
}
216230
}
231+
232+
pub fn chip_revision(&self, connection: &mut Connection) -> Result<Option<u32>, Error> {
233+
let rev = match self {
234+
Chip::Esp32 => Some(Esp32.chip_revision(connection)?),
235+
Chip::Esp32c3 => Some(Esp32c3.chip_revision(connection)?),
236+
_ => None,
237+
};
238+
239+
Ok(rev)
240+
}
217241
}

espflash/src/connection.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ use crate::{
1111
flasher::Command,
1212
};
1313

14-
pub struct Connection {
15-
serial: SystemPort,
16-
decoder: Decoder,
17-
}
18-
1914
#[derive(Debug, Copy, Clone, BinRead)]
2015
pub struct CommandResponse {
2116
pub resp: u8,
@@ -26,6 +21,12 @@ pub struct CommandResponse {
2621
pub error: u8,
2722
}
2823

24+
pub struct Connection {
25+
serial: SystemPort,
26+
speed: BaudRate,
27+
decoder: Decoder,
28+
}
29+
2930
#[derive(Zeroable, Pod, Copy, Clone, Debug)]
3031
#[repr(C)]
3132
struct WriteRegParams {
@@ -39,6 +40,7 @@ impl Connection {
3940
pub fn new(serial: SystemPort) -> Self {
4041
Connection {
4142
serial,
43+
speed: BaudRate::Baud115200,
4244
decoder: Decoder::new(),
4345
}
4446
}
@@ -78,11 +80,17 @@ impl Connection {
7880
}
7981

8082
pub fn set_baud(&mut self, speed: BaudRate) -> Result<(), Error> {
83+
self.speed = speed;
8184
self.serial
8285
.reconfigure(&|setup: &mut dyn SerialPortSettings| setup.set_baud_rate(speed))?;
86+
8387
Ok(())
8488
}
8589

90+
pub fn get_baud(&self) -> BaudRate {
91+
self.speed
92+
}
93+
8694
pub fn with_timeout<T, F: FnMut(&mut Connection) -> Result<T, Error>>(
8795
&mut self,
8896
timeout: Duration,

espflash/src/flasher.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,11 @@ impl Flasher {
444444
Ok(result)
445445
}
446446

447+
/// The active serial connection being used by the flasher
448+
pub fn connection(&mut self) -> &mut Connection {
449+
&mut self.connection
450+
}
451+
447452
/// The chip type that the flasher is connected to
448453
pub fn chip(&self) -> Chip {
449454
self.chip

0 commit comments

Comments
 (0)