libretiny: clean up stale comments and tighten patch_linker script

- hal.h: collapse the four-way USE_LIBRETINY_VARIANT_BK72* guard into
  USE_BK72XX.
- libretiny/__init__.py: drop the stale reference to growing .itcm from
  4.5 kB to 8.5 kB; BK72xx no longer gets any .ld patching.
- patch_linker.py.script: hoist the duplicated "import subprocess" to the
  top, pull the fallback IRAM_ATTR symbols out into a module-level
  frozenset, and split the ELF scan into a helper so _post_link is just
  the print logic.
This commit is contained in:
J. Nick Koston
2026-04-15 15:26:36 -10:00
parent 8a7de40f40
commit f0944a944a
3 changed files with 42 additions and 41 deletions
+5 -7
View File
@@ -468,16 +468,14 @@ async def component_to_code(config):
build_src_flags += " -Os"
cg.add_platformio_option("build_src_flags", build_src_flags)
# IRAM_ATTR on LibreTiny expands to section(".sram.text") on families
# where executable RAM is available (see esphome/core/hal.h). This pre-
# link hook rewrites the processed .ld files in the build dir so that
# section lands in each family's executable RAM output section:
# - BK7231N: grow .itcm from 4.5 kB to 8.5 kB (steal from .tcm) and
# inject KEEP(*(.sram.text*)) into .itcm.code.
# where the ISR-during-flash race is real (see esphome/core/hal.h). This
# pre-link hook routes that section into each family's executable RAM:
# - LN882H: inject KEEP(*(.sram.text*)) into .flash_copysection.
# - RTL8710B: inject KEEP(*(.sram.text*)) into .image2.ram.text.
# - RTL8720C: no-op (stock linker already consumes *(.sram.text*)).
# BK7231T/Q/7251 have no executable RAM region; their SDK disables IRQ
# + FIQ around flash writes, so IRAM_ATTR is left a no-op on them.
# BK72xx (all variants) is no-op: the Beken SDK wraps every flash write
# in GLOBAL_INT_DISABLE() so no ISR can fire during a flash stall; the
# race IRAM_ATTR guards against cannot occur.
cg.add_platformio_option("extra_scripts", ["pre:patch_linker.py"])
# dummy version code
cg.add_define("USE_ARDUINO_VERSION_CODE", cg.RawExpression("VERSION_CODE(0, 0, 0)"))
@@ -3,6 +3,7 @@ Import("env") # noqa
import os
import re
import subprocess
# ESPHome marks ISR code IRAM_ATTR, which on LibreTiny expands to
# section(".sram.text") (see esphome/core/hal.h). Each family's linker script
@@ -122,46 +123,50 @@ def _pre_link(target, source, env):
_patch_build_dir(_patchers, env.subst("$BUILD_DIR"))
def _post_link(target, source, env):
"""Print where IRAM_ATTR ended up so users can confirm at a glance."""
nm = env.subst("$NM") or "arm-none-eabi-nm"
elf = env.subst("$BUILD_DIR/${PROGNAME}.elf")
if not os.path.isfile(elf):
return
# Well-known ESPHome IRAM_ATTR symbols used as a fallback on RTL8720C, where
# we cannot inject the __esphome_sram_text_start/end markers.
_FALLBACK_IRAM_SYMBOLS = frozenset({
"_ZN7esphome21wake_loop_any_contextEv",
"_ZN7esphome17wake_loop_isrsafeEPl",
"_ZN7esphome9Component28enable_loop_soon_any_contextEv",
})
def _collect_iram_symbols(nm, elf):
"""Return (start, end, fallback_addresses) for the IRAM_ATTR payload."""
try:
import subprocess
out = subprocess.check_output([nm, "--defined-only", elf], text=True)
except (OSError, subprocess.CalledProcessError):
return
return None, None, []
start = end = None
sample = []
fallback = []
for line in out.splitlines():
parts = line.split(maxsplit=2)
if len(parts) != 3:
continue
addr, _kind, name = parts
addr_str, _kind, name = parts
if name == "__esphome_sram_text_start":
start = int(addr, 16)
start = int(addr_str, 16)
elif name == "__esphome_sram_text_end":
end = int(addr, 16)
elif name in (
"_ZN7esphome21wake_loop_any_contextEv",
"_ZN7esphome17wake_loop_isrsafeEPl",
"_ZN7esphome9Component28enable_loop_soon_any_contextEv",
):
sample.append((int(addr, 16), name))
header = "ESPHome: IRAM_ATTR placement summary ({}):".format(_variant)
end = int(addr_str, 16)
elif name in _FALLBACK_IRAM_SYMBOLS:
fallback.append(int(addr_str, 16))
return start, end, fallback
def _post_link(target, source, env):
"""Print where IRAM_ATTR ended up so users can confirm at a glance."""
elf = env.subst("$BUILD_DIR/${PROGNAME}.elf")
if not os.path.isfile(elf):
return
start, end, fallback = _collect_iram_symbols(env.subst("$NM"), elf)
print("ESPHome: IRAM_ATTR placement summary ({}):".format(_variant))
if start is not None and end is not None:
print(header)
print(" .sram.text: {} bytes at 0x{:08x} - 0x{:08x}".format(end - start, start, end))
elif sample:
print(header)
sample.sort()
lo = sample[0][0]
hi = sample[-1][0]
elif fallback:
lo, hi = min(fallback), max(fallback)
print(" IRAM symbols at 0x{:08x} - 0x{:08x} (approx {} bytes)".format(lo, hi, hi - lo))
else:
print(header)
print(" no IRAM_ATTR symbols found in the ELF")
+6 -8
View File
@@ -56,10 +56,11 @@
#include <freertos/task.h>
#endif
#if defined(USE_LIBRETINY_VARIANT_BK7231N) || defined(USE_LIBRETINY_VARIANT_BK7231T) || \
defined(USE_LIBRETINY_VARIANT_BK7231Q) || defined(USE_LIBRETINY_VARIANT_BK7251)
#ifdef USE_BK72XX
// Declared in the Beken FreeRTOS port (portmacro.h) and built in ARM mode so
// it is callable from Thumb code via interworking.
// it is callable from Thumb code via interworking. The MRS CPSR instruction
// is ARM-only and user code here may be built in Thumb, so in_isr_context()
// defers to this port helper on BK72xx instead of reading CPSR inline.
extern "C" uint32_t platform_is_in_interrupt_context(void);
#endif
@@ -79,11 +80,8 @@ __attribute__((always_inline)) inline bool in_isr_context() {
uint32_t ipsr;
__asm__ volatile("mrs %0, ipsr" : "=r"(ipsr));
return ipsr != 0;
#elif defined(USE_LIBRETINY_VARIANT_BK7231N) || defined(USE_LIBRETINY_VARIANT_BK7231T) || \
defined(USE_LIBRETINY_VARIANT_BK7231Q) || defined(USE_LIBRETINY_VARIANT_BK7251)
// BK72xx is ARM968E-S (ARM9). The MRS CPSR instruction is ARM-only, and
// user code here may be built in Thumb mode. Defer to the FreeRTOS port
// helper declared above (compiled in ARM mode by the SDK).
#elif defined(USE_BK72XX)
// BK72xx is ARM968E-S (ARM9); see extern declaration above.
return platform_is_in_interrupt_context() != 0;
#elif defined(USE_LIBRETINY)
// Cortex-M (AmebaZ, AmebaZ2, LN882H). IPSR is the active exception number;