You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have tried comparing multiple legacy projects, and without exception, the 3.0.0 version always consumes more Flash space than the 2.X.X versions.
All configurations, microcontroller options, and third-party libraries have been kept identical.
Win11 25H2
Arduino 2.3.10
U8G2 2.36.19
Debug symbols and core logs:"None"
Optimize:"Smallest (-OS) with LTO"
Board part number:"Generic G030F6Px"
U(S)ART support:"Enabled (generic ‘Serial’)"
"Optimize for debug" is not checked.
For example, in this project, the Flash footprint after compilation is completely different.
STM32 CORE 2.6.0
Sketch uses 31588 bytes (96%) of program storage space. Maximum is 32768 bytes.
Global variables use 3132 bytes (38%) of dynamic memory, leaving 5060 bytes for local variables. Maximum is 8192 bytes.
STM32 CORE 2.11.0
Sketch uses 31620 bytes (96%) of program storage space. Maximum is 32768 bytes.
Global variables use 3084 bytes (37%) of dynamic memory, leaving 5108 bytes for local variables. Maximum is 8192 bytes.
STM32 CORE 2.12.0
Sketch uses 31780 bytes (96%) of program storage space. Maximum is 32768 bytes.
Global variables use 3084 bytes (37%) of dynamic memory, leaving 5108 bytes for local variables. Maximum is 8192 bytes.
STM32 CORE 3.0.0
region `FLASH' overflowed by 3884 bytes
Deployment of the ArduinoCore-API is the main responsible of this.
Here the analysis made using GH Copilot:
ArduinoCore-API is not merely renamed headers. It changes the concrete C++ types and method contracts that the core, Wire, SPI, Serial, and user libraries compile against.
The main cost comes from:
New object model and virtual interface: Print, Stream, String, Uart, SPIClass, and TwoWire now conform to shared ArduinoCore-API contracts. That retains vtables, virtual dispatch entries, destructors, and compatibility methods where the old STM32-specific implementation could be simpler.
Broader API signatures: The migration changes values such as pin identifiers and lengths to portable types like pin_size_t and size_t. On Cortex-M0+, that can require conversions, wider arithmetic, and distinct overloads. It also prevents some old call paths from folding exactly the same way under LTO.
API compatibility surface: The new implementations need to support standard ArduinoCore-API overloads, including multiple Wire.begin, requestFrom, endTransmission, SPI.begin, SPISettings, and serial methods. Even if a sketch calls one overload, virtual/interface reachability and internal delegation can retain more code.
Less target-specific optimization: 2.12.0 types and APIs were STM32-only, so the compiler saw more local assumptions. ArduinoCore-API requires behavior shared across Arduino platforms, preserving generic paths for pin handling, bus mode, callbacks, and configuration.
Cascading recompile effect: With LTO, a type/signature change alters inlining, devirtualization, and constant propagation across the whole program. A small API adjustment can change generated code in U8g2, Wire, SPI, Serial, interrupts, and startup, not just in the migrated files.
Your symbols reflect this: the new image retains API-driven Wire/SPI/Uart functions totaling several KB, while the old image retained HardwareSerial, legacy String, Stream, and Print forms. The net code increase is not one large library; it is many changed call boundaries that no longer optimize into the same compact machine code.
The migration’s benefit is cross-core API consistency and easier library portability. The size cost is the price of preserving that common abstraction on a very small Cortex-M0+ target.
This discussion was converted from issue #3066 on September 01, 2026 15:40.
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
I have tried comparing multiple legacy projects, and without exception, the 3.0.0 version always consumes more Flash space than the 2.X.X versions.
All configurations, microcontroller options, and third-party libraries have been kept identical.
Win11 25H2
Arduino 2.3.10
U8G2 2.36.19
Debug symbols and core logs:"None"
Optimize:"Smallest (-OS) with LTO"
Board part number:"Generic G030F6Px"
U(S)ART support:"Enabled (generic ‘Serial’)"
"Optimize for debug" is not checked.
For example, in this project, the Flash footprint after compilation is completely different.
STM32 CORE 2.6.0
Sketch uses 31588 bytes (96%) of program storage space. Maximum is 32768 bytes.
Global variables use 3132 bytes (38%) of dynamic memory, leaving 5060 bytes for local variables. Maximum is 8192 bytes.
STM32 CORE 2.11.0
Sketch uses 31620 bytes (96%) of program storage space. Maximum is 32768 bytes.
Global variables use 3084 bytes (37%) of dynamic memory, leaving 5108 bytes for local variables. Maximum is 8192 bytes.
STM32 CORE 2.12.0
Sketch uses 31780 bytes (96%) of program storage space. Maximum is 32768 bytes.
Global variables use 3084 bytes (37%) of dynamic memory, leaving 5108 bytes for local variables. Maximum is 8192 bytes.
STM32 CORE 3.0.0
region `FLASH' overflowed by 3884 bytes
All reactions