I just started with arduino and it's great fun - but actually my arduino shows a strange behavior which I can't explain.
As soon as I use a certain amount of SRAM the program goes crazy - debug output on the serial interface are random characters etc.
I have an Arduino-Ethernet with an ATmega328. This means 2k of SRAM should be available. As long as I use only 1730 all is fine. (add the data and bss section of the avr-size output):
>avr-size LedController.cpp.elf
text data bss dec hex filename
23256 854 876 24986 619a LedController.cpp.elf
But as soon as I use 1834 the problem occures:
>avr-size LedController.cpp.elf
text data bss dec hex filename
23352 958 876 25186 6262 LedController.cpp.elf
I am pretty sure that's not a programming error, because the only difference in the code are the following dummy lines anywhere in the program (it can't just be a single string because the compiler would optimise it away):
I checked if the flash was correctly written with avrdude - seems ok.
>avrdude -p m328p -c stk500v1 -P COM2 -F -U flash:w:Led
oller.cpp.hex
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.05s
avrdude: Device signature = 0x000000
avrdude: Yikes! Invalid device signature.
avrdude: Expected signature for ATMEGA328P is 1E 95 0F
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "LedController.cpp.hex"
avrdude: input file LedController.cpp.hex auto detected as Intel Hex
avrdude: writing flash (18920 bytes):
Writing | ################################################## | 100% 7.08s
avrdude: 18920 bytes of flash written
avrdude: verifying flash memory against LedController.cpp.hex:
avrdude: load data flash data from input file LedController.cpp.hex:
avrdude: input file LedController.cpp.hex auto detected as Intel Hex
avrdude: input file LedController.cpp.hex contains 18920 bytes
avrdude: reading on-chip flash data:
Reading | ################################################## | 100% 6.38s
avrdude: verifying ...
avrdude: 18920 bytes of flash verified
avrdude: safemode: Fuses OK
avrdude done. Thank you.
Then I tried to validate the SRAM by reading values from an array as suggested by florinc.
Program:
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
int errors = 0;
Serial.println("init ok");
char testa[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\0";
int counta = strlen(testa);
char testb[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\0";
int countb = strlen(testb);
Serial.println("start...");
Serial.print("count a: ");
Serial.println(counta);
Serial.print("count b: ");
Serial.println(countb);
// test a
for(int i=0; i<counta; i++) {
if(testa[i] != 'a'){
Serial.print("error in 'a' at ");
Serial.println(i);
errors++;
} else {
Serial.print("ok in 'a' at ");
Serial.println(i);
}
}
Serial.println("'a' completed");
// test b
for(int i=0; i<countb; i++) {
if(testb[i] != 'b'){
Serial.print("error in 'b' at ");
Serial.println(i);
errors++;
} else {
Serial.print("ok in 'b' at ");
Serial.println(i);
}
}
Serial.println("'b' completed");
Serial.println();
Serial.print(errors);
Serial.println(" errors");
}
void loop()
{
// nothing happens after setup
}
I found an ATMEL Application Note for testing RAM (http://www.atmel.com/Images/doc7715.pdf) and reconsidered the issue. Seems more like a collision with the Stack (...)
Code:
#define RAM_COUNT 1700 // bytes in RAM to be allocated an tested. If it's too high a problem with the stack pointer occures and
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
PROGMEM int errors = 0;
PROGMEM char msg_error[] = " RAM errors";
PROGMEM char currentByte;
PROGMEM int i;
PROGMEM char pattern_55 = 0x55;
PROGMEM char pattern_AA = 0xAA;
// allocate heap
volatile char * test = (char*) malloc (RAM_COUNT);
// test heap
for(i=0; i<RAM_COUNT; i++) {
currentByte = test[i];
test[i] = pattern_55;
if(test[i] != pattern_55) errors++;
test[i] = pattern_AA;
if(test[i] != pattern_AA) errors++;
test[i] = currentByte;
}
Serial.print(errors);
Serial.println(msg_error);
printRam();
}
void loop()
{
// nothing happens after setup
}
void printIntHex(char *s, int v) {
Serial.print(s);
Serial.print(": ");
Serial.println(v);
}
void printRam() {
extern int __heap_start, __bss_start, __data_start;
int stack;
int heapend = getHeapend();
//printIntHex("End of RAM: ", RAMEND);
//printIntHex("Stack pointer:", SP);
//printIntHex("Stack pointer:", (int) &stack);
//printIntHex("Heap end: ", heapend);
//printIntHex("Heap start: ", (int) &__heap_start);
//printIntHex("BSS start ", (int) & __bss_start);
//printIntHex("Data start ", (int) & __data_start);
printIntHex("Free RAM: ", SP-heapend);
printIntHex("BSS used: ", (int) &__heap_start - (int) & __bss_start);
printIntHex("Data used: ", (int) & __bss_start - (int) & __data_start);
printIntHex("Heap used: ", heapend - (int) &__heap_start);
}
int getHeapend() {
extern int __heap_start, *__brkval;
if((int)__brkval == 0) {
return (int)&__heap_start;
}
else {
return (int) __brkval;
}
}