STM32g030k6p6 simple sketch overflows the flash memory?

So first I setup PlatformIO with a boards/genericSTM32G030K6.json with

{
    "build": {
      "core": "stm32",
      "cpu": "cortex-m0plus",
      "extra_flags": "-DSTM32G0xx -DSTM32G030xx",
      "f_cpu": "64000000L",
      "mcu": "stm32g030k6t6",
      "product_line": "STM32G030xx",
      "variant": "STM32G0xx/G030K(6-8)T"
    },
    "debug": {
      "default_tools": [
        "stlink"
      ],
      "jlink_device": "STM32G030K6",
      "openocd_target": "stm32g0x",
      "svd_path": "STM32G030.svd"
    },
    "frameworks": [
      "arduino",
      "cmsis",
      "libopencm3",
      "stm32cube"
    ],
    "name": "STM32G030K6P6 (8k RAM. 32k Flash)",
    "upload": {
      "maximum_ram_size": 8192,
      "maximum_size": 32768,
      "protocol": "serial",
      "protocols": [
        "blackmagic",
        "dfu",
        "jlink",
        "serial",
        "stlink"
      ]
    },
    "url": "https://www.st.com/en/microcontrollers-microprocessors/stm32g030k6.html",
    "vendor": "Generic"
  }

and then in the platformio.ini I configured it as

[env:genericSTM32G030K6]
platform = ststm32
board = genericSTM32G030K6
framework = arduino
lib_deps =
   adafruit/Adafruit MPRLS Library@^1.2.0
   SPI
; force successfull compilation by pretending we have more flash
board_upload.maximum_size = 64000
; generate debug symbols (good for size report)
build_flags = -g3 -ggdb

With the above code I generate the firmware and then the elf report for the firmware with mbed-os-linker-report, see Deleted

The basic breakdown is of the 34332 bytes in .text (code) are

  • code in STM32 Arduino core: 21306 bytes
    • code in system drivers: 12398 bytes
      • UART HAL: 4483 bytes (because sketch uses Serial)
      • I2C HAL: 4316 bytes (because I2C is used)
      • RCC HAL: 1600 bytes (clock control)
      • Timer Hal: 572 bytes (arduino-internal timers)
      • RCC Ex: 460 bytes (extension of RCC)
      • some other smaller ones, sum ~ 1000 bytes
  • Arduino core libraries: 6162 bytes
    • Wire (for I2C): 3096 bytes
    • “SrcWrapper” (abstraction layer on top of system drivers): 3066 bytes
  • Arduino core objects: 2558 bytes
    • HardwareSerial: 1108 bytes
    • Print: 514 bytes
    • wiring_digital (digitalWrite, pinMode, …): 416 bytes
    • Print.h, Stream.cpp: 330 bytes…
  • used external libraries: 782 bytes
    • Adafruit MPRLS: 488 bytes
    • Adafruit BusIO: 294 bytes (abstraction on top of I2C/SPI)
  • sketch code: 200 bytes
  • LibC code (standard-C library functions or support functions from the compiler): 11950 bytes
    • __aebi_dsub (Double-floatingpoint subtraction): 1828 bytes
    • __aebi_dadd (Double-floatingpoint addition): 1748 bytes
    • __aebi_ddiv (Double-floatingpoint division): 1488 bytes
    • __aebi_dmul (Double-floatingpoint multiplication): 1240 bytes
    • __aebi_fadd (Single-floatingpoint add): 824 bytes
    • __aebi_fmul (Single-floatingpoint multiplication): 564 bytes
    • __aebi_fdiv (Single-floatingpoint division): 536 bytes
    • __udivsi3 (unsigned 32-bit division): 266 bytes
    • lots of other smaller functions…

And for .rodata (constants or initial value of variables) the sketch has 1380, this also lands in flash.

So what stands out here is:

  • lots of abstraction layers from the hardware registers, first with the system drivers, then SrcWrapper, but on top of that the Arduino objects (HardwareSerial) and libraries (Wire), and even on top of that library-made abstractions like Adafruit’s BusIO library
  • The Cortex-M0+ core of the STM32G030K6 chip lacks a floating point unit (FPU) and even hardware integer multiply. This means that when the code uses floating point numbers or wants to divide two general integers, the compiler has to supply a software routine that computes the result, instead of letting the core’s ALU or FPU do the work with a specialized instruction. This is incredibly costly in your example because your sensor values are float and double type and working requires all these needed functions. Even worse, the sketch or library seems to use both float and double, requiring to put routines for both of these types in the firmware. If the firmware could only use float or double it would be less expensive.
1 Like