Two fixes on top of the initial landing:
- BK72xx builds Thumb-mode TUs alongside its ARM FreeRTOS port, and the
MRS CPSR instruction is ARM-only, so in_isr_context() failed to
assemble on cb3s. Delegate to the port's own platform_is_in_interrupt_context()
helper (declared extern "C" in portmacro.h and built in ARM mode) instead
of embedding inline CPSR reads in Thumb code.
- Section name unified to ".sram.text" for every LibreTiny family to avoid
the "setting incorrect section attributes for .data.*" GAS warning. The
pre-link patcher now knows how to route that section into each family's
RAM-resident output:
* BK72xx: flip SRAM region (rw!x) -> (rwx) and inject
KEEP(*(.sram.text*)) into .data : { ... }
* LN882H: inject KEEP(*(.sram.text*)) into .flash_copysection : { ... }
* RTL8710B: inject KEEP(*(.sram.text*)) into .image2.ram.text : { ... }
* RTL8720C: no-op (linker already consumes *(.sram.text*))
The injection uses a "/* esphome .sram.text */" marker so repeated runs
are idempotent.
Two issues surfaced building cb3s-test.yaml:
1. BK72xx's ARM9 FreeRTOS port does not define portYIELD_FROM_ISR; context
switches happen naturally at IRQ exit. Wrap the call in #ifdef so the
wake path compiles on ports that lack it.
2. Placing functions directly in section(".data") provoked assembler
"ignoring changed section attributes" warnings and a hard DWARF error
("leb128 operand is an undefined symbol: .LVU31") because the compiler
emits code-style attributes ("ax") that collide with .data's
data-style attributes ("aw"). Use section(".data.iram_text") instead;
the linker still folds it into the .data output via "*(.data.*)", so
the bytes land in SRAM via the SDK's .data copy, but the assembler no
longer sees conflicting attributes.
target_platform for LibreTiny devices is one of bk72xx, rtl87xx, ln882x
(not "libretiny" itself), so writer.py's platform-dispatched copy_files()
call was not reaching libretiny.copy_files(). That left the pre-link
patch_linker.py script absent from the build dir, so PlatformIO failed
with "missing SConscript file 'patch_linker.py'".
Add a delegating copy_files() to each generated sub-component and to
generate_components.py so regeneration keeps them in sync.
Previously, IRAM_ATTR was an empty no-op on every LibreTiny family, so any
ISR handler (gpio binary sensor, cc1101, sx126x/sx127x, mcp23xxx, pcf8574,
pca9554, pca6416a, pi4ioe5v6408, tca9555, ...) lived in flash. When the
ISR fired while flash was busy (XIP stall, OTA, logger flash write), the
device could deadlock or crash.
- hal.h: IRAM_ATTR now routes each family into a RAM-resident section
(RTL8710B .image2.ram.text, RTL8720C .sram.text, BK72xx / LN882H .data,
which the SDK startup code copies from flash into SRAM before main).
Also adds esphome::in_isr_context() as a portable always_inline ISR
detection helper: xPortInIsrContext on ESP32, PS.INTLEVEL on ESP8266,
IPSR on Cortex-M cores, CPSR mode on BK72xx ARM9.
- main_task.h: both notify helpers marked always_inline so IRAM callers
keep the wake path in IRAM; removes the ESP32-only notify_any_context
which moves into wake.h.
- wake.h / wake.cpp: LibreTiny now shares the ESP32 wake path via a new
wake_main_task_any_context() helper that picks between xTaskNotifyGive
and vTaskNotifyGiveFromISR using in_isr_context(). wake_loop_any_context
and wake_loop_isrsafe are now IRAM_ATTR entry points on LibreTiny too.
- libretiny/patch_linker.py.script: pre-link hook modelled on the ESP8266
testing_mode patcher. BK72xx linker templates declare the SRAM region
as (rw!x), blocking code placement in .data. The hook flips that to
(rwx) so IRAM_ATTR functions can be emitted there; the MMU already
permits RAM execution (the Wi-Fi driver runs from SRAM). No-op on the
other families.
Replace mutable tag references with immutable commit SHAs
to prevent supply-chain attacks via compromised tags.
Version comments are preserved for readability.