mirror of
https://github.com/richonguzman/LoRa_APRS_iGate.git
synced 2026-10-30 18:41:58 +01:00
update esptool to build
This commit is contained in:
1 parent
a763200220
commit
fd9df47bd3
35 files changed
+20
-7827
No files matched your search
+20
-17
@@ -122,7 +122,10 @@ jobs:
|
||||
|
||||
- uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: "3.9"
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install esptool
|
||||
run: pip install "esptool>=5,<6"
|
||||
|
||||
- name: Install PlatformIO Core
|
||||
run: pip install --upgrade platformio
|
||||
@@ -148,44 +151,44 @@ jobs:
|
||||
- name: Merge for web flashing
|
||||
run: |
|
||||
if [ "${{ matrix.target.chip }}" == "esp32" ]; then
|
||||
python installer/bin/esptool/esptool.py --chip esp32 merge_bin \
|
||||
esptool --chip esp32 merge-bin \
|
||||
-o installer/web_factory.bin \
|
||||
--flash_mode dio \
|
||||
--flash_freq 40m \
|
||||
--flash_size 4MB \
|
||||
--flash-mode dio \
|
||||
--flash-freq 40m \
|
||||
--flash-size 4MB \
|
||||
0x1000 installer/firmware/bootloader.bin \
|
||||
0x8000 installer/firmware/partitions.bin \
|
||||
0xe000 installer/firmware/boot_app0.bin \
|
||||
0x10000 installer/firmware/firmware.bin \
|
||||
0x3D0000 installer/firmware/spiffs.bin
|
||||
elif [ "${{ matrix.target.chip }}" == "esp32s2" ]; then
|
||||
python installer/bin/esptool/esptool.py --chip esp32s2 merge_bin \
|
||||
esptool --chip esp32s2 merge-bin \
|
||||
-o installer/web_factory.bin \
|
||||
--flash_mode dio \
|
||||
--flash_freq 40m \
|
||||
--flash_size 4MB \
|
||||
--flash-mode dio \
|
||||
--flash-freq 40m \
|
||||
--flash-size 4MB \
|
||||
0x1000 installer/firmware/bootloader.bin \
|
||||
0x8000 installer/firmware/partitions.bin \
|
||||
0xe000 installer/firmware/boot_app0.bin \
|
||||
0x10000 installer/firmware/firmware.bin \
|
||||
0x3D0000 installer/firmware/spiffs.bin
|
||||
elif [ "${{ matrix.target.chip }}" == "esp32s3" ]; then
|
||||
python installer/bin/esptool/esptool.py --chip esp32s3 merge_bin \
|
||||
esptool --chip esp32s3 merge-bin \
|
||||
-o installer/web_factory.bin \
|
||||
--flash_mode dio \
|
||||
--flash_freq 40m \
|
||||
--flash_size 8MB \
|
||||
--flash-mode dio \
|
||||
--flash-freq 40m \
|
||||
--flash-size 8MB \
|
||||
0x0000 installer/firmware/bootloader.bin \
|
||||
0x8000 installer/firmware/partitions.bin \
|
||||
0xe000 installer/firmware/boot_app0.bin \
|
||||
0x10000 installer/firmware/firmware.bin \
|
||||
0x3D0000 installer/firmware/spiffs.bin
|
||||
elif [ "${{ matrix.target.chip }}" == "esp32c3" ]; then
|
||||
python installer/bin/esptool/esptool.py --chip esp32c3 merge_bin \
|
||||
esptool --chip esp32c3 merge-bin \
|
||||
-o installer/web_factory.bin \
|
||||
--flash_mode dio \
|
||||
--flash_freq 40m \
|
||||
--flash_size 4MB \
|
||||
--flash-mode dio \
|
||||
--flash-freq 40m \
|
||||
--flash-size 4MB \
|
||||
0x1000 installer/firmware/bootloader.bin \
|
||||
0x8000 installer/firmware/partitions.bin \
|
||||
0xe000 installer/firmware/boot_app0.bin \
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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
|
||||
|
||||
# This executable script is a thin wrapper around the main functionality
|
||||
# in the esptool Python package
|
||||
|
||||
# When updating this script, please also update espefuse.py and espsecure.py
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import sys
|
||||
|
||||
if os.name != "nt":
|
||||
# Linux/macOS: remove current script directory to avoid importing this file
|
||||
# as a module; we want to import the installed esptool module instead
|
||||
with contextlib.suppress(ValueError):
|
||||
if sys.path[0].endswith("/bin"):
|
||||
sys.path.pop(0)
|
||||
sys.path.remove(os.path.dirname(sys.executable))
|
||||
|
||||
# Linux/macOS: delete imported module entry to force Python to load
|
||||
# the module from scratch; this enables importing esptool module in
|
||||
# other Python scripts
|
||||
with contextlib.suppress(KeyError):
|
||||
del sys.modules["esptool"]
|
||||
|
||||
import esptool
|
||||
|
||||
if __name__ == "__main__":
|
||||
esptool._main()
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,9 +0,0 @@
|
||||
# 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
@@ -1,92 +0,0 @@
|
||||
# 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
@@ -1,178 +0,0 @@
|
||||
# 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)
|
||||
@@ -1,31 +0,0 @@
|
||||
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 .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,
|
||||
}
|
||||
|
||||
CHIP_LIST = list(CHIP_DEFS.keys())
|
||||
ROM_LIST = list(CHIP_DEFS.values())
|
||||
@@ -1,393 +0,0 @@
|
||||
# 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
|
||||
|
||||
FPGA_SLOW_BOOT = True
|
||||
|
||||
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
|
||||
|
||||
""" 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, "chip_id")
|
||||
|
||||
def read_mac(self):
|
||||
"""Read MAC from EFUSE region"""
|
||||
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):
|
||||
# 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()
|
||||
|
||||
|
||||
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
|
||||
@@ -1,165 +0,0 @@
|
||||
# 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
|
||||
|
||||
|
||||
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"],
|
||||
]
|
||||
|
||||
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_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 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
|
||||
|
||||
|
||||
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
|
||||
@@ -1,210 +0,0 @@
|
||||
# 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
|
||||
|
||||
FPGA_SLOW_BOOT = False
|
||||
|
||||
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 value for ESP32C3 eco 1+2 and ESP32C3 eco3 respectivly
|
||||
CHIP_DETECT_MAGIC_VALUE = [0x6921506F, 0x1B31506F]
|
||||
|
||||
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
|
||||
|
||||
RTC_CNTL_WDT_WKEY = 0x50D83AA1
|
||||
RTCCNTL_BASE_REG = 0x60008000
|
||||
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0090
|
||||
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00A8
|
||||
|
||||
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"],
|
||||
]
|
||||
|
||||
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_chip_description(self):
|
||||
chip_name = {
|
||||
0: "ESP32-C3",
|
||||
}.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):
|
||||
return ["WiFi", "BLE"]
|
||||
|
||||
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):
|
||||
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_rtc_watchdog(self):
|
||||
# When USB-JTAG/Serial is used, the RTC watchdog is not reset
|
||||
# and can then reset the board during flashing. Disable it.
|
||||
if self.uses_usb_jtag_serial():
|
||||
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)
|
||||
|
||||
def _post_connect(self):
|
||||
if not self.sync_stub_detected: # Don't run if stub is reused
|
||||
self.disable_rtc_watchdog()
|
||||
|
||||
|
||||
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
|
||||
@@ -1,189 +0,0 @@
|
||||
# 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
|
||||
|
||||
FPGA_SLOW_BOOT = False
|
||||
|
||||
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
|
||||
|
||||
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"],
|
||||
]
|
||||
|
||||
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_chip_description(self):
|
||||
chip_name = {
|
||||
0: "ESP32-C6",
|
||||
}.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):
|
||||
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-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)
|
||||
|
||||
|
||||
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
|
||||
@@ -1,26 +0,0 @@
|
||||
# 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",
|
||||
}.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
|
||||
@@ -1,65 +0,0 @@
|
||||
# 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
|
||||
|
||||
|
||||
class ESP32H2ROM(ESP32C6ROM):
|
||||
CHIP_NAME = "ESP32-H2"
|
||||
IMAGE_CHIP_ID = 16
|
||||
|
||||
# Magic value for ESP32H2
|
||||
CHIP_DETECT_MAGIC_VALUE = [0xD7B73E80]
|
||||
|
||||
FLASH_FREQUENCY = {
|
||||
"48m": 0xF,
|
||||
"24m": 0x0,
|
||||
"16m": 0x1,
|
||||
"12m": 0x2,
|
||||
}
|
||||
|
||||
def get_pkg_version(self):
|
||||
num_word = 3
|
||||
block1_addr = self.EFUSE_BASE + 0x044
|
||||
word3 = self.read_reg(block1_addr + (4 * num_word))
|
||||
pkg_version = (word3 >> 21) & 0x0F
|
||||
return pkg_version
|
||||
|
||||
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"]
|
||||
|
||||
def get_crystal_freq(self):
|
||||
# ESP32H2 XTAL is fixed to 32MHz
|
||||
return 32
|
||||
|
||||
|
||||
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
|
||||
@@ -1,164 +0,0 @@
|
||||
# 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 = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x0F
|
||||
|
||||
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_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):
|
||||
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
|
||||
@@ -1,43 +0,0 @@
|
||||
# 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
|
||||
@@ -1,305 +0,0 @@
|
||||
# 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
|
||||
|
||||
FPGA_SLOW_BOOT = False
|
||||
|
||||
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"],
|
||||
]
|
||||
|
||||
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_psram_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 28) & 0x0F
|
||||
|
||||
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_version() + self.get_psram_version() * 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_version(), "Unknown Embedded Flash")
|
||||
features += [flash_version]
|
||||
|
||||
psram_version = {
|
||||
0: "No Embedded PSRAM",
|
||||
1: "Embedded PSRAM 2MB",
|
||||
2: "Embedded PSRAM 4MB",
|
||||
}.get(self.get_psram_version(), "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):
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
@@ -1,315 +0,0 @@
|
||||
# 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]
|
||||
|
||||
FPGA_SLOW_BOOT = False
|
||||
|
||||
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
|
||||
|
||||
RTC_CNTL_WDT_WKEY = 0x50D83AA1
|
||||
RTCCNTL_BASE_REG = 0x60008000
|
||||
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0090
|
||||
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00B0
|
||||
|
||||
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"],
|
||||
]
|
||||
|
||||
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()
|
||||
return f"{self.CHIP_NAME} (revision v{major_rev}.{minor_rev})"
|
||||
|
||||
def get_chip_features(self):
|
||||
return ["WiFi", "BLE"]
|
||||
|
||||
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):
|
||||
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_rtc_watchdog(self):
|
||||
# When USB-JTAG/Serial is used, the RTC watchdog is not reset
|
||||
# and can then reset the board during flashing. Disable it.
|
||||
if self.uses_usb_jtag_serial():
|
||||
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)
|
||||
|
||||
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_rtc_watchdog()
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
@@ -1,42 +0,0 @@
|
||||
# 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
|
||||
|
||||
def get_chip_description(self):
|
||||
major_rev = self.get_major_chip_version()
|
||||
minor_rev = self.get_minor_chip_version()
|
||||
return f"{self.CHIP_NAME} (revision v{major_rev}.{minor_rev})"
|
||||
|
||||
|
||||
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
|
||||
@@ -1,191 +0,0 @@
|
||||
# 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, NotImplementedInROMError
|
||||
|
||||
|
||||
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"],
|
||||
]
|
||||
|
||||
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):
|
||||
"""Read MAC from OTP ROM"""
|
||||
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 NotImplementedInROMError(
|
||||
"Overriding VDDSDIO setting only applies to ESP32"
|
||||
)
|
||||
|
||||
|
||||
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
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1074521560,
|
||||
"text": "CAD0PxwA9D8AAPQ/AMD8PxAA9D82QQAh+v/AIAA4AkH5/8AgACgEICB0nOIGBQAAAEH1/4H2/8AgAKgEiAigoHTgCAALImYC54b0/yHx/8AgADkCHfAAAKDr/T8Ya/0/hIAAAEBAAABYq/0/pOv9PzZBALH5/yCgdBARIKXHAJYaBoH2/5KhAZCZEZqYwCAAuAmR8/+goHSaiMAgAJIYAJCQ9BvJwMD0wCAAwlgAmpvAIACiSQDAIACSGACB6v+QkPSAgPSHmUeB5f+SoQGQmRGamMAgAMgJoeX/seP/h5wXxgEAfOiHGt7GCADAIACJCsAgALkJRgIAwCAAuQrAIACJCZHX/5qIDAnAIACSWAAd8AAA+CD0P/gw9D82QQCR/f/AIACICYCAJFZI/5H6/8AgAIgJgIAkVkj/HfAAAAAQIPQ/ACD0PwAAAAg2QQAQESCl/P8h+v8MCMAgAIJiAJH6/4H4/8AgAJJoAMAgAJgIVnn/wCAAiAJ88oAiMCAgBB3wAAAAAEA2QQAQESDl+/8Wav+B7P+R+//AIACSaADAIACYCFZ5/x3wAAAMwPw/////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/7KiC6IGbBC7sBARIKWPAPfqEvZHD7KiDRC7sHq7oksAG3eG8f9867eawWZHCIImGje4Aoe1nCKiCxAisGC2IK0CgZv/4AgAEBEgpd//rQIcCxARICXj/xARIKXe/ywKgbH/4AgAHfAIIPQ/cOL6P0gkBkDwIgZANmEAEBEg5cr/EKEggfv/4AgAPQoMEvwqiAGSogCQiBCJARARIKXP/5Hy/6CiAcAgAIIpAKCIIMAgAIJpALIhAKHt/4Hu/+AIAKAjgx3wAAD/DwAANkEAgTv/DBmSSAAwnEGZKJH7/zkYKTgwMLSaIiozMDxBDAIpWDlIEBEgJfj/LQqMGiKgxR3wAABQLQZANkEAQSz/WDRQM2MWYwRYFFpTUFxBRgEAEBEgZcr/iESmGASIJIel7xARIKXC/xZq/6gUzQO9AoHx/+AIAKCgdIxKUqDEUmQFWBQ6VVkUWDQwVcBZNB3wAADA/D9PSEFJqOv9P3DgC0AU4AtADAD0PzhA9D///wAAjIAAABBAAACs6/0/vOv9PwTA/D8IwPw/BOz9PxQA9D/w//8AqOv9Pxjr/D8kwPw/fGgAQOxnAEBYhgBAbCoGQDgyBkAULAZAzCwGQEwsBkA0hQBAzJAAQHguBkAw7wVAWJIAQEyCAEA2wQAh3v8MCiJhCEKgAIHu/+AIACHZ/zHa/8YAAEkCSyI3MvgQESBlw/8MS6LBIBARIOXG/yKhARARICXC/1GR/pAiESolMc//sc//wCAAWQIheP4MDAxaMmIAgdz/4AgAMcr/QqEBwCAAKAMsCkAiIMAgACkDgTH/4AgAgdX/4AgAIcP/wCAAKALMuhzDMCIQIsL4DBMgo4MMC4HO/+AIAPG8/wwdwqABDBvioQBA3REAzBGAuwGioACBx//gCAAhtv8MBCpVIcP+ctIrwCAAKAUWcv/AIAA4BQwSwCAASQUiQRAiAwEMKCJBEYJRCUlRJpIHHDiHEh4GCAAiAwOCAwKAIhGAIiBmQhEoI8AgACgCKVFGAQAAHCIiUQkQESCls/8Mi6LBEBARIGW3/4IDAyIDAoCIESCIICGY/yAg9IeyHKKgwBARICWy/6Kg7hARIKWx/xARICWw/4bb/wAAIgMBHDknOTT2IhjG1AAAACLCLyAgdPZCcJGJ/5AioCgCoAIAIsL+ICB0HBknuQLGywCRhP+QIqAoAqACAJLCMJCQdLZZyQbGACxKbQQioMCnGAIGxABJUQxyrQQQESDlqv+tBBARIGWq/xARIOWo/xARIKWo/wyLosEQIsL/EBEg5av/ViL9RikADBJWyCyCYQ+Bev/gCACI8aAog8auACaIBAwSxqwAmCNoM2CJIICAtFbY/pnBEBEgZcf/mMFqKZwqBvf/AACgrEGBbf/gCABW6vxi1vBgosDMJgaBAACgkPRWGf6GBACgoPWZwYFl/+AIAJjBVpr6kGbADBkAmRFgosBnOeEGBAAAAKCsQYFc/+AIAFaq+GLW8GCiwFam/sZvAABtBCKgwCaIAoaNAG0EDALGiwAAACa484ZhAAwSJrgCBoUAuDOoIxARIOWh/6AkgwaBAAwcZrhTiEMgrBFtBCKgwoe6AoZ+ALhTqCPJ4RARIOXA/8YLAAwcZrgviEMgrBFtBCKgwoe6AoZ1ACgzuFOoIyBogsnhEBEgZb7/ITT+SWIi0itpIsjhoMSDLQyGaQChL/5tBLIKACKgxhY7GpgjgsjwIqDAh5kBKFoMCaKg70YCAJqzsgsYG5mwqjCHKfKCAwWSAwSAiBGQiCCSAwZtBACZEYCZIIIDB4CIAZCIIICqwIKgwaAok0ZVAIEY/m0EoggAIqDGFnoUqDgioMhW+hMoWKJIAMZNAByKbQQMEqcYAsZKAPhz6GPYU8hDuDOoI4EM/+AIAG0KoCSDRkQAAAwSJkgCRj8AqCO9BIEE/+AIAAYeAICwNG0EIqDAVgsPgGRBi8N8/UYOAKg8ucHJ4dnRgQD/4AgAyOG4wSgsmByoDNIhDZCSECYCDsAgAOIqACAtMOAiECCZIMAgAJkKG7vCzBBnO8LGm/9mSAJGmv9tBCKgwAYmAAwSJrgCRiEAIdz+mFOII5kCIdv+iQItBIYcAGHX/gwb2AaCyPCtBC0EgCuT0KuDIKoQbQQioMZW6gXB0f4ioMnoDIc+U4DwFCKgwFavBC0KRgIAKqOoaksiqQmtCyD+wCqdhzLtFprfIcT++QyZAsZ7/wwSZogWIcH+iAIWKACCoMhJAiG9/kkCDBKAJINtBEYBAABtBCKg/yCgdBARIOV5/2CgdBARIGV5/xARIOV3/1aiviIDARwoJzge9jICBvf+IsL9ICB0DPgnuAKG8/6BrP6AIqAoAqACAIKg0ocSUoKg1IcSegbt/gAAAIgzoqJxwKoRaCOJ8YGw/uAIACGh/pGi/sAgACgCiPEgNDXAIhGQIhAgIyCAIoKtBGCywoGn/uAIAKKj6IGk/uAIAAbb/gAA2FPIQ7gzqCMQESAlff9G1v4AsgMDIgMCgLsRILsgssvwosMYEBEgZZn/Rs/+ACIDA4IDAmGP/YAiEZg2gCIgIsLwkCJjFiKymBaakpCcQUYCAJnBEBEgZWL/mMGoRqYaBKgmp6nrEBEgpVr/Fmr/qBbNArLDGIGG/uAIAIw6MqDEOVY4FiozORY4NiAjwCk2xrX+ggMCIsMYMgMDDByAMxGAMyAyw/AGIwCBbP6RHf3oCDlx4JnAmWGYJwwal7MBDDqJ8anR6cEQESAlW/+o0ZFj/ujBqQGhYv7dCb0CwsEc8sEYmcGBa/7gCAC4J80KqHGI8aC7wLknoDPAuAiqIqhhmMGqu90EDBq5CMDag5C7wNDgdMx90tuA0K6TFmoBrQmJ8ZnByeEQESAlif+I8ZjByOGSaABhTv2INoyjwJ8xwJnA1ikAVvj11qwAMUn9IqDHKVNGAACMPJwIxoL+FoigYUT9IqDIKVZGf/4AMUH9IqDJKVNGfP4oI1bCnq0EgUX+4AgAoqJxwKoRgT7+4AgAgUL+4AgAxnP+AAAoMxaCnK0EgTz+4AgAoqPogTb+4AgA4AIARmz+HfAAAAA2QQCdAoKgwCgDh5kPzDIMEoYHAAwCKQN84oYPACYSByYiGIYDAAAAgqDbgCkjh5kqDCIpA3zyRggAAAAioNwnmQoMEikDLQgGBAAAAIKg3Xzyh5kGDBIpAyKg2x3wAAA=",
|
||||
"text_start": 1074520064,
|
||||
"data": "GOv8P9jnC0Bx6AtA8+wLQO3oC0CP6AtA7egLQEnpC0AG6gtAeOoLQCHqC0CB5wtAo+kLQPjpC0Bn6QtAmuoLQI7pC0Ca6gtAXegLQLPoC0Dt6AtASekLQHfoC0BM6wtAs+wLQKXmC0DX7AtApeYLQKXmC0Cl5gtApeYLQKXmC0Cl5gtApeYLQKXmC0Dz6gtApeYLQM3rC0Cz7AtA",
|
||||
"data_start": 1073605544
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1077413304,
|
||||
"text": "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",
|
||||
"text_start": 1077411840,
|
||||
"data": "GGvKP+AIOEAsCThAhAk4QCgKOECUCjhAQgo4QKgHOEDkCThAJAo4QJgJOEBYBzhAzAk4QFgHOEC6CDhA/gg4QCwJOECECThAzAg4QBIIOEBCCDhAyAg4QOYMOEAsCThArAs4QJoMOECkBjhAxAw4QKQGOECkBjhApAY4QKQGOECkBjhApAY4QKQGOECkBjhASAs4QKQGOEDICzhAmgw4QA==",
|
||||
"data_start": 1070295976
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1077413532,
|
||||
"text": "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",
|
||||
"text_start": 1077411840,
|
||||
"data": "IGvIP1YKOECmCjhA/go4QKILOEAODDhAvAs4QCIJOEBeCzhAngs4QBILOEDSCDhARgs4QNIIOEAwCjhAdgo4QKYKOED+CjhAQgo4QIYJOEC2CThAPgo4QGAOOECmCjhAJg04QBgOOEASCDhAQA44QBIIOEASCDhAEgg4QBIIOEASCDhAEgg4QBIIOEASCDhAwgw4QBIIOEBEDThAGA44QA==",
|
||||
"data_start": 1070164912
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1082132112,
|
||||
"text": "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",
|
||||
"text_start": 1082130432,
|
||||
"data": "HCuEQCoKgEB6CoBA0gqAQHYLgEDiC4BAkAuAQPYIgEAyC4BAcguAQOYKgECmCIBAGguAQKYIgEAECoBASgqAQHoKgEDSCoBAFgqAQFoJgECKCYBAEgqAQDQOgEB6CoBA+gyAQOwNgEDmB4BAFA6AQOYHgEDmB4BA5geAQOYHgEDmB4BA5geAQOYHgEDmB4BAlgyAQOYHgEAYDYBA7A2AQA==",
|
||||
"data_start": 1082469292
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1077413318,
|
||||
"text": "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",
|
||||
"text_start": 1077411840,
|
||||
"data": "GGvIP/gIOEBECThAnAk4QEAKOECsCjhAWgo4QMAHOED8CThAPAo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QP4MOEBECThAxAs4QLIMOEC8BjhA3Aw4QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAYAs4QLwGOEDgCzhAsgw4QA==",
|
||||
"data_start": 1070164904
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1082132112,
|
||||
"text": "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",
|
||||
"text_start": 1082130432,
|
||||
"data": "HCuDQCoKgEB6CoBA0gqAQHYLgEDiC4BAkAuAQPYIgEAyC4BAcguAQOYKgECmCIBAGguAQKYIgEAECoBASgqAQHoKgEDSCoBAFgqAQFoJgECKCYBAEgqAQDQOgEB6CoBA+gyAQOwNgEDmB4BAFA6AQOYHgEDmB4BA5geAQOYHgEDmB4BA5geAQOYHgEDmB4BAlgyAQOYHgEAYDYBA7A2AQA==",
|
||||
"data_start": 1082403756
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1077413318,
|
||||
"text": "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",
|
||||
"text_start": 1077411840,
|
||||
"data": "GGvIP/gIOEBECThAnAk4QEAKOECsCjhAWgo4QMAHOED8CThAPAo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QP4MOEBECThAxAs4QLIMOEC8BjhA3Aw4QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAYAs4QLwGOEDgCzhAsgw4QA==",
|
||||
"data_start": 1070164904
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1077413318,
|
||||
"text": "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",
|
||||
"text_start": 1077411840,
|
||||
"data": "GGvIP/gIOEBECThAnAk4QEAKOECsCjhAWgo4QMAHOED8CThAPAo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QP4MOEBECThAxAs4QLIMOEC8BjhA3Aw4QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAYAs4QLwGOEDgCzhAsgw4QA==",
|
||||
"data_start": 1070164904
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1073907696,
|
||||
"text": "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 truncated
|
||||
"text_start": 1073905664,
|
||||
"data": "ZCv9PzaLAkDBiwJAhpACQEqMAkDjiwJASowCQKmMAkByjQJA5Y0CQI2NAkDAigJAC40CQGSNAkDMjAJACI4CQPaMAkAIjgJAr4sCQA6MAkBKjAJAqYwCQMeLAkACiwJAx44CQD2QAkDYiQJAZZACQNiJAkDYiQJA2IkCQNiJAkDYiQJA2IkCQNiJAkDYiQJAZI4CQNiJAkBZjwJAPZACQA==",
|
||||
"data_start": 1073622012
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1077381684,
|
||||
"text": "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 truncated
|
||||
"text_start": 1077379072,
|
||||
"data": "ZCvKP5aNN0B7jjdAPJM3QAaPN0CbjjdABo83QGWPN0AykDdApZA3QE2QN0AhjTdAyI83QCSQN0CIjzdAx5A3QLKPN0DHkDdAaY43QMaON0AGjzdAZY83QIGON0BijTdAiJE3QAKTN0A+jDdAIpM3QD6MN0A+jDdAPow3QD6MN0A+jDdAPow3QD6MN0A+jDdAIpE3QD6MN0AdkjdAApM3QAQInwAAAAAAAAAYAQQIBQAAAAAAAAAIAQQIBgAAAAAAAAAAAQQIIQAAAAAAIAAAEQQI3AAAAAAAIAAAEQQIDAAAAAAAIAAAAQQIEgAAAAAAIAAAESAoDAAQAQAA",
|
||||
"data_start": 1070279668
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1077381176,
|
||||
"text": "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 truncated
|
||||
"text_start": 1077379072,
|
||||
"data": "ZCvKP4KLN0APjDdA15A3QJqMN0AvjDdAmow3QPmMN0DGjTdAOY43QOGNN0ANizdAXI03QLiNN0AcjTdAXI43QEaNN0BcjjdA/Ys3QFqMN0CajDdA+Yw3QBWMN0BOizdAHI83QJuQN0AsijdAvZA3QCyKN0AsijdALIo3QCyKN0AsijdALIo3QCyKN0AsijdAto43QCyKN0CyjzdAm5A3QA==",
|
||||
"data_start": 1070279668
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"entry": 1074843652,
|
||||
"text": "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 truncated
|
||||
"text_start": 1074843648,
|
||||
"data": "CIH+PwUFBAACAwcAAwMLALnXEEDv1xBAHdgQQLrYEEBo5xBAHtkQQHTZEEDA2RBAaOcQQILaEED/2hBAwNsQQGjnEEBo5xBAWNwQQGjnEEA33xBAAOAQQDvgEEBo5xBAaOcQQNfgEEBo5xBAv+EQQGXiEECj4xBAY+QQQDTlEEBo5xBAaOcQQGjnEEBo5xBAYuYQQGjnEEBX5xBAkN0QQI/YEECm5RBAq9oQQPzZEEBo5xBA7OYQQDHnEEBo5xBAaOcQQGjnEEBo5xBAaOcQQGjnEEBo5xBAaOcQQCLaEEBf2hBAvuUQQAEAAAACAAAAAwAAAAQAAAAFAAAABwAAAAkAAAANAAAAEQAAABkAAAAhAAAAMQAAAEEAAABhAAAAgQAAAMEAAAABAQAAgQEAAAECAAABAwAAAQQAAAEGAAABCAAAAQwAAAEQAAABGAAAASAAAAEwAAABQAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABgAAAAcAAAAHAAAACAAAAAgAAAAJAAAACQAAAAoAAAAKAAAACwAAAAsAAAAMAAAADAAAAA0AAAANAAAAAAAAAAAAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAANAAAADwAAABEAAAATAAAAFwAAABsAAAAfAAAAIwAAACsAAAAzAAAAOwAAAEMAAABTAAAAYwAAAHMAAACDAAAAowAAAMMAAADjAAAAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAgAAAAIAAAACAAAAAgAAAAMAAAADAAAAAwAAAAMAAAAEAAAABAAAAAQAAAAEAAAABQAAAAUAAAAFAAAABQAAAAAAAAAAAAAAAAAAABAREgAIBwkGCgULBAwDDQIOAQ8AAQEAAAEAAAAEAAAA",
|
||||
"data_start": 1073720488
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
# 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 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 "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 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())
|
||||
|
||||
|
||||
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,
|
||||
"Function %s is not supported for %s." % (function_name, 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)
|
||||
Reference in new issue
Block a user