Skip to content

nRF52840 (ports/nordic): Board-level LD override ignored? Can’t remove SPIM3_RAM reservation to reclaim 8 KB APP_RAM #10655

@zachar-apps

Description

@zachar-apps

CircuitPython version and board name

Description

I’m building a custom nRF52840 board (BOARD=sensera2) and want to disable SPIM3 and reclaim the 8 KB reserved “SPIM3_RAM” back into APP_RAM. I created a board-local linker script without SPIM3_RAM and pointed my board to it, but the final build still shows SPIM3_RAM: 8 KB and APP_RAM stays at 192 KB.

It looks like the build system may still be using the template/generated linker instead of my board-local .ld, or it’s otherwise re-introducing the SPIM3 region.

Environment

  • Repo: https://github.com/adafruit/circuitpython (fresh clone; current main as of Oct 6, 2025)
  • Port: ports/nordic
  • Board: custom sensera2
  • Host OS: Linux (Ubuntu-like)
  • Build toolchain: arm-none-eabi-gcc (version not captured)

### Code/REPL

```python
import gc
gc.collect()
print("heap_total:", gc.mem_free() + gc.mem_alloc())

Behavior

What I did (board-only changes)

ports/nordic/boards/sensera2/mpconfigboard.mk

USB_VID = 0x239A
USB_PID = 0x80DA
USB_PRODUCT = "PCA10056"
USB_MANUFACTURER = "Nordic Semiconductor"

MCU_CHIP = nrf52840
UF2_NAME = "SENSERA_Device"
CIRCUITPY_BUILD_EXTENSIONS = bin,uf2

QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = "GD25Q16C, W25Q16JVxQ"

# Core BLE module + workflows
CIRCUITPY_BLEIO = 1
CIRCUITPY_BLE_WORKFLOW = 1
CIRCUITPY_BLE_FILE_SERVICE = 1

# Use a board-local linker without SPIM3 reservation
override LD_FILE = boards/sensera2/nrf52840_no_spim3.ld

# Disable SPIM3 for this board
CFLAGS += -DNRFX_SPIM3_ENABLED=0

# BLE: single peripheral link
CIRCUITPY_BLE = 1
CIRCUITPY_BLE_MAX_CONNECTIONS = 1
CFLAGS += -DNRF_SDH_BLE_PERIPHERAL_LINK_COUNT=1
CFLAGS += -DNRF_SDH_BLE_CENTRAL_LINK_COUNT=0

ports/nordic/boards/sensera2/board.cmake

set(MCU_VARIANT nrf52840)
set(OUTPUT_NAME "Sensera_Firmware")

# Use the board-local linker (no SPIM3 reservation)
set(LD_FILE ${CMAKE_CURRENT_LIST_DIR}/nrf52840_no_spim3.ld CACHE STRING "" FORCE)

(Happy to also set LD_TEMPLATE_FILE if that’s the correct knob for the template path.)

ports/nordic/boards/sensera2/nrf52840_no_spim3.ld (board-local; no SPIM3 region)

MEMORY
{
    RAM     (rwx) : ORIGIN = 0x20000000, LENGTH = 0x40000   /* 256 KB */
    SD_RAM  (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0E000   /* 56 KB */
    APP_RAM (rwx) : ORIGIN = 0x2000E000, LENGTH = 0x32000   /* 200 KB */
}

Commands & log

source venv/bin/activate
cd circuitpython/ports/nordic
make clean BOARD=sensera2
make BOARD=sensera2 V=1 2>&1 | tee build-sensera2.log

Size summary (end of build):

Memory region         Used Size  Region Size  %age Used
           FLASH:          0 GB         1 MB      0.00%
       FLASH_MBR:          0 GB         4 KB      0.00%
        FLASH_SD:          0 GB       148 KB      0.00%
       FLASH_ISR:         248 B         4 KB      6.05%
  FLASH_FIRMWARE:      610340 B       780 KB     76.41%
FLASH_BLE_CONFIG:          0 GB        32 KB      0.00%
       FLASH_NVM:          0 GB         8 KB      0.00%
     FLASH_FATFS:          0 GB         0 GB
FLASH_BOOTLOADER:          0 GB        40 KB      0.00%
FLASH_BOOTLOADER_SETTINGS:          0 GB         4 KB      0.00%
             RAM:          0 GB       256 KB      0.00%
          SD_RAM:          0 GB        56 KB      0.00%
       SPIM3_RAM:          0 GB         8 KB      0.00%
         APP_RAM:       51884 B       192 KB     26.39%

I expected no SPIM3_RAM line and APP_RAM = 200 KB.

Local checks of the board linker file:

ls -l ports/nordic/boards/sensera2/nrf52840_no_spim3.ld
# -rwxrwx--- (readable; no exec required)

grep -n '^[[:space:]]*SPIM3_RAM' ports/nordic/boards/sensera2/nrf52840_no_spim3.ld
# OK: no SPIM3_RAM region

awk '/^MEMORY/{p=1} p; /^\}/{p=0}' ports/nordic/boards/sensera2/nrf52840_no_spim3.ld
# shows RAM 256 KB, SD_RAM 56 KB, APP_RAM 200 KB

(I also set override LD_FILE = boards/sensera2/nrf52840_no_spim3.ld in mpconfigboard.mk, and forced the same via board.cmake with set(LD_FILE ... FORCE).)

What I expected

  • The link step to use my board-local .ld, or to generate a firmware.ld without SPIM3_RAM.
  • Size summary to show no SPIM3_RAM and APP_RAM = 200 KB, so I get ~8 KB more heap at runtime.

What happened instead

  • The size summary still shows SPIM3_RAM: 8 KB and APP_RAM: 192 KB, suggesting the build is either:

    • not picking up my board-local LD, or
    • regenerating a link script that reintroduces SPIM3_RAM, or
    • computing size output from values independent of the linker file.

Questions

  1. For ports/nordic, what’s the canonical way (per board) to remove the SPIM3_RAM reservation?

    • Override LD_FILE?
    • Override LD_TEMPLATE_FILE in board.cmake?
    • Another variable?
  2. Is there any caching / CMake behavior that could ignore a board-level LD_FILE override?

  3. Is the size summary derived strictly from the linked regions, or from separate build variables (which might still include SPIM3)?

  4. If the template path is preferred, can you point me to the correct set of CMake variables to set per board so the generated firmware.ld excludes SPIM3_RAM?

Happy to provide the -T ...ld line from the verbose link step if needed; right now the size report implies the default template/regions are still in effect.

Thanks!

Description

No response

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions