cancel
Showing results for 
Search instead for 
Did you mean: 

Why would increasing array size slightly cause a "RAM overflowed" error

magene
Senior II

I wrote my own FIFO class that doesn't use dynamic memory allocation as far as I can tell. It has been working fine until I tried to increase the size of an array in the struct that my class puts in the FIFO. Here's the FIFO.hpp file:

#pragma once
 
#include 
#include 
 
using namespace std;
 
#include "main.hpp"
//#include "C:\Users\gene\Documents\CPF\ElecEngr\cpfSTM32H7A3_SOM\Code\CPF_H7A3\CPF\ETL\include\etl\string.h"
//#include "C:\Users\gene\Documents\CPF\ElecEngr\cpfSTM32H7A3_SOM\Code\CPF_H7A3\CPF\ETL\include\etl\queue.h"
 
//From https://www.techiedelight.com/queue-implementation-cpp/
 
class FIFO
{
public:
	FIFO(string qID)		//TODO might want to pass struct to be queued in constructor instead of forcing it to be FIFORecord
	{
		head = 0;
		tail = -1;
		count = 0;
		qName = qID;
 
		//etlTest();
	}
 
	struct FIFORecord		//TODO it would be better to figure out a way to set the queue width and depth through the constructor
	{
		uint64_t tickstamp;
		uint8_t message[161];
	};
	
	~FIFO()      			   // destructor
	{
		//delete[] arr;
	}
 
	int32_t dequeue(uint64_t &tickstamp, MainFIFORecordIDs &id, uint8_t deQBytes[]);
	int32_t dequeue(uint64_t &tickstamp, uint8_t deQBytes[]);
	int32_t enqueue(uint64_t tickstamp, MainFIFORecordIDs id, uint8_t enQBytes[]);
	int32_t enqueue(uint64_t tickstamp, uint8_t enQBytes[]);
	int32_t dequeue(FIFORecord &deQueueRecord);
	int32_t enqueue(FIFORecord enQueueRecord);
	int peek();
	int getCount();
	bool isEmpty();
	bool isFull();
	void clearRecord(FIFORecord &inRecord);
 
	uint32_t qWidth;
	
protected:
	uint32_t capacity;       // maximum capacity of the queue
	int32_t head;          	// points to front element in the queue (if any)
	int32_t tail;           // points to last element in the queue
	int32_t count;          // current size of the queue
	string qName;
	
	FIFORecord fifoRecords[32]; 
 
private :
	void etlTest();
 
	//Just to see how much memory a stl queue takes.
	//queue stlQ;	
};

The FIFO class allows for up to 32 FIFORecord structs (line 59) to be put in the FIFO. The FIFORecord struct has a uint64_t tickstamp (line 29) and a uint8_t message[***] (line 30). And I have 3 FIFOs instantiated in my program. Normally the message[***] size is an integer multiple of 2 but I'm trying to figure out exactly where the problem is. With uint8_t message[160], it compiles fine with this memory usage:

------------------- Memory utilization report -------------------

Used FLASH: 274KB out of 2048KB (13%)

Used SRAM: 127KB out of 1024KB (12%)

Used DTCMRAM: 0 bytes out of 128KB (0%)

Used ITCMRAM: 0 bytes out of 64KB (0%)

========== Project Rebuild Summary ==========

  CPF rebuilt in 00:11

========== Rebuild: 1 Succeeded, 0 Failed, 0 Skipped ==========

With uint8_t message[161] as shown above, I get this error:

 ../VisualGDB/Debug/CPF section `._user_heap_stack' will not fit in region `RAM' CPF                                                                                                                                                  1   
Note     region `RAM' overflowed by 4744 bytes                                           CPF                                                                                                                                                  1   
Error    Build failed: arm-none-eabi-g++.exe exited with code 1                          CPF                                                                                                                                                  1   
Error    ld returned 1 exit status                                                       CPF     C:\Users\gene\Documents\CPF\ElecEngr\cpfSTM32H7A3_SOM\Code\CPF_H7A3\CPF\collect2.exe                                                         0   

Seems like there's plenty of memory available to increase the message array size from 160 to 161. And the overflow of 4744 bytes doesn't seem to be evenly divisible by 32, 160 or 161. I've been reviewing the .map file (attached) but haven't been able to figure out what I'm doing wrong. Any help will be greatly appreciated.

1 ACCEPTED SOLUTION

Accepted Solutions

You have even more variables that appear multiple times, "monthText", for example.

Are you declaring these variables in your .h file like this:

static FIFO gps1FIFO;   // in .h file, trying to force only 1 instance?

That isn't what "static" does, and specially not here. This causes a "module local" (i.e. visible only to code in that source file), non-global" instance of gpsFIFO in **EVERY** source file that includes that include file.

If you want one instance that is accessible to other source files, declare it like this in you r.h file:

// Put this in, say, gps.h.  It tells everyone there is a global somewhere named
// gpsFIFO, but doesn't "instantiate" it (doesn't create it).
extern FIFO gpsFIFO;

Then in ONE and only one cpp file declare the variable:

// For example, in gps.cpp, declare this at "global" scope, i.e. outside of
// any function.
FIFO gpsFIFO;

Look through your code for any variable declared static in an include file and change them to the above pattern.

And, yeah, what @Community member​ said below.

View solution in original post

6 REPLIES 6
Bob S
Principal

I see 9 instances of __ZL8gps1FIFO (C++ mangled, perhaps gps1FIFO), 9 instances of _ZL8ctd1FIFO (ctd1FIFO ??). 1 instance of each is in modules SubmergeState.o, UARTs.o, main.o, CTD1.o, GPS1.o, InitPlatformState.o, Logger.o, RecoveryState.o and StateBase.o. There is also 1 instance of mainFIFO (hmm, non-mangled name) in main.o.

Are you perhaps declaring the gps and ctd FIFOs in an include file without the "extern"?

magene
Senior II

@Bob S​ Well that seems like I'm doing something wrong. I have the FIFO class instantiated in 3 places but with the static keyword. I thought that would guarantee there is only one copy of the class regardless of how many times it gets included. I'm still pretty new to the C++ world and it's highly likely I'm doing this incorrectly. I will investigate. Thanks a ton for the pointer.

Which STM32?

From the mapfile:

> RAM             0x24000000        0x00020000        xrw

i.e. you have allocated 0x2'0000=128kB of RAM in the linker script (and that linker script is some magically generated something, is of no relevance - it's your code, your project, your responsibility).

And then the highest address allocated into RAM is

>  *fill*        0x24020288    0x1000

>                0x24021288               . = ALIGN (0x8)

which clearly overflows the allocated 0x2400'0000-0x2402'0000 area by 0x1288 (=4744) bytes.

I don't know where this

> Used SRAM: 127KB out of 1024KB (12%)

is from - again some "magic" courtesy the toolchain you use.

JW

You have even more variables that appear multiple times, "monthText", for example.

Are you declaring these variables in your .h file like this:

static FIFO gps1FIFO;   // in .h file, trying to force only 1 instance?

That isn't what "static" does, and specially not here. This causes a "module local" (i.e. visible only to code in that source file), non-global" instance of gpsFIFO in **EVERY** source file that includes that include file.

If you want one instance that is accessible to other source files, declare it like this in you r.h file:

// Put this in, say, gps.h.  It tells everyone there is a global somewhere named
// gpsFIFO, but doesn't "instantiate" it (doesn't create it).
extern FIFO gpsFIFO;

Then in ONE and only one cpp file declare the variable:

// For example, in gps.cpp, declare this at "global" scope, i.e. outside of
// any function.
FIFO gpsFIFO;

Look through your code for any variable declared static in an include file and change them to the above pattern.

And, yeah, what @Community member​ said below.

magene
Senior II

@Bob S​ and @Community member​ First of all, thank you very much for taking the time to fix my problem and explain it in a way that I understand what I was doing wrong. I just made the change from static to extern for the gps1FIFO and it only shows up once in the map file. Now I can fix all the places where I use static incorrectly and also track down the allocation mysteries.

@Community member​ -  I'm using the STM32H7A3.

Thanks again.

magene
Senior II

BTW - that "Used SRAM: 127KB ..." comes for the output that Visual GDB (the IDE I use) gives at the end of a successful build. Just changing gps1FIFO from static to extern dropped SRAM from 127 KB to 88KB. For me personally, VisualGDB is incredibly effective and I'll ask on their forum where that metric comes from.