pro mini sketch size limit

Dear Forum,

My Arduino Pro Mini is fitted with an ATMega328 and according to the datasheet it has 32kB of flash for program memory. From that number about 2kB is taken off for the bootloader. That should leave about 30kB for my sketch. When compiling, the Arduino IDE says at the bottom of the window:

'Binary sketch size: 17484 bytes (of a 30720 byte maximum)'

I've written a sketch that is about 17kB and I've noticed that for some reason when I upload the program my pro-mini becomes unstable. It becomes stable again when I delete some functions and reduce my sketch size.

The lines of code from the functions I comment out to reduce the sketch size are just simple Serial.println statements.

The maximum sketch size that seems to still work properly is around 17,484 Bytes. When I add some code and my sketch goes to a size of around 17,546 Bytes it's unstable when I run it.

By 'unstable' I mean that when run the board outputs a few lines of serial output to the USB/Serial console (as per the correct workings of the program thus far) and then either locks up, or constantly resets at that point. It locks up/resets at different points when I change the sketch size.

I use IDE version 0021 on Debian and I have configured the IDE to use the 'Arduino Pro or Pro Mini (5V, 16MHz) w/ ATMega328' as per the board I have.

I have been programming this board for several months in this configuration without any issues. It only seems to go wrong when I hit this 17kB limit. Smaller programs run just fine on this board.

Am I reading the size reported by the IDE incorrectly or is there some other issue that I am unaware of?

I hope some of you have come across this before and are able to point me in the direction of a solution (if there is one).

Thanks in advance!

That mean you got screwed and who ever you bought it from assembled it wrong

might be running out of RAM

MakerMann, I am only aware of one company that assembles ATmega328's

Unstable behavior can be caused by exceeding the RAM size. When your data collides with the stack, bad things happen. It could be that trimming your sketch reduces RAM usage leading you to the wrong conclusion.

I agree that it sounds like a RAM problem but if captcha is only removing serial.print statements that's unlikely.

It is possible that the heap is so close to the stack that a single serial.print makes a difference, this could be prooved by removing all but one of the serial.print statements.

capchta: How much variable data have you defined? Is there any code path that can cause you to be 100s deep in calls? ie a recursive function.


Rob

Thanks for all the quick replies..

How much variable data have you defined?

I may have aroud 30 int type variables declared in the 'main' loop and most likely double that in the functions. I also use a fair amount of strings to send to LCD and Serial about what the program is doing.

I must admit I'm not an expert when it comes to programming in limited-ram environments so I'm not sure how to gauge 'how much' variable data I have defined. Yes, I am using variables and functions but the majority is just simple variables holding values below 65535. There is a fair bit of text output using serial in addition to a 3-Wire LCD function (uses a serial shift register) and I'm using I2C which currently only talks to a 24LC512 EEPROM.

In the program I am calling functions left right and center but I can see that my program hasn't completed even one full loop before the thing locks up or resets.

Is there any code path that can cause you to be 100s deep in calls? ie a recursive function.

Nice suggestion regarding the recursive loop, but I don't think that's happening because the program works fine when I uncomment just one line (for instance the serial.print statement) in the code. If recursives were happening the serial.print statement should not make a difference to nesting behaviour.

This is probably a question I should have asked in the beginning of my programming career, but should I re-use as many variables as I can in order to optimise ram management?

Also just found this link.. http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213583720;start=all

Seems like I'm having the RAM problem as you already pointed out.

Anyway, I think I have found a few things to test first regarding memory size and see where I can optimise my code. Thanks all for your help so far.

Never thought RAM might become a problem so soon.

I agree that it sounds like a RAM problem but if captcha is only removing serial.print statements that's unlikely.

Keep in mind that Serial.println("This text uses RAM") will use RAM. If this is what gets removed, I would say RAM shortage is more than likely.

A better alternative is to put text strings in flash memory.

Actually, does

Serial.print(“a lot of really long words”);

case the string to be copied to the stack?

EDIT: Thanks BenF, that answers that question.


Rob

The call to Serial.print will only put a pointer on the stack, but the string itself is in RAM. This is a consequence of the Harward architecture. Strings will be copied to RAM when referenced or during C runtime initialization for global data.

Serial.print is not compatible with pointers to flash and so this step is needed for the function to work.

In an effort to help with this thread I decided to write a small test program. The object was to artificially inflate the program size to the 17k odd that captcha was having trouble with by padding the code with a large constant array.

The test code is as follows

const byte x[1856] = {'a'};

void setup () {
  Serial.begin(9600);
};

void loop () {
  volatile int i = 0;
  while(1) Serial.print(x[i], BYTE);
};

Note the array size, the program works fine up to a size of 1848, then things go strange. The following is the output of the program as seen on the serial monitor, the number on the left of each line is the array size.

<=1848 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> fast
1849 aaa
1850 aaa
1851 aaa
1853 aaa
1854 aaa
1855 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> but slow
1856 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> but slow
1860 no output

Now I’m guessing that the const array is copied to RAM (is that correct?), and at around the 1848 size it hits the stack.


Rob

If you look at the following breakdown of your test app (using avr-size on the elf file):

   text    data     bss
   2362    1874     160

The total size (4236) is the sum of code (2362) and initialized data (1874) which is displayed in the Arduino IDE as sketch size. Const data will indeed occupy RAM unless you explicitly place the data in flash.

The data and bss segments occupy RAM for a total of 2034 bytes. Out of a total of 2048 bytes this doesn't leave much room for the stack and so is likely to crash.

Yes that’s obviously what’s happening. So how does one force the data to stay in flash (or rather not be moved into RAM)? In a previous life I seem to remember a __flash directive but GCC doesn’t like that, so I’ve done some research.

Here is a modified version of the above test code.

#include <avr/pgmspace.h>

const byte x[20000] __attribute__((progmem)) = {'a'};

void setup () {
  Serial.begin(9600);
};

void loop () {
  volatile int i = 0;
  while(1) {
    Serial.print(pgm_read_byte(&(x[i])), BYTE);
  }
};

This creates the 20,000-byte array in flash and forces the compiler to leave it there. Note that there is a macro to make this look neater.

const byte x[20000] PROGMEM = {'a'};

The trouble with this is that the normal indexing into an array does not work because of the afformentioned Harvard achitecture, at the assembly level however it can be done and it seems that macros have been written to allow code to access the flash memory

pgm_read_byte(&(x*))*
gets a value from the array.
So the test prog appears to work now.
Sorry to highjack your thread captcha but it was in a good cause I think.
______
Rob

The following may come in handy for moving constant strings from RAM to flash:

#include <avr/pgmspace.h>

void setup()
{
  Serial.begin(57600);
  print_P(PSTR("String in flash\r\n"));
}

// print a character string from program memory
void print_P(const char *str)
{
  uint8_t val;
  while (true) {
    val=pgm_read_byte(str);
    if (!val) break;
    Serial.write(val);
    str++;
  }
}

void loop()
{
}

The PSTR macro allows for inline definition of strings and so makes it easier to update existing code.

Ahh, interesting. Ive been having this exact problem on one of my projects. Its using the I2C interface as well as an LCD, SD write and serial input.

Ill have to go through and be more memory efficient i think.

BenF: Thanks for that code snippet (I'll be saving it for future use) and for the info in general.

captcha: Any luck on the original problem?


Rob

Mikal Hart's Flash Library...

http://arduiniana.org/libraries/flash/

...works well for managing PROGMEM string constants. The next version will be even more efficient.

Thanks CB, I've bookmarked that as well.


Rob

Hey all,

Just a quick update..

Any luck on the original problem?

Graynomad, BenF, MurMan and Osgeld, your suspicions about RAM filling up by my sketch were all spot on!

Here is the output of avr-size when I ran it on code that didn't work properly.

   text    data     bss     dec     hex filename
  16222    1324     378   17924    4604 sensorboard_v1.cpp.elf

From what I understand I need to add data + bss = 1702 Bytes to see how much RAM is being used.

Now, I'm not sure how much space is taken up by other processes but as soon as I added PROGMEM functionality and moved a lot of text strings to prog_char as per the example at http://www.arduino.cc/en/Reference/PROGMEM I noticed my 'data' and 'bss' values were decreasing and therefore freeing up valueable RAM.

I'm not finished yet moving all possible constants and text strings to PROGMEM but at the moment data=950 and bss=366 and the program is running fine again! :)

Thank you all.