Since the release of Arduino 1.0, some libraries have seen a huge increase in compiled file size. This is _not_ a fix for those. This will be taken care of the community sooner or later!
Here are a few general things you can do to get a smaller .hex file size:
Make sure the used variables are of the correct size.
Use ‘char’ instead of ‘int’ if you only need it for a short for-loop counting from 0 to 10. It is also helpful for compiler optimizations to specify the variables as good as you can. Don’t need any negative numbers? Declare your variables as ‘unsigned …’, e.g. ‘unsigned char’, ‘unsigned int’, ‘uint8_t’, ‘uint16_t’…
Supply your own main() function!
Instead of the usual
1 2 3 4 5 |
void setup(void) { } void loop(void) { } |
use this to save a couple of 100 bytes of FLASH. This disables ‘serial event’ code btw.
1 2 3 4 5 6 7 8 9 |
int main(void) { init(); // don't forget this! { // place your setup code in here } while(1) { // place your loop code in here } } |
Using the hardware serial port
You can shave off a couple of hundred bytes by changing a few things in ‘HardwareSerial.cpp’. This applies the 1st tip to properly size and declare variables as needed.
Reduce ‘SERIAL_BUFFER_SIZE’ (both cases) to 8 or even 4.
Search for ‘struct ring_buffer’ and change ‘volatile int head’ to ‘volatile uint8_t head’, change ‘volatile int tail’ to ‘volatile uint8_t tail’.
Search for ‘inline void store_char(…)’ and replace the first part of the line starting with ‘int i = (unsigned int) …’ with ‘uint8_t i = (uint8_t) …’ and leave the remaining part as is.
On linux with avr-libc 1.7.1 or later
You can again save FLASH space (about 200 bytes), by using the built-in ’round()’ function of ‘math.h’ and disabling a #define in ‘Arduino.h’.
1 2 3 |
#if __AVR_LIBC_VERSION__ < 10701UL #define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) #endif |
Just add lines 1 and 3 around ‘#define round(x)…’ and you’re done. This is only effective if you actually use round(x) of course!
An Example
Compiling this example with an unmodified version of Arduino 1.0 and the ‘UNO’ board selected gives a file size of ‘2596 bytes’!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* DigitalReadSerial Reads a digital input on pin 2, prints the result to the serial monitor This example code is in the public domain. */ void setup() { Serial.begin(9600); pinMode(2, INPUT); } void loop() { int sensorValue = digitalRead(2); Serial.println(sensorValue); } |
File size with the modifications (buffer size of 4) to ‘HardwareSerial.cpp’ is ‘2342 bytes’.
When using your own main() function as suggested above
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* DigitalReadSerial Reads a digital input on pin 2, prints the result to the serial monitor This example code is in the public domain. */ int main(void) { init(); Serial.begin(9600); pinMode(2, INPUT); while(1) { int sensorValue = digitalRead(2); Serial.println(sensorValue); } } |
the compiled file size is just ‘2278 bytes’ !
Total savings for this test case: 318 bytes of FLASH space.
Happy hacking!
Hi, robert,
Only recently found Arduino (=fair n00b alert…) and just found your site.
I have some code – that works! yipee! – in the usual setup-loop fashion. But it has some interrupt code (“ISR(_vect)”, 3 routines in all), and I don’t now where I should place them in this “main-init-while(1)” structure. My first attempt was:
int main(void) {
init();
{
//setup code
}
ISR(_vect) {
//interrupt routine 1 code
}
ISR(_vect) {
//interrupt routine 2 code
}
while(1) {
//loop code
}
}
… but that failed miserably. Probably “obviously!”…
Could you enlighten me about the correct place to put the interrupt routines?
Thanks!
yamark
The ISR() definitions should go outside of main(), just like other functions.
int main(void) {
// whatever
}
ISR(…) {
// some code
}
Please note: it’s quite possible that things have changed a bit since Arduino 1.0, so that may also explain unexpected behaviour.