Skip to content

Commit

Permalink
Support different crystal frequencies bootloader (#553)
Browse files Browse the repository at this point in the history
* feat: Support bootloader for different xtal freqs

* docs: Add changelog entry

* docs: Format changelog
  • Loading branch information
SergioGasquez authored Jan 24, 2024
1 parent 074f8bc commit 027e24b
Show file tree
Hide file tree
Showing 17 changed files with 266 additions and 83 deletions.
13 changes: 7 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
24 changes: 16 additions & 8 deletions cargo-espflash/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -580,13 +582,19 @@ 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,
args.save_image_args.file,
flash_data,
args.save_image_args.merge,
args.save_image_args.skip_padding,
xtal_freq,
)?;

Ok(())
Expand Down
Binary file not shown.
Binary file not shown.
24 changes: 16 additions & 8 deletions espflash/src/bin/espflash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -325,13 +327,19 @@ 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,
args.save_image_args.file,
flash_data,
args.save_image_args.merge,
args.save_image_args.skip_padding,
xtal_freq,
)?;

Ok(())
Expand Down
26 changes: 18 additions & 8 deletions espflash/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<XtalFrequency>,
}

/// Open the serial monitor without flashing
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand All @@ -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());

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

Expand Down Expand Up @@ -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(())
Expand Down
17 changes: 10 additions & 7 deletions espflash/src/flasher/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
error::{ConnectionError, Error, ResultExt},
image_format::ImageFormatKind,
interface::Interface,
targets::Chip,
targets::{Chip, XtalFrequency},
};

mod stubs;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)?;

Expand All @@ -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")]
Expand Down Expand Up @@ -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;
}

Expand Down
48 changes: 35 additions & 13 deletions espflash/src/targets/esp32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -16,15 +18,6 @@ const FLASH_RANGES: &[Range<u32>] = &[
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;

Expand Down Expand Up @@ -140,10 +133,14 @@ impl Target for Esp32 {
Ok((self.read_efuse(connection, 5)? >> 24) & 0x3)
}

fn crystal_freq(&self, connection: &mut Connection) -> Result<u32, Error> {
fn crystal_freq(&self, connection: &mut Connection) -> Result<XtalFrequency, 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;
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)
}
Expand All @@ -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<Box<dyn ImageFormat<'a> + '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,
Expand Down
Loading

0 comments on commit 027e24b

Please sign in to comment.