Commit Graph

14506 Commits

Author SHA1 Message Date
J. Nick Koston f296a86675 libretiny: drop unnecessary CC-derived nm fallback 2026-04-15 16:10:29 -10:00
J. Nick Koston 1aeb04b4dc libretiny: log nm failure reason instead of silently swallowing 2026-04-15 16:09:55 -10:00
J. Nick Koston 384f8f6870 libretiny: derive nm from CC path when $NM is unset 2026-04-15 16:08:58 -10:00
J. Nick Koston 1cc0ae5443 libretiny: skip patch_linker.py entirely on BK72xx
IRAM_ATTR is a no-op on BK72xx so there is nothing for the script to
patch or summarize. Guard the extra_scripts registration with a
COMPONENT_BK72XX check and drop the BK72xx variants from
KNOWN_VARIANTS.
2026-04-15 16:07:43 -10:00
J. Nick Koston f961f9bfb3 libretiny: fix post-link summary for RTL8710B + LN882H
Post-link was not registered for RTL8710B (condition was too narrow
after removing it from _PATCHERS_BY_VARIANT). Use a BK72xx exclusion
set instead so all IRAM-active variants get the summary.

Also fall back to TOOLCHAIN_PREFIX-nm when $NM is empty, which fixes
the empty summary on LN882H.
2026-04-15 16:06:48 -10:00
J. Nick Koston 9fc54d30e5 libretiny: use native section names for RTL8710B; patcher now LN882H-only
RTL8710B's stock linker already consumes *(.image2.ram.text*) into its
.ram_image2.text output (> BD_RAM), so hal.h can place IRAM_ATTR
functions directly into section(".image2.ram.text") without any linker
patching. RTL8720C already worked this way with section(".sram.text").

The patcher is now only needed for LN882H, whose stock linker has no
glob that catches ".sram.text" — we inject KEEP(*(.sram.text*)) into
.flash_copysection (> RAM0 AT> FLASH).

This removes the _RTL8710B_IMAGE2 regex, the RTL8710B entry from
_PATCHERS_BY_VARIANT, and simplifies the header comments.
2026-04-15 16:05:12 -10:00
J. Nick Koston 853782b251 libretiny: exclude veneer symbols from post-link IRAM fallback
Linker-generated interworking veneers (e.g. ___ZN...enable_loop_soon_
any_context_veneer at 0x9b062588) contain the same function name
substrings but live at unrelated addresses, producing a bogus multi-GB
range in the summary. Filter them out.
2026-04-15 15:59:26 -10:00
J. Nick Koston 35cafd52a5 libretiny: inline _collect_iram_symbols into _post_link 2026-04-15 15:54:02 -10:00
J. Nick Koston 3b0ac8ebed libretiny: simplify _pre_link, inline _patch_build_dir 2026-04-15 15:50:34 -10:00
J. Nick Koston 22781aff74 libretiny: reference _PATCHERS_BY_VARIANT instead of individual regex names in error 2026-04-15 15:47:45 -10:00
J. Nick Koston f9c4ed65ff libretiny: fix ESP8266 in_isr_context; use demangled names for fallback
- ESP8266 in_isr_context() was checking PS.INTLEVEL which gives false
  positives when user code masks interrupts. Return false unconditionally
  since the ESP8266 wake path is context-agnostic and never calls
  in_isr_context().
- Replace brittle mangled C++ symbol names in the post-link fallback
  with substring matches on demangled names via nm --demangle. Survives
  namespace/signature changes.
2026-04-15 15:47:06 -10:00
J. Nick Koston 663c1784b7 libretiny: use walrus operator for variant/patchers assignment 2026-04-15 15:44:29 -10:00
J. Nick Koston 65f10feee4 libretiny: fix stale .image2.ram.text comments; rename dir -> script_dir; link regex from error
Review feedback:
- three comments still referenced the input glob '.image2.ram.text' after
  the output section was fixed to '.ram_image2.text' in eae6e6d32b; update
  comments in hal.h, libretiny/__init__.py, and patch_linker.py.script so
  they match the regex.
- rename the 'dir' local in libretiny.copy_files() to 'script_dir' to
  avoid shadowing the Python builtin.
- the 'no linker script patched' RuntimeError now names the per-family
  regex constants a maintainer should update when a LibreTiny template
  changes shape.
2026-04-15 15:36:13 -10:00
J. Nick Koston eae6e6d32b libretiny: fix RTL8710B linker regex — output is .ram_image2.text not .image2.ram.text
Confused the output section name with the input glob. RTL8710B's linker
template has:

  .ram_image2.text : {
    KEEP(*(.image2.ram.text*))
  } > BD_RAM

so we need to match ".ram_image2.text :" and inject our extra
KEEP(*(.sram.text*)) alongside the existing input glob. CI caught this;
the test_build_components rtl87xx-ard smoke test now exercises the
patcher.
2026-04-15 15:28:46 -10:00
J. Nick Koston f0944a944a 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.
2026-04-15 15:26:36 -10:00
J. Nick Koston 8a7de40f40 libretiny: KNOWN_VARIANTS -> frozenset for O(1) membership 2026-04-15 15:22:12 -10:00
J. Nick Koston 05df654a3e libretiny: drop BK72xx from IRAM_ATTR coverage
After confirming via the Beken SDKs (both BK7231T and BK7231N flash.c use
GLOBAL_INT_DISABLE around every erase/program) and searching the libretiny
+ esphome issue trackers, the ISR-during-flash race IRAM_ATTR is designed
to prevent cannot actually occur on any BK72xx variant:

  - Beken SDK wraps every flash op in GLOBAL_INT_DISABLE(), masking FIQ +
    IRQ at the CPU for the ~0.5-20 ms of the write, so no ISR fires while
    flash is stalled.
  - Interrupts are delayed (not dropped outright for single-shot sources)
    by that mask, but that is an SDK-level design choice and cannot be
    reduced from this layer.
  - No BK72xx user has reported the crash pattern IRAM_ATTR fixes; the
    real reports of that pattern are on RTL8710B (see libretiny#167).

Make IRAM_ATTR a no-op on every BK72xx variant and remove the BK7231N-
specific ITCM shuffling from patch_linker.py.script. The fix now covers
only the families where the race is real: RTL8710B, RTL8720C, LN882H.
2026-04-15 15:17:41 -10:00
J. Nick Koston bc672d358b libretiny: scope BK72xx IRAM_ATTR to BK7231N; T/Q/7251 stay no-op
BK7231T / BK7231Q / BK7251 share a LibreTiny linker template that only
declares flash + ram, no executable RAM region. Their SDK wraps flash
writes in GLOBAL_INT_DISABLE() which masks both FIQ and IRQ, so no ISR
fires while flash is stalled and the "code in flash while flash is busy"
scenario IRAM_ATTR is guarding against does not occur on those variants.
Map IRAM_ATTR to nothing on them rather than orphan-linking .sram.text
into flash and drop the T/Q/7251 entries from _PATCHERS_BY_VARIANT so
the pre-link hook is not registered for them.

BK7231N still gets the full fix (grown .itcm.code) because its SDK takes
the defense-in-depth route of also placing flash/ISR/FreeRTOS critical
code in ITCM, so our IRAM_ATTR functions need to live there too.

Also make _grow_bk72xx_itcm fail loudly if the tcm/itcm declarations in
the BK7231N template ever change shape, matching the fail-hard stance of
the rest of the script.
2026-04-15 14:34:16 -10:00
J. Nick Koston 85d1ab7303 libretiny: grow BK72xx .itcm region from 4.5 kB to 8.5 kB
The SDK's built-in ISR / flash / FreeRTOS critical-path code already fills
most of the stock 4.5 kB .itcm executable RAM region, leaving under 500
bytes for ESPHome's IRAM_ATTR functions. cb3s overflowed by 248 bytes on
first link. Physically .tcm (rw!x, data) and .itcm (rwx, code) are
contiguous SRAM blocks on ARM968E-S; the template's boundary is just a
linker carve-out. Shift it back 4 kB so .tcm shrinks 60k -> 56k and .itcm
grows 4.5k -> 8.5k. Confirmed fits every ESPHome IRAM_ATTR function on cb3s
with ample headroom.
2026-04-15 14:24:57 -10:00
J. Nick Koston 365ff86bac libretiny: target BK72xx .itcm.code instead of .data for IRAM_ATTR
cb3s flashed firmware crashed after logger init. Main SRAM on ARM968E-S
is not instruction-fetchable: the stock linker marks it (rw!x) because
the bus does not allow instruction fetches from that region, so putting
IRAM_ATTR code in .data landed the bytes in RAM but triggered a prefetch
abort when the first IRAM function was called.

The ARM968 design has a separate tightly-coupled instruction memory
("itcm", 4.5 kB, rwx) where the SDK already routes its own ISR, flash,
and FreeRTOS critical-path code via the .itcm.code output section.
Inject KEEP(*(.sram.text*)) into .itcm.code so our IRAM_ATTR functions
share that executable RAM region. No (rw!x) flip is needed since we no
longer touch the main SRAM layout.
2026-04-15 14:18:39 -10:00
J. Nick Koston a1970737c6 libretiny: dedupe per-variant patchers into a shared injector and dict lookup 2026-04-15 14:10:39 -10:00
J. Nick Koston 8dba87014a libretiny: use strong linker assignments for SRAM text markers
PROVIDE symbols without references get garbage-collected by the linker, so
the post-link summary was falling back to the symbol-scrape path on every
family. Use direct assignment so the markers always land in the ELF symbol
table, giving an exact byte count for the ESPHome IRAM_ATTR contribution.
2026-04-15 14:07:31 -10:00
J. Nick Koston ab382c1e52 libretiny: print IRAM_ATTR placement summary after link
After linking, walk the ELF symbol table and print one of:

  ESPHome: IRAM_ATTR placement summary (BK7231N):
    .sram.text:  312 bytes at 0x004001d0 - 0x00400308

  ESPHome: IRAM_ATTR placement summary (RTL8720C):
    IRAM symbols at 0x10002f6c - 0x10002fa8 (approx 60 bytes)

On the three families whose linker scripts we already patch (BK72xx, LN882H,
RTL8710B) the PROVIDE(__esphome_sram_text_start/end = .) markers injected
alongside KEEP(*(.sram.text*)) give an exact byte count for the ESPHome
IRAM_ATTR contribution. On RTL8720C we cannot patch the linker script (it
is loaded directly from the framework package) so the summary falls back to
reading the addresses of the three core IRAM_ATTR symbols. Either way the
address range is visible proof that the functions ended up in SRAM rather
than flash.
2026-04-15 14:05:48 -10:00
J. Nick Koston 33118e0e57 libretiny: patch_linker.py.script — fail hard if IRAM_ATTR cannot land in SRAM
Two issues from the cb3s smoke test:

- The previous CPPDEFINES-only variant detection missed the
  USE_LIBRETINY_VARIANT_* define on BK72xx in the pre-script environment,
  so no patcher registered and the .sram.text section silently landed in
  flash. Check BUILD_FLAGS as a fallback so the define is picked up
  regardless of when PlatformIO finishes populating CPPDEFINES.

- When the variant could not be detected, or no .ld file was modified, the
  script exited quietly and the firmware linked with IRAM_ATTR functions
  in flash — the exact bug this PR is trying to fix. Raise a RuntimeError
  in all three failure cases (variant missing, variant unknown, no .ld
  patched) so the build fails loudly instead of producing broken firmware.
2026-04-15 13:59:42 -10:00
J. Nick Koston 55845b3e85 Address copilot review: update extra_scripts comment to match current implementation 2026-04-15 13:56:39 -10:00
J. Nick Koston 90b311258a libretiny: move Beken extern "C" declaration out of function body 2026-04-15 13:54:23 -10:00
J. Nick Koston e5b46540ee libretiny: fix BK72xx Thumb asm; unify IRAM_ATTR on .sram.text
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.
2026-04-15 13:53:35 -10:00
J. Nick Koston f404768fd1 libretiny: fix BK72xx build — guard portYIELD_FROM_ISR; use .data.iram_text
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.
2026-04-15 13:48:11 -10:00
J. Nick Koston c1ef3cab37 libretiny: wire copy_files() through each target_platform module
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.
2026-04-15 13:46:37 -10:00
J. Nick Koston 3e5c4fd603 Make IRAM_ATTR functional on LibreTiny
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.
2026-04-15 13:42:17 -10:00
dependabot[bot] 403a9f7b7e Bump github/codeql-action from 4.35.1 to 4.35.2 (#15759)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-15 10:12:30 -10:00
dependabot[bot] 10f52f2056 Bump aioesphomeapi from 44.15.0 to 44.16.0 (#15757)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-15 09:07:49 -10:00
Jonathan Swoboda 274c01ca74 [sx126x][sx127x] Fix frequency precision loss from float32 codegen (#15753) 2026-04-15 14:32:33 -04:00
Jonathan Swoboda 3b82c6e38b [st7789v] Fix swapped offset_width/offset_height in model presets (#15755) 2026-04-15 14:32:11 -04:00
Jesse Hills f59a1011df Merge branch 'release' into dev 2026-04-15 22:45:16 +12:00
Jesse Hills 82c0cb8929 Merge pull request #15745 from esphome/bump-2026.4.0
2026.4.0
2026.4.0
2026-04-15 22:44:27 +12:00
Jesse Hills 2bdd9f6217 Bump version to 2026.4.0 2026-04-15 20:44:30 +12:00
Jesse Hills 193e7d476d Pin GitHub Actions to commit SHAs
Replace mutable tag references with immutable commit SHAs
to prevent supply-chain attacks via compromised tags.
Version comments are preserved for readability.
2026-04-15 13:12:20 +12:00
Jesse Hills 1b3e7d5ec4 Merge branch 'beta' into dev 2026-04-15 13:10:45 +12:00
Jesse Hills 767a8c49b0 Merge pull request #15739 from esphome/bump-2026.4.0b3
2026.4.0b3
2026.4.0b3
2026-04-15 13:10:09 +12:00
Jesse Hills 4c43f7e9d0 Bump version to 2026.4.0b3 2026-04-15 10:58:30 +12:00
Edward Firmo 3ef140e25d [nextion] Fix command spacing pacer never throttling sends (#15664)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-04-15 10:58:30 +12:00
J. Nick Koston 0a568a3e1e [light] Avoid addressable transition stall at low gamma-corrected values (#15726) 2026-04-15 10:58:30 +12:00
Alexey Spirkov ef44491c69 [i2s_audio] Add PDM mics support for ESP32-P4 (#15333)
Co-authored-by: Alexey Spirkov <dev@alsp.net>
2026-04-15 10:58:30 +12:00
J. Nick Koston 089a2c99e2 [globals] Fix TemplatableFn deprecation warning for globals.set (#15733) 2026-04-15 10:58:30 +12:00
J. Nick Koston 311812c8cc [esphome] Skip missing extra flash images in upload_using_esptool (#15723)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-04-15 10:58:30 +12:00
J. Nick Koston a77ab59436 [web_server] Reset OTA backend on new upload to avoid brick after interrupted OTA (#15720) 2026-04-15 10:58:30 +12:00
J. Nick Koston 89fbfc6f71 [adc] Place ADC oneshot control functions in IRAM for cache safety (#15717) 2026-04-15 10:58:29 +12:00
J. Nick Koston 28f3bcdba3 [api] Add speed_optimized to SubscribeLogsResponse (#15698)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-04-15 10:58:29 +12:00
Jonathan Swoboda 445715b9fd [esp32] Update the recommended platform to 55.03.38-1 (#15705) 2026-04-15 10:58:29 +12:00