From fe3bd80a4855d036b50b818622a29846dbacfab7 Mon Sep 17 00:00:00 2001 From: Sergio Gasquez Date: Wed, 17 Jan 2024 11:59:46 +0100 Subject: [PATCH 1/3] feat: Support bootloader for different xtal freqs --- cargo-espflash/src/main.rs | 24 +++++--- .../bootloaders/esp32_26-bootloader.bin | Bin 0 -> 26640 bytes .../bootloaders/esp32c2_26-bootloader.bin | Bin 0 -> 18944 bytes espflash/src/bin/espflash.rs | 24 +++++--- espflash/src/cli/mod.rs | 26 ++++++--- espflash/src/flasher/mod.rs | 17 +++--- espflash/src/targets/esp32.rs | 48 +++++++++++----- espflash/src/targets/esp32c2.rs | 50 ++++++++++++----- espflash/src/targets/esp32c3.rs | 14 ++++- espflash/src/targets/esp32c6.rs | 14 ++++- espflash/src/targets/esp32h2.rs | 13 ++++- espflash/src/targets/esp32p4.rs | 13 ++++- espflash/src/targets/esp32s2.rs | 16 +++++- espflash/src/targets/esp32s3.rs | 14 ++++- espflash/src/targets/esp8266.rs | 11 +++- espflash/src/targets/mod.rs | 52 +++++++++++++++++- 16 files changed, 259 insertions(+), 77 deletions(-) create mode 100644 espflash/resources/bootloaders/esp32_26-bootloader.bin create mode 100644 espflash/resources/bootloaders/esp32c2_26-bootloader.bin 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 0000000000000000000000000000000000000000..fe5e98d75e20c27a4c2e3ecef8bbdfccc084b9b0 GIT binary patch literal 26640 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 literal 0 HcmV?d00001 diff --git a/espflash/resources/bootloaders/esp32c2_26-bootloader.bin b/espflash/resources/bootloaders/esp32c2_26-bootloader.bin new file mode 100644 index 0000000000000000000000000000000000000000..db48928e41e431f7edbb1a812ade0eb5d12cac42 GIT binary patch literal 18944 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 XcjooH*)ObLP2I8UeAC&n+2#KLF;vhJ literal 0 HcmV?d00001 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? From 52473df62fef08a7f62f529e1117599d26a87824 Mon Sep 17 00:00:00 2001 From: Sergio Gasquez Date: Wed, 24 Jan 2024 16:15:34 +0100 Subject: [PATCH 2/3] docs: Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86872a17..d3e46aef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 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 `serialport` feature. (#535) +- Add support for 26 MHz bootloader for ESP32 and ESP32-C2 (#553) ### Fixed From c5f644f2ff695ac793d2057f9b7d5f9003db58a6 Mon Sep 17 00:00:00 2001 From: Sergio Gasquez Date: Wed, 24 Jan 2024 16:15:43 +0100 Subject: [PATCH 3/3] docs: Format changelog --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3e46aef..2ca99e63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,15 +10,15 @@ 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)