From 3aa10acfdf60b7280ca965a56423e38b12df558a Mon Sep 17 00:00:00 2001 From: Maxim Prokhorov Date: Sun, 1 Nov 2026 09:56:07 +0300 Subject: [PATCH 1/6] si2c - section attr set exactly once > cores/esp8266/core_esp8266_si2c.cpp:268:44: warning: ignoring attribute 'section ("\".iram.text.core_esp8266_si2c.cpp.268.16\"")' because it conflicts with previous 'section ("\".iram.text.core_esp8266_si2c.cpp.148.12\"")' [-Wattributes] > 268 | void IRAM_ATTR Twi::busywait(unsigned int v) > | ^ > cores/esp8266/core_esp8266_si2c.cpp:148:20: note: previous declaration here > 148 | void IRAM_ATTR busywait(unsigned int v); > | ^~~~~~~~ etc. --- cores/esp8266/core_esp8266_si2c.cpp | 87 ++++++++++++++--------------- cores/esp8266/wiring_private.h | 2 - 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.cpp b/cores/esp8266/core_esp8266_si2c.cpp index 98f8115b8b..dc7ced4db3 100644 --- a/cores/esp8266/core_esp8266_si2c.cpp +++ b/cores/esp8266/core_esp8266_si2c.cpp @@ -117,7 +117,7 @@ class Twi uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; volatile int twi_rxBufferIndex = 0; - void (*twi_onSlaveTransmit)(void); + void (*twi_onSlaveTransmit)(); void (*twi_onSlaveReceive)(uint8_t*, size_t); // ETS queue/timer interfaces @@ -136,23 +136,23 @@ class Twi ETSTimer timer; // Event/IRQ callbacks, so they can't use "this" and need to be static - static void IRAM_ATTR onSclChange(void); - static void IRAM_ATTR onSdaChange(void); - static void eventTask(ETSEvent* e); - static void IRAM_ATTR onTimer(void* unused); + static void onSclChange(); + static void onSdaChange(); + static void eventTask(ETSEvent* e); + static void onTimer(void*); // Allow not linking in the slave code if there is no call to setAddress bool _slaveEnabled = false; // Internal use functions - void IRAM_ATTR busywait(unsigned int v); - bool write_start(void); - bool write_stop(void); - bool write_bit(bool bit); - bool read_bit(void); - bool write_byte(unsigned char byte); - unsigned char read_byte(bool nack); - void IRAM_ATTR onTwipEvent(uint8_t status); + void busywait(unsigned int v); + bool write_start(); + bool write_stop(); + bool write_bit(bool bit); + bool read_bit(); + bool write_byte(unsigned char byte); + unsigned char read_byte(bool nack); + void onTwipEvent(uint8_t status); // Handle the case where a slave needs to stretch the clock with a time-limited busy wait inline void WAIT_CLOCK_STRETCH() @@ -170,24 +170,24 @@ class Twi } // Generate a clock "valley" (at the end of a segment, just before a repeated start) - void twi_scl_valley(void); + void twi_scl_valley(); public: - void setClock(unsigned int freq); - void setClockStretchLimit(uint32_t limit); - void init(unsigned char sda, unsigned char scl); - void setAddress(uint8_t address); - unsigned char writeTo(unsigned char address, unsigned char* buf, unsigned int len, + void setClock(unsigned int freq); + void setClockStretchLimit(uint32_t limit); + void init(unsigned char sda, unsigned char scl); + void setAddress(uint8_t address); + unsigned char writeTo(unsigned char address, unsigned char* buf, unsigned int len, + unsigned char sendStop); + unsigned char readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop); - unsigned char readFrom(unsigned char address, unsigned char* buf, unsigned int len, - unsigned char sendStop); - uint8_t status(); - uint8_t transmit(const uint8_t* data, uint8_t length); - void attachSlaveRxEvent(void (*function)(uint8_t*, size_t)); - void attachSlaveTxEvent(void (*function)(void)); - void IRAM_ATTR reply(uint8_t ack); - void IRAM_ATTR releaseBus(void); - void enableSlave(); + uint8_t status(); + uint8_t transmit(const uint8_t* data, uint8_t length); + void attachSlaveRxEvent(void (*function)(uint8_t*, size_t)); + void attachSlaveTxEvent(void (*function)()); + void reply(uint8_t ack); + void releaseBus(); + void enableSlave(); }; static Twi twi; @@ -275,7 +275,7 @@ void IRAM_ATTR Twi::busywait(unsigned int v) } } -bool Twi::write_start(void) +bool Twi::write_start() { SCL_HIGH(twi_scl); SDA_HIGH(twi_sda); @@ -294,7 +294,7 @@ bool Twi::write_start(void) return true; } -bool Twi::write_stop(void) +bool Twi::write_stop() { SCL_LOW(twi_scl); SDA_LOW(twi_sda); @@ -326,7 +326,7 @@ bool Twi::write_bit(bool bit) return true; } -bool Twi::read_bit(void) +bool Twi::read_bit() { SCL_LOW(twi_scl); SDA_HIGH(twi_sda); @@ -447,7 +447,7 @@ unsigned char Twi::readFrom(unsigned char address, unsigned char* buf, unsigned return 0; } -void Twi::twi_scl_valley(void) +void Twi::twi_scl_valley() { SCL_LOW(twi_scl); busywait(twi_dcount); @@ -510,14 +510,14 @@ uint8_t Twi::transmit(const uint8_t* data, uint8_t length) return 0; } -void Twi::attachSlaveRxEvent(void (*function)(uint8_t*, size_t)) +void Twi::attachSlaveRxEvent(void (*cb)(uint8_t*, size_t)) { - twi_onSlaveReceive = function; + twi_onSlaveReceive = cb; } -void Twi::attachSlaveTxEvent(void (*function)(void)) +void Twi::attachSlaveTxEvent(void (*cb)()) { - twi_onSlaveTransmit = function; + twi_onSlaveTransmit = cb; } // DO NOT INLINE, inlining reply() in combination with compiler optimizations causes function @@ -541,7 +541,7 @@ void IRAM_ATTR Twi::reply(uint8_t ack) } } -void IRAM_ATTR Twi::releaseBus(void) +void IRAM_ATTR Twi::releaseBus() { // release bus // TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); @@ -660,9 +660,8 @@ void IRAM_ATTR Twi::onTwipEvent(uint8_t status) } } -void IRAM_ATTR Twi::onTimer(void* unused) +void IRAM_ATTR Twi::onTimer(void*) { - (void)unused; twi.releaseBus(); twi.onTwipEvent(TW_BUS_ERROR); twi.twip_mode = TWIPM_WAIT; @@ -709,7 +708,7 @@ void Twi::eventTask(ETSEvent* e) // Shorthand for if the state is any of the or'd bitmask x #define IFSTATE(x) if (twip_state_mask & (x)) -void IRAM_ATTR Twi::onSclChange(void) +void IRAM_ATTR Twi::onSclChange() { unsigned int sda; unsigned int scl; @@ -907,7 +906,7 @@ void IRAM_ATTR Twi::onSclChange(void) } } -void IRAM_ATTR Twi::onSdaChange(void) +void IRAM_ATTR Twi::onSdaChange() { unsigned int sda; unsigned int scl; @@ -1054,7 +1053,7 @@ extern "C" twi.attachSlaveRxEvent(cb); } - void twi_attachSlaveTxEvent(void (*cb)(void)) + void twi_attachSlaveTxEvent(void (*cb)()) { twi.attachSlaveTxEvent(cb); } @@ -1064,12 +1063,12 @@ extern "C" twi.reply(r); } - void twi_releaseBus(void) + void twi_releaseBus() { twi.releaseBus(); } - void twi_enableSlaveMode(void) + void twi_enableSlaveMode() { twi.enableSlave(); } diff --git a/cores/esp8266/wiring_private.h b/cores/esp8266/wiring_private.h index cb52f05393..0200536c96 100644 --- a/cores/esp8266/wiring_private.h +++ b/cores/esp8266/wiring_private.h @@ -34,8 +34,6 @@ extern "C" { #endif -typedef void (*voidFuncPtr)(void); - void initPins(); void resetPins(); From 5e67257f6c4afc3f58b502b222f3555429915f43 Mon Sep 17 00:00:00 2001 From: Maxim Prokhorov Date: Fri, 30 Oct 2026 12:59:08 +0300 Subject: [PATCH 2/6] UMM - section attr in compilation unit --- cores/esp8266/heap_api_debug.h | 14 +++++++------- cores/esp8266/mmu_iram.h | 2 +- cores/esp8266/umm_malloc/umm_info.c | 12 ++++++++++++ cores/esp8266/umm_malloc/umm_local.c | 3 ++- cores/esp8266/umm_malloc/umm_local.h | 5 ++--- cores/esp8266/umm_malloc/umm_malloc_cfg.h | 23 ++++++++++------------- 6 files changed, 34 insertions(+), 25 deletions(-) diff --git a/cores/esp8266/heap_api_debug.h b/cores/esp8266/heap_api_debug.h index 62f7e7bad5..2058dd06bb 100644 --- a/cores/esp8266/heap_api_debug.h +++ b/cores/esp8266/heap_api_debug.h @@ -27,11 +27,11 @@ extern "C" { #include // Reuse pvPort* calls, since they already support passing location information. // Specifically the debug version (heap_...) that does not force DRAM heap. -void *IRAM_ATTR heap_pvPortMalloc(size_t size, const char *file, int line); -void *IRAM_ATTR heap_pvPortCalloc(size_t count, size_t size, const char *file, int line); -void *IRAM_ATTR heap_pvPortRealloc(void *ptr, size_t size, const char *file, int line); -void *IRAM_ATTR heap_pvPortZalloc(size_t size, const char *file, int line); -void IRAM_ATTR heap_vPortFree(void *ptr, const char *file, int line); +void *heap_pvPortMalloc(size_t size, const char *file, int line); +void *heap_pvPortCalloc(size_t count, size_t size, const char *file, int line); +void *heap_pvPortRealloc(void *ptr, size_t size, const char *file, int line); +void *heap_pvPortZalloc(size_t size, const char *file, int line); +void heap_vPortFree(void *ptr, const char *file, int line); #define malloc(s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; heap_pvPortMalloc(s, mem_debug_file, __LINE__); }) #define calloc(n,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; heap_pvPortCalloc(n, s, mem_debug_file, __LINE__); }) @@ -45,10 +45,10 @@ void IRAM_ATTR heap_vPortFree(void *ptr, const char *file, int line); #elif defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE) // #elif for #ifdef DEBUG_ESP_OOM #include -void *IRAM_ATTR heap_pvPortRealloc(void *ptr, size_t size, const char *file, int line); +void *heap_pvPortRealloc(void *ptr, size_t size, const char *file, int line); #define realloc(p,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; heap_pvPortRealloc(p, s, mem_debug_file, __LINE__); }) -void IRAM_ATTR heap_vPortFree(void *ptr, const char *file, int line); +void heap_vPortFree(void *ptr, const char *file, int line); // C - to be discussed /* Problem, I would like to report the file and line number with the umm poison diff --git a/cores/esp8266/mmu_iram.h b/cores/esp8266/mmu_iram.h index e80c5ec348..01c4346a7a 100644 --- a/cores/esp8266/mmu_iram.h +++ b/cores/esp8266/mmu_iram.h @@ -109,7 +109,7 @@ DBG_MMU_FLUSH(0) * in IROM, review printing method and comments in hwdt_app_entry.cpp. * */ -void IRAM_ATTR mmu_wrap_irom_fn(void (*fn)(void)); +void mmu_wrap_irom_fn(void (*fn)(void)); static inline __attribute__((always_inline)) bool mmu_is_iram(const void *addr) { diff --git a/cores/esp8266/umm_malloc/umm_info.c b/cores/esp8266/umm_malloc/umm_info.c index c0ebb7948f..af9e9060b2 100644 --- a/cores/esp8266/umm_malloc/umm_info.c +++ b/cores/esp8266/umm_malloc/umm_info.c @@ -25,6 +25,7 @@ // UMM_HEAP_INFO ummHeapInfo; +void *umm_info(void *ptr, bool force) ICACHE_FLASH_ATTR; void *umm_info(void *ptr, bool force) { UMM_CRITICAL_DECL(id_info); @@ -170,6 +171,11 @@ void *umm_info(void *ptr, bool force) { /* ------------------------------------------------------------------------ */ +#if defined(UMM_STATS) || defined(UMM_STATS_FULL) +size_t umm_free_heap_size_core(umm_heap_context_t *_context) ICACHE_FLASH_ATTR; +size_t umm_free_heap_size(void) ICACHE_FLASH_ATTR; +#endif + size_t umm_free_heap_size_core(umm_heap_context_t *_context) { return (size_t)_context->info.freeBlocks * sizeof(umm_block); } @@ -194,10 +200,12 @@ size_t umm_free_heap_size(void) { // C umm_max_free_block_size() keeping old function name for (dot) releases. // C TODO: update at next major release. // C size_t umm_max_free_block_size( void ) { +size_t umm_max_block_size_core(umm_heap_context_t *_context) ICACHE_FLASH_ATTR; size_t umm_max_block_size_core(umm_heap_context_t *_context) { return _context->info.maxFreeContiguousBlocks * sizeof(umm_block); } +size_t umm_max_block_size(void) ICACHE_FLASH_ATTR; size_t umm_max_block_size(void) { umm_info(NULL, false); return umm_max_block_size_core(umm_get_current_heap()); @@ -208,6 +216,7 @@ size_t umm_max_block_size(void) { umm_fragmentation_metric() must to be preceded by a call to umm_info(NULL, false) for updated results. */ +int umm_usage_metric_core(umm_heap_context_t *_context) ICACHE_FLASH_ATTR; int umm_usage_metric_core(umm_heap_context_t *_context) { // C Note, umm_metrics also appears in the upstrean w/o definition. I suspect it is suppose to be ummHeapInfo. // DBGLOG_DEBUG( "usedBlocks %d totalBlocks %d\n", umm_metrics.usedBlocks, ummHeapInfo.totalBlocks); @@ -219,6 +228,7 @@ int umm_usage_metric_core(umm_heap_context_t *_context) { return -1; // no freeBlocks } +int umm_usage_metric(void) ICACHE_FLASH_ATTR; int umm_usage_metric(void) { #ifndef UMM_INLINE_METRICS umm_info(NULL, false); @@ -228,6 +238,7 @@ int umm_usage_metric(void) { } uint32_t sqrt32(uint32_t n); +int umm_fragmentation_metric_core(umm_heap_context_t *_context) ICACHE_FLASH_ATTR; int umm_fragmentation_metric_core(umm_heap_context_t *_context) { // DBGLOG_DEBUG( "freeBlocks %d freeBlocksSquared %d\n", umm_metrics.freeBlocks, ummHeapInfo.freeBlocksSquared); DBGLOG_DEBUG("freeBlocks %d freeBlocksSquared %d\n", _context->info.freeBlocks, _context->info.freeBlocksSquared); @@ -239,6 +250,7 @@ int umm_fragmentation_metric_core(umm_heap_context_t *_context) { } } +int umm_fragmentation_metric(void) ICACHE_FLASH_ATTR; int umm_fragmentation_metric(void) { #ifndef UMM_INLINE_METRICS umm_info(NULL, false); diff --git a/cores/esp8266/umm_malloc/umm_local.c b/cores/esp8266/umm_malloc/umm_local.c index c08e2a27ca..dc0e4fcb07 100644 --- a/cores/esp8266/umm_malloc/umm_local.c +++ b/cores/esp8266/umm_malloc/umm_local.c @@ -168,7 +168,7 @@ void umm_poison_free_fl(void *ptr, const char *file, int line) { For internal, mainly used by UMM_STATS_FULL; exported so external components can perform Heap related calculations. */ -size_t umm_block_size(void) { +size_t ICACHE_FLASH_ATTR umm_block_size(void) { return sizeof(umm_block); } #endif @@ -256,6 +256,7 @@ size_t xPortGetFreeHeapSize(void) { #endif #if defined(UMM_STATS) || defined(UMM_STATS_FULL) +void umm_print_stats(int force) ICACHE_FLASH_ATTR; void umm_print_stats(int force) { umm_heap_context_t *_context = umm_get_current_heap(); diff --git a/cores/esp8266/umm_malloc/umm_local.h b/cores/esp8266/umm_malloc/umm_local.h index c5dcffd73c..848c20131e 100644 --- a/cores/esp8266/umm_malloc/umm_local.h +++ b/cores/esp8266/umm_malloc/umm_local.h @@ -50,12 +50,11 @@ static bool check_poison_neighbors(umm_heap_context_t *_context, uint16_t cur); #if defined(UMM_STATS) || defined(UMM_STATS_FULL) -void ICACHE_FLASH_ATTR umm_print_stats(int force); +void umm_print_stats(int force); #endif - -int ICACHE_FLASH_ATTR umm_info_safe_printf_P(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +int umm_info_safe_printf_P(const char *fmt, ...) __attribute__((format(printf, 1, 2))); #define UMM_INFO_PRINTF(fmt, ...) umm_info_safe_printf_P(PSTR(fmt),##__VA_ARGS__) diff --git a/cores/esp8266/umm_malloc/umm_malloc_cfg.h b/cores/esp8266/umm_malloc/umm_malloc_cfg.h index bcc355f893..e5633cd48c 100644 --- a/cores/esp8266/umm_malloc/umm_malloc_cfg.h +++ b/cores/esp8266/umm_malloc/umm_malloc_cfg.h @@ -194,23 +194,20 @@ typedef struct UMM_HEAP_INFO_t { UMM_HEAP_INFO; // extern UMM_HEAP_INFO ummHeapInfo; -extern ICACHE_FLASH_ATTR void *umm_info(void *ptr, bool force); -#if defined(UMM_STATS) || defined(UMM_STATS_FULL) -extern ICACHE_FLASH_ATTR size_t umm_free_heap_size(void); -extern ICACHE_FLASH_ATTR size_t umm_free_heap_size_core(umm_heap_context_t *_context); -#else +extern void *umm_info(void *ptr, bool force); extern size_t umm_free_heap_size(void); extern size_t umm_free_heap_size_core(umm_heap_context_t *_context); -#endif // umm_max_block_size changed to umm_max_free_block_size in upstream. -extern ICACHE_FLASH_ATTR size_t umm_max_block_size(void); -extern ICACHE_FLASH_ATTR int umm_usage_metric(void); -extern ICACHE_FLASH_ATTR int umm_fragmentation_metric(void); -extern ICACHE_FLASH_ATTR size_t umm_max_block_size_core(umm_heap_context_t *_context); -extern ICACHE_FLASH_ATTR int umm_usage_metric_core(umm_heap_context_t *_context); -extern ICACHE_FLASH_ATTR int umm_fragmentation_metric_core(umm_heap_context_t *_context); +extern size_t umm_max_block_size(void); +extern size_t umm_max_block_size_core(umm_heap_context_t *_context); + +extern int umm_usage_metric(void); +extern int umm_usage_metric_core(umm_heap_context_t *_context); + +extern int umm_fragmentation_metric(void); +extern int umm_fragmentation_metric_core(umm_heap_context_t *_context); #endif /* @@ -289,7 +286,7 @@ extern size_t umm_get_oom_count(void); #endif #if defined(UMM_STATS) || defined(UMM_STATS_FULL) || defined(UMM_INFO) -size_t ICACHE_FLASH_ATTR umm_block_size(void); +size_t umm_block_size(void); #endif #ifdef UMM_STATS_FULL From 773ccf59bf337dd8d254c0363ba34b3904e37ca4 Mon Sep 17 00:00:00 2001 From: Maxim Prokhorov Date: Sun, 1 Nov 2026 10:31:27 +0300 Subject: [PATCH 3/6] Waveform - attributes clean-up continue fixes of section attribute being set multiple times also clears up declarations incorrectly placing attr intended for func --- cores/esp8266/core_esp8266_waveform_phase.cpp | 18 ++++++----- cores/esp8266/core_esp8266_waveform_pwm.cpp | 30 +++++++++++-------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/cores/esp8266/core_esp8266_waveform_phase.cpp b/cores/esp8266/core_esp8266_waveform_phase.cpp index 4240ccb3c1..4d1b77d983 100644 --- a/cores/esp8266/core_esp8266_waveform_phase.cpp +++ b/cores/esp8266/core_esp8266_waveform_phase.cpp @@ -45,8 +45,9 @@ #include "ets_sys.h" #include +extern "C" { -extern "C" void enablePhaseLockedWaveform (void) +void enablePhaseLockedWaveform () { // Does nothing, added to app to enable linking these versions // of the waveform functions instead of the default. @@ -54,10 +55,11 @@ extern "C" void enablePhaseLockedWaveform (void) } // No-op calls to override the PWM implementation -extern "C" void _setPWMFreq_weak(uint32_t freq) { (void) freq; } -extern "C" IRAM_ATTR bool _stopPWM_weak(int pin) { (void) pin; return false; } -extern "C" bool _setPWM_weak(int pin, uint32_t val, uint32_t range) { (void) pin; (void) val; (void) range; return false; } +void _setPWMFreq_weak(uint32_t) {} +bool IRAM_ATTR _stopPWM_weak(int) { return false; } +bool _setPWM_weak(int, uint32_t, uint32_t) { return false; } +} // extern "C" // Timer is 80MHz fixed. 160MHz CPU frequency need scaling. constexpr bool ISCPUFREQ160MHZ = clockCyclesPerMicrosecond() == 160; @@ -111,7 +113,7 @@ namespace { } // Interrupt on/off control -static IRAM_ATTR void timer1Interrupt(); +static void timer1Interrupt(); // Non-speed critical bits #pragma GCC optimize ("Os") @@ -218,7 +220,7 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCc } // Stops a waveform on a pin -IRAM_ATTR int stopWaveform_weak(uint8_t pin) { +int IRAM_ATTR stopWaveform_weak(uint8_t pin) { // Can't possibly need to stop anything if there is no timer active if (!waveform.timer1Running) { return false; @@ -252,7 +254,7 @@ IRAM_ATTR int stopWaveform_weak(uint8_t pin) { // For dynamic CPU clock frequency switch in loop the scaling logic would have to be adapted. // Using constexpr makes sure that the CPU clock frequency is compile-time fixed. -static inline IRAM_ATTR int32_t scaleCcys(const int32_t ccys, const bool isCPU2X) { +static inline int32_t IRAM_ATTR scaleCcys(const int32_t ccys, const bool isCPU2X) { if (ISCPUFREQ160MHZ) { return isCPU2X ? ccys : (ccys >> 1); } @@ -261,7 +263,7 @@ static inline IRAM_ATTR int32_t scaleCcys(const int32_t ccys, const bool isCPU2X } } -static IRAM_ATTR void timer1Interrupt() { +static void IRAM_ATTR timer1Interrupt() { const uint32_t isrStartCcy = ESP.getCycleCount(); int32_t clockDrift = isrStartCcy - waveform.nextEventCcy; const bool isCPU2X = CPU2X & 1; diff --git a/cores/esp8266/core_esp8266_waveform_pwm.cpp b/cores/esp8266/core_esp8266_waveform_pwm.cpp index f85ccb76aa..b80400aa09 100644 --- a/cores/esp8266/core_esp8266_waveform_pwm.cpp +++ b/cores/esp8266/core_esp8266_waveform_pwm.cpp @@ -94,10 +94,11 @@ static WVFState wvfState; #pragma GCC optimize ("Os") // Interrupt on/off control -static IRAM_ATTR void timer1Interrupt(); +static void timer1Interrupt(); static bool timerRunning = false; -static __attribute__((noinline)) void initTimer() { +static void initTimer() __attribute__((noinline)); +static void initTimer() { if (!timerRunning) { timer1_disable(); ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL); @@ -108,7 +109,7 @@ static __attribute__((noinline)) void initTimer() { } } -static IRAM_ATTR void forceTimerInterrupt() { +static void IRAM_ATTR forceTimerInterrupt() { if (T1L > microsecondsToClockCycles(10)) { T1L = microsecondsToClockCycles(10); } @@ -145,7 +146,7 @@ static uint32_t _pwmPeriod = microsecondsToClockCycles(1000000UL) / _pwmFreq; // If there are no more scheduled activities, shut down Timer 1. // Otherwise, do nothing. -static IRAM_ATTR void disableIdleTimer() { +static void IRAM_ATTR disableIdleTimer() { if (timerRunning && !wvfState.waveformEnabled && !pwmState.cnt && !wvfState.timer1CB) { ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL); timer1_disable(); @@ -156,7 +157,7 @@ static IRAM_ATTR void disableIdleTimer() { // Notify the NMI that a new PWM state is available through the mailbox. // Wait for mailbox to be emptied (either busy or delay() as needed) -static IRAM_ATTR void _notifyPWM(PWMState *p, bool idle) { +static void IRAM_ATTR _notifyPWM(PWMState *p, bool idle) { p->pwmUpdate = nullptr; pwmState.pwmUpdate = p; MEMBARRIER(); @@ -171,7 +172,6 @@ static IRAM_ATTR void _notifyPWM(PWMState *p, bool idle) { static void _addPWMtoList(PWMState &p, int pin, uint32_t val, uint32_t range); - // Called when analogWriteFreq() changed to update the PWM total period extern void _setPWMFreq_weak(uint32_t freq) __attribute__((weak)); void _setPWMFreq_weak(uint32_t freq) { @@ -208,6 +208,7 @@ void _setPWMFreq_weak(uint32_t freq) { disableIdleTimer(); } } + static void _setPWMFreq_bound(uint32_t freq) __attribute__((weakref("_setPWMFreq_weak"))); void _setPWMFreq(uint32_t freq) { _setPWMFreq_bound(freq); @@ -238,7 +239,7 @@ static void _cleanAndRemovePWM(PWMState *p, int pin) { // Disable PWM on a specific pin (i.e. when a digitalWrite or analogWrite(0%/100%)) extern bool _stopPWM_weak(uint8_t pin) __attribute__((weak)); -IRAM_ATTR bool _stopPWM_weak(uint8_t pin) { +bool IRAM_ATTR _stopPWM_weak(uint8_t pin) { if (!((1< Date: Sun, 1 Nov 2026 10:02:15 +0300 Subject: [PATCH 4/6] `spi_flash_read` wrapper - section attr set exactly once > cores/esp8266/core_esp8266_phy.cpp:317:85: warning: ignoring attribute 'section ("\".iram.text.core_esp8266_phy.cpp.317.2\"")' because it conflicts with previous 'section ("\".iram.text.core_esp8266_phy.cpp.303.1\"")' [-Wattributes] > 317 | extern int IRAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size) > | ^ > cores/esp8266/core_esp8266_phy.cpp:303:22: note: previous declaration here > 303 | extern int IRAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size); > | ^~~~~~~~~~~~~~~~~~~~~ --- cores/esp8266/core_esp8266_phy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/core_esp8266_phy.cpp b/cores/esp8266/core_esp8266_phy.cpp index 4657bb0081..7785cd666b 100644 --- a/cores/esp8266/core_esp8266_phy.cpp +++ b/cores/esp8266/core_esp8266_phy.cpp @@ -300,7 +300,7 @@ static const uint8_t ICACHE_FLASH_ATTR phy_init_data[128] = static bool spoof_init_data = false; extern int __real_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size); -extern int IRAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size); +extern int __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size); extern int __get_adc_mode(); /* @@ -376,4 +376,4 @@ void user_rf_pre_init() void IRAM_ATTR user_spi_flash_dio_to_qio_pre_init() {} -}; +} // extern "C" From 0a3442980a8b91182cb5d52c36264adc4d20fd3b Mon Sep 17 00:00:00 2001 From: Maxim Prokhorov Date: Sun, 1 Nov 2026 10:33:28 +0300 Subject: [PATCH 5/6] libc replacements - section attribute set exactly once --- cores/esp8266/libc_replacements.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/libc_replacements.cpp b/cores/esp8266/libc_replacements.cpp index da03516b4f..049ee9adad 100644 --- a/cores/esp8266/libc_replacements.cpp +++ b/cores/esp8266/libc_replacements.cpp @@ -95,7 +95,7 @@ int IRAM_ATTR _write_r(struct _reent* r, int file, char *ptr, int len) { return len; } -int IRAM_ATTR _putc_r(struct _reent* r, int c, FILE* file) __attribute__((weak)); +int _putc_r(struct _reent* r, int c, FILE* file) __attribute__((weak)); int IRAM_ATTR _putc_r(struct _reent* r, int c, FILE* file) { (void) r; @@ -133,4 +133,4 @@ int atexit(void (*func)()) { return 0; } -}; +} // extern "C" From 787c3d24682d9041608c1161b92d01504226d933 Mon Sep 17 00:00:00 2001 From: Maxim Prokhorov Date: Sun, 1 Nov 2026 10:50:24 +0300 Subject: [PATCH 6/6] c_types.h - section attr w/o quotes section name is already used as string, do not assume it is a literal injected somewhere e.g. for asm hints after `.section` --- tests/host/common/c_types.h | 12 +++--------- tools/sdk/include/c_types.h | 4 ++-- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/tests/host/common/c_types.h b/tests/host/common/c_types.h index 9ba8968aeb..e0028d87fe 100644 --- a/tests/host/common/c_types.h +++ b/tests/host/common/c_types.h @@ -94,15 +94,9 @@ typedef enum #ifdef ICACHE_FLASH #define __ICACHE_STRINGIZE_NX(A) #A #define __ICACHE_STRINGIZE(A) __ICACHE_STRINGIZE_NX(A) -#define ICACHE_FLASH_ATTR \ - __attribute__((section("\".irom0.text." __FILE__ "." __ICACHE_STRINGIZE( \ - __LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\""))) -#define IRAM_ATTR \ - __attribute__((section("\".iram.text." __FILE__ "." __ICACHE_STRINGIZE( \ - __LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\""))) -#define ICACHE_RODATA_ATTR \ - __attribute__((section("\".irom.text." __FILE__ "." __ICACHE_STRINGIZE( \ - __LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\""))) +#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__)))) +#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__)))) +#define IRAM_ATTR __attribute__((section(".iram.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__)))) #else #define ICACHE_FLASH_ATTR #define IRAM_ATTR diff --git a/tools/sdk/include/c_types.h b/tools/sdk/include/c_types.h index 0bb7c6df06..129cefa4a5 100644 --- a/tools/sdk/include/c_types.h +++ b/tools/sdk/include/c_types.h @@ -86,8 +86,8 @@ typedef enum { #ifdef ICACHE_FLASH #define __ICACHE_STRINGIZE_NX(A) #A #define __ICACHE_STRINGIZE(A) __ICACHE_STRINGIZE_NX(A) -#define ICACHE_FLASH_ATTR __attribute__((section("\".irom0.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\""))) -#define IRAM_ATTR __attribute__((section("\".iram.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\""))) +#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__)))) +#define IRAM_ATTR __attribute__((section(".iram.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__)))) #else #define ICACHE_FLASH_ATTR #define IRAM_ATTR