OK understood. So Particle OS has some dynamic memory allocation inside it that will take "dozens" of KB to make room for...
And is the compiler checking for that? I thought dynamic memory allocation causes stack overflow issues, not complete inability to compile.
To me, it seems more likely that there is indeed some kind of fragmentation issue, like @jettonj was talking about above.
Deep dive on map file
Compile window shows:
C:/Users/macdo/.particle/toolchains/gcc-arm/10.2.1/bin/arm-none-eabi-size --format=berkeley c:/PARTICLE_LOCAL/LinkApp/target/4.1.0/argon/LinkApp.elf
text data bss dec hex filename
258548 1100 83000 342648 53a78 c:/PARTICLE_LOCAL/LinkApp/target/4.1.0/argon/LinkApp.elf
I modified the @jettonj python script to make it work for me:
- Needed to add some file path OS magic
- Works when it is in the same directory as
LinkApp.map
- Added timestamp and file path to beginning of output
- Added size summary at the end
- Made output go into a file called "MapReport.txt"
import re
import os
import datetime
def parse_memory_config(map_file):
memory_config = {}
with open(map_file, "r") as f:
in_memory_config = False
for line in f:
line = line.strip()
#print(f"Processing Line: {line}")
# Detect the start of Memory Configuration section
if "Memory Configuration" in line:
#print("Found Memory Configuration section.")
in_memory_config = True
continue
# Skip the header row and blank lines within the Memory Configuration section
if in_memory_config and (line == "" or line.startswith("Name")):
continue
# Detect the end of the Memory Configuration section
if in_memory_config and not re.match(r"\S+\s+0x[\da-fA-F]+\s+0x[\da-fA-F]+", line):
#print("End of Memory Configuration section.")
break
# Process valid memory configuration entries
if in_memory_config:
match = re.match(r"(\S+)\s+0x([\da-fA-F]+)\s+0x([\da-fA-F]+)", line)
if match:
name = match.group(1)
origin = int(match.group(2), 16)
length = int(match.group(3), 16)
memory_config[name] = {"origin": origin, "length": length}
#print(f"Parsed: Name={name}, Origin=0x{origin:08X}, Length=0x{length:08X}")
#else:
#print("Line did not match the expected format.")
return memory_config
def parse_sections(map_file):
sections = []
with open(map_file, "r") as f:
for line in f:
match = re.search(r"(\.\w+)\s+0x([\da-fA-F]+)\s+0x([\da-fA-F]+)", line)
if match:
section_name = match.group(1)
start_addr = int(match.group(2), 16)
size = int(match.group(3), 16)
end_addr = start_addr + size
sections.append((section_name, start_addr, end_addr))
if "lmao" in section_name:
print(f"Parsed Section: {section_name} Start=0x{start_addr:08X} End=0x{end_addr:08X}")
return sections
def find_unused_memory(sections, memory_config):
unused_regions = []
for name, config in memory_config.items():
if name == "*default*": # Skip overly broad *default* region
continue
start, end = config["origin"], config["origin"] + config["length"]
#print(f"Checking Memory Region: {name} Start=0x{start:08X} End=0x{end:08X}")
# Filter and sort relevant sections
relevant_sections = [
(s_start, s_end) for _, s_start, s_end in sections
if start <= s_start < end and s_start != s_end
]
relevant_sections.sort()
#print(f"Relevant Sections for {name}: {relevant_sections}")
# Track gaps between sections
current_addr = start
for s_start, s_end in relevant_sections:
# Detect and add gaps
if current_addr < s_start:
unused_regions.append((current_addr, s_start))
#print(f"Found Gap: 0x{current_addr:08X} to 0x{s_start:08X}")
# Move current address to the end of the current section
current_addr = s_end
# Check for gap between the last section and the memory region's end
if current_addr < end:
unused_regions.append((current_addr, end))
#print(f"Found Gap at End: 0x{current_addr:08X} to 0x{end:08X}")
# Sort and deduplicate gaps
filtered_regions = sorted(set(unused_regions), key=lambda region: region[0])
return filtered_regions
# Main logic
__location__ = os.path.realpath(
os.path.join(os.getcwd(), os.path.dirname(__file__)))
map_file = os.path.join(__location__, 'LinkApp.map')
# Parse Memory Configuration and Sections
memory_config = parse_memory_config(map_file)
sections = parse_sections(map_file)
with open(os.path.join(__location__, 'MapReport.txt'), 'w') as oFile:
now = datetime.datetime.now()
oFile.write(f"Map File Analysis Report For {map_file}- {now.strftime('%Y-%m-%d %H:%M:%S')}\n\n")
oFile.write("Memory Configuration:\n")
for name, config in memory_config.items():
oFile.write(f"Origin=0x{config['origin']:08X} Length=0x{config['length']:08X} : {name}\n")
# Find and display unused memory regions
unused_memory = find_unused_memory(sections, memory_config)
oFile.write("Unused memory regions:\n")
total_ram_size = 0
total_flash_size = 0
for start, end in unused_memory:
oFile.write(f"0x{start:08X} to 0x{end:08X} (size: {end - start} bytes)\n")
# Check if start is bigger than start of RAM range
if start >= 0x2002A2C4:
total_ram_size += end - start
else:
total_flash_size += end - start
oFile.write("-----------------------------------------\n")
oFile.write(f"Total Un-Used Flash: {total_flash_size} bytes\n")
oFile.write(f"\nTotal Un-Used RAM: {total_ram_size} bytes\n")
Here is the output that I got:
Map File Analysis Report For C:\PARTICLE_LOCAL\LinkApp\target\4.1.0\argon\LinkApp.map- 2024-11-22 12:34:55
Memory Configuration:
Origin=0x2003F400 Length=0x00000C00 : BACKUPSRAM
Origin=0x2003F000 Length=0x00000380 : BACKUPSRAM_SYSTEM
Origin=0x2003F3C0 Length=0x00000040 : BACKUPSRAM_SYSTEM_FLAGS
Origin=0x2003F380 Length=0x00000040 : BACKUPSRAM_REGISTERS
Origin=0x2003F000 Length=0x00001000 : BACKUPSRAM_ALL
Origin=0x000B4000 Length=0x00040000 : APP_FLASH
Origin=0x2002A27C Length=0x00014584 : SRAM
Origin=0x00000000 Length=0xFFFFFFFF : *default*
Unused memory regions:
0x000B401C to 0x000B4020 (size: 4 bytes)
0x000B40A2 to 0x000B4188 (size: 230 bytes)
0x000B41A8 to 0x000B41D0 (size: 40 bytes)
0x000B4200 to 0x000B4E3C (size: 3132 bytes)
0x000B4E4C to 0x000B539C (size: 1360 bytes)
0x000B5524 to 0x000BA425 (size: 20225 bytes)
0x000BB650 to 0x000BB770 (size: 288 bytes)
0x000BB780 to 0x000BC29C (size: 2844 bytes)
0x000BC2B0 to 0x000BE518 (size: 8808 bytes)
0x000BE5D8 to 0x000BE8A8 (size: 720 bytes)
0x000BE8B8 to 0x000BEB64 (size: 684 bytes)
0x000BEBB4 to 0x000BEBD4 (size: 32 bytes)
0x000BEBE4 to 0x000BEBF4 (size: 16 bytes)
0x000BEC04 to 0x000BED7E (size: 378 bytes)
0x000BEDC8 to 0x000BF296 (size: 1230 bytes)
0x000BF298 to 0x000BF2FE (size: 102 bytes)
0x000BF300 to 0x000BFA8C (size: 1932 bytes)
0x000BFA98 to 0x000C0398 (size: 2304 bytes)
0x000C039E to 0x000C0BA8 (size: 2058 bytes)
0x000C0BAA to 0x000C1468 (size: 2238 bytes)
0x000C148A to 0x000C14EA (size: 96 bytes)
0x000C14EC to 0x000C1594 (size: 168 bytes)
0x000C1596 to 0x000C1630 (size: 154 bytes)
0x000C1FA4 to 0x000C1FB8 (size: 20 bytes)
0x000C1FEC to 0x000C2016 (size: 42 bytes)
0x000C20C8 to 0x000C21CC (size: 260 bytes)
0x000C2274 to 0x000C23EC (size: 376 bytes)
0x000C2434 to 0x000CB378 (size: 36676 bytes)
0x000F31C8 to 0x000F330D (size: 325 bytes)
0x2002A2C4 to 0x2002A3B8 (size: 244 bytes)
0x2002ABBC to 0x2002AD60 (size: 420 bytes)
0x20035D4C to 0x20035D7C (size: 48 bytes)
0x20035D80 to 0x20035DA8 (size: 40 bytes)
0x20035DB8 to 0x20035DD0 (size: 24 bytes)
0x20035DD4 to 0x20035DDC (size: 8 bytes)
0x20035DE0 to 0x2003E614 (size: 34868 bytes)
0x2003E619 to 0x2003E630 (size: 23 bytes)
0x2003E634 to 0x2003E638 (size: 4 bytes)
0x2003E63C to 0x2003E644 (size: 8 bytes)
0x2003E650 to 0x2003E6D0 (size: 128 bytes)
0x2003E6E0 to 0x2003E7EC (size: 268 bytes)
0x2003E7F0 to 0x2003E800 (size: 16 bytes)
0x2003F000 to 0x2003F400 (size: 1024 bytes)
0x2003F000 to 0x2003F380 (size: 896 bytes)
0x2003F380 to 0x2003F3C0 (size: 64 bytes)
0x2003F3C0 to 0x2003F400 (size: 64 bytes)
0x2003F6E4 to 0x20040000 (size: 2332 bytes)
-----------------------------------------
Total Un-Used Flash: 86742 bytes
Total Un-Used RAM: 40479 bytes
Which seems to be showing that
- There is 3kB of RAM address space reserved for BACKUPSRAM
- A further 1 kB is taked for particle OS backups:
- BACKUPSRAM_SYSTEM
- BACKUPSRAM_SYSTEM_FLAGS
- BACKUPSRAM_REGISTERS
- There is 40,479 bytes of unused RAM?
- The biggest unused chunk of RAM is 34868 bytes?
I think that this implies that there is only a total of just under 129 kB of RAM available in total?
So, not sure how the total RAM space is coming out to only 129 kB....
Where is the missing RAM?
Here is my map file for reference: