Portenta H7 doesn't have 2MB Flash size in Zephyr

Hi,

I use Zephyr and I received a smaller FLASH size than expected from MAP-file:

Name             Origin             Length             Attributes
FLASH            0x0000000008040000 0x0000000000060000 xr

prj.conf:

CONFIG_FLASH_SIZE=2048
CONFIG_FLASH_BASE_ADDRESS=0x8000000
CONFIG_FLASH_LOAD_OFFSET=0x00
# Make sure Zephyr uses the custom partition
CONFIG_USE_DT_CODE_PARTITION=y

overlay file:

/* Replace entire flash0 definition with a 2 MB region and a single partition */
&flash0 {
    reg = <0x08000000 0x00200000>;   /* 2 MB total flash */

    partitions {
        compatible = "fixed-partitions";
        #address-cells = <1>;
        #size-cells = <1>;

        /* full 2 MB for app */
        app_region: partition@0 {
            label = "app";
            reg = <0x08000000 0x00200000>;
        };
    };
};

It looks like the MAP file is shrinking your flash region because of one thing:
in the partition you used the absolute address, but Zephyr expects the offset inside flash0.

So instead of:

reg = <0x08000000 0x00200000>;

it should be:

reg = <0x00000000 0x00200000>;

flash0 already defines the base (0x08000000), so the partition must start at offset 0, not the physical address.
If the partition uses an absolute address, Zephyr silently falls back to the SoC’s default flash size — which is why your MAP file only shows a smaller region.

Fixing the reg to use the offset usually makes the full 2MB show up correctly.

I change:

&flash0 {
    reg = <0x08000000 0x00200000>;   /* 2 MB total flash */

    partitions {
        compatible = "fixed-partitions";
        #address-cells = <1>;
        #size-cells = <1>;

        /* full 2 MB for app */
        app_region: partition@0 {
            label = "app";
            reg = <0x00000000 0x00200000>;
        };
    };
};

But the result is still the same.

Before I've change the first reg right below flash0. But that changed the Origin in mapfile to 0x40000 only.

I think your DTS changes are correct now, so if the MAP file is still showing the smaller flash size, the problem is probably not in the partition section anymore.

From what I’ve seen with STM32 boards, Zephyr takes the “real” flash size from the SoC’s base DTS file (like stm32f4xx.dtsi). If that file defines a smaller flash region, your overlay can’t enlarge it — Zephyr will always fall back to the size declared in the SoC.

Two things I think are worth checking:

  1. Look in the SoC DT file for something like:
flash0: flash@8000000 {
    reg = <0x08000000 0x00040000>;
};

If this value is small, it will override everything else.
2. Make sure your overlay is actually being applied.
Sometimes CMake ignores an overlay silently.
Adding a tiny change (like disabling a node) is an easy way to confirm it's loaded.

If you want, share your board name and the generated zephyr.dts from the build folder — I think that will show exactly where the flash size is coming from.

I found stm32h747Xi_m7.dtsi :

/*
 * Copyright (c) 2019 Linaro Limited
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <st/h7/stm32h747.dtsi>

/delete-node/ &flash1;

/ {
	cpus {
		/delete-node/ cpu@1;
	};

	soc {
		flash-controller@52002000 {
			flash0: flash@8000000 {
				reg = <0x08000000 DT_SIZE_K(1024)>;
			};
		};

		mailbox@58026400 {
			interrupts = <125 0>;
		};
	};
};

Maybe DT_SIZE_K(1024) is the problem ?

I found also arduino_portenta_h7_stm32h747xx_m7.dts:

&flash0 {
	partitions {
		compatible = "fixed-partitions";
		#address-cells = <1>;
		#size-cells = <1>;

		boot_partition: partition@0 {
			label = "mcuboot";
			reg = <0x00000000 0x00010000>;
			read-only;
		};

		/*
		 * The flash starting at 0x00010000 and ending at
		 * 0x0001ffff (sectors 16-31) is reserved for use
		 * by the application.
		 */
		scratch_partition: partition@10000 {
			label = "image-scratch";
			reg = <0x00010000 0x00030000>;
		};

		/* The arduino default bootloader occupies the address space 0x0 - 0x40000.
		 * This way regardless of the user's choice to use the mcuboot bootloader,
		 * applications will be located at 0x40000 which will be loaded by the
		 * arduino bootloader.
		 */
		slot0_partition: partition@40000 {
			label = "image-0";
			reg = <0x00040000 0x00060000>;
		};

		slot1_partition: partition@A0000 {
			label = "image-1";
			reg = <0x000A0000 0x00060000>;
		};
	};
};

When I add a syntax error in my overlay file it stops with that error -> I guess overlay file is used.

Board name:

arduino_portenta_h7/stm32h747xx/m7

I think you just found the real issue.

DT_SIZE_K(1024) in flash0 is almost certainly what is limiting your effective flash size.
On STM32H747 the M7 core can access more than 1 MB depending on how the vendor DTS is written, but Zephyr will not let any overlay enlarge the flash beyond whatever is declared in the SoC or board DTS.

In your case:

flash0: flash@8000000 {
    reg = <0x08000000 DT_SIZE_K(1024)>;
};

That line forces Zephyr to assume the flash is only 1 MB, no matter what you put in your overlay.
So even if your partition says "2MB", the MAP file will still show 1 MB, because the upper layers can’t override the lower-level “real” flash definition.

Also the Portenta DTS has several reserved areas:

  • Arduino bootloader region (0x0000–0x40000)
  • MCUBoot
  • Scratch
  • Slot 0 / Slot 1

So the layout is already quite constrained, and Zephyr is simply respecting that.
Your overlay won't be able to stretch slot0 beyond the board definition.

If you want the full 2 MB available to your app, I think the next steps would be:

  1. Modify stm32h747Xi_m7.dtsi so that flash0 has the real 2MB size, e.g.:
reg = <0x08000000 DT_SIZE_K(2048)>;
  1. Or alternatively check arduino_portenta_h7_stm32h747xx_m7.dts because the Arduino bootloader constraints may intentionally limit usable flash.

I’m not 100% sure what Arduino’s intention was with the 1 MB cap, but I think this is the reason your MAP file still shows the smaller flash region.

Hi, my guess is to allow the M4 processor to have the other 1MB. In the Arduino IDE you can split the flash 100% M7, 75% M7 - 25% M4 or 50/50. Not sure how that works with Zephyr as I don't use it.

That actually makes sense I didn’t consider the M4/M7 flash split used by the Arduino core.
If the board definition assumes a shared 2MB flash and reserves half for the M4 side, then Zephyr simply inheriting a 1MB region for the M7 would match what you’re seeing

I’ll check whether the Arduino DTS explicitly enforces that split or if it’s only done in their IDE config
If Zephyr is treating the M4 region as unavailable that would explain why increasing the size in the overlay has no effect

Thanks for pointing that out it gives me a clearer direction to investigate

Now I'm a bit step further:

I use following overlay file:

/* Override internal flash0 node from SoC DTS */
&flash0 {
    status = "okay";
    reg = <0x08000000 0x00200000>;   /* 2 MB internal flash */
};

/* Disable default MCUboot-style partitions */
&slot0_partition { status = "disabled"; };
&slot1_partition { status = "disabled"; };
&scratch_partition { status = "disabled"; };
&boot_partition { status = "disabled"; };

/ {
    chosen {
        zephyr,code-partition = &flash0;
    };
};

And the result look better:

[475/475] Linking CXX executable zephyr/zephyr.elf
Memory region         Used Size  Region Size  %age Used
           FLASH:      552596 B         2 MB     26.35%

But the flash is at a wrong position in the mapfile:

Name             Origin             Length             Attributes
FLASH            0x0000000010000000 0x0000000000200000 xr

Do you have any idea ?

It looks like the overlay is accepted, but Zephyr is still pulling the flash base address from the SoC-level DTS rather than your overlay. The 0x10000000 origin usually means it’s using the default STM32 AXI flash mapping instead of the internal flash region you set. I’m not completely sure, but you may need to override the entire memory@… node or adjust the alias/chosen section so Zephyr actually rebinds flash0 instead of keeping the original mapping. Sometimes the overlay changes the size but not the address unless the parent node is overridden too.

I've build for a similar stm-board: stm32h757i_eval/stm32h757xx/m7 which referes to 747i in the include tree and it worked with overlay:

&flash0 {
    status = "okay";
    reg = <0x08000000 0x00200000>;   /* 2 MB internal flash */
};

/* Disable default MCUboot-style partitions */
&slot0_partition { status = "disabled"; };
&slot1_partition { status = "disabled"; };
&boot_partition { status = "disabled"; };

/ {
    chosen {
        zephyr,code-partition = &flash0;
    };
};

I received in map-file:

FLASH            0x0000000008000000 0x0000000000200000 xr

So I guess the problem is somewhere in the arduino-extension.

It could very well be an Arduino-core quirk, but I’m not fully certain either. The Portenta H7 layer adds its own DTS fragments through the Arduino BSP, and some of those use fixed AXI flash mappings. In that case your overlay only updates the child node (flash0), while the parent memory@… node or the Arduino-specific flash aliases still point to 0x10000000 and override the origin during linking.

So the difference to the STM32H757 eval board might simply be that the Arduino extension injects a higher-priority DTS include.

If that’s the case, you may need to override the entire flash controller node (not only flash0) or locate the Arduino-specific DTS file that defines the memory@10000000 region and override it too. I’m not 100% sure, but the address is likely coming from that layer, not from Zephyr itself