Full RAM is almost certainly your problem. You want to keep an extra 200-400 bytes for the stack, depending on your program complexity. I tend to have a large stack, so I keep at least 400 open all the time. If it gets less than that free, it is time to optimize something.
Here is an example to show you how much you have left:
#define RAMSIZE 2048 //You can probably get this from another define somewhere
int availableMemory() {
int size = RAMSIZE;
byte *buf;
while ((buf = (byte *)
malloc(--size)) == NULL);
free(buf);
return size;
}
void chkMem() {
Serial.print("chkMem free= ");
Serial.print(availableMemory());
Serial.print(", memory used=");
Serial.println(RAMSIZE-availableMemory());
}
Arduino release 0022 has been quite problematic for me. I instead use 0021 and grab fat16lib which is lighter and serves my data logging needs. If you can do without directories, use 8.3 filenames, and SD cards <= 2 GB, it's very helpful and works!
Finally, if you have a lot of string data in your program (like println debugging statements or other long strings, consider accessing those directly from the ATmega328's flash memory, which will also save RAM. I use a convenient library for this purpose, called Flash incidentally. See Flash. I also highly recommend Mikal's Streaming and PString library. The gent writes some
really well-thought-out libraries IMHO.
Example using Flash lib:
Serial.print(F("really long debug message "));
I have created a little project with a custom build system (using Ruby) that makes this pretty easy without having to install the Arduino IDE. Basically, it uses a template Makefile, and a ruby script to make compiling the Arduino libraries extremely easy. You can see it at https://github.com/Earlz/make-wiring
However, I'm leaving the old answer here for information on rolling your own. It's quite cumbersome and annoying though:
Directions:
- Download a copy of the Arduino IDE source code
- Copy the contents of
hardware/arduino/cores/arduino
to a new directory I'll refer to as arduino_build
- Copy the
pins_arduino.h
file from whichever Arduino variant is yours from hardware/arduino/variants
(check boards.txt if you're not sure) to arduino_build
- Add this makefile to arduino_build:
.
#BSD licensed, see http://lastyearswishes.com/static/Makefile for full license
HDRS = Arduino.h binary.h Client.h HardwareSerial.h IPAddress.h new.h pins_arduino.h Platform.h Printable.h Print.h \
Server.h Stream.h Udp.h USBAPI.h USBCore.h USBDesc.h WCharacter.h wiring_private.h WString.h
OBJS = WInterrupts.o wiring_analog.o wiring.o wiring_digital.o wiring_pulse.o wiring_shift.o CDC.o HardwareSerial.o \
HID.o IPAddress.o main.o new.o Print.o Stream.o Tone.o USBCore.o WMath.o WString.o
#may need to adjust -mmcu if you have an older atmega168
#may also need to adjust F_CPU if your clock isn't set to 16Mhz
CFLAGS = -I./ -std=gnu99 -DF_CPU=16000000UL -Os -mmcu=atmega328p
CPPFLAGS = -I./ -DF_CPU=16000000UL -Os -mmcu=atmega328p
CC=avr-gcc
CPP=avr-g++
AR=avr-ar
default: libarduino.a
libarduino.a: ${OBJS}
${AR} crs libarduino.a $(OBJS)
.c.o: ${HDRS}
${CC} ${CFLAGS} -c $*.c
.cpp.o: ${HDRS}
${CPP} ${CPPFLAGS} -c $*.cpp
clean:
rm -f ${OBJS} core a.out errs
install: libarduino.a
mkdir -p ${PREFIX}/lib
mkdir -p ${PREFIX}/include
cp *.h ${PREFIX}/include
cp *.a ${PREFIX}/lib
And then just run
make
make install PREFIX=/usr/arduino (or whatever)
And then to make use of the compiled libraries and such you can use a simple makefile like this:
default:
avr-g++ -L/usr/arduino/lib -I/usr/arduino/include -Wall -DF_CPU=16000000UL -Os -mmcu=atmega328p -o main.elf main.c -larduino
avr-objcopy -O ihex -R .eeprom main.elf out.hex
upload:
avrdude -c arduino -p m328p -b 57600 -P /dev/ttyUSB0 -U flash:w:out.hex
all: default upload
Also, if you try to compile the libraries in libraries/
you'll get a linker error if you don't do things in the right order. For instance, I had to do this to use SoftwareSerial:
avr-g++ -L/usr/arduino/lib -I/usr/arduino/include -Wall -DF_CPU=16000000UL -Os -mmcu=atmega328p -o main.elf main.c -lSoftwareSerial -larduino
The -larduino
must be the last library on the command line
Anyway, this was a pretty easy way to compile it for me. As future versions of the Ardunio come out, this makefile should be fairly future-proof, requiring just a few modifications to OBJS and HDRS. Also, this makefile should work with both BSD make and GNU make
See also a slightly modified version of this answer on my blog with an already compiled binary of the library (compiled using the "standard" pins_arduino.h).
** EDIT **
I found that adding the following compiler optimization flags to both the library building Makefile and each individual project Makefile greatly reduces the size of the final compiled binary. This makes the final binary size comparable to that of the IDE.
-Wl,--gc-sections -ffunction-sections -fdata-sections
.
So, for the library build makefile:
CFLAGS = -I./ -std=gnu99 -DF_CPU=16000000UL -Os -Wl,--gc-sections -ffunction-sections -fdata-sections -mmcu=atmega328p
CPPFLAGS = -I./ -DF_CPU=16000000UL -Os -Wl,--gc-sections -ffunction-sections -fdata-sections -mmcu=atmega328p
and, for each project makefile:
avr-g++ -L/usr/arduino/lib -I/usr/arduino/include -Wall -DF_CPU=16000000UL -Os -Wl,--gc-sections -ffunction-sections -fdata-sections -mmcu=atmega328p -o main.elf main.c -larduino
.
Ref: http://arduino.cc/forum/index.php?topic=153186.0
Best Answer
I'll take a stab. I haven't written code for Arduino, but I've done a lot of C and C++ programming. It would help if I actually saw your errors, but nonetheless.
The main thing you need to always remember when using C++ with C code is that your C++ code needs functions declared with "extern "C"" if you want C code to be able to link against the C++ code. The "extern "C"" is what tells the C++ compiler that I'm creating linkable code for C files or I'm using code from C files. So all your functions in the library API header should correlate with a function in the source file defined liked "extern "C" void dosomething()". If you're trying to use classes in C++, remember that C code can't call it, you'll need to create functions (extern "C") to access the object. Now, if your C code is compiled with a C++ compiler, then don't worry about "extern "C"".
If you want to call C code inside your C++ code, then you need to wrap the C header with a construct like this:
If you working in C++, don't use a lot a #defines unless you're creating compile-time flags like "DEBUG" or "VERSION2" to create special sets of code. Otherwise use "const int/char/float" for number defines for safe type checking. The compilers are usually smart enough to optimize these out, so they wind up in ROM/code space (depends though). Also, don't create MACROS, use inline functions. Also, don't always follow convention when programming if it's stupid such as using a lot of macros and number defines in C++. The same thing applies to C99 version of C, it has added things like inline functions and consts from C++. The industry realizes how much buggy code and hard to maintain code comes from overuse of the preprocessor language.
Eclipse usually stores the obj files in a directory under your project. If you're doing a "Debug" build, then it's located under the "Debug" folder under your project folder. If you're doing a "Release" build, then look under "Release", etc. Normally a clean build just works for me in Eclipse, so I don't know what's going wrong with your setup. I guess make sure you're not creating precompiled headers.