Obese sketches

The sketch for my current project keeps growing. It's not prohibitive yet, but it could conceivably get significantly larger.

Sketch uses 13522 bytes (44%) of program storage space. Maximum is 30720 bytes.
Global variables use 769 bytes (37%) of dynamic memory, leaving 1279 bytes for local variables. Maximum is 2048 bytes.

So as a start I'm looking at rationalising variable scope, and how I use functions.
Also, I struggle with the concept of Objects, but feel they may be something helpful I just need to get my head round.

Without going into my specific sketch, any tips or techniques for retrospectively dealing with obese code?

Using 37% of dynamic memory would not worry me.

To minimise RAM usage use the F Macro to store any fixed strings in program memory.

Make sure that each data item uses the smallest practical data type - for example use byte rather than int for values that never exceed 255.

Use the CONST modifier for any values that won't change - then the compiler won't allocate storage space for them For example
const byte servoPin = 7;

...R

Without going into my specific sketch

Well that is a little difficult, If you have included libraries things can grow quite quickly without much effort. The question is, do you expect to get into trouble with the limited space ?

Thanks Robin.

With your example, does
const byte servoPin = 7;
inherantly take up more space than
int servoPin = 7;
or is it just a risk? And if it's just a risk, what factors influence it?

F() might be a bit above my pay grade at the moment. :slight_smile:

With your example, does
const byte servoPin = 7;
inherently take up more space than
int servoPin = 7;

An int takes 2 bytes of memory (more on some boards)
A byte, by definition, only takes 1 byte of memory
In addition, making a variable const will usually result it being stored in a processor register so it takes no memory

Deva_Rishi:
Well that is a little difficult, If you have included libraries things can grow quite quickly without much effort. The question is, do you expect to get into trouble with the limited space ?

I am expecting to add at least 2 more libraries, and some more core functionality to the sketch. So I can see how it would turn into a problem.
Right now I'm just trying to l think about good coding habits and avoid future problems.

Without seeing you full sketch it is not possible to say for sure, but if you have suitable data structures it may be possible to store them in program memory instead of RAM

Whilst inevitably that increases the use of program memory there may be advantages to it, but without seeing your code, who knows ?

Have you considered moving to a board with more memory ?

UKHeliBob:
An int takes 2 bytes of memory (more on some boards)
A byte, by definition, only takes 1 byte of memory
In addition, making a variable const will usually result it being stored in a processor register so it takes no memory

Thanks.

UKHeliBob:
Without seeing you full sketch it is not possible to say for sure, but if you have suitable data structures it may be possible to store them in program memory instead of RAM

Whilst inevitably that increases the use of program memory there may be advantages to it, but without seeing your code, who knows ?

Have you considered moving to a board with more memory ?

Yes. But I'm trying to learn about writing good code as my thinking time is cheaper. :slight_smile:

fenghuang:
F() might be a bit above my pay grade at the moment. :slight_smile:

No, really, it's the simplest RAM saver there is.

As long as you don't show the code, we can only give you tips. Of course datastructure, but without the code it is hard to tell what is going to matter most. At times it can be a trade of. Any library function that you call will be compiled and any variable the you use will take up RAM. Of course local variables get release when a function ends. If a library has a datastructure of it's own, whatever part that is used may be part of the object and take up space. Some libraries are quite small, both in data requirements and code.
If within your code you have sections repeating, it will be worth creating function that you can call. This will same flash space. The question is really, what are you going to be short of ? RAM due to libraries taking it up, or due to your own datastructure. What you don't use should not be compiled, but i am not always convinced this is what happens with objects, and that depends also on how the library was written. Again, without your code it is all just vague information and a few tips.

fenghuang:
Thanks.Yes. But I'm trying to learn about writing good code as my thinking time is cheaper. :slight_smile:

While you are learning, learn to test each tiny addition you make to the code!!!!
Paul

fenghuang:
F() might be a bit above my pay grade at the moment. :slight_smile:

Well, you have a bit of a problem, then. Because that's the way you consume less RAM.

Essentially, any initialised constant data becomes part of your binary image, because of course it does: how else would your code have access to it? All of these initialised constants get copied from the binary image into RAM, so that your program can work with them.

But what you can do is to tell the compiler to not copy those blocks of data into RAM, to leave them in read-only "program memory". And this is fine for blocks of data that don't change: blocks of text. Chunks of HTML. pre-computed lookup tables for hardware.

But, but, if they are not in RAM your program can't get at them. So, what's the use of that? Well, the arduino libraries give you a way to pull them out of program memory one byte at a time. Each of these chunks of data has an address that looks like a regular pointer, "memory address 12345", but address 12345 in RAM will contain garbage if you pull it out directly. You have to use pgm_read_X_near, where 'X' is 'byte' or 'word'. This function has machine code in it that accesses progmem rather than regular RAM.

Of course, there are utility functions to make this a bit easier.

C++ supports overloaded functions. you can make two different functions with the same name but different argument types, and the compiler will distinguish between them. The arduino libraries use this to distinguish between pointers that are regular RAM pointers, and pointers that are references into program memory. The arduino defines a type named __FlashStringHelper.

So there are two functions in Serial named println.

void println(const char *);
void println(const __FlashStringHelper *);

The second one knows that when it is passed a pointer to a string, it has to fetch each character of the string from program memory.

The F() macro is defined like so:

#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))

PSTR wraps your string constant, telling the loader to leave it in program memory. The cast gooses the type of the pointer, informing the compiler that when println is called, it needs to use the "other" println.

TL;DR: learn to use F().

It also looks like you are using a Nano with an obese bootloader. You can also free up 1500 bytes of flash memory by reconfiguring it as a Uno.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.