diff --git a/CHANGELOG.md b/CHANGELOG.md index 86872a17..2ca99e63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,16 +10,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added reset strategies (#487) -- Read esp-println generated defmt messages (#466) -- Add --target-app-partition argument to flash command (#461) -- Add --confirm-port argument to flash command (#455) -- Add --chip argument for flash and write-bin commands (#514) -- Add --partition-table-offset argument for specifying the partition table offset (#516) +- Read `esp-println` generated `defmt` messages (#466) +- Add `--target-app-partition` argument to flash command (#461) +- Add `--confirm-port` argument to flash command (#455) +- Add `--chip argument` for flash and write-bin commands (#514) +- Add `--partition-table-offset` argument for specifying the partition table offset (#516) - Add `Serialize` and `Deserialize` to `FlashFrequency`, `FlashMode` and `FlashSize`. (#528) - Add `checksum-md5` command (#536) - Add verify and skipping of unchanged flash regions - add `--no-verify` and `--no-skip` (#538) -- Add --min-chip-rev argument to specify minimum chip revision (#252) +- Add `--min-chip-rev` argument to specify minimum chip revision (#525) - Add `serialport` feature. (#535) +- Add support for 26 MHz bootloader for ESP32 and ESP32-C2 (#553) ### Fixed diff --git a/cargo-espflash/src/main.rs b/cargo-espflash/src/main.rs index 517bb372..53a95267 100644 --- a/cargo-espflash/src/main.rs +++ b/cargo-espflash/src/main.rs @@ -18,7 +18,7 @@ use espflash::{ flasher::{FlashData, FlashSettings}, image_format::ImageFormatKind, logging::initialize_logger, - targets::Chip, + targets::{Chip, XtalFrequency}, update::check_for_update, }; use log::{debug, info, LevelFilter}; @@ -339,19 +339,21 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> { )?; } - flash_elf_image(&mut flasher, &elf_data, flash_data)?; + flash_elf_image(&mut flasher, &elf_data, flash_data, target_xtal_freq)?; } if args.flash_args.monitor { let pid = flasher.get_usb_pid()?; // The 26MHz ESP32-C2's need to be treated as a special case. - let default_baud = - if chip == Chip::Esp32c2 && args.connect_args.no_stub && target_xtal_freq == 26 { - 74_880 - } else { - 115_200 - }; + let default_baud = if chip == Chip::Esp32c2 + && args.connect_args.no_stub + && target_xtal_freq == XtalFrequency::_26Mhz + { + 74_880 + } else { + 115_200 + }; monitor( flasher.into_interface(), @@ -580,6 +582,11 @@ fn save_image(args: SaveImageArgs) -> Result<()> { args.save_image_args.min_chip_rev, )?; + let xtal_freq = args + .save_image_args + .xtal_freq + .unwrap_or(XtalFrequency::default(args.save_image_args.chip)); + save_elf_as_image( &elf_data, args.save_image_args.chip, @@ -587,6 +594,7 @@ fn save_image(args: SaveImageArgs) -> Result<()> { flash_data, args.save_image_args.merge, args.save_image_args.skip_padding, + xtal_freq, )?; Ok(()) diff --git a/espflash/resources/bootloaders/esp32_26-bootloader.bin b/espflash/resources/bootloaders/esp32_26-bootloader.bin new file mode 100644 index 00000000..fe5e98d7 Binary files /dev/null and b/espflash/resources/bootloaders/esp32_26-bootloader.bin differ diff --git a/espflash/resources/bootloaders/esp32c2_26-bootloader.bin b/espflash/resources/bootloaders/esp32c2_26-bootloader.bin new file mode 100644 index 00000000..db48928e Binary files /dev/null and b/espflash/resources/bootloaders/esp32c2_26-bootloader.bin differ diff --git a/espflash/src/bin/espflash.rs b/espflash/src/bin/espflash.rs index 4df6c83f..e761268c 100644 --- a/espflash/src/bin/espflash.rs +++ b/espflash/src/bin/espflash.rs @@ -17,7 +17,7 @@ use espflash::{ flasher::{FlashData, FlashSettings}, image_format::ImageFormatKind, logging::initialize_logger, - targets::Chip, + targets::{Chip, XtalFrequency}, update::check_for_update, }; use log::{debug, info, LevelFilter}; @@ -263,19 +263,21 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> { )?; } - flash_elf_image(&mut flasher, &elf_data, flash_data)?; + flash_elf_image(&mut flasher, &elf_data, flash_data, target_xtal_freq)?; } if args.flash_args.monitor { let pid = flasher.get_usb_pid()?; // The 26MHz ESP32-C2's need to be treated as a special case. - let default_baud = - if chip == Chip::Esp32c2 && args.connect_args.no_stub && target_xtal_freq == 26 { - 74_880 - } else { - 115_200 - }; + let default_baud = if chip == Chip::Esp32c2 + && args.connect_args.no_stub + && target_xtal_freq == XtalFrequency::_26Mhz + { + 74_880 + } else { + 115_200 + }; monitor( flasher.into_interface(), @@ -325,6 +327,11 @@ fn save_image(args: SaveImageArgs) -> Result<()> { args.save_image_args.min_chip_rev, )?; + let xtal_freq = args + .save_image_args + .xtal_freq + .unwrap_or(XtalFrequency::default(args.save_image_args.chip)); + save_elf_as_image( &elf_data, args.save_image_args.chip, @@ -332,6 +339,7 @@ fn save_image(args: SaveImageArgs) -> Result<()> { flash_data, args.save_image_args.merge, args.save_image_args.skip_padding, + xtal_freq, )?; Ok(()) diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index 7dd5ad9a..61647005 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -38,7 +38,7 @@ use crate::{ flasher::{FlashData, FlashFrequency, FlashMode, FlashSize, Flasher, ProgressCallbacks}, image_format::ImageFormatKind, interface::Interface, - targets::Chip, + targets::{Chip, XtalFrequency}, }; pub mod config; @@ -220,6 +220,9 @@ pub struct SaveImageArgs { /// Don't pad the image to the flash size #[arg(long, short = 'P', requires = "merge")] pub skip_padding: bool, + /// Cristal frequency of the target + #[arg(long, short = 'x')] + pub xtal_freq: Option, } /// Open the serial monitor without flashing @@ -372,7 +375,7 @@ pub fn print_board_info(flasher: &mut Flasher) -> Result<()> { } else { println!(); } - println!("Crystal frequency: {}MHz", info.crystal_frequency); + println!("Crystal frequency: {}", info.crystal_frequency); println!("Flash size: {}", info.flash_size); println!("Features: {}", info.features.join(", ")); println!("MAC address: {}", info.mac_address); @@ -400,7 +403,7 @@ pub fn serial_monitor(args: MonitorArgs, config: &Config) -> Result<()> { // The 26MHz ESP32-C2's need to be treated as a special case. let default_baud = if chip == Chip::Esp32c2 && args.connect_args.no_stub - && target.crystal_freq(flasher.connection())? == 26 + && target.crystal_freq(flasher.connection())? == XtalFrequency::_26Mhz { 74_880 } else { @@ -424,15 +427,16 @@ pub fn save_elf_as_image( flash_data: FlashData, merge: bool, skip_padding: bool, + xtal_freq: XtalFrequency, ) -> Result<()> { let image = ElfFirmwareImage::try_from(elf_data)?; if merge { // To get a chip revision, the connection is needed // For simplicity, the revision None is used - let image = chip - .into_target() - .get_flash_image(&image, flash_data.clone(), None)?; + let image = + chip.into_target() + .get_flash_image(&image, flash_data.clone(), None, xtal_freq)?; display_image_size(image.app_size(), image.part_size()); @@ -466,7 +470,7 @@ pub fn save_elf_as_image( } else { let image = chip .into_target() - .get_flash_image(&image, flash_data, None)?; + .get_flash_image(&image, flash_data, None, xtal_freq)?; display_image_size(image.app_size(), image.part_size()); @@ -573,10 +577,16 @@ pub fn flash_elf_image( flasher: &mut Flasher, elf_data: &[u8], flash_data: FlashData, + xtal_freq: XtalFrequency, ) -> Result<()> { // Load the ELF data, optionally using the provider bootloader/partition // table/image format, to the device's flash memory. - flasher.load_elf_to_flash(elf_data, flash_data, Some(&mut EspflashProgress::default()))?; + flasher.load_elf_to_flash( + elf_data, + flash_data, + Some(&mut EspflashProgress::default()), + xtal_freq, + )?; info!("Flashing has completed!"); Ok(()) diff --git a/espflash/src/flasher/mod.rs b/espflash/src/flasher/mod.rs index 157a5b9a..0fff55c5 100644 --- a/espflash/src/flasher/mod.rs +++ b/espflash/src/flasher/mod.rs @@ -23,7 +23,7 @@ use crate::{ error::{ConnectionError, Error, ResultExt}, image_format::ImageFormatKind, interface::Interface, - targets::Chip, + targets::{Chip, XtalFrequency}, }; mod stubs; @@ -461,7 +461,7 @@ pub struct DeviceInfo { /// The revision of the chip pub revision: Option<(u32, u32)>, /// The crystal frequency of the chip - pub crystal_frequency: u32, + pub crystal_frequency: XtalFrequency, /// The total available flash size pub flash_size: FlashSize, /// Device features @@ -894,6 +894,7 @@ impl Flasher { elf_data: &[u8], flash_data: FlashData, mut progress: Option<&mut dyn ProgressCallbacks>, + xtal_freq: XtalFrequency, ) -> Result<(), Error> { let image = ElfFirmwareImage::try_from(elf_data)?; @@ -914,10 +915,12 @@ impl Flasher { None }; - let image = self - .chip - .into_target() - .get_flash_image(&image, flash_data, chip_revision)?; + let image = self.chip.into_target().get_flash_image( + &image, + flash_data, + chip_revision, + xtal_freq, + )?; // When the `cli` feature is enabled, display the image size information. #[cfg(feature = "cli")] @@ -995,7 +998,7 @@ impl Flasher { // The ROM code thinks it uses a 40 MHz XTAL. Recompute the baud rate in order // to trick the ROM code to set the correct baud rate for a 26 MHz XTAL. let mut new_baud = speed; - if self.chip == Chip::Esp32c2 && !self.use_stub && xtal_freq == 26 { + if self.chip == Chip::Esp32c2 && !self.use_stub && xtal_freq == XtalFrequency::_26Mhz { new_baud = new_baud * 40 / 26; } diff --git a/espflash/src/targets/esp32.rs b/espflash/src/targets/esp32.rs index 03e9135d..d54f5223 100644 --- a/espflash/src/targets/esp32.rs +++ b/espflash/src/targets/esp32.rs @@ -6,7 +6,9 @@ use crate::{ error::{Error, UnsupportedImageFormatError}, flasher::{FlashData, FlashFrequency}, image_format::{IdfBootloaderFormat, ImageFormat, ImageFormatKind}, - targets::{bytes_to_mac_addr, Chip, Esp32Params, ReadEFuse, SpiRegisters, Target}, + targets::{ + bytes_to_mac_addr, Chip, Esp32Params, ReadEFuse, SpiRegisters, Target, XtalFrequency, + }, }; const CHIP_DETECT_MAGIC_VALUES: &[u32] = &[0x00f0_1d83]; @@ -16,15 +18,6 @@ const FLASH_RANGES: &[Range] = &[ 0x3f40_0000..0x3f80_0000, // DROM ]; -const PARAMS: Esp32Params = Esp32Params::new( - 0x1000, - 0x1_0000, - 0x3f_0000, - 0, - FlashFrequency::_40Mhz, - include_bytes!("../../resources/bootloaders/esp32-bootloader.bin"), -); - const UART_CLKDIV_REG: u32 = 0x3ff4_0014; const UART_CLKDIV_MASK: u32 = 0xfffff; @@ -140,10 +133,14 @@ impl Target for Esp32 { Ok((self.read_efuse(connection, 5)? >> 24) & 0x3) } - fn crystal_freq(&self, connection: &mut Connection) -> Result { + fn crystal_freq(&self, connection: &mut Connection) -> Result { 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; - let norm_xtal = if est_xtal > 33 { 40 } else { 26 }; + let norm_xtal = if est_xtal > 33 { + XtalFrequency::_40Mhz + } else { + XtalFrequency::_26Mhz + }; Ok(norm_xtal) } @@ -153,17 +150,42 @@ impl Target for Esp32 { image: &'a dyn FirmwareImage<'a>, flash_data: FlashData, _chip_revision: Option<(u32, u32)>, + xtal_freq: XtalFrequency, ) -> Result + 'a>, Error> { let image_format = flash_data .image_format .unwrap_or(ImageFormatKind::EspBootloader); + let booloader: &'static [u8] = match xtal_freq { + XtalFrequency::_40Mhz => { + include_bytes!("../../resources/bootloaders/esp32-bootloader.bin") + } + XtalFrequency::_26Mhz => { + include_bytes!("../../resources/bootloaders/esp32_26-bootloader.bin") + } + _ => { + return Err(Error::UnsupportedFeature { + chip: Chip::Esp32, + feature: "the selected crystal frequency".into(), + }) + } + }; + + let params = Esp32Params::new( + 0x1000, + 0x1_0000, + 0x3f_0000, + 0, + FlashFrequency::_40Mhz, + booloader, + ); + match image_format { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, Chip::Esp32, flash_data.min_chip_rev, - PARAMS, + params, flash_data.partition_table, flash_data.partition_table_offset, flash_data.target_app_partition, diff --git a/espflash/src/targets/esp32c2.rs b/espflash/src/targets/esp32c2.rs index 848ec164..9ba7ae8c 100644 --- a/espflash/src/targets/esp32c2.rs +++ b/espflash/src/targets/esp32c2.rs @@ -6,7 +6,9 @@ use crate::{ error::Error, flasher::{FlashData, FlashFrequency}, image_format::{DirectBootFormat, IdfBootloaderFormat, ImageFormat, ImageFormatKind}, - targets::{bytes_to_mac_addr, Chip, Esp32Params, ReadEFuse, SpiRegisters, Target}, + targets::{ + bytes_to_mac_addr, Chip, Esp32Params, ReadEFuse, SpiRegisters, Target, XtalFrequency, + }, }; const CHIP_DETECT_MAGIC_VALUES: &[u32] = &[ @@ -19,15 +21,6 @@ const FLASH_RANGES: &[Range] = &[ 0x3c00_0000..0x3c40_0000, // DROM ]; -const PARAMS: Esp32Params = Esp32Params::new( - 0x0, - 0x1_0000, - 0x1f_0000, - 12, - FlashFrequency::_30Mhz, - include_bytes!("../../resources/bootloaders/esp32c2-bootloader.bin"), -); - const UART_CLKDIV_REG: u32 = 0x6000_0014; const UART_CLKDIV_MASK: u32 = 0xfffff; @@ -66,10 +59,14 @@ impl Target for Esp32c2 { Ok(self.read_efuse(connection, 17)? >> 16 & 0xf) } - fn crystal_freq(&self, connection: &mut Connection) -> Result { + fn crystal_freq(&self, connection: &mut Connection) -> Result { 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; - let norm_xtal = if est_xtal > 33 { 40 } else { 26 }; + let norm_xtal = if est_xtal > 33 { + XtalFrequency::_40Mhz + } else { + XtalFrequency::_26Mhz + }; Ok(norm_xtal) } @@ -87,17 +84,44 @@ impl Target for Esp32c2 { image: &'a dyn FirmwareImage<'a>, flash_data: FlashData, _chip_revision: Option<(u32, u32)>, + xtal_freq: XtalFrequency, ) -> Result + 'a>, Error> { let image_format = flash_data .image_format .unwrap_or(ImageFormatKind::EspBootloader); + let booloader: &'static [u8] = match xtal_freq { + XtalFrequency::_40Mhz => { + println!("Using 40MHz bootloader"); + include_bytes!("../../resources/bootloaders/esp32c2-bootloader.bin") + } + XtalFrequency::_26Mhz => { + println!("Using 26MHz bootloader"); + include_bytes!("../../resources/bootloaders/esp32c2_26-bootloader.bin") + } + _ => { + return Err(Error::UnsupportedFeature { + chip: Chip::Esp32c2, + feature: "the selected crystal frequency".into(), + }) + } + }; + + let params = Esp32Params::new( + 0x0, + 0x1_0000, + 0x1f_0000, + 12, + FlashFrequency::_30Mhz, + booloader, + ); + match image_format { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, Chip::Esp32c2, flash_data.min_chip_rev, - PARAMS, + params, flash_data.partition_table, flash_data.partition_table_offset, flash_data.target_app_partition, diff --git a/espflash/src/targets/esp32c3.rs b/espflash/src/targets/esp32c3.rs index 0dc98679..c4f226f8 100644 --- a/espflash/src/targets/esp32c3.rs +++ b/espflash/src/targets/esp32c3.rs @@ -6,7 +6,7 @@ use crate::{ error::{Error, UnsupportedImageFormatError}, flasher::{FlashData, FlashFrequency}, image_format::{DirectBootFormat, IdfBootloaderFormat, ImageFormat, ImageFormatKind}, - targets::{Chip, Esp32Params, ReadEFuse, SpiRegisters, Target}, + targets::{Chip, Esp32Params, ReadEFuse, SpiRegisters, Target, XtalFrequency}, }; const CHIP_DETECT_MAGIC_VALUES: &[u32] = &[ @@ -66,9 +66,9 @@ impl Target for Esp32c3 { Ok((hi << 3) + lo) } - fn crystal_freq(&self, _connection: &mut Connection) -> Result { + fn crystal_freq(&self, _connection: &mut Connection) -> Result { // The ESP32-C3's XTAL has a fixed frequency of 40MHz. - Ok(40) + Ok(XtalFrequency::_40Mhz) } fn get_flash_image<'a>( @@ -76,11 +76,19 @@ impl Target for Esp32c3 { image: &'a dyn FirmwareImage<'a>, flash_data: FlashData, chip_revision: Option<(u32, u32)>, + xtal_freq: XtalFrequency, ) -> Result + 'a>, Error> { let image_format = flash_data .image_format .unwrap_or(ImageFormatKind::EspBootloader); + if xtal_freq != XtalFrequency::_40Mhz { + return Err(Error::UnsupportedFeature { + chip: Chip::Esp32c3, + feature: "the selected crystal frequency".into(), + }); + } + match (image_format, chip_revision) { (ImageFormatKind::EspBootloader, _) => Ok(Box::new(IdfBootloaderFormat::new( image, diff --git a/espflash/src/targets/esp32c6.rs b/espflash/src/targets/esp32c6.rs index 035605cc..b6b3bd53 100644 --- a/espflash/src/targets/esp32c6.rs +++ b/espflash/src/targets/esp32c6.rs @@ -6,7 +6,7 @@ use crate::{ error::Error, flasher::{FlashData, FlashFrequency}, image_format::{DirectBootFormat, IdfBootloaderFormat, ImageFormat, ImageFormatKind}, - targets::{Chip, Esp32Params, ReadEFuse, SpiRegisters, Target}, + targets::{Chip, Esp32Params, ReadEFuse, SpiRegisters, Target, XtalFrequency}, }; const CHIP_DETECT_MAGIC_VALUES: &[u32] = &[0x2CE0_806F]; @@ -61,9 +61,9 @@ impl Target for Esp32c6 { Ok((hi << 3) + lo) } - fn crystal_freq(&self, _connection: &mut Connection) -> Result { + fn crystal_freq(&self, _connection: &mut Connection) -> Result { // The ESP32-C6's XTAL has a fixed frequency of 40MHz. - Ok(40) + Ok(XtalFrequency::_40Mhz) } fn get_flash_image<'a>( @@ -71,11 +71,19 @@ impl Target for Esp32c6 { image: &'a dyn FirmwareImage<'a>, flash_data: FlashData, _chip_revision: Option<(u32, u32)>, + xtal_freq: XtalFrequency, ) -> Result + 'a>, Error> { let image_format = flash_data .image_format .unwrap_or(ImageFormatKind::EspBootloader); + if xtal_freq != XtalFrequency::_40Mhz { + return Err(Error::UnsupportedFeature { + chip: Chip::Esp32c6, + feature: "the selected crystal frequency".into(), + }); + } + match image_format { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, diff --git a/espflash/src/targets/esp32h2.rs b/espflash/src/targets/esp32h2.rs index 943e6ba9..7f1adb18 100644 --- a/espflash/src/targets/esp32h2.rs +++ b/espflash/src/targets/esp32h2.rs @@ -8,6 +8,7 @@ use crate::{ error::Error, flasher::{FlashData, FlashFrequency}, image_format::{DirectBootFormat, IdfBootloaderFormat, ImageFormat, ImageFormatKind}, + targets::XtalFrequency, }; const CHIP_DETECT_MAGIC_VALUES: &[u32] = &[0xD7B7_3E80]; @@ -61,9 +62,9 @@ impl Target for Esp32h2 { Ok((hi << 3) + lo) } - fn crystal_freq(&self, _connection: &mut Connection) -> Result { + fn crystal_freq(&self, _connection: &mut Connection) -> Result { // The ESP32-H2's XTAL has a fixed frequency of 32MHz. - Ok(32) + Ok(XtalFrequency::_32Mhz) } fn flash_frequency_encodings(&self) -> HashMap { @@ -79,11 +80,19 @@ impl Target for Esp32h2 { image: &'a dyn FirmwareImage<'a>, flash_data: FlashData, _chip_revision: Option<(u32, u32)>, + xtal_freq: XtalFrequency, ) -> Result + 'a>, Error> { let image_format = flash_data .image_format .unwrap_or(ImageFormatKind::EspBootloader); + if xtal_freq != XtalFrequency::_32Mhz { + return Err(Error::UnsupportedFeature { + chip: Chip::Esp32h2, + feature: "the selected crystal frequency".into(), + }); + } + match image_format { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, diff --git a/espflash/src/targets/esp32p4.rs b/espflash/src/targets/esp32p4.rs index 09c40017..0baa7bcd 100644 --- a/espflash/src/targets/esp32p4.rs +++ b/espflash/src/targets/esp32p4.rs @@ -7,6 +7,7 @@ use crate::{ error::Error, flasher::{FlashData, FlashFrequency}, image_format::{DirectBootFormat, IdfBootloaderFormat, ImageFormat, ImageFormatKind}, + targets::XtalFrequency, }; const CHIP_DETECT_MAGIC_VALUES: &[u32] = &[0x0]; @@ -59,9 +60,9 @@ impl Target for Esp32p4 { Ok(0) } - fn crystal_freq(&self, _connection: &mut Connection) -> Result { + fn crystal_freq(&self, _connection: &mut Connection) -> Result { // The ESP32-P4's XTAL has a fixed frequency of 40MHz. - Ok(40) + Ok(XtalFrequency::_40Mhz) } fn get_flash_image<'a>( @@ -69,11 +70,19 @@ impl Target for Esp32p4 { image: &'a dyn FirmwareImage<'a>, flash_data: FlashData, _chip_revision: Option<(u32, u32)>, + xtal_freq: XtalFrequency, ) -> Result + 'a>, Error> { let image_format = flash_data .image_format .unwrap_or(ImageFormatKind::EspBootloader); + if xtal_freq != XtalFrequency::_40Mhz { + return Err(Error::UnsupportedFeature { + chip: Chip::Esp32p4, + feature: "the selected crystal frequency".into(), + }); + } + match image_format { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, diff --git a/espflash/src/targets/esp32s2.rs b/espflash/src/targets/esp32s2.rs index cabb2e56..215486cf 100644 --- a/espflash/src/targets/esp32s2.rs +++ b/espflash/src/targets/esp32s2.rs @@ -6,7 +6,9 @@ use crate::{ error::{Error, UnsupportedImageFormatError}, flasher::{FlashData, FlashFrequency, FLASH_WRITE_SIZE}, image_format::{IdfBootloaderFormat, ImageFormat, ImageFormatKind}, - targets::{Chip, Esp32Params, ReadEFuse, SpiRegisters, Target, MAX_RAM_BLOCK_SIZE}, + targets::{ + Chip, Esp32Params, ReadEFuse, SpiRegisters, Target, XtalFrequency, MAX_RAM_BLOCK_SIZE, + }, }; const CHIP_DETECT_MAGIC_VALUES: &[u32] = &[0x0000_07c6]; @@ -121,9 +123,9 @@ impl Target for Esp32s2 { Ok((hi << 3) + lo) } - fn crystal_freq(&self, _connection: &mut Connection) -> Result { + fn crystal_freq(&self, _connection: &mut Connection) -> Result { // The ESP32-S2's XTAL has a fixed frequency of 40MHz. - Ok(40) + Ok(XtalFrequency::_40Mhz) } fn flash_write_size(&self, connection: &mut Connection) -> Result { @@ -139,11 +141,19 @@ impl Target for Esp32s2 { image: &'a dyn FirmwareImage<'a>, flash_data: FlashData, _chip_revision: Option<(u32, u32)>, + xtal_freq: XtalFrequency, ) -> Result + 'a>, Error> { let image_format = flash_data .image_format .unwrap_or(ImageFormatKind::EspBootloader); + if xtal_freq != XtalFrequency::_40Mhz { + return Err(Error::UnsupportedFeature { + chip: Chip::Esp32s2, + feature: "the selected crystal frequency".into(), + }); + } + match image_format { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, diff --git a/espflash/src/targets/esp32s3.rs b/espflash/src/targets/esp32s3.rs index f4df473a..79937c78 100644 --- a/espflash/src/targets/esp32s3.rs +++ b/espflash/src/targets/esp32s3.rs @@ -6,7 +6,7 @@ use crate::{ error::Error, flasher::{FlashData, FlashFrequency}, image_format::{DirectBootFormat, IdfBootloaderFormat, ImageFormat, ImageFormatKind}, - targets::{Chip, Esp32Params, ReadEFuse, SpiRegisters, Target}, + targets::{Chip, Esp32Params, ReadEFuse, SpiRegisters, Target, XtalFrequency}, }; const CHIP_DETECT_MAGIC_VALUES: &[u32] = &[0x9]; @@ -83,9 +83,9 @@ impl Target for Esp32s3 { Ok((hi << 3) + lo) } - fn crystal_freq(&self, _connection: &mut Connection) -> Result { + fn crystal_freq(&self, _connection: &mut Connection) -> Result { // The ESP32-S3's XTAL has a fixed frequency of 40MHz. - Ok(40) + Ok(XtalFrequency::_40Mhz) } fn get_flash_image<'a>( @@ -93,11 +93,19 @@ impl Target for Esp32s3 { image: &'a dyn FirmwareImage<'a>, flash_data: FlashData, _chip_revision: Option<(u32, u32)>, + xtal_freq: XtalFrequency, ) -> Result + 'a>, Error> { let image_format = flash_data .image_format .unwrap_or(ImageFormatKind::EspBootloader); + if xtal_freq != XtalFrequency::_40Mhz { + return Err(Error::UnsupportedFeature { + chip: Chip::Esp32s3, + feature: "the selected crystal frequency".into(), + }); + } + match image_format { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, diff --git a/espflash/src/targets/esp8266.rs b/espflash/src/targets/esp8266.rs index 53f73564..9f054fd6 100644 --- a/espflash/src/targets/esp8266.rs +++ b/espflash/src/targets/esp8266.rs @@ -6,7 +6,7 @@ use crate::{ error::{Error, UnsupportedImageFormatError}, flasher::FlashData, image_format::{Esp8266Format, ImageFormat, ImageFormatKind}, - targets::{bytes_to_mac_addr, Chip, ReadEFuse, SpiRegisters, Target}, + targets::{bytes_to_mac_addr, Chip, ReadEFuse, SpiRegisters, Target, XtalFrequency}, }; const CHIP_DETECT_MAGIC_VALUES: &[u32] = &[0xfff0_c101]; @@ -60,10 +60,14 @@ impl Target for Esp8266 { }) } - fn crystal_freq(&self, connection: &mut Connection) -> Result { + fn crystal_freq(&self, connection: &mut Connection) -> Result { 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; - let norm_xtal = if est_xtal > 33 { 40 } else { 26 }; + let norm_xtal = if est_xtal > 33 { + XtalFrequency::_40Mhz + } else { + XtalFrequency::_26Mhz + }; Ok(norm_xtal) } @@ -73,6 +77,7 @@ impl Target for Esp8266 { image: &'a dyn FirmwareImage<'a>, flash_data: FlashData, _chip_revision: Option<(u32, u32)>, + _xtal_freq: XtalFrequency, ) -> Result + 'a>, Error> { let image_format = flash_data .image_format diff --git a/espflash/src/targets/mod.rs b/espflash/src/targets/mod.rs index 6816f36a..f1170f4d 100644 --- a/espflash/src/targets/mod.rs +++ b/espflash/src/targets/mod.rs @@ -9,6 +9,7 @@ use std::collections::HashMap; use esp_idf_part::{AppType, DataType, Partition, PartitionTable, SubType, Type}; +use serde::{Deserialize, Serialize}; use strum::{Display, EnumIter, EnumString, EnumVariantNames}; use self::flash_target::MAX_RAM_BLOCK_SIZE; @@ -46,6 +47,54 @@ mod esp32s3; mod esp8266; mod flash_target; +/// Supported crystal frequencies +/// +/// Note that not all frequencies are supported by each target device. +#[cfg_attr(feature = "cli", derive(clap::ValueEnum))] +#[derive( + Debug, + Default, + Clone, + Copy, + Hash, + PartialEq, + Eq, + Display, + EnumVariantNames, + Serialize, + Deserialize, +)] +#[non_exhaustive] +#[repr(u32)] +pub enum XtalFrequency { + #[strum(serialize = "26 MHz")] + /// 26 MHz + _26Mhz, + #[strum(serialize = "32 MHz")] + /// 32 MHz + _32Mhz, + #[strum(serialize = "40 MHz")] + /// 40 MHz + #[default] + _40Mhz, +} + +impl XtalFrequency { + pub fn default(chip: Chip) -> Self { + match chip { + Chip::Esp32 => Self::_40Mhz, + Chip::Esp32c2 => Self::_40Mhz, + Chip::Esp32c3 => Self::_40Mhz, + Chip::Esp32c6 => Self::_40Mhz, + Chip::Esp32h2 => Self::_32Mhz, + Chip::Esp32p4 => Self::_40Mhz, + Chip::Esp32s2 => Self::_40Mhz, + Chip::Esp32s3 => Self::_40Mhz, + Chip::Esp8266 => Self::_40Mhz, + } + } +} + /// All supported devices #[cfg_attr(feature = "cli", derive(clap::ValueEnum))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Display, EnumIter, EnumString, EnumVariantNames)] @@ -284,7 +333,7 @@ pub trait Target: ReadEFuse { fn minor_chip_version(&self, connection: &mut Connection) -> Result; /// What is the crystal frequency? - fn crystal_freq(&self, connection: &mut Connection) -> Result; + fn crystal_freq(&self, connection: &mut Connection) -> Result; /// Numeric encodings for the flash frequencies supported by a chip fn flash_frequency_encodings(&self) -> HashMap { @@ -306,6 +355,7 @@ pub trait Target: ReadEFuse { image: &'a dyn FirmwareImage<'a>, flash_data: FlashData, chip_revision: Option<(u32, u32)>, + xtal_freq: XtalFrequency, ) -> Result + 'a>, Error>; /// What is the MAC address?