This commit is contained in:
Jonas Zeunert
2024-08-16 21:57:55 +02:00
parent adeb5c5ec7
commit 4309a2d185
1696 changed files with 279655 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import esptool
if __name__ == "__main__":
esptool._main()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,92 @@
# SPDX-FileCopyrightText: 2014-2023 Espressif Systems (Shanghai) CO LTD,
# other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import configparser
import os
CONFIG_OPTIONS = [
"timeout",
"chip_erase_timeout",
"max_timeout",
"sync_timeout",
"md5_timeout_per_mb",
"erase_region_timeout_per_mb",
"erase_write_timeout_per_mb",
"mem_end_rom_timeout",
"serial_write_timeout",
"connect_attempts",
"write_block_attempts",
"reset_delay",
"custom_reset_sequence",
]
def _validate_config_file(file_path, verbose=False):
if not os.path.exists(file_path):
return False
cfg = configparser.RawConfigParser()
try:
cfg.read(file_path, encoding="UTF-8")
# Only consider it a valid config file if it contains [esptool] section
if cfg.has_section("esptool"):
if verbose:
unknown_opts = list(set(cfg.options("esptool")) - set(CONFIG_OPTIONS))
unknown_opts.sort()
no_of_unknown_opts = len(unknown_opts)
if no_of_unknown_opts > 0:
suffix = "s" if no_of_unknown_opts > 1 else ""
print(
"Ignoring unknown config file option{}: {}".format(
suffix, ", ".join(unknown_opts)
)
)
return True
except (UnicodeDecodeError, configparser.Error) as e:
if verbose:
print(f"Ignoring invalid config file {file_path}: {e}")
return False
def _find_config_file(dir_path, verbose=False):
for candidate in ("esptool.cfg", "setup.cfg", "tox.ini"):
cfg_path = os.path.join(dir_path, candidate)
if _validate_config_file(cfg_path, verbose):
return cfg_path
return None
def load_config_file(verbose=False):
set_with_env_var = False
env_var_path = os.environ.get("ESPTOOL_CFGFILE")
if env_var_path is not None and _validate_config_file(env_var_path):
cfg_file_path = env_var_path
set_with_env_var = True
else:
home_dir = os.path.expanduser("~")
os_config_dir = (
f"{home_dir}/.config/esptool"
if os.name == "posix"
else f"{home_dir}/AppData/Local/esptool/"
)
# Search priority: 1) current dir, 2) OS specific config dir, 3) home dir
for dir_path in (os.getcwd(), os_config_dir, home_dir):
cfg_file_path = _find_config_file(dir_path, verbose)
if cfg_file_path:
break
cfg = configparser.ConfigParser()
cfg["esptool"] = {} # Create an empty esptool config for when no file is found
if cfg_file_path is not None:
# If config file is found and validated, read and parse it
cfg.read(cfg_file_path)
if verbose:
msg = " (set with ESPTOOL_CFGFILE)" if set_with_env_var else ""
print(
f"Loaded custom configuration from "
f"{os.path.abspath(cfg_file_path)}{msg}"
)
return cfg, cfg_file_path

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,178 @@
# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os
import struct
import time
from .util import FatalError
# Used for resetting into bootloader on Unix-like systems
if os.name != "nt":
import fcntl
import termios
# Constants used for terminal status lines reading/setting.
# Taken from pySerial's backend for IO:
# https://github.com/pyserial/pyserial/blob/master/serial/serialposix.py
TIOCMSET = getattr(termios, "TIOCMSET", 0x5418)
TIOCMGET = getattr(termios, "TIOCMGET", 0x5415)
TIOCM_DTR = getattr(termios, "TIOCM_DTR", 0x002)
TIOCM_RTS = getattr(termios, "TIOCM_RTS", 0x004)
DEFAULT_RESET_DELAY = 0.05 # default time to wait before releasing boot pin after reset
class ResetStrategy(object):
def __init__(self, port, reset_delay=DEFAULT_RESET_DELAY):
self.port = port
self.reset_delay = reset_delay
def __call__():
pass
def _setDTR(self, state):
self.port.setDTR(state)
def _setRTS(self, state):
self.port.setRTS(state)
# Work-around for adapters on Windows using the usbser.sys driver:
# generate a dummy change to DTR so that the set-control-line-state
# request is sent with the updated RTS state and the same DTR state
self.port.setDTR(self.port.dtr)
def _setDTRandRTS(self, dtr=False, rts=False):
status = struct.unpack(
"I", fcntl.ioctl(self.port.fileno(), TIOCMGET, struct.pack("I", 0))
)[0]
if dtr:
status |= TIOCM_DTR
else:
status &= ~TIOCM_DTR
if rts:
status |= TIOCM_RTS
else:
status &= ~TIOCM_RTS
fcntl.ioctl(self.port.fileno(), TIOCMSET, struct.pack("I", status))
class ClassicReset(ResetStrategy):
"""
Classic reset sequence, sets DTR and RTS lines sequentially.
"""
def __call__(self):
self._setDTR(False) # IO0=HIGH
self._setRTS(True) # EN=LOW, chip in reset
time.sleep(0.1)
self._setDTR(True) # IO0=LOW
self._setRTS(False) # EN=HIGH, chip out of reset
time.sleep(self.reset_delay)
self._setDTR(False) # IO0=HIGH, done
class UnixTightReset(ResetStrategy):
"""
UNIX-only reset sequence with custom implementation,
which allows setting DTR and RTS lines at the same time.
"""
def __call__(self):
self._setDTRandRTS(False, False)
self._setDTRandRTS(True, True)
self._setDTRandRTS(False, True) # IO0=HIGH & EN=LOW, chip in reset
time.sleep(0.1)
self._setDTRandRTS(True, False) # IO0=LOW & EN=HIGH, chip out of reset
time.sleep(self.reset_delay)
self._setDTRandRTS(False, False) # IO0=HIGH, done
self._setDTR(False) # Needed in some environments to ensure IO0=HIGH
class USBJTAGSerialReset(ResetStrategy):
"""
Custom reset sequence, which is required when the device
is connecting via its USB-JTAG-Serial peripheral.
"""
def __call__(self):
self._setRTS(False)
self._setDTR(False) # Idle
time.sleep(0.1)
self._setDTR(True) # Set IO0
self._setRTS(False)
time.sleep(0.1)
self._setRTS(True) # Reset. Calls inverted to go through (1,1) instead of (0,0)
self._setDTR(False)
self._setRTS(True) # RTS set as Windows only propagates DTR on RTS setting
time.sleep(0.1)
self._setDTR(False)
self._setRTS(False) # Chip out of reset
class HardReset(ResetStrategy):
"""
Reset sequence for hard resetting the chip.
Can be used to reset out of the bootloader or to restart a running app.
"""
def __init__(self, port, uses_usb_otg=False):
super().__init__(port)
self.uses_usb_otg = uses_usb_otg
def __call__(self):
self._setRTS(True) # EN->LOW
if self.uses_usb_otg:
# Give the chip some time to come out of reset,
# to be able to handle further DTR/RTS transitions
time.sleep(0.2)
self._setRTS(False)
time.sleep(0.2)
else:
time.sleep(0.1)
self._setRTS(False)
class CustomReset(ResetStrategy):
"""
Custom reset strategy defined with a string.
CustomReset object is created as "rst = CustomReset(port, seq_str)"
and can be later executed simply with "rst()"
The seq_str input string consists of individual commands divided by "|".
Commands (e.g. R0) are defined by a code (R) and an argument (0).
The commands are:
D: setDTR - 1=True / 0=False
R: setRTS - 1=True / 0=False
U: setDTRandRTS (Unix-only) - 0,0 / 0,1 / 1,0 / or 1,1
W: Wait (time delay) - positive float number
e.g.
"D0|R1|W0.1|D1|R0|W0.05|D0" represents the ClassicReset strategy
"U1,1|U0,1|W0.1|U1,0|W0.05|U0,0" represents the UnixTightReset strategy
"""
format_dict = {
"D": "self.port.setDTR({})",
"R": "self.port.setRTS({})",
"W": "time.sleep({})",
"U": "self._setDTRandRTS({})",
}
def __call__(self):
exec(self.constructed_strategy)
def __init__(self, port, seq_str):
super().__init__(port)
self.constructed_strategy = self._parse_string_to_seq(seq_str)
def _parse_string_to_seq(self, seq_str):
try:
cmds = seq_str.split("|")
fn_calls_list = [self.format_dict[cmd[0]].format(cmd[1:]) for cmd in cmds]
except Exception as e:
raise FatalError(f'Invalid "custom_reset_sequence" option format: {e}')
return "\n".join(fn_calls_list)

View File

@@ -0,0 +1,33 @@
from .esp32 import ESP32ROM
from .esp32c2 import ESP32C2ROM
from .esp32c3 import ESP32C3ROM
from .esp32c6 import ESP32C6ROM
from .esp32c6beta import ESP32C6BETAROM
from .esp32h2 import ESP32H2ROM
from .esp32h2beta1 import ESP32H2BETA1ROM
from .esp32h2beta2 import ESP32H2BETA2ROM
from .esp32p4 import ESP32P4ROM
from .esp32s2 import ESP32S2ROM
from .esp32s3 import ESP32S3ROM
from .esp32s3beta2 import ESP32S3BETA2ROM
from .esp8266 import ESP8266ROM
CHIP_DEFS = {
"esp8266": ESP8266ROM,
"esp32": ESP32ROM,
"esp32s2": ESP32S2ROM,
"esp32s3beta2": ESP32S3BETA2ROM,
"esp32s3": ESP32S3ROM,
"esp32c3": ESP32C3ROM,
"esp32c6beta": ESP32C6BETAROM,
"esp32h2beta1": ESP32H2BETA1ROM,
"esp32h2beta2": ESP32H2BETA2ROM,
"esp32c2": ESP32C2ROM,
"esp32c6": ESP32C6ROM,
"esp32h2": ESP32H2ROM,
"esp32p4": ESP32P4ROM,
}
CHIP_LIST = list(CHIP_DEFS.keys())
ROM_LIST = list(CHIP_DEFS.values())

View File

@@ -0,0 +1,401 @@
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import struct
import time
from ..loader import ESPLoader
from ..util import FatalError, NotSupportedError
class ESP32ROM(ESPLoader):
"""Access class for ESP32 ROM bootloader"""
CHIP_NAME = "ESP32"
IMAGE_CHIP_ID = 0
IS_STUB = False
CHIP_DETECT_MAGIC_VALUE = [0x00F01D83]
IROM_MAP_START = 0x400D0000
IROM_MAP_END = 0x40400000
DROM_MAP_START = 0x3F400000
DROM_MAP_END = 0x3F800000
# ESP32 uses a 4 byte status reply
STATUS_BYTES_LENGTH = 4
SPI_REG_BASE = 0x3FF42000
SPI_USR_OFFS = 0x1C
SPI_USR1_OFFS = 0x20
SPI_USR2_OFFS = 0x24
SPI_MOSI_DLEN_OFFS = 0x28
SPI_MISO_DLEN_OFFS = 0x2C
EFUSE_RD_REG_BASE = 0x3FF5A000
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE + 0x18
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 7 # EFUSE_RD_DISABLE_DL_ENCRYPT
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_RD_REG_BASE # EFUSE_BLK0_WDATA0_REG
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7F << 20 # EFUSE_FLASH_CRYPT_CNT
EFUSE_RD_ABS_DONE_REG = EFUSE_RD_REG_BASE + 0x018
EFUSE_RD_ABS_DONE_0_MASK = 1 << 4
EFUSE_RD_ABS_DONE_1_MASK = 1 << 5
DR_REG_SYSCON_BASE = 0x3FF66000
APB_CTL_DATE_ADDR = DR_REG_SYSCON_BASE + 0x7C
APB_CTL_DATE_V = 0x1
APB_CTL_DATE_S = 31
SPI_W0_OFFS = 0x80
UART_CLKDIV_REG = 0x3FF40014
XTAL_CLK_DIVIDER = 1
RTCCALICFG1 = 0x3FF5F06C
TIMERS_RTC_CALI_VALUE = 0x01FFFFFF
TIMERS_RTC_CALI_VALUE_S = 7
FLASH_SIZES = {
"1MB": 0x00,
"2MB": 0x10,
"4MB": 0x20,
"8MB": 0x30,
"16MB": 0x40,
"32MB": 0x50,
"64MB": 0x60,
"128MB": 0x70,
}
FLASH_FREQUENCY = {
"80m": 0xF,
"40m": 0x0,
"26m": 0x1,
"20m": 0x2,
}
BOOTLOADER_FLASH_OFFSET = 0x1000
OVERRIDE_VDDSDIO_CHOICES = ["1.8V", "1.9V", "OFF"]
MEMORY_MAP = [
[0x00000000, 0x00010000, "PADDING"],
[0x3F400000, 0x3F800000, "DROM"],
[0x3F800000, 0x3FC00000, "EXTRAM_DATA"],
[0x3FF80000, 0x3FF82000, "RTC_DRAM"],
[0x3FF90000, 0x40000000, "BYTE_ACCESSIBLE"],
[0x3FFAE000, 0x40000000, "DRAM"],
[0x3FFE0000, 0x3FFFFFFC, "DIRAM_DRAM"],
[0x40000000, 0x40070000, "IROM"],
[0x40070000, 0x40078000, "CACHE_PRO"],
[0x40078000, 0x40080000, "CACHE_APP"],
[0x40080000, 0x400A0000, "IRAM"],
[0x400A0000, 0x400BFFFC, "DIRAM_IRAM"],
[0x400C0000, 0x400C2000, "RTC_IRAM"],
[0x400D0000, 0x40400000, "IROM"],
[0x50000000, 0x50002000, "RTC_DATA"],
]
FLASH_ENCRYPTED_WRITE_ALIGN = 32
UF2_FAMILY_ID = 0x1C5F21B0
""" Try to read the BLOCK1 (encryption key) and check if it is valid """
def is_flash_encryption_key_valid(self):
"""Bit 0 of efuse_rd_disable[3:0] is mapped to BLOCK1
this bit is at position 16 in EFUSE_BLK0_RDATA0_REG"""
word0 = self.read_efuse(0)
rd_disable = (word0 >> 16) & 0x1
# reading of BLOCK1 is NOT ALLOWED so we assume valid key is programmed
if rd_disable:
return True
else:
# reading of BLOCK1 is ALLOWED so we will read and verify for non-zero.
# When ESP32 has not generated AES/encryption key in BLOCK1,
# the contents will be readable and 0.
# If the flash encryption is enabled it is expected to have a valid
# non-zero key. We break out on first occurance of non-zero value
key_word = [0] * 7
for i in range(len(key_word)):
key_word[i] = self.read_efuse(14 + i)
# key is non-zero so break & return
if key_word[i] != 0:
return True
return False
def get_flash_crypt_config(self):
"""For flash encryption related commands we need to make sure
user has programmed all the relevant efuse correctly so before
writing encrypted write_flash_encrypt esptool will verify the values
of flash_crypt_config to be non zero if they are not read
protected. If the values are zero a warning will be printed
bit 3 in efuse_rd_disable[3:0] is mapped to flash_crypt_config
this bit is at position 19 in EFUSE_BLK0_RDATA0_REG"""
word0 = self.read_efuse(0)
rd_disable = (word0 >> 19) & 0x1
if rd_disable == 0:
"""we can read the flash_crypt_config efuse value
so go & read it (EFUSE_BLK0_RDATA5_REG[31:28])"""
word5 = self.read_efuse(5)
word5 = (word5 >> 28) & 0xF
return word5
else:
# if read of the efuse is disabled we assume it is set correctly
return 0xF
def get_encrypted_download_disabled(self):
return (
self.read_reg(self.EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG)
& self.EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT
)
def get_flash_encryption_enabled(self):
flash_crypt_cnt = (
self.read_reg(self.EFUSE_SPI_BOOT_CRYPT_CNT_REG)
& self.EFUSE_SPI_BOOT_CRYPT_CNT_MASK
)
# Flash encryption enabled when odd number of bits are set
return bin(flash_crypt_cnt).count("1") & 1 != 0
def get_secure_boot_enabled(self):
efuses = self.read_reg(self.EFUSE_RD_ABS_DONE_REG)
rev = self.get_chip_revision()
return efuses & self.EFUSE_RD_ABS_DONE_0_MASK or (
rev >= 300 and efuses & self.EFUSE_RD_ABS_DONE_1_MASK
)
def get_pkg_version(self):
word3 = self.read_efuse(3)
pkg_version = (word3 >> 9) & 0x07
pkg_version += ((word3 >> 2) & 0x1) << 3
return pkg_version
def get_chip_revision(self):
return self.get_major_chip_version() * 100 + self.get_minor_chip_version()
def get_minor_chip_version(self):
return (self.read_efuse(5) >> 24) & 0x3
def get_major_chip_version(self):
rev_bit0 = (self.read_efuse(3) >> 15) & 0x1
rev_bit1 = (self.read_efuse(5) >> 20) & 0x1
apb_ctl_date = self.read_reg(self.APB_CTL_DATE_ADDR)
rev_bit2 = (apb_ctl_date >> self.APB_CTL_DATE_S) & self.APB_CTL_DATE_V
combine_value = (rev_bit2 << 2) | (rev_bit1 << 1) | rev_bit0
revision = {
0: 0,
1: 1,
3: 2,
7: 3,
}.get(combine_value, 0)
return revision
def get_chip_description(self):
pkg_version = self.get_pkg_version()
major_rev = self.get_major_chip_version()
minor_rev = self.get_minor_chip_version()
rev3 = major_rev == 3
single_core = self.read_efuse(3) & (1 << 0) # CHIP_VER DIS_APP_CPU
chip_name = {
0: "ESP32-S0WDQ6" if single_core else "ESP32-D0WDQ6",
1: "ESP32-S0WD" if single_core else "ESP32-D0WD",
2: "ESP32-D2WD",
4: "ESP32-U4WDH",
5: "ESP32-PICO-V3" if rev3 else "ESP32-PICO-D4",
6: "ESP32-PICO-V3-02",
7: "ESP32-D0WDR2-V3",
}.get(pkg_version, "unknown ESP32")
# ESP32-D0WD-V3, ESP32-D0WDQ6-V3
if chip_name.startswith("ESP32-D0WD") and rev3:
chip_name += "-V3"
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
def get_chip_features(self):
features = ["WiFi"]
word3 = self.read_efuse(3)
# names of variables in this section are lowercase
# versions of EFUSE names as documented in TRM and
# ESP-IDF efuse_reg.h
chip_ver_dis_bt = word3 & (1 << 1)
if chip_ver_dis_bt == 0:
features += ["BT"]
chip_ver_dis_app_cpu = word3 & (1 << 0)
if chip_ver_dis_app_cpu:
features += ["Single Core"]
else:
features += ["Dual Core"]
chip_cpu_freq_rated = word3 & (1 << 13)
if chip_cpu_freq_rated:
chip_cpu_freq_low = word3 & (1 << 12)
if chip_cpu_freq_low:
features += ["160MHz"]
else:
features += ["240MHz"]
pkg_version = self.get_pkg_version()
if pkg_version in [2, 4, 5, 6]:
features += ["Embedded Flash"]
if pkg_version == 6:
features += ["Embedded PSRAM"]
word4 = self.read_efuse(4)
adc_vref = (word4 >> 8) & 0x1F
if adc_vref:
features += ["VRef calibration in efuse"]
blk3_part_res = word3 >> 14 & 0x1
if blk3_part_res:
features += ["BLK3 partially reserved"]
word6 = self.read_efuse(6)
coding_scheme = word6 & 0x3
features += [
"Coding Scheme %s"
% {0: "None", 1: "3/4", 2: "Repeat (UNSUPPORTED)", 3: "Invalid"}[
coding_scheme
]
]
return features
def read_efuse(self, n):
"""Read the nth word of the ESP3x EFUSE region."""
return self.read_reg(self.EFUSE_RD_REG_BASE + (4 * n))
def chip_id(self):
raise NotSupportedError(self, "Function chip_id")
def read_mac(self, mac_type="BASE_MAC"):
"""Read MAC from EFUSE region"""
if mac_type != "BASE_MAC":
return None
words = [self.read_efuse(2), self.read_efuse(1)]
bitstring = struct.pack(">II", *words)
bitstring = bitstring[2:8] # trim the 2 byte CRC
return tuple(bitstring)
def get_erase_size(self, offset, size):
return size
def override_vddsdio(self, new_voltage):
new_voltage = new_voltage.upper()
if new_voltage not in self.OVERRIDE_VDDSDIO_CHOICES:
raise FatalError(
"The only accepted VDDSDIO overrides are '1.8V', '1.9V' and 'OFF'"
)
RTC_CNTL_SDIO_CONF_REG = 0x3FF48074
RTC_CNTL_XPD_SDIO_REG = 1 << 31
RTC_CNTL_DREFH_SDIO_M = 3 << 29
RTC_CNTL_DREFM_SDIO_M = 3 << 27
RTC_CNTL_DREFL_SDIO_M = 3 << 25
# RTC_CNTL_SDIO_TIEH = (1 << 23)
# not used here, setting TIEH=1 would set 3.3V output,
# not safe for esptool.py to do
RTC_CNTL_SDIO_FORCE = 1 << 22
RTC_CNTL_SDIO_PD_EN = 1 << 21
reg_val = RTC_CNTL_SDIO_FORCE # override efuse setting
reg_val |= RTC_CNTL_SDIO_PD_EN
if new_voltage != "OFF":
reg_val |= RTC_CNTL_XPD_SDIO_REG # enable internal LDO
if new_voltage == "1.9V":
reg_val |= (
RTC_CNTL_DREFH_SDIO_M | RTC_CNTL_DREFM_SDIO_M | RTC_CNTL_DREFL_SDIO_M
) # boost voltage
self.write_reg(RTC_CNTL_SDIO_CONF_REG, reg_val)
print("VDDSDIO regulator set to %s" % new_voltage)
def read_flash_slow(self, offset, length, progress_fn):
BLOCK_LEN = 64 # ROM read limit per command (this limit is why it's so slow)
data = b""
while len(data) < length:
block_len = min(BLOCK_LEN, length - len(data))
r = self.check_command(
"read flash block",
self.ESP_READ_FLASH_SLOW,
struct.pack("<II", offset + len(data), block_len),
)
if len(r) < block_len:
raise FatalError(
"Expected %d byte block, got %d bytes. Serial errors?"
% (block_len, len(r))
)
# command always returns 64 byte buffer,
# regardless of how many bytes were actually read from flash
data += r[:block_len]
if progress_fn and (len(data) % 1024 == 0 or len(data) == length):
progress_fn(len(data), length)
return data
def get_rom_cal_crystal_freq(self):
"""
Get the crystal frequency calculated by the ROM
"""
# - Simulate the calculation in the ROM to get the XTAL frequency
# calculated by the ROM
cali_val = (
self.read_reg(self.RTCCALICFG1) >> self.TIMERS_RTC_CALI_VALUE_S
) & self.TIMERS_RTC_CALI_VALUE
clk_8M_freq = self.read_efuse(4) & (0xFF) # EFUSE_RD_CK8M_FREQ
rom_calculated_freq = cali_val * 15625 * clk_8M_freq / 40
return rom_calculated_freq
def change_baud(self, baud):
assert self.CHIP_NAME == "ESP32", "This workaround should only apply to ESP32"
# It's a workaround to avoid esp32 CK_8M frequency drift.
rom_calculated_freq = self.get_rom_cal_crystal_freq()
valid_freq = 40000000 if rom_calculated_freq > 33000000 else 26000000
false_rom_baud = int(baud * rom_calculated_freq // valid_freq)
print(f"Changing baud rate to {baud}")
self.command(self.ESP_CHANGE_BAUDRATE, struct.pack("<II", false_rom_baud, 0))
print("Changed.")
self._set_port_baudrate(baud)
time.sleep(0.05) # get rid of garbage sent during baud rate change
self.flush_input()
def check_spi_connection(self, spi_connection):
# Pins 30, 31 do not exist
if not set(spi_connection).issubset(set(range(0, 30)) | set((32, 33))):
raise FatalError("SPI Pin numbers must be in the range 0-29, 32, or 33.")
class ESP32StubLoader(ESP32ROM):
"""Access class for ESP32 stub loader, runs on top of ROM."""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
def change_baud(self, baud):
ESPLoader.change_baud(self, baud)
ESP32ROM.STUB_CLASS = ESP32StubLoader

View File

@@ -0,0 +1,182 @@
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import struct
import time
from .esp32c3 import ESP32C3ROM
from ..loader import ESPLoader
from ..util import FatalError
class ESP32C2ROM(ESP32C3ROM):
CHIP_NAME = "ESP32-C2"
IMAGE_CHIP_ID = 12
IROM_MAP_START = 0x42000000
IROM_MAP_END = 0x42400000
DROM_MAP_START = 0x3C000000
DROM_MAP_END = 0x3C400000
# Magic value for ESP32C2 ECO0 and ECO1 respectively
CHIP_DETECT_MAGIC_VALUE = [0x6F51306F, 0x7C41A06F]
EFUSE_BASE = 0x60008800
EFUSE_BLOCK2_ADDR = EFUSE_BASE + 0x040
MAC_EFUSE_REG = EFUSE_BASE + 0x040
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x30
EFUSE_SECURE_BOOT_EN_MASK = 1 << 21
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x30
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_BASE + 0x30
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 6
EFUSE_XTS_KEY_LENGTH_256_REG = EFUSE_BASE + 0x30
EFUSE_XTS_KEY_LENGTH_256 = 1 << 10
EFUSE_BLOCK_KEY0_REG = EFUSE_BASE + 0x60
EFUSE_RD_DIS_REG = EFUSE_BASE + 0x30
EFUSE_RD_DIS = 3
FLASH_FREQUENCY = {
"60m": 0xF,
"30m": 0x0,
"20m": 0x1,
"15m": 0x2,
}
MEMORY_MAP = [
[0x00000000, 0x00010000, "PADDING"],
[0x3C000000, 0x3C400000, "DROM"],
[0x3FCA0000, 0x3FCE0000, "DRAM"],
[0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
[0x3FF00000, 0x3FF50000, "DROM_MASK"],
[0x40000000, 0x40090000, "IROM_MASK"],
[0x42000000, 0x42400000, "IROM"],
[0x4037C000, 0x403C0000, "IRAM"],
]
UF2_FAMILY_ID = 0x2B88D29C
def get_pkg_version(self):
num_word = 1
return (self.read_reg(self.EFUSE_BLOCK2_ADDR + (4 * num_word)) >> 22) & 0x07
def get_chip_description(self):
chip_name = {
0: "ESP32-C2",
1: "ESP32-C2",
}.get(self.get_pkg_version(), "unknown ESP32-C2")
major_rev = self.get_major_chip_version()
minor_rev = self.get_minor_chip_version()
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
def get_minor_chip_version(self):
num_word = 1
return (self.read_reg(self.EFUSE_BLOCK2_ADDR + (4 * num_word)) >> 16) & 0xF
def get_major_chip_version(self):
num_word = 1
return (self.read_reg(self.EFUSE_BLOCK2_ADDR + (4 * num_word)) >> 20) & 0x3
def get_flash_cap(self):
# ESP32-C2 doesn't have eFuse field FLASH_CAP.
# Can't get info about the flash chip.
return 0
def get_flash_vendor(self):
# ESP32-C2 doesn't have eFuse field FLASH_VENDOR.
# Can't get info about the flash chip.
return ""
def get_crystal_freq(self):
# The crystal detection algorithm of ESP32/ESP8266 works for ESP32-C2 as well.
return ESPLoader.get_crystal_freq(self)
def change_baud(self, baud):
rom_with_26M_XTAL = not self.IS_STUB and self.get_crystal_freq() == 26
if rom_with_26M_XTAL:
# The code is copied over from ESPLoader.change_baud().
# Probably this is just a temporary solution until the next chip revision.
# 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.
false_rom_baud = baud * 40 // 26
print(f"Changing baud rate to {baud}")
self.command(
self.ESP_CHANGE_BAUDRATE, struct.pack("<II", false_rom_baud, 0)
)
print("Changed.")
self._set_port_baudrate(baud)
time.sleep(0.05) # get rid of garbage sent during baud rate change
self.flush_input()
else:
ESPLoader.change_baud(self, baud)
def _post_connect(self):
# ESP32C2 ECO0 is no longer supported by the flasher stub
if not self.secure_download_mode and self.get_chip_revision() == 0:
self.stub_is_disabled = True
self.IS_STUB = False
""" Try to read (encryption key) and check if it is valid """
def is_flash_encryption_key_valid(self):
key_len_256 = (
self.read_reg(self.EFUSE_XTS_KEY_LENGTH_256_REG)
& self.EFUSE_XTS_KEY_LENGTH_256
)
word0 = self.read_reg(self.EFUSE_RD_DIS_REG) & self.EFUSE_RD_DIS
rd_disable = word0 == 3 if key_len_256 else word0 == 1
# reading of BLOCK3 is NOT ALLOWED so we assume valid key is programmed
if rd_disable:
return True
else:
# reading of BLOCK3 is ALLOWED so we will read and verify for non-zero.
# When chip has not generated AES/encryption key in BLOCK3,
# the contents will be readable and 0.
# If the flash encryption is enabled it is expected to have a valid
# non-zero key. We break out on first occurance of non-zero value
key_word = [0] * 7 if key_len_256 else [0] * 3
for i in range(len(key_word)):
key_word[i] = self.read_reg(self.EFUSE_BLOCK_KEY0_REG + i * 4)
# key is non-zero so break & return
if key_word[i] != 0:
return True
return False
def check_spi_connection(self, spi_connection):
if not set(spi_connection).issubset(set(range(0, 21))):
raise FatalError("SPI Pin numbers must be in the range 0-20.")
class ESP32C2StubLoader(ESP32C2ROM):
"""Access class for ESP32C2 stub loader, runs on top of ROM.
(Basically the same as ESP32StubLoader, but different base class.
Can possibly be made into a mixin.)
"""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
ESP32C2ROM.STUB_CLASS = ESP32C2StubLoader

View File

@@ -0,0 +1,260 @@
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import struct
from .esp32 import ESP32ROM
from ..loader import ESPLoader
from ..util import FatalError, NotImplementedInROMError
class ESP32C3ROM(ESP32ROM):
CHIP_NAME = "ESP32-C3"
IMAGE_CHIP_ID = 5
IROM_MAP_START = 0x42000000
IROM_MAP_END = 0x42800000
DROM_MAP_START = 0x3C000000
DROM_MAP_END = 0x3C800000
SPI_REG_BASE = 0x60002000
SPI_USR_OFFS = 0x18
SPI_USR1_OFFS = 0x1C
SPI_USR2_OFFS = 0x20
SPI_MOSI_DLEN_OFFS = 0x24
SPI_MISO_DLEN_OFFS = 0x28
SPI_W0_OFFS = 0x58
BOOTLOADER_FLASH_OFFSET = 0x0
# Magic values for ESP32-C3 eco 1+2, eco 3, eco 6, and eco 7 respectively
CHIP_DETECT_MAGIC_VALUE = [0x6921506F, 0x1B31506F, 0x4881606F, 0x4361606F]
UART_DATE_REG_ADDR = 0x60000000 + 0x7C
UART_CLKDIV_REG = 0x60000014
EFUSE_BASE = 0x60008800
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044
MAC_EFUSE_REG = EFUSE_BASE + 0x044
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY0_SHIFT = 24
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY1_SHIFT = 28
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY2_SHIFT = 0
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY3_SHIFT = 4
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY4_SHIFT = 8
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY5_SHIFT = 12
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
PURPOSE_VAL_XTS_AES128_KEY = 4
SUPPORTS_ENCRYPTED_FLASH = True
FLASH_ENCRYPTED_WRITE_ALIGN = 16
UARTDEV_BUF_NO = 0x3FCDF07C # Variable in ROM .bss which indicates the port in use
UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3 # The above var when USB-JTAG/Serial is used
RTCCNTL_BASE_REG = 0x60008000
RTC_CNTL_SWD_CONF_REG = RTCCNTL_BASE_REG + 0x00AC
RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 31
RTC_CNTL_SWD_WPROTECT_REG = RTCCNTL_BASE_REG + 0x00B0
RTC_CNTL_SWD_WKEY = 0x8F1D312A
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0090
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00A8
RTC_CNTL_WDT_WKEY = 0x50D83AA1
MEMORY_MAP = [
[0x00000000, 0x00010000, "PADDING"],
[0x3C000000, 0x3C800000, "DROM"],
[0x3FC80000, 0x3FCE0000, "DRAM"],
[0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
[0x3FF00000, 0x3FF20000, "DROM_MASK"],
[0x40000000, 0x40060000, "IROM_MASK"],
[0x42000000, 0x42800000, "IROM"],
[0x4037C000, 0x403E0000, "IRAM"],
[0x50000000, 0x50002000, "RTC_IRAM"],
[0x50000000, 0x50002000, "RTC_DRAM"],
[0x600FE000, 0x60100000, "MEM_INTERNAL2"],
]
UF2_FAMILY_ID = 0xD42BA06C
def get_pkg_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x07
def get_minor_chip_version(self):
hi_num_word = 5
hi = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * hi_num_word)) >> 23) & 0x01
low_num_word = 3
low = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * low_num_word)) >> 18) & 0x07
return (hi << 3) + low
def get_major_chip_version(self):
num_word = 5
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 24) & 0x03
def get_flash_cap(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 27) & 0x07
def get_flash_vendor(self):
num_word = 4
vendor_id = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x07
return {1: "XMC", 2: "GD", 3: "FM", 4: "TT", 5: "ZBIT"}.get(vendor_id, "")
def get_chip_description(self):
chip_name = {
0: "ESP32-C3 (QFN32)",
1: "ESP8685 (QFN28)",
2: "ESP32-C3 AZ (QFN32)",
3: "ESP8686 (QFN24)",
}.get(self.get_pkg_version(), "unknown ESP32-C3")
major_rev = self.get_major_chip_version()
minor_rev = self.get_minor_chip_version()
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
def get_chip_features(self):
features = ["WiFi", "BLE"]
flash = {
0: None,
1: "Embedded Flash 4MB",
2: "Embedded Flash 2MB",
3: "Embedded Flash 1MB",
4: "Embedded Flash 8MB",
}.get(self.get_flash_cap(), "Unknown Embedded Flash")
if flash is not None:
features += [flash + f" ({self.get_flash_vendor()})"]
return features
def get_crystal_freq(self):
# ESP32C3 XTAL is fixed to 40MHz
return 40
def override_vddsdio(self, new_voltage):
raise NotImplementedInROMError(
"VDD_SDIO overrides are not supported for ESP32-C3"
)
def read_mac(self, mac_type="BASE_MAC"):
"""Read MAC from EFUSE region"""
if mac_type != "BASE_MAC":
return None
mac0 = self.read_reg(self.MAC_EFUSE_REG)
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
bitstring = struct.pack(">II", mac1, mac0)[2:]
return tuple(bitstring)
def get_flash_crypt_config(self):
return None # doesn't exist on ESP32-C3
def get_secure_boot_enabled(self):
return (
self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG)
& self.EFUSE_SECURE_BOOT_EN_MASK
)
def get_key_block_purpose(self, key_block):
if key_block < 0 or key_block > 5:
raise FatalError("Valid key block numbers must be in range 0-5")
reg, shift = [
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
][key_block]
return (self.read_reg(reg) >> shift) & 0xF
def is_flash_encryption_key_valid(self):
# Need to see an AES-128 key
purposes = [self.get_key_block_purpose(b) for b in range(6)]
return any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes)
def change_baud(self, baud):
ESPLoader.change_baud(self, baud)
def uses_usb_jtag_serial(self):
"""
Check the UARTDEV_BUF_NO register to see if USB-JTAG/Serial is being used
"""
if self.secure_download_mode:
return False # Can't detect USB-JTAG/Serial in secure download mode
return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_JTAG_SERIAL
def disable_watchdogs(self):
# When USB-JTAG/Serial is used, the RTC WDT and SWD watchdog are not reset
# and can then reset the board during flashing. Disable or autofeed them.
if self.uses_usb_jtag_serial():
# Disable RTC WDT
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY)
self.write_reg(self.RTC_CNTL_WDTCONFIG0_REG, 0)
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0)
# Automatically feed SWD
self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, self.RTC_CNTL_SWD_WKEY)
self.write_reg(
self.RTC_CNTL_SWD_CONF_REG,
self.read_reg(self.RTC_CNTL_SWD_CONF_REG)
| self.RTC_CNTL_SWD_AUTO_FEED_EN,
)
self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, 0)
def _post_connect(self):
if not self.sync_stub_detected: # Don't run if stub is reused
self.disable_watchdogs()
def check_spi_connection(self, spi_connection):
if not set(spi_connection).issubset(set(range(0, 22))):
raise FatalError("SPI Pin numbers must be in the range 0-21.")
if any([v for v in spi_connection if v in [18, 19]]):
print(
"WARNING: GPIO pins 18 and 19 are used by USB-Serial/JTAG, "
"consider using other pins for SPI flash connection."
)
class ESP32C3StubLoader(ESP32C3ROM):
"""Access class for ESP32C3 stub loader, runs on top of ROM.
(Basically the same as ESP32StubLoader, but different base class.
Can possibly be made into a mixin.)
"""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
ESP32C3ROM.STUB_CLASS = ESP32C3StubLoader

View File

@@ -0,0 +1,212 @@
# SPDX-FileCopyrightText: 2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import struct
from .esp32c3 import ESP32C3ROM
from ..util import FatalError, NotImplementedInROMError
class ESP32C6ROM(ESP32C3ROM):
CHIP_NAME = "ESP32-C6"
IMAGE_CHIP_ID = 13
IROM_MAP_START = 0x42000000
IROM_MAP_END = 0x42800000
DROM_MAP_START = 0x42800000
DROM_MAP_END = 0x43000000
BOOTLOADER_FLASH_OFFSET = 0x0
# Magic value for ESP32C6
CHIP_DETECT_MAGIC_VALUE = [0x2CE0806F]
SPI_REG_BASE = 0x60003000
SPI_USR_OFFS = 0x18
SPI_USR1_OFFS = 0x1C
SPI_USR2_OFFS = 0x20
SPI_MOSI_DLEN_OFFS = 0x24
SPI_MISO_DLEN_OFFS = 0x28
SPI_W0_OFFS = 0x58
UART_DATE_REG_ADDR = 0x60000000 + 0x7C
EFUSE_BASE = 0x600B0800
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044
MAC_EFUSE_REG = EFUSE_BASE + 0x044
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY0_SHIFT = 24
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY1_SHIFT = 28
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY2_SHIFT = 0
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY3_SHIFT = 4
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY4_SHIFT = 8
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY5_SHIFT = 12
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
PURPOSE_VAL_XTS_AES128_KEY = 4
SUPPORTS_ENCRYPTED_FLASH = True
FLASH_ENCRYPTED_WRITE_ALIGN = 16
UARTDEV_BUF_NO = 0x4087F580 # Variable in ROM .bss which indicates the port in use
UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3 # The above var when USB-JTAG/Serial is used
DR_REG_LP_WDT_BASE = 0x600B1C00
RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_RWDT_CONFIG0_REG
RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0018 # LP_WDT_RWDT_WPROTECT_REG
RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x001C # LP_WDT_SWD_CONFIG_REG
RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 18
RTC_CNTL_SWD_WPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0020 # LP_WDT_SWD_WPROTECT_REG
RTC_CNTL_SWD_WKEY = 0x50D83AA1 # LP_WDT_SWD_WKEY, same as WDT key in this case
FLASH_FREQUENCY = {
"80m": 0x0, # workaround for wrong mspi HS div value in ROM
"40m": 0x0,
"20m": 0x2,
}
MEMORY_MAP = [
[0x00000000, 0x00010000, "PADDING"],
[0x42800000, 0x43000000, "DROM"],
[0x40800000, 0x40880000, "DRAM"],
[0x40800000, 0x40880000, "BYTE_ACCESSIBLE"],
[0x4004AC00, 0x40050000, "DROM_MASK"],
[0x40000000, 0x4004AC00, "IROM_MASK"],
[0x42000000, 0x42800000, "IROM"],
[0x40800000, 0x40880000, "IRAM"],
[0x50000000, 0x50004000, "RTC_IRAM"],
[0x50000000, 0x50004000, "RTC_DRAM"],
[0x600FE000, 0x60100000, "MEM_INTERNAL2"],
]
UF2_FAMILY_ID = 0x540DDF62
def get_pkg_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 24) & 0x07
def get_minor_chip_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 18) & 0x0F
def get_major_chip_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 22) & 0x03
def get_chip_description(self):
chip_name = {
0: "ESP32-C6 (QFN40)",
1: "ESP32-C6FH4 (QFN32)",
}.get(self.get_pkg_version(), "unknown ESP32-C6")
major_rev = self.get_major_chip_version()
minor_rev = self.get_minor_chip_version()
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
def get_chip_features(self):
return ["WiFi 6", "BT 5", "IEEE802.15.4"]
def get_crystal_freq(self):
# ESP32C6 XTAL is fixed to 40MHz
return 40
def override_vddsdio(self, new_voltage):
raise NotImplementedInROMError(
"VDD_SDIO overrides are not supported for ESP32-C6"
)
def read_mac(self, mac_type="BASE_MAC"):
"""Read MAC from EFUSE region"""
mac0 = self.read_reg(self.MAC_EFUSE_REG)
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
base_mac = struct.pack(">II", mac1, mac0)[2:]
ext_mac = struct.pack(">H", (mac1 >> 16) & 0xFFFF)
eui64 = base_mac[0:3] + ext_mac + base_mac[3:6]
# BASE MAC: 60:55:f9:f7:2c:a2
# EUI64 MAC: 60:55:f9:ff:fe:f7:2c:a2
# EXT_MAC: ff:fe
macs = {
"BASE_MAC": tuple(base_mac),
"EUI64": tuple(eui64),
"MAC_EXT": tuple(ext_mac),
}
return macs.get(mac_type, None)
def get_flash_crypt_config(self):
return None # doesn't exist on ESP32-C6
def get_secure_boot_enabled(self):
return (
self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG)
& self.EFUSE_SECURE_BOOT_EN_MASK
)
def get_key_block_purpose(self, key_block):
if key_block < 0 or key_block > 5:
raise FatalError("Valid key block numbers must be in range 0-5")
reg, shift = [
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
][key_block]
return (self.read_reg(reg) >> shift) & 0xF
def is_flash_encryption_key_valid(self):
# Need to see an AES-128 key
purposes = [self.get_key_block_purpose(b) for b in range(6)]
return any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes)
def check_spi_connection(self, spi_connection):
if not set(spi_connection).issubset(set(range(0, 31))):
raise FatalError("SPI Pin numbers must be in the range 0-30.")
if any([v for v in spi_connection if v in [12, 13]]):
print(
"WARNING: GPIO pins 12 and 13 are used by USB-Serial/JTAG, "
"consider using other pins for SPI flash connection."
)
class ESP32C6StubLoader(ESP32C6ROM):
"""Access class for ESP32C6 stub loader, runs on top of ROM.
(Basically the same as ESP32StubLoader, but different base class.
Can possibly be made into a mixin.)
"""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
ESP32C6ROM.STUB_CLASS = ESP32C6StubLoader

View File

@@ -0,0 +1,27 @@
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
from .esp32c3 import ESP32C3ROM
class ESP32C6BETAROM(ESP32C3ROM):
CHIP_NAME = "ESP32-C6(beta)"
IMAGE_CHIP_ID = 7
CHIP_DETECT_MAGIC_VALUE = [0x0DA1806F]
UART_DATE_REG_ADDR = 0x00000500
def get_chip_description(self):
chip_name = {
0: "ESP32-C6 (QFN40)",
1: "ESP32-C6FH4 (QFN32)",
}.get(self.get_pkg_version(), "unknown ESP32-C6")
major_rev = self.get_major_chip_version()
minor_rev = self.get_minor_chip_version()
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
def _post_connect(self):
pass

View File

@@ -0,0 +1,91 @@
# SPDX-FileCopyrightText: 2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
from .esp32c6 import ESP32C6ROM
from ..util import FatalError
class ESP32H2ROM(ESP32C6ROM):
CHIP_NAME = "ESP32-H2"
IMAGE_CHIP_ID = 16
# Magic value for ESP32H2
CHIP_DETECT_MAGIC_VALUE = [0xD7B73E80]
DR_REG_LP_WDT_BASE = 0x600B1C00
RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_RWDT_CONFIG0_REG
RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x001C # LP_WDT_RWDT_WPROTECT_REG
RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x0020 # LP_WDT_SWD_CONFIG_REG
RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 18
RTC_CNTL_SWD_WPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0024 # LP_WDT_SWD_WPROTECT_REG
RTC_CNTL_SWD_WKEY = 0x50D83AA1 # LP_WDT_SWD_WKEY, same as WDT key in this case
FLASH_FREQUENCY = {
"48m": 0xF,
"24m": 0x0,
"16m": 0x1,
"12m": 0x2,
}
UF2_FAMILY_ID = 0x332726F6
def get_pkg_version(self):
num_word = 4
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x07
def get_minor_chip_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 18) & 0x07
def get_major_chip_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x03
def get_chip_description(self):
chip_name = {
0: "ESP32-H2",
}.get(self.get_pkg_version(), "unknown ESP32-H2")
major_rev = self.get_major_chip_version()
minor_rev = self.get_minor_chip_version()
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
def get_chip_features(self):
return ["BLE", "IEEE802.15.4"]
def get_crystal_freq(self):
# ESP32H2 XTAL is fixed to 32MHz
return 32
def check_spi_connection(self, spi_connection):
if not set(spi_connection).issubset(set(range(0, 28))):
raise FatalError("SPI Pin numbers must be in the range 0-27.")
if any([v for v in spi_connection if v in [26, 27]]):
print(
"WARNING: GPIO pins 26 and 27 are used by USB-Serial/JTAG, "
"consider using other pins for SPI flash connection."
)
class ESP32H2StubLoader(ESP32H2ROM):
"""Access class for ESP32H2 stub loader, runs on top of ROM.
(Basically the same as ESP32StubLoader, but different base class.
Can possibly be made into a mixin.)
"""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
ESP32H2ROM.STUB_CLASS = ESP32H2StubLoader

View File

@@ -0,0 +1,164 @@
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import struct
from .esp32c3 import ESP32C3ROM
from ..util import FatalError, NotImplementedInROMError
class ESP32H2BETA1ROM(ESP32C3ROM):
CHIP_NAME = "ESP32-H2(beta1)"
IMAGE_CHIP_ID = 10
IROM_MAP_START = 0x42000000
IROM_MAP_END = 0x42800000
DROM_MAP_START = 0x3C000000
DROM_MAP_END = 0x3C800000
SPI_REG_BASE = 0x60002000
SPI_USR_OFFS = 0x18
SPI_USR1_OFFS = 0x1C
SPI_USR2_OFFS = 0x20
SPI_MOSI_DLEN_OFFS = 0x24
SPI_MISO_DLEN_OFFS = 0x28
SPI_W0_OFFS = 0x58
BOOTLOADER_FLASH_OFFSET = 0x0
CHIP_DETECT_MAGIC_VALUE = [0xCA26CC22]
UART_DATE_REG_ADDR = 0x60000000 + 0x7C
EFUSE_BASE = 0x6001A000
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044
MAC_EFUSE_REG = EFUSE_BASE + 0x044
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY0_SHIFT = 24
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY1_SHIFT = 28
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY2_SHIFT = 0
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY3_SHIFT = 4
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY4_SHIFT = 8
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY5_SHIFT = 12
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
PURPOSE_VAL_XTS_AES128_KEY = 4
SUPPORTS_ENCRYPTED_FLASH = True
FLASH_ENCRYPTED_WRITE_ALIGN = 16
MEMORY_MAP = []
FLASH_FREQUENCY = {
"48m": 0xF,
"24m": 0x0,
"16m": 0x1,
"12m": 0x2,
}
def get_pkg_version(self):
num_word = 4
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x07
def get_minor_chip_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 18) & 0x07
def get_major_chip_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x03
def get_chip_description(self):
chip_name = {
0: "ESP32-H2",
}.get(self.get_pkg_version(), "unknown ESP32-H2")
major_rev = self.get_major_chip_version()
minor_rev = self.get_minor_chip_version()
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
def get_chip_features(self):
return ["BLE", "IEEE802.15.4"]
def get_crystal_freq(self):
return 32
def override_vddsdio(self, new_voltage):
raise NotImplementedInROMError(
"VDD_SDIO overrides are not supported for ESP32-H2"
)
def read_mac(self, mac_type="BASE_MAC"):
"""Read MAC from EFUSE region"""
if mac_type != "BASE_MAC":
return None
mac0 = self.read_reg(self.MAC_EFUSE_REG)
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
bitstring = struct.pack(">II", mac1, mac0)[2:]
return tuple(bitstring)
def get_flash_crypt_config(self):
return None # doesn't exist on ESP32-H2
def get_key_block_purpose(self, key_block):
if key_block < 0 or key_block > 5:
raise FatalError("Valid key block numbers must be in range 0-5")
reg, shift = [
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
][key_block]
return (self.read_reg(reg) >> shift) & 0xF
def is_flash_encryption_key_valid(self):
# Need to see an AES-128 key
purposes = [self.get_key_block_purpose(b) for b in range(6)]
return any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes)
def _post_connect(self):
pass
class ESP32H2BETA1StubLoader(ESP32H2BETA1ROM):
"""Access class for ESP32H2BETA1 stub loader, runs on top of ROM.
(Basically the same as ESP32StubLoader, but different base class.
Can possibly be made into a mixin.)
"""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
ESP32H2BETA1ROM.STUB_CLASS = ESP32H2BETA1StubLoader

View File

@@ -0,0 +1,43 @@
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
from .esp32h2beta1 import ESP32H2BETA1ROM
class ESP32H2BETA2ROM(ESP32H2BETA1ROM):
CHIP_NAME = "ESP32-H2(beta2)"
IMAGE_CHIP_ID = 14
CHIP_DETECT_MAGIC_VALUE = [0x6881B06F]
def get_chip_description(self):
chip_name = {
1: "ESP32-H2(beta2)",
}.get(self.get_pkg_version(), "unknown ESP32-H2")
major_rev = self.get_major_chip_version()
minor_rev = self.get_minor_chip_version()
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
class ESP32H2BETA2StubLoader(ESP32H2BETA2ROM):
"""Access class for ESP32H2BETA2 stub loader, runs on top of ROM.
(Basically the same as ESP32StubLoader, but different base class.
Can possibly be made into a mixin.)
"""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
ESP32H2BETA2ROM.STUB_CLASS = ESP32H2BETA2StubLoader

View File

@@ -0,0 +1,195 @@
# SPDX-FileCopyrightText: 2023 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import struct
from .esp32 import ESP32ROM
from ..loader import ESPLoader
from ..util import FatalError, NotImplementedInROMError
class ESP32P4ROM(ESP32ROM):
CHIP_NAME = "ESP32-P4"
IMAGE_CHIP_ID = 18
IROM_MAP_START = 0x40000000
IROM_MAP_END = 0x4C000000
DROM_MAP_START = 0x40000000
DROM_MAP_END = 0x4C000000
BOOTLOADER_FLASH_OFFSET = 0x2000 # First 2 sectors are reserved for FE purposes
CHIP_DETECT_MAGIC_VALUE = [0x0]
UART_DATE_REG_ADDR = 0x500CA000 + 0x8C
EFUSE_BASE = 0x5012D000
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044
MAC_EFUSE_REG = EFUSE_BASE + 0x044
SPI_REG_BASE = 0x5008D000 # SPIMEM1
SPI_USR_OFFS = 0x18
SPI_USR1_OFFS = 0x1C
SPI_USR2_OFFS = 0x20
SPI_MOSI_DLEN_OFFS = 0x24
SPI_MISO_DLEN_OFFS = 0x28
SPI_W0_OFFS = 0x58
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY0_SHIFT = 24
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY1_SHIFT = 28
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY2_SHIFT = 0
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY3_SHIFT = 4
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY4_SHIFT = 8
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY5_SHIFT = 12
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
PURPOSE_VAL_XTS_AES256_KEY_1 = 2
PURPOSE_VAL_XTS_AES256_KEY_2 = 3
PURPOSE_VAL_XTS_AES128_KEY = 4
SUPPORTS_ENCRYPTED_FLASH = True
FLASH_ENCRYPTED_WRITE_ALIGN = 16
MEMORY_MAP = [
[0x00000000, 0x00010000, "PADDING"],
[0x40000000, 0x4C000000, "DROM"],
[0x4FF00000, 0x4FFA0000, "DRAM"],
[0x4FF00000, 0x4FFA0000, "BYTE_ACCESSIBLE"],
[0x4FC00000, 0x4FC20000, "DROM_MASK"],
[0x4FC00000, 0x4FC20000, "IROM_MASK"],
[0x40000000, 0x4C000000, "IROM"],
[0x4FF00000, 0x4FFA0000, "IRAM"],
[0x50108000, 0x50110000, "RTC_IRAM"],
[0x50108000, 0x50110000, "RTC_DRAM"],
[0x600FE000, 0x60100000, "MEM_INTERNAL2"],
]
UF2_FAMILY_ID = 0x3D308E94
def get_pkg_version(self):
# ESP32P4 TODO
return 0
def get_minor_chip_version(self):
# ESP32P4 TODO
return 0
def get_major_chip_version(self):
# ESP32P4 TODO
return 0
def get_chip_description(self):
chip_name = {
0: "ESP32-P4",
}.get(self.get_pkg_version(), "unknown ESP32-P4")
major_rev = self.get_major_chip_version()
minor_rev = self.get_minor_chip_version()
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
def get_chip_features(self):
return ["High-Performance MCU"]
def get_crystal_freq(self):
# ESP32P4 XTAL is fixed to 40MHz
return 40
def override_vddsdio(self, new_voltage):
raise NotImplementedInROMError(
"VDD_SDIO overrides are not supported for ESP32-P4"
)
def read_mac(self, mac_type="BASE_MAC"):
"""Read MAC from EFUSE region"""
if mac_type != "BASE_MAC":
return None
mac0 = self.read_reg(self.MAC_EFUSE_REG)
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
bitstring = struct.pack(">II", mac1, mac0)[2:]
return tuple(bitstring)
def get_flash_crypt_config(self):
return None # doesn't exist on ESP32-P4
def get_secure_boot_enabled(self):
return (
self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG)
& self.EFUSE_SECURE_BOOT_EN_MASK
)
def get_key_block_purpose(self, key_block):
if key_block < 0 or key_block > 5:
raise FatalError("Valid key block numbers must be in range 0-5")
reg, shift = [
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
][key_block]
return (self.read_reg(reg) >> shift) & 0xF
def is_flash_encryption_key_valid(self):
# Need to see either an AES-128 key or two AES-256 keys
purposes = [self.get_key_block_purpose(b) for b in range(6)]
if any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes):
return True
return any(p == self.PURPOSE_VAL_XTS_AES256_KEY_1 for p in purposes) and any(
p == self.PURPOSE_VAL_XTS_AES256_KEY_2 for p in purposes
)
def change_baud(self, baud):
ESPLoader.change_baud(self, baud)
def _post_connect(self):
pass
# TODO: Disable watchdogs when USB modes are supported in the stub
# if not self.sync_stub_detected: # Don't run if stub is reused
# self.disable_watchdogs()
def check_spi_connection(self, spi_connection):
pass # TODO: Define GPIOs for --spi-connection
class ESP32P4StubLoader(ESP32P4ROM):
"""Access class for ESP32P4 stub loader, runs on top of ROM.
(Basically the same as ESP32StubLoader, but different base class.
Can possibly be made into a mixin.)
"""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
ESP32P4ROM.STUB_CLASS = ESP32P4StubLoader

View File

@@ -0,0 +1,323 @@
# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os
import struct
from .esp32 import ESP32ROM
from ..loader import ESPLoader
from ..reset import HardReset
from ..util import FatalError, NotImplementedInROMError
class ESP32S2ROM(ESP32ROM):
CHIP_NAME = "ESP32-S2"
IMAGE_CHIP_ID = 2
IROM_MAP_START = 0x40080000
IROM_MAP_END = 0x40B80000
DROM_MAP_START = 0x3F000000
DROM_MAP_END = 0x3F3F0000
CHIP_DETECT_MAGIC_VALUE = [0x000007C6]
SPI_REG_BASE = 0x3F402000
SPI_USR_OFFS = 0x18
SPI_USR1_OFFS = 0x1C
SPI_USR2_OFFS = 0x20
SPI_MOSI_DLEN_OFFS = 0x24
SPI_MISO_DLEN_OFFS = 0x28
SPI_W0_OFFS = 0x58
MAC_EFUSE_REG = 0x3F41A044 # ESP32-S2 has special block for MAC efuses
UART_CLKDIV_REG = 0x3F400014
SUPPORTS_ENCRYPTED_FLASH = True
FLASH_ENCRYPTED_WRITE_ALIGN = 16
# todo: use espefuse APIs to get this info
EFUSE_BASE = 0x3F41A000
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044
EFUSE_BLOCK2_ADDR = EFUSE_BASE + 0x05C
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY0_SHIFT = 24
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY1_SHIFT = 28
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY2_SHIFT = 0
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY3_SHIFT = 4
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY4_SHIFT = 8
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY5_SHIFT = 12
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 19
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
EFUSE_RD_REPEAT_DATA3_REG = EFUSE_BASE + 0x3C
EFUSE_RD_REPEAT_DATA3_REG_FLASH_TYPE_MASK = 1 << 9
PURPOSE_VAL_XTS_AES256_KEY_1 = 2
PURPOSE_VAL_XTS_AES256_KEY_2 = 3
PURPOSE_VAL_XTS_AES128_KEY = 4
UARTDEV_BUF_NO = 0x3FFFFD14 # Variable in ROM .bss which indicates the port in use
UARTDEV_BUF_NO_USB_OTG = 2 # Value of the above indicating that USB-OTG is in use
USB_RAM_BLOCK = 0x800 # Max block size USB-OTG is used
GPIO_STRAP_REG = 0x3F404038
GPIO_STRAP_SPI_BOOT_MASK = 0x8 # Not download mode
RTC_CNTL_OPTION1_REG = 0x3F408128
RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1 # Is download mode forced over USB?
MEMORY_MAP = [
[0x00000000, 0x00010000, "PADDING"],
[0x3F000000, 0x3FF80000, "DROM"],
[0x3F500000, 0x3FF80000, "EXTRAM_DATA"],
[0x3FF9E000, 0x3FFA0000, "RTC_DRAM"],
[0x3FF9E000, 0x40000000, "BYTE_ACCESSIBLE"],
[0x3FF9E000, 0x40072000, "MEM_INTERNAL"],
[0x3FFB0000, 0x40000000, "DRAM"],
[0x40000000, 0x4001A100, "IROM_MASK"],
[0x40020000, 0x40070000, "IRAM"],
[0x40070000, 0x40072000, "RTC_IRAM"],
[0x40080000, 0x40800000, "IROM"],
[0x50000000, 0x50002000, "RTC_DATA"],
]
UF2_FAMILY_ID = 0xBFDD4EEE
def get_pkg_version(self):
num_word = 4
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x0F
def get_minor_chip_version(self):
hi_num_word = 3
hi = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * hi_num_word)) >> 20) & 0x01
low_num_word = 4
low = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * low_num_word)) >> 4) & 0x07
return (hi << 3) + low
def get_major_chip_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 18) & 0x03
def get_flash_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x0F
def get_flash_cap(self):
return self.get_flash_version()
def get_psram_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 28) & 0x0F
def get_psram_cap(self):
return self.get_psram_version()
def get_block2_version(self):
# BLK_VERSION_MINOR
num_word = 4
return (self.read_reg(self.EFUSE_BLOCK2_ADDR + (4 * num_word)) >> 4) & 0x07
def get_chip_description(self):
chip_name = {
0: "ESP32-S2",
1: "ESP32-S2FH2",
2: "ESP32-S2FH4",
102: "ESP32-S2FNR2",
100: "ESP32-S2R2",
}.get(
self.get_flash_cap() + self.get_psram_cap() * 100,
"unknown ESP32-S2",
)
major_rev = self.get_major_chip_version()
minor_rev = self.get_minor_chip_version()
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
def get_chip_features(self):
features = ["WiFi"]
if self.secure_download_mode:
features += ["Secure Download Mode Enabled"]
flash_version = {
0: "No Embedded Flash",
1: "Embedded Flash 2MB",
2: "Embedded Flash 4MB",
}.get(self.get_flash_cap(), "Unknown Embedded Flash")
features += [flash_version]
psram_version = {
0: "No Embedded PSRAM",
1: "Embedded PSRAM 2MB",
2: "Embedded PSRAM 4MB",
}.get(self.get_psram_cap(), "Unknown Embedded PSRAM")
features += [psram_version]
block2_version = {
0: "No calibration in BLK2 of efuse",
1: "ADC and temperature sensor calibration in BLK2 of efuse V1",
2: "ADC and temperature sensor calibration in BLK2 of efuse V2",
}.get(self.get_block2_version(), "Unknown Calibration in BLK2")
features += [block2_version]
return features
def get_crystal_freq(self):
# ESP32-S2 XTAL is fixed to 40MHz
return 40
def override_vddsdio(self, new_voltage):
raise NotImplementedInROMError(
"VDD_SDIO overrides are not supported for ESP32-S2"
)
def read_mac(self, mac_type="BASE_MAC"):
"""Read MAC from EFUSE region"""
if mac_type != "BASE_MAC":
return None
mac0 = self.read_reg(self.MAC_EFUSE_REG)
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
bitstring = struct.pack(">II", mac1, mac0)[2:]
return tuple(bitstring)
def flash_type(self):
return (
1
if self.read_reg(self.EFUSE_RD_REPEAT_DATA3_REG)
& self.EFUSE_RD_REPEAT_DATA3_REG_FLASH_TYPE_MASK
else 0
)
def get_flash_crypt_config(self):
return None # doesn't exist on ESP32-S2
def get_secure_boot_enabled(self):
return (
self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG)
& self.EFUSE_SECURE_BOOT_EN_MASK
)
def get_key_block_purpose(self, key_block):
if key_block < 0 or key_block > 5:
raise FatalError("Valid key block numbers must be in range 0-5")
reg, shift = [
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
][key_block]
return (self.read_reg(reg) >> shift) & 0xF
def is_flash_encryption_key_valid(self):
# Need to see either an AES-128 key or two AES-256 keys
purposes = [self.get_key_block_purpose(b) for b in range(6)]
if any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes):
return True
return any(p == self.PURPOSE_VAL_XTS_AES256_KEY_1 for p in purposes) and any(
p == self.PURPOSE_VAL_XTS_AES256_KEY_2 for p in purposes
)
def uses_usb_otg(self):
"""
Check the UARTDEV_BUF_NO register to see if USB-OTG console is being used
"""
if self.secure_download_mode:
return False # can't detect native USB in secure download mode
return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_OTG
def _post_connect(self):
if self.uses_usb_otg():
self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK
def _check_if_can_reset(self):
"""
Check the strapping register to see if we can reset out of download mode.
"""
if os.getenv("ESPTOOL_TESTING") is not None:
print("ESPTOOL_TESTING is set, ignoring strapping mode check")
# Esptool tests over USB-OTG run with GPIO0 strapped low,
# don't complain in this case.
return
strap_reg = self.read_reg(self.GPIO_STRAP_REG)
force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG)
if (
strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0
and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0
):
print(
"WARNING: {} chip was placed into download mode using GPIO0.\n"
"esptool.py can not exit the download mode over USB. "
"To run the app, reset the chip manually.\n"
"To suppress this note, set --after option to 'no_reset'.".format(
self.get_chip_description()
)
)
raise SystemExit(1)
def hard_reset(self):
uses_usb_otg = self.uses_usb_otg()
if uses_usb_otg:
self._check_if_can_reset()
print("Hard resetting via RTS pin...")
HardReset(self._port, uses_usb_otg)()
def change_baud(self, baud):
ESPLoader.change_baud(self, baud)
def check_spi_connection(self, spi_connection):
if not set(spi_connection).issubset(set(range(0, 22)) | set(range(26, 47))):
raise FatalError("SPI Pin numbers must be in the range 0-21, or 26-46.")
if any([v for v in spi_connection if v in [19, 20]]):
print(
"WARNING: GPIO pins 19 and 20 are used by USB-OTG, "
"consider using other pins for SPI flash connection."
)
class ESP32S2StubLoader(ESP32S2ROM):
"""Access class for ESP32-S2 stub loader, runs on top of ROM.
(Basically the same as ESP32StubLoader, but different base class.
Can possibly be made into a mixin.)
"""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
if rom_loader.uses_usb_otg():
self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK
self.FLASH_WRITE_SIZE = self.USB_RAM_BLOCK
ESP32S2ROM.STUB_CLASS = ESP32S2StubLoader

View File

@@ -0,0 +1,387 @@
# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os
import struct
from .esp32 import ESP32ROM
from ..loader import ESPLoader
from ..reset import HardReset
from ..util import FatalError, NotImplementedInROMError
class ESP32S3ROM(ESP32ROM):
CHIP_NAME = "ESP32-S3"
IMAGE_CHIP_ID = 9
CHIP_DETECT_MAGIC_VALUE = [0x9]
IROM_MAP_START = 0x42000000
IROM_MAP_END = 0x44000000
DROM_MAP_START = 0x3C000000
DROM_MAP_END = 0x3E000000
UART_DATE_REG_ADDR = 0x60000080
SPI_REG_BASE = 0x60002000
SPI_USR_OFFS = 0x18
SPI_USR1_OFFS = 0x1C
SPI_USR2_OFFS = 0x20
SPI_MOSI_DLEN_OFFS = 0x24
SPI_MISO_DLEN_OFFS = 0x28
SPI_W0_OFFS = 0x58
BOOTLOADER_FLASH_OFFSET = 0x0
SUPPORTS_ENCRYPTED_FLASH = True
FLASH_ENCRYPTED_WRITE_ALIGN = 16
# todo: use espefuse APIs to get this info
EFUSE_BASE = 0x60007000 # BLOCK0 read base address
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x44
EFUSE_BLOCK2_ADDR = EFUSE_BASE + 0x5C
MAC_EFUSE_REG = EFUSE_BASE + 0x044
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY0_SHIFT = 24
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
EFUSE_PURPOSE_KEY1_SHIFT = 28
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY2_SHIFT = 0
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY3_SHIFT = 4
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY4_SHIFT = 8
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
EFUSE_PURPOSE_KEY5_SHIFT = 12
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
EFUSE_RD_REPEAT_DATA3_REG = EFUSE_BASE + 0x3C
EFUSE_RD_REPEAT_DATA3_REG_FLASH_TYPE_MASK = 1 << 9
PURPOSE_VAL_XTS_AES256_KEY_1 = 2
PURPOSE_VAL_XTS_AES256_KEY_2 = 3
PURPOSE_VAL_XTS_AES128_KEY = 4
UARTDEV_BUF_NO = 0x3FCEF14C # Variable in ROM .bss which indicates the port in use
UARTDEV_BUF_NO_USB_OTG = 3 # The above var when USB-OTG is used
UARTDEV_BUF_NO_USB_JTAG_SERIAL = 4 # The above var when USB-JTAG/Serial is used
RTCCNTL_BASE_REG = 0x60008000
RTC_CNTL_SWD_CONF_REG = RTCCNTL_BASE_REG + 0x00B4
RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 31
RTC_CNTL_SWD_WPROTECT_REG = RTCCNTL_BASE_REG + 0x00B8
RTC_CNTL_SWD_WKEY = 0x8F1D312A
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0098
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00B0
RTC_CNTL_WDT_WKEY = 0x50D83AA1
USB_RAM_BLOCK = 0x800 # Max block size USB-OTG is used
GPIO_STRAP_REG = 0x60004038
GPIO_STRAP_SPI_BOOT_MASK = 0x8 # Not download mode
RTC_CNTL_OPTION1_REG = 0x6000812C
RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1 # Is download mode forced over USB?
UART_CLKDIV_REG = 0x60000014
MEMORY_MAP = [
[0x00000000, 0x00010000, "PADDING"],
[0x3C000000, 0x3D000000, "DROM"],
[0x3D000000, 0x3E000000, "EXTRAM_DATA"],
[0x600FE000, 0x60100000, "RTC_DRAM"],
[0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
[0x3FC88000, 0x403E2000, "MEM_INTERNAL"],
[0x3FC88000, 0x3FD00000, "DRAM"],
[0x40000000, 0x4001A100, "IROM_MASK"],
[0x40370000, 0x403E0000, "IRAM"],
[0x600FE000, 0x60100000, "RTC_IRAM"],
[0x42000000, 0x42800000, "IROM"],
[0x50000000, 0x50002000, "RTC_DATA"],
]
UF2_FAMILY_ID = 0xC47E5767
def get_pkg_version(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x07
def is_eco0(self, minor_raw):
# 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.
return (
(minor_raw & 0x7) == 0
and self.get_blk_version_major() == 1
and self.get_blk_version_minor() == 1
)
def get_minor_chip_version(self):
minor_raw = self.get_raw_minor_chip_version()
if self.is_eco0(minor_raw):
return 0
return minor_raw
def get_raw_minor_chip_version(self):
hi_num_word = 5
hi = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * hi_num_word)) >> 23) & 0x01
low_num_word = 3
low = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * low_num_word)) >> 18) & 0x07
return (hi << 3) + low
def get_blk_version_major(self):
num_word = 4
return (self.read_reg(self.EFUSE_BLOCK2_ADDR + (4 * num_word)) >> 0) & 0x03
def get_blk_version_minor(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 24) & 0x07
def get_major_chip_version(self):
minor_raw = self.get_raw_minor_chip_version()
if self.is_eco0(minor_raw):
return 0
return self.get_raw_major_chip_version()
def get_raw_major_chip_version(self):
num_word = 5
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 24) & 0x03
def get_chip_description(self):
major_rev = self.get_major_chip_version()
minor_rev = self.get_minor_chip_version()
pkg_version = self.get_pkg_version()
chip_name = {
0: "ESP32-S3 (QFN56)",
1: "ESP32-S3-PICO-1 (LGA56)",
}.get(pkg_version, "unknown ESP32-S3")
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
def get_flash_cap(self):
num_word = 3
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 27) & 0x07
def get_flash_vendor(self):
num_word = 4
vendor_id = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x07
return {1: "XMC", 2: "GD", 3: "FM", 4: "TT", 5: "BY"}.get(vendor_id, "")
def get_psram_cap(self):
num_word = 4
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 3) & 0x03
def get_psram_vendor(self):
num_word = 4
vendor_id = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 7) & 0x03
return {1: "AP_3v3", 2: "AP_1v8"}.get(vendor_id, "")
def get_chip_features(self):
features = ["WiFi", "BLE"]
flash = {
0: None,
1: "Embedded Flash 8MB",
2: "Embedded Flash 4MB",
}.get(self.get_flash_cap(), "Unknown Embedded Flash")
if flash is not None:
features += [flash + f" ({self.get_flash_vendor()})"]
psram = {
0: None,
1: "Embedded PSRAM 8MB",
2: "Embedded PSRAM 2MB",
}.get(self.get_psram_cap(), "Unknown Embedded PSRAM")
if psram is not None:
features += [psram + f" ({self.get_psram_vendor()})"]
return features
def get_crystal_freq(self):
# ESP32S3 XTAL is fixed to 40MHz
return 40
def get_flash_crypt_config(self):
return None # doesn't exist on ESP32-S3
def get_key_block_purpose(self, key_block):
if key_block < 0 or key_block > 5:
raise FatalError("Valid key block numbers must be in range 0-5")
reg, shift = [
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
][key_block]
return (self.read_reg(reg) >> shift) & 0xF
def is_flash_encryption_key_valid(self):
# Need to see either an AES-128 key or two AES-256 keys
purposes = [self.get_key_block_purpose(b) for b in range(6)]
if any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes):
return True
return any(p == self.PURPOSE_VAL_XTS_AES256_KEY_1 for p in purposes) and any(
p == self.PURPOSE_VAL_XTS_AES256_KEY_2 for p in purposes
)
def get_secure_boot_enabled(self):
return (
self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG)
& self.EFUSE_SECURE_BOOT_EN_MASK
)
def override_vddsdio(self, new_voltage):
raise NotImplementedInROMError(
"VDD_SDIO overrides are not supported for ESP32-S3"
)
def read_mac(self, mac_type="BASE_MAC"):
"""Read MAC from EFUSE region"""
if mac_type != "BASE_MAC":
return None
mac0 = self.read_reg(self.MAC_EFUSE_REG)
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
bitstring = struct.pack(">II", mac1, mac0)[2:]
return tuple(bitstring)
def flash_type(self):
return (
1
if self.read_reg(self.EFUSE_RD_REPEAT_DATA3_REG)
& self.EFUSE_RD_REPEAT_DATA3_REG_FLASH_TYPE_MASK
else 0
)
def uses_usb_otg(self):
"""
Check the UARTDEV_BUF_NO register to see if USB-OTG console is being used
"""
if self.secure_download_mode:
return False # can't detect native USB in secure download mode
return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_OTG
def uses_usb_jtag_serial(self):
"""
Check the UARTDEV_BUF_NO register to see if USB-JTAG/Serial is being used
"""
if self.secure_download_mode:
return False # can't detect USB-JTAG/Serial in secure download mode
return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_JTAG_SERIAL
def disable_watchdogs(self):
# When USB-JTAG/Serial is used, the RTC WDT and SWD watchdog are not reset
# and can then reset the board during flashing. Disable them.
if self.uses_usb_jtag_serial():
# Disable RTC WDT
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY)
self.write_reg(self.RTC_CNTL_WDTCONFIG0_REG, 0)
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0)
# Automatically feed SWD
self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, self.RTC_CNTL_SWD_WKEY)
self.write_reg(
self.RTC_CNTL_SWD_CONF_REG,
self.read_reg(self.RTC_CNTL_SWD_CONF_REG)
| self.RTC_CNTL_SWD_AUTO_FEED_EN,
)
self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, 0)
def _post_connect(self):
if self.uses_usb_otg():
self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK
if not self.sync_stub_detected: # Don't run if stub is reused
self.disable_watchdogs()
def _check_if_can_reset(self):
"""
Check the strapping register to see if we can reset out of download mode.
"""
if os.getenv("ESPTOOL_TESTING") is not None:
print("ESPTOOL_TESTING is set, ignoring strapping mode check")
# Esptool tests over USB-OTG run with GPIO0 strapped low,
# don't complain in this case.
return
strap_reg = self.read_reg(self.GPIO_STRAP_REG)
force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG)
if (
strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0
and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0
):
print(
"WARNING: {} chip was placed into download mode using GPIO0.\n"
"esptool.py can not exit the download mode over USB. "
"To run the app, reset the chip manually.\n"
"To suppress this note, set --after option to 'no_reset'.".format(
self.get_chip_description()
)
)
raise SystemExit(1)
def hard_reset(self):
uses_usb_otg = self.uses_usb_otg()
if uses_usb_otg:
self._check_if_can_reset()
print("Hard resetting via RTS pin...")
HardReset(self._port, uses_usb_otg)()
def change_baud(self, baud):
ESPLoader.change_baud(self, baud)
def check_spi_connection(self, spi_connection):
if not set(spi_connection).issubset(set(range(0, 22)) | set(range(26, 49))):
raise FatalError("SPI Pin numbers must be in the range 0-21, or 26-48.")
if spi_connection[3] > 46: # hd_gpio_num must be <= SPI_GPIO_NUM_LIMIT (46)
raise FatalError("SPI HD Pin number must be <= 46.")
if any([v for v in spi_connection if v in [19, 20]]):
print(
"WARNING: GPIO pins 19 and 20 are used by USB-Serial/JTAG and USB-OTG, "
"consider using other pins for SPI flash connection."
)
class ESP32S3StubLoader(ESP32S3ROM):
"""Access class for ESP32S3 stub loader, runs on top of ROM.
(Basically the same as ESP32StubLoader, but different base class.
Can possibly be made into a mixin.)
"""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
if rom_loader.uses_usb_otg():
self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK
self.FLASH_WRITE_SIZE = self.USB_RAM_BLOCK
ESP32S3ROM.STUB_CLASS = ESP32S3StubLoader

View File

@@ -0,0 +1,37 @@
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
from .esp32s3 import ESP32S3ROM
class ESP32S3BETA2ROM(ESP32S3ROM):
CHIP_NAME = "ESP32-S3(beta2)"
IMAGE_CHIP_ID = 4
CHIP_DETECT_MAGIC_VALUE = [0xEB004136]
EFUSE_BASE = 0x6001A000 # BLOCK0 read base address
class ESP32S3BETA2StubLoader(ESP32S3BETA2ROM):
"""Access class for ESP32S3 stub loader, runs on top of ROM.
(Basically the same as ESP32StubLoader, but different base class.
Can possibly be made into a mixin.)
"""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
ESP32S3BETA2ROM.STUB_CLASS = ESP32S3BETA2StubLoader

View File

@@ -0,0 +1,196 @@
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
from ..loader import ESPLoader
from ..util import FatalError, NotSupportedError
class ESP8266ROM(ESPLoader):
"""Access class for ESP8266 ROM bootloader"""
CHIP_NAME = "ESP8266"
IS_STUB = False
CHIP_DETECT_MAGIC_VALUE = [0xFFF0C101]
# OTP ROM addresses
ESP_OTP_MAC0 = 0x3FF00050
ESP_OTP_MAC1 = 0x3FF00054
ESP_OTP_MAC3 = 0x3FF0005C
SPI_REG_BASE = 0x60000200
SPI_USR_OFFS = 0x1C
SPI_USR1_OFFS = 0x20
SPI_USR2_OFFS = 0x24
SPI_MOSI_DLEN_OFFS = None
SPI_MISO_DLEN_OFFS = None
SPI_W0_OFFS = 0x40
UART_CLKDIV_REG = 0x60000014
XTAL_CLK_DIVIDER = 2
FLASH_SIZES = {
"512KB": 0x00,
"256KB": 0x10,
"1MB": 0x20,
"2MB": 0x30,
"4MB": 0x40,
"2MB-c1": 0x50,
"4MB-c1": 0x60,
"8MB": 0x80,
"16MB": 0x90,
}
FLASH_FREQUENCY = {
"80m": 0xF,
"40m": 0x0,
"26m": 0x1,
"20m": 0x2,
}
BOOTLOADER_FLASH_OFFSET = 0
MEMORY_MAP = [
[0x3FF00000, 0x3FF00010, "DPORT"],
[0x3FFE8000, 0x40000000, "DRAM"],
[0x40100000, 0x40108000, "IRAM"],
[0x40201010, 0x402E1010, "IROM"],
]
UF2_FAMILY_ID = 0x7EAB61ED
def get_efuses(self):
# Return the 128 bits of ESP8266 efuse as a single Python integer
result = self.read_reg(0x3FF0005C) << 96
result |= self.read_reg(0x3FF00058) << 64
result |= self.read_reg(0x3FF00054) << 32
result |= self.read_reg(0x3FF00050)
return result
def _get_flash_size(self, efuses):
# rX_Y = EFUSE_DATA_OUTX[Y]
r0_4 = (efuses & (1 << 4)) != 0
r3_25 = (efuses & (1 << 121)) != 0
r3_26 = (efuses & (1 << 122)) != 0
r3_27 = (efuses & (1 << 123)) != 0
if r0_4 and not r3_25:
if not r3_27 and not r3_26:
return 1
elif not r3_27 and r3_26:
return 2
if not r0_4 and r3_25:
if not r3_27 and not r3_26:
return 2
elif not r3_27 and r3_26:
return 4
return -1
def get_chip_description(self):
efuses = self.get_efuses()
is_8285 = (
efuses & ((1 << 4) | 1 << 80)
) != 0 # One or the other efuse bit is set for ESP8285
if is_8285:
flash_size = self._get_flash_size(efuses)
max_temp = (
efuses & (1 << 5)
) != 0 # This efuse bit identifies the max flash temperature
chip_name = {
1: "ESP8285H08" if max_temp else "ESP8285N08",
2: "ESP8285H16" if max_temp else "ESP8285N16",
}.get(flash_size, "ESP8285")
return chip_name
return "ESP8266EX"
def get_chip_features(self):
features = ["WiFi"]
if "ESP8285" in self.get_chip_description():
features += ["Embedded Flash"]
return features
def flash_spi_attach(self, hspi_arg):
if self.IS_STUB:
super(ESP8266ROM, self).flash_spi_attach(hspi_arg)
else:
# ESP8266 ROM has no flash_spi_attach command in serial protocol,
# but flash_begin will do it
self.flash_begin(0, 0)
def flash_set_parameters(self, size):
# not implemented in ROM, but OK to silently skip for ROM
if self.IS_STUB:
super(ESP8266ROM, self).flash_set_parameters(size)
def chip_id(self):
"""
Read Chip ID from efuse - the equivalent of the SDK system_get_chip_id() func
"""
id0 = self.read_reg(self.ESP_OTP_MAC0)
id1 = self.read_reg(self.ESP_OTP_MAC1)
return (id0 >> 24) | ((id1 & 0xFFFFFF) << 8)
def read_mac(self, mac_type="BASE_MAC"):
"""Read MAC from OTP ROM"""
if mac_type != "BASE_MAC":
return None
mac0 = self.read_reg(self.ESP_OTP_MAC0)
mac1 = self.read_reg(self.ESP_OTP_MAC1)
mac3 = self.read_reg(self.ESP_OTP_MAC3)
if mac3 != 0:
oui = ((mac3 >> 16) & 0xFF, (mac3 >> 8) & 0xFF, mac3 & 0xFF)
elif ((mac1 >> 16) & 0xFF) == 0:
oui = (0x18, 0xFE, 0x34)
elif ((mac1 >> 16) & 0xFF) == 1:
oui = (0xAC, 0xD0, 0x74)
else:
raise FatalError("Unknown OUI")
return oui + ((mac1 >> 8) & 0xFF, mac1 & 0xFF, (mac0 >> 24) & 0xFF)
def get_erase_size(self, offset, size):
"""Calculate an erase size given a specific size in bytes.
Provides a workaround for the bootloader erase bug."""
sectors_per_block = 16
sector_size = self.FLASH_SECTOR_SIZE
num_sectors = (size + sector_size - 1) // sector_size
start_sector = offset // sector_size
head_sectors = sectors_per_block - (start_sector % sectors_per_block)
if num_sectors < head_sectors:
head_sectors = num_sectors
if num_sectors < 2 * head_sectors:
return (num_sectors + 1) // 2 * sector_size
else:
return (num_sectors - head_sectors) * sector_size
def override_vddsdio(self, new_voltage):
raise NotSupportedError(self, "Overriding VDDSDIO")
def check_spi_connection(self, spi_connection):
raise NotSupportedError(self, "Setting --spi-connection")
class ESP8266StubLoader(ESP8266ROM):
"""Access class for ESP8266 stub loader, runs on top of ROM."""
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
IS_STUB = True
def __init__(self, rom_loader):
self.secure_download_mode = rom_loader.secure_download_mode
self._port = rom_loader._port
self._trace_enabled = rom_loader._trace_enabled
self.cache = rom_loader.cache
self.flush_input() # resets _slip_reader
def get_erase_size(self, offset, size):
return size # stub doesn't have same size bug as ROM loader
ESP8266ROM.STUB_CLASS = ESP8266StubLoader

View File

@@ -0,0 +1,8 @@
{
"entry": 1074521580,
"text": "CAD0PxwA9D8AAPQ/AMD8PxAA9D82QQAh+v/AIAA4AkH5/8AgACgEICB0nOIGBQAAAEH1/4H2/8AgAKgEiAigoHTgCAALImYC54b0/yHx/8AgADkCHfAAAKDr/T8Ya/0/hIAAAEBAAABYq/0/pOv9PzZBALH5/yCgdBARIOXOAJYaBoH2/5KhAZCZEZqYwCAAuAmR8/+goHSaiMAgAJIYAJCQ9BvJwMD0wCAAwlgAmpvAIACiSQDAIACSGACB6v+QkPSAgPSHmUeB5f+SoQGQmRGamMAgAMgJoeX/seP/h5wXxgEAfOiHGt7GCADAIACJCsAgALkJRgIAwCAAuQrAIACJCZHX/5qIDAnAIACSWAAd8AAA+CD0P/gw9D82QQCR/f/AIACICYCAJFZI/5H6/8AgAIgJgIAkVkj/HfAAAAAQIPQ/ACD0PwAAAAg2QQAQESCl/P8h+v8MCMAgAIJiAJH6/4H4/8AgAJJoAMAgAJgIVnn/wCAAiAJ88oAiMCAgBB3wAAAAAEA2QQAQESDl+/8Wav+B7P+R+//AIACSaADAIACYCFZ5/x3wAAAMQP0/////AAQg9D82QQAh/P84QhaDBhARIGX4/xb6BQz4DAQ3qA2YIoCZEIKgAZBIg0BAdBARICX6/xARICXz/4giDBtAmBGQqwHMFICrAbHt/7CZELHs/8AgAJJrAJHO/8AgAKJpAMAgAKgJVnr/HAkMGkCag5AzwJqIOUKJIh3wAAAskgBANkEAoqDAgf3/4AgAHfAAADZBAIKgwK0Ch5IRoqDbgff/4AgAoqDcRgQAAAAAgqDbh5IIgfL/4AgAoqDdgfD/4AgAHfA2QQA6MsYCAACiAgAbIhARIKX7/zeS8R3wAAAAfNoFQNguBkCc2gVAHNsFQDYhIaLREIH6/+AIAEYLAAAADBRARBFAQ2PNBL0BrQKB9f/gCACgoHT8Ws0EELEgotEQgfH/4AgASiJAM8BWA/0iogsQIrAgoiCy0RCB7P/gCACtAhwLEBEgpff/LQOGAAAioGMd8AAA/GcAQNCSAEAIaABANkEhYqEHwGYRGmZZBiwKYtEQDAVSZhqB9//gCAAMGECIEUe4AkZFAK0GgdT/4AgAhjQAAJKkHVBzwOCZERqZQHdjiQnNB70BIKIggc3/4AgAkqQd4JkRGpmgoHSICYyqDAiCZhZ9CIYWAAAAkqQd4JkREJmAgmkAEBEgJer/vQetARARIKXt/xARICXp/80HELEgYKYggbv/4AgAkqQd4JkRGpmICXAigHBVgDe1sJKhB8CZERqZmAmAdcCXtwJG3P+G5v8MCIJGbKKkGxCqoIHK/+AIAFYK/7KiC6IGbBC7sBARIOWWAPfqEvZHD7KiDRC7sHq7oksAG3eG8f9867eawWZHCIImGje4Aoe1nCKiCxAisGC2IK0CgZv/4AgAEBEgpd//rQIcCxARICXj/xARIKXe/ywKgbH/4AgAHfAIIPQ/cOL6P0gkBkDwIgZANmEAEBEg5cr/EKEggfv/4AgAPQoMEvwqiAGSogCQiBCJARARIKXP/5Hy/6CiAcAgAIIpAKCIIMAgAIJpALIhAKHt/4Hu/+AIAKAjgx3wAAD/DwAANkEAgTv/DBmSSAAwnEGZKJH7/zkYKTgwMLSaIiozMDxBDAIpWDlIEBEgJfj/LQqMGiKgxR3wAABQLQZANkEAQSz/WDRQM2MWYwRYFFpTUFxBRgEAEBEgZcr/iESmGASIJIel7xARIKXC/xZq/6gUzQO9AoHx/+AIAKCgdIxKUqDEUmQFWBQ6VVkUWDQwVcBZNB3wAADA/D9PSEFJqOv9P3DgC0AU4AtADAD0PzhA9D///wAAjIAAABBAAACs6/0/vOv9P2CQ9D//j///ZJD0P2iQ9D9ckPQ/BMD8PwjA/D8E7P0/FAD0P/D//wCo6/0/DMD8PyRA/T98aABA7GcAQFiGAEBsKgZAODIGQBQsBkDMLAZATCwGQDSFAEDMkABAeC4GQDDvBUBYkgBATIIAQDbBACHZ/wwKImEIQqAAge7/4AgAIdT/MdX/xgAASQJLIjcy+BARICXC/wxLosEgEBEgpcX/IqEBEBEg5cD/QYz+kCIRKiQxyv+xyv/AIABJAiFz/gwMDFoyYgCB3P/gCAAxxf9SoQHAIAAoAywKUCIgwCAAKQOBLP/gCACB1f/gCAAhvv/AIAAoAsy6HMMwIhAiwvgMEyCjgwwLgc7/4AgA8bf/DB3CoAGyoAHioQBA3REAzBGAuwGioACBx//gCAAhsP9Rv/4qRGLVK8AgACgEFnL/wCAAOAQMBwwSwCAAeQQiQRAiAwEMKCJBEYJRCXlRJpIHHDd3Eh3GBwAiAwNyAwKAIhFwIiBmQhAoI8AgACgCKVEGAQAcIiJRCRARIGWy/wyLosEQEBEgJbb/ggMDIgMCgIgRIIggIZP/ICD0h7IcoqDAEBEg5bD/oqDuEBEgZbD/EBEg5a7/Rtv/AAAiAwEcNyc3NPYiGEbvAAAAIsIvICB09kJwcYT/cCKgKAKgAgAiwv4gIHQcFye3AkbmAHF//3AioCgCoAIAcsIwcHB0tlfJhuAALEkMByKgwJcYAobeAHlRDHKtBxARIKWp/60HEBEgJan/EBEgpaf/EBEgZaf/DIuiwRAiwv8QESClqv9WIv1GKAAMElZoM4JhD4F6/+AIAIjxoCiDRskAJogFDBJGxwAAeCMoMyCHIICAtFbI/hARICXG/yp3nBrG9/8AoKxBgW7/4AgAVir9ItLwIKfAzCIGnAAAoID0Vhj+hgQAoKD1ifGBZv/gCACI8Vba+oAiwAwYAIgRIKfAJzjhBgQAAACgrEGBXf/gCABW6vgi0vAgp8BWov7GigAADAcioMAmiAIGqQAMBy0HRqcAJrj1Bn0ADBImuAIGoQC4M6gjDAcQESDloP+gJ4OGnAAMGWa4XIhDIKkRDAcioMKHugIGmgC4U6IjApJhDhARIOW//5jhoJeDhg0ADBlmuDGIQyCpEQwHIqDCh7oCRo8AKDO4U6gjIHiCmeEQESDlvP8hL/4MCJjhiWIi0it5IqCYgy0JxoIAkSn+DAeiCQAioMZ3mgJGgQB4I4LI8CKgwIeXAShZDAeSoO9GAgB6o6IKGBt3oJkwhyfyggMFcgMEgIgRcIggcgMGAHcRgHcgggMHgIgBcIgggJnAgqDBDAeQKJPGbQCBEf4ioMaSCAB9CRaZGpg4DAcioMh3GQIGZwAoWJJIAEZiAByJDAcMEpcYAgZiAPhz6GPYU8hDuDOoI4EJ/+AIAAwIfQqgKIMGWwAMEiZIAkZWAJHy/oHy/sAgAHgJMCIRgHcQIHcgqCPAIAB5CZHt/gwLwCAAeAmAdxAgdyDAIAB5CZHp/sAgAHgJgHcQIHcgwCAAeQmR5f7AIAB4CYB3ECAnIMAgACkJgez+4AgABiAAAAAAgJA0DAcioMB3GQIGPQCAhEGLs3z8xg4AqDuJ8ZnhucHJ0YHm/uAIALjBiPEoK3gbqAuY4cjRcHIQJgINwCAA2AogLDDQIhAgdyDAIAB5ChuZsssQhznAxoD/ZkgCRn//DAcioMCGJgAMEia4AsYhACHC/ohTeCOJAiHB/nkCDAIGHQCxvf4MB9gLDBqCyPCdBy0HgCqT0JqDIJkQIqDGd5lgwbf+fQnoDCKgyYc+U4DwFCKgwFavBC0JhgIAACqTmGlLIpkHnQog/sAqfYcy7Rap2PkMeQvGYP8MEmaIGCGn/oIiAIwYgqDIDAd5AiGj/nkCDBKAJ4MMB0YBAAAMByKg/yCgdBARICVy/3CgdBARIGVx/xARICVw/1bytyIDARwnJzcf9jICRtz+IsL9ICB0DPcntwLG2P5xkv5wIqAoAqACAAByoNJ3Ek9yoNR3EncG0v6IM6KiccCqEXgjifGBlv7gCAAhh/6RiP7AIAAoAojxIDQ1wCIRkCIQICMggCKCDApwssKBjf7gCACio+iBiv7gCADGwP4AANhTyEO4M6gjEBEgZXX/Brz+ALIDAyIDAoC7ESC7ILLL8KLDGBARIKWR/wa1/gAiAwNyAwKAIhFwIiBxb/0iwvCIN4AiYxaSq4gXioKAjEFGAgCJ8RARIKVa/4jxmEemGQSYJ5eo6xARIOVS/xZq/6gXzQKywxiBbP7gCACMOjKgxDlXOBcqMzkXODcgI8ApN4ab/iIDA4IDAnLDGIAiETg1gCIgIsLwVsMJ9lIChiUAIqDJRioAMU/+gU/96AMpceCIwIlhiCatCYeyAQw6meGp0enBEBEgpVL/qNGBRv6pAejBoUX+3Qi9B8LBHPLBGInxgU7+4AgAuCbNCqhxmOGgu8C5JqAiwLgDqneoYYjxqrsMCrkDwKmDgLvAoNB0zJri24CtDeCpgxbqAa0IifGZ4cnREBEgpYD/iPGY4cjRiQNGAQAAAAwcnQyMsjg1jHPAPzHAM8CWs/XWfAAioMcpVQZn/lacmSg1FkKZIqDIBvv/qCNWmpiBLf7gCACionHAqhGBJv7gCACBKv7gCACGW/4AACgzFnKWDAqBJP7gCACio+iBHv7gCADgAgAGVP4d8AAAADZBAJ0CgqDAKAOHmQ/MMgwShgcADAIpA3zihg8AJhIHJiIYhgMAAACCoNuAKSOHmSoMIikDfPJGCAAAACKg3CeZCgwSKQMtCAYEAAAAgqDdfPKHmQYMEikDIqDbHfAAAA==",
"text_start": 1074520064,
"data": "DMD8P+znC0B/6AtAZ+0LQAbpC0Cf6AtABukLQGXpC0CC6gtA9OoLQJ3qC0CV5wtAGuoLQHTqC0CI6QtAGOsLQLDpC0AY6wtAbegLQMroC0AG6QtAZekLQIXoC0DI6wtAKe0LQLjmC0BL7QtAuOYLQLjmC0C45gtAuOYLQLjmC0C45gtAuOYLQLjmC0Bv6wtAuOYLQEnsC0Ap7QtA",
"data_start": 1073605544,
"bss_start": 1073528832
}

View File

@@ -0,0 +1,8 @@
{
"entry": 1077413304,
"text": "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",
"text_start": 1077411840,
"data": "DEDKP+AIOEAsCThAhAk4QFIKOEC+CjhAbAo4QKgHOEAOCjhATgo4QJgJOEBYBzhAzAk4QFgHOEC6CDhA/gg4QCwJOECECThAzAg4QBIIOEBCCDhAyAg4QBYNOEAsCThA1gs4QMoMOECkBjhA9Aw4QKQGOECkBjhApAY4QKQGOECkBjhApAY4QKQGOECkBjhAcgs4QKQGOEDyCzhAygw4QA==",
"data_start": 1070295976,
"bss_start": 1070219264
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
{
"entry": 1077413318,
"text": "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",
"text_start": 1077411840,
"data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==",
"data_start": 1070164904,
"bss_start": 1070088192
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
{
"entry": 1077413318,
"text": "ARG3BwBgTsaDqYcASsg3Scg/JspSxAbOIsy3BABgfVoTCQkAwEwTdPQ/DeDyQGJEI6g0AUJJ0kSySSJKBWGCgIhAgycJABN19Q+Cl30U4xlE/8m/EwcADJRBqodjGOUAhUeFxiOgBQB5VYKABUdjh+YACUZjjcYAfVWCgEIFEwewDUGFY5XnAolHnMH1t5MGwA1jFtUAmMETBQAMgoCTBtANfVVjldcAmMETBbANgoC3dck/QRGThQW6BsZhP2NFBQa3d8k/k4eHsQOnBwgD1kcIE3X1D5MGFgDCBsGCI5LXCDKXIwCnAAPXRwiRZ5OHBwRjHvcCN/fIPxMHh7GhZ7qXA6YHCLc2yT+3d8k/k4eHsZOGhrVjH+YAI6bHCCOg1wgjkgcIIaD5V+MG9fyyQEEBgoAjptcII6DnCN23NycAYHxLnYv1/zc3AGB8S52L9f+CgEERBsbdN7cnAGAjpgcCNwcACJjDmEN9/8hXskATRfX/BYlBAYKAQREGxtk/fd03BwBAtycAYJjDNycAYBxD/f+yQEEBgoBBESLEN8TIP5MHxABKwAOpBwEGxibCYwoJBEU3OcW9RxMExACBRGPWJwEERL2Ik7QUAH03hT8cRDcGgAATl8cAmeA3BgABt/b/AHWPtyYAYNjCkMKYQn3/QUeR4AVHMwnpQLqXIygkARzEskAiRJJEAklBAYKAQREGxhMHAAxjEOUCEwWwDZcAyP/ngMDjEwXADbJAQQEXA8j/ZwDD4hMHsA3jGOX+lwDI/+eAwOETBdANxbdBESLEJsIGxiqEswS1AGMXlACyQCJEkkRBAYKAA0UEAAUERTfttxMFAAwXA8j/ZwBD3jVxJstOx/1yhWn9dCLNSslSxVbDBs+ThIT6FpGThwkHppcYCLOE5wAqiSaFLoSXAMj/54DgNpOHCQcYCAVqupezikdBMeQFZ311kwWF+pMHBwcTBYX5FAiqlzOF1wCTBwcHrpezhdcAKsaXAMj/54CgMzJFwUWhPwFFhWIWkfpAakTaREpJukkqSppKDWGCgKKJY3OKAIVpTobWhUqFlwDI/+eA4OATdfUPAe1OhtaFJoWXAMj/54DgLk6ZMwQ0QVG3EwUwBlW/MXH9ck7XUtVW017PBt8i3SbbStla0WLNZstqyW7HqokWkRMFAAIuirKKtosCypcAyP/ngKAphWdj4FcThWR9dBMEhPqThwQHopcYCDOE5wAihZcAyP/ngCAofXsTDDv5kwyL+ROHBAeThwQHFAhil+aXAUkzDNcAs4zXAFJNY3xNCWNxqQNBqFU1poUIAaU9cT0mhgwBIoWXAMj/54AAJKaZJpljdUkDswepQWPxdwOzBCpBY/OaANaEJoYMAU6FlwDI/+eAQNITdfUPVd0CzIFEeV2NTaMJAQBihZcAyP/ngADEffkDRTEB5oUFMWNPBQDj4p3+hWeThwcHppcYCLqX2pcjiqf4hQTxt+MVpf2RR+OF9PYFZ311kwcHB5MFhfoTBYX5FAiqlzOF1wCTBwcHrpezhdcAKsaXAMj/54AgGu0zMkXBRX07zTMTBQAClwDI/+eAwBeFYhaR+lBqVNpUSlm6WSpamloKW/pLakzaTEpNuk0pYYKAAREGziLMnTk3BM4/bAATBQT/lwDI/+eAQMiqhwVFleeyR5P3ByA+xkE5NycAYBxHtwZAABMFBP/VjxzHskWXAMj/54DAxTM1oADyQGJEBWGCgEERt8fIPwbGk4fHAAVHI4DnABPXxQCYxwVnfRfMw8jH+Y06laqVsYGMyyOqBwBBNxnBEwVQDLJAQQGCgAERIsw3xMg/kwfEACbKxEdOxgbOSsiqiRMExABj85UAroSpwAMpRAAmmRNZyQAcSGNV8AAcRGNe+QLpNn3dSEAmhs6FlwDI/+eAQLkTdfUPAcWTB0AMXMhcQKaXXMBcRIWPXMTyQGJE0kRCSbJJBWGCgOE+bb+3V0FJGXGTh/eEAUU+zobeotym2srYztbS1NbS2tDezuLM5srqyO7GlwDI/+eAoKy3R8g/N3fJP5OHBwATB4e6Y+XnFK0xkUVoCD05jTG398g/k4eHsSFnPpcjIPcItwU4QLcHOECThwcLAUaThQUAN0nIPxVFIyD5AJcAyP/ngMD8NwcAYFxHEwUAArd5yT+T5xcQXMeXAMj/54CA+5cAyP/ngAAMt0cAYJxfk4mJsRMJCQAJ5fGL4RcTtRcAgUWXAMj/54CgrcFnt8TIP/0XEwcAEIVmQWa3BQABAUWThMQAt0rIPw1qlwDI/+eAIKgTi8oAJpqDp8kI9d+Dq8kIhUcjpgkIIwLxAoPHGwAJRyMT4QKjAvECAtRNR2OL5wZRR2OJ5wYpR2Of5wCDxzsAA8crAKIH2Y8RR2OW5wCDp4sAnEM+1KU2oUVIEDU+g8c7AAPHKwCiB9mPEWdBB2N+9wITBbANlwDI/+eAAJMTBcANlwDI/+eAQJITBeAOlwDI/+eAgJElNr23I6AHAJEHRb3JRyMT8QJ9twPHGwDRRmPn5gKFRmPm5gABTBME8A+dqHkXE3f3D8lG4+jm/rd2yT8KB5OGxro2lxhDAoeTBgcDk/b2DxFG42nW/BMH9wITd/cPjUZj7uYIt3bJPwoHk4aGvzaXGEMChxMHQAJjmucQAtQdRAFFlwDI/+eA4IgBRSU8aTxhPKFFSBB9FK00ffABTAFEE3X0DwU0E3X8Dyk8tTzjEQTsg8cbAElHY2X3MAlH43n36vUXk/f3Dz1H42P36jd3yT+KBxMHh8C6l5xDgocFRJ3rcBCBRQFFlyDJ/+eA4Icd4dFFaBAxNAFEMagFRIHvlwDI/+eAAI0zNKAAKaAhR2OF5wAFRAFMYbcDrIsAA6TLALNnjADSB/X3sTFl9cFsIpz9HH19MwWMQF3cs3eVAZXjwWwzBYxAY+aMAv18MwWMQF3QMYGXAMj/54AgiF35ZpT1tzGBlwDI/+eAIIdd8WqU0bdBgZcAyP/ngOCFWfkzBJRBwbchR+OK5/ABTBMEAAw5t0FHzb9BRwVE453n9oOlywADpYsAcTK5v0FHBUTjk+f2A6cLAZFnY+jnHoOlSwEDpYsACTGBt0FHBUTjlOf0g6cLARFnY2n3HAOnywCDpUsBA6WLADOE5wLxPiOsBAAjJIqwCb8DxwQAYwMHFAOniwDBFxMEAAxjE/cAwEgBR5MG8A5jRvcCg8dbAAPHSwABTKIH2Y8Dx2sAQgddj4PHewDiB9mP44T25hMEEAyFtTOG6wADRoYBBQexjuG3g8cEAP3H3ERjnQcUwEgjgAQAVb1hR2OW5wKDp8sBA6eLAYOmSwEDpgsBg6XLAAOliwCX8Mf/54AgdiqMMzSgAAG9AUwFRCm1EUcFROOd5+a3lwBgtEtld30XBWb5jtGOA6WLALTL9EOBRfmO0Y70w/RL+Y7RjvTLtEN1j1GPuMOX8Mf/54BAdAW1E/f3AOMXB+qT3EcAE4SLAAFMfV3jd5zbSESX8Mf/54BAYBhEVEAQQPmOYwenARxCE0f3/32P2Y4UwgUMQQTZvxFHtbVBRwVE45rn3oOniwADp0sBIyT5ACMi6QDJs4MlSQDBF5Hlic8BTBMEYAyhuwMniQBjZvcGE/c3AOMbB+IDKIkAAUYBRzMF6ECzhuUAY2n3AOMHBtIjJKkAIyLZAA2zM4brABBOEQeQwgVG6b8hRwVE45Tn2AMkiQAZwBMEgAwjJAkAIyIJADM0gAC9swFMEwQgDMW5AUwTBIAM5bEBTBMEkAzFsRMHIA1jg+cMEwdADeOR57oDxDsAg8crACIEXYyX8Mf/54CgXgOsxABBFGNzhAEijOMPDLbAQGKUMYCcSGNV8ACcRGNa9Arv8A/gdd3IQGKGk4WLAZfwx//ngKBaAcWTB0AM3MjcQOKX3MDcRLOHh0HcxJfwx//ngIBZFb4JZRMFBXEDrMsAA6SLAJfwx//ngMBKtwcAYNhLtwYAAcEWk1dHARIHdY+9i9mPs4eHAwFFs9WHApfwx//ngKBLEwWAPpfwx//ngGBH3bSDpksBA6YLAYOlywADpYsA7/AP9sG8g8U7AIPHKwAThYsBogXdjcEVgTptvO/wb9mBtwPEOwCDxysAE4yLASIEXYzcREEUxeORR4VLY/6HCJMHkAzcyHm0A6cNACLQBUizh+xAPtaDJ4qwY3P0AA1IQsY6xO/w79QiRzJIN8XIP+KFfBCThsoAEBATBUUCl/DH/+eAoEg398g/kwjHAIJXA6eIsIOlDQAdjB2PPpyyVyOk6LCqi76VI6C9AJOHygCdjQHFoWdjlvUAWoV1MCOgbQEJxNxEmcPjQHD5Y98LAJMHcAyFv4VLt33JP7fMyD+TjY26k4zMAOm/45ULntxE44IHnpMHgAyxt4OniwDjmwecAUWX8Mf/54CAOAllEwUFcZfwx//ngKA0l/DH/+eAIDhNugOkywDjBgSaAUWX8Mf/54DgNRMFgD6X8Mf/54AgMgKUQbr2UGZU1lRGWbZZJlqWWgZb9ktmTNZMRk22TQlhgoA=",
"text_start": 1077411840,
"data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==",
"data_start": 1070164904,
"bss_start": 1070088192
}

View File

@@ -0,0 +1,8 @@
{
"entry": 1077413318,
"text": "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",
"text_start": 1077411840,
"data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==",
"data_start": 1070164904,
"bss_start": 1070088192
}

View File

@@ -0,0 +1,8 @@
{
"entry": 1341195718,
"text": "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",
"text_start": 1341194240,
"data": "DAD1T+4I8U86CfFPkgnxT2gK8U/UCvFPggrxT7YH8U8kCvFPZArxT6YJ8U9mB/FP2gnxT2YH8U/ICPFPDAnxTzoJ8U+SCfFP2gjxTyAI8U9QCPFP1gjxTywN8U86CfFP7AvxT+AM8U+yBvFPCg3xT7IG8U+yBvFPsgbxT7IG8U+yBvFPsgbxT7IG8U+yBvFPiAvxT7IG8U8IDPFP4AzxTw==",
"data_start": 1341533096,
"bss_start": 1341456384
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
{
"entry": 1077380596,
"text": "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",
"text_start": 1077379072,
"data": "DADKPxeIN0CriDdAw403QDeJN0DLiDdAN4k3QJaJN0C2ijdAKIs3QNGKN0ChhzdASIo3QKiKN0C5iTdATIs3QOGJN0BMizdAmYg3QPiIN0A3iTdAlok3QLGIN0DjhzdABIw3QIWNN0DAhjdAp403QMCGN0DAhjdAwIY3QMCGN0DAhjdAwIY3QMCGN0DAhjdAqYs3QMCGN0CZjDdAhY03QA==",
"data_start": 1070279592,
"bss_start": 1070202880
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env python
#
# SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: GPL-2.0-or-later
# Code was originally licensed under Apache 2.0 before the release of ESP-IDF v5.2
import hashlib
import os
import struct
from typing import List
from esptool.util import div_roundup
class UF2Writer(object):
# The UF2 format is described here: https://github.com/microsoft/uf2
UF2_BLOCK_SIZE = 512
# max value of CHUNK_SIZE reduced by optional parts. Currently, MD5_PART only.
UF2_DATA_SIZE = 476
UF2_MD5_PART_SIZE = 24
UF2_FIRST_MAGIC = 0x0A324655
UF2_SECOND_MAGIC = 0x9E5D5157
UF2_FINAL_MAGIC = 0x0AB16F30
UF2_FLAG_FAMILYID_PRESENT = 0x00002000
UF2_FLAG_MD5_PRESENT = 0x00004000
def __init__(
self,
chip_id: int,
output_file: os.PathLike,
chunk_size: int,
md5_enabled: bool = True,
) -> None:
if not md5_enabled:
self.UF2_MD5_PART_SIZE = 0
self.UF2_FLAG_MD5_PRESENT = 0x00000000
self.md5_enabled = md5_enabled
self.chip_id = chip_id
self.CHUNK_SIZE = (
self.UF2_DATA_SIZE - self.UF2_MD5_PART_SIZE
if chunk_size is None
else chunk_size
)
self.f = open(output_file, "wb")
def __enter__(self) -> "UF2Writer":
return self
def __exit__(self, exc_type: str, exc_val: int, exc_tb: List) -> None:
if self.f:
self.f.close()
@staticmethod
def _to_uint32(num: int) -> bytes:
return struct.pack("<I", num)
def _write_block(
self, addr: int, chunk: bytes, len_chunk: int, block_no: int, blocks: int
) -> None:
assert len_chunk > 0
assert len_chunk <= self.CHUNK_SIZE
assert block_no < blocks
block = struct.pack(
"<IIIIIIII",
self.UF2_FIRST_MAGIC,
self.UF2_SECOND_MAGIC,
self.UF2_FLAG_FAMILYID_PRESENT | self.UF2_FLAG_MD5_PRESENT,
addr,
len_chunk,
block_no,
blocks,
self.chip_id,
)
block += chunk
if self.md5_enabled:
md5_part = struct.pack("<II", addr, len_chunk)
md5_part += hashlib.md5(chunk).digest()
assert len(md5_part) == self.UF2_MD5_PART_SIZE
block += md5_part
block += b"\x00" * (self.UF2_DATA_SIZE - self.UF2_MD5_PART_SIZE - len_chunk)
block += self._to_uint32(self.UF2_FINAL_MAGIC)
assert len(block) == self.UF2_BLOCK_SIZE
self.f.write(block)
def add_file(self, addr: int, image: bytes) -> None:
blocks = div_roundup(len(image), self.CHUNK_SIZE)
chunks = [
image[i : i + self.CHUNK_SIZE]
for i in range(0, len(image), self.CHUNK_SIZE)
]
for i, chunk in enumerate(chunks):
len_chunk = len(chunk)
self._write_block(addr, chunk, len_chunk, i, blocks)
addr += len_chunk

View File

@@ -0,0 +1,186 @@
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os
import re
import struct
import sys
def byte(bitstr, index):
return bitstr[index]
def mask_to_shift(mask):
"""Return the index of the least significant bit in the mask"""
shift = 0
while mask & 0x1 == 0:
shift += 1
mask >>= 1
return shift
def div_roundup(a, b):
"""Return a/b rounded up to nearest integer,
equivalent result to int(math.ceil(float(int(a)) / float(int(b))), only
without possible floating point accuracy errors.
"""
return (int(a) + int(b) - 1) // int(b)
def flash_size_bytes(size):
"""Given a flash size of the type passed in args.flash_size
(ie 512KB or 1MB) then return the size in bytes.
"""
if size is None:
return None
if "MB" in size:
return int(size[: size.index("MB")]) * 1024 * 1024
elif "KB" in size:
return int(size[: size.index("KB")]) * 1024
else:
raise FatalError("Unknown size %s" % size)
def hexify(s, uppercase=True):
format_str = "%02X" if uppercase else "%02x"
return "".join(format_str % c for c in s)
def pad_to(data, alignment, pad_character=b"\xFF"):
"""Pad to the next alignment boundary"""
pad_mod = len(data) % alignment
if pad_mod != 0:
data += pad_character * (alignment - pad_mod)
return data
def print_overwrite(message, last_line=False):
"""Print a message, overwriting the currently printed line.
If last_line is False, don't append a newline at the end
(expecting another subsequent call will overwrite this one.)
After a sequence of calls with last_line=False, call once with last_line=True.
If output is not a TTY (for example redirected a pipe),
no overwriting happens and this function is the same as print().
"""
if hasattr(sys.stdout, "isatty") and sys.stdout.isatty():
print("\r%s" % message, end="\n" if last_line else "")
else:
print(message)
def expand_chip_name(chip_name):
"""Change chip name to official form, e.g. `esp32s3beta2` -> `ESP32-S3(beta2)`"""
# Put "-" after "esp32"
chip_name = re.sub(r"(esp32)(?!$)", r"\1-", chip_name)
# Put "()" around "betaN"
chip_name = re.sub(r"(beta\d*)", r"(\1)", chip_name)
# Uppercase everything before "(betaN)"
chip_name = re.sub(r"^[^\(]+", lambda x: x.group(0).upper(), chip_name)
return chip_name
def strip_chip_name(chip_name):
"""Strip chip name to normalized form, e.g. `ESP32-S3(beta2)` -> `esp32s3beta2`"""
return re.sub(r"[-()]", "", chip_name.lower())
def get_file_size(path_to_file):
"""Returns the file size in bytes"""
file_size = 0
with open(path_to_file, "rb") as f:
f.seek(0, os.SEEK_END)
file_size = f.tell()
return file_size
class FatalError(RuntimeError):
"""
Wrapper class for runtime errors that aren't caused by internal bugs, but by
ESP ROM responses or input content.
"""
def __init__(self, message):
RuntimeError.__init__(self, message)
@staticmethod
def WithResult(message, result):
"""
Return a fatal error object that appends the hex values of
'result' and its meaning as a string formatted argument.
"""
err_defs = {
# ROM error codes
0x101: "Out of memory",
0x102: "Invalid argument",
0x103: "Invalid state",
0x104: "Invalid size",
0x105: "Requested resource not found",
0x106: "Operation or feature not supported",
0x107: "Operation timed out",
0x108: "Received response was invalid",
0x109: "CRC or checksum was invalid",
0x10A: "Version was invalid",
0x10B: "MAC address was invalid",
# Flasher stub error codes
0xC000: "Bad data length",
0xC100: "Bad data checksum",
0xC200: "Bad blocksize",
0xC300: "Invalid command",
0xC400: "Failed SPI operation",
0xC500: "Failed SPI unlock",
0xC600: "Not in flash mode",
0xC700: "Inflate error",
0xC800: "Not enough data",
0xC900: "Too much data",
0xFF00: "Command not implemented",
}
err_code = struct.unpack(">H", result[:2])
message += " (result was {}: {})".format(
hexify(result), err_defs.get(err_code[0], "Unknown result")
)
return FatalError(message)
class NotImplementedInROMError(FatalError):
"""
Wrapper class for the error thrown when a particular ESP bootloader function
is not implemented in the ROM bootloader.
"""
def __init__(self, bootloader, func):
FatalError.__init__(
self,
"%s ROM does not support function %s."
% (bootloader.CHIP_NAME, func.__name__),
)
class NotSupportedError(FatalError):
def __init__(self, esp, function_name):
FatalError.__init__(
self,
f"{function_name} is not supported by {esp.CHIP_NAME}.",
)
class UnsupportedCommandError(RuntimeError):
"""
Wrapper class for when ROM loader returns an invalid command response.
Usually this indicates the loader is running in Secure Download Mode.
"""
def __init__(self, esp, op):
if esp.secure_download_mode:
msg = "This command (0x%x) is not supported in Secure Download Mode" % op
else:
msg = "Invalid (unsupported) command 0x%x" % op
RuntimeError.__init__(self, msg)