I want to make a sketch that is as small as possible, for test purposes. The problem is, when i compile the BareMinimum sketch (with an empty setup and loop), i get 466 bytes for the Uno and a whopping 4,242 for the Leonardo. Is there any way to write your own code that has no extra functions (namely Timer0 for millis()
and delay()
). I would also like to be able to disable the keyboard/mouse functions for the Leonardo.
-
4Shouldn't this be tagged leonardo and not uno (and focus on one board)? These are separate questions.– asheeshrFeb 14, 2014 at 2:09
-
I'm just pointing out that a blank compiled sketch is large for a lot of boards, especially the native USB based ones– TheDoctorFeb 14, 2014 at 2:17
-
I would also like to be able to disable the keyboard/mouse functions for the Leonardo. is the second question.– asheeshrFeb 14, 2014 at 2:18
4 Answers
You should be able to create your own board definition with a custom boards.txt file as per https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification. As I see there are several usb features in the leonardo's definition. I would hope that the compiles inclusion of the 4K is based off of these flags and not the processor type.
Where the boards.txt would use the upload, bootloader sections from the Leonardo and the build from the uno.
This is all assuming the core library build does not use processor specific flags to include USB functions.
If you get such working. post back, I am sure others would be interested in such.
I recently ran into this 4K used limitation on a library demo that actually maxed out the UNO and had to put in a
#if !defined(__AVR_ATmega32U4__)
...
around a large chunk of extra features in the sketch to fit on the Leonardo.
I had assume (wrong) that this 4K was because I still included Serial.print which when over the USB's CDC on the Leo. But I see after a memory dump of an empty sketch they are still there.
C:\Users\mflaga\AppData\Local\Temp\build8958339595868119500.tmp>avr-objdump -d sketch_feb13a.cpp.elf > sketch_feb13a.cpp.elf.lst
Which makes sense. As the Leonardo still requires the USB-CDC client (the 4K) as to detect the 1200 Baud connect from AVR-DUDE as to stroke the remote reboot.
Hence making a custom boards.txt without USB in the build, also needs to have
leonardo.upload.use_1200bps_touch=true
removed.
Once loaded on the target, this would require the upload to be synchronized with a manual reset of the target. As the ability to remote reboot is lost.
-
updated as to why 4K is still compiled in, even if Serial.print is omitted.– mpflagaFeb 14, 2014 at 14:52
I recently wanted to do exactly this. Since there is no nice way to do so, I wound up writing a patch for the Stino sublime-text arduino plugin to do exactly this. It's subsequently been accepted, so it should be in any up-to-date Stino installs.
This adds a new option to Stino:
Using this mode produces compilation results like the following:
For a Uno:
Binary sketch size: 172 bytes (of a 32256 byte maximum, 0.53 percent).
Estimated memory use: 0 bytes (of a 1024 byte maximum, 0.00 percent).
For a leonardo
Binary sketch size: 240 bytes (of a 28672 byte maximum, 0.84 percent).
Estimated memory use: 0 bytes (of a 2560 byte maximum, 0.00 percent).
Actually programming the leonardo with the above compiled output is probably a bad idea, as it might break the auto-reset functionality, but you could, if you wanted. Hat-tip to mpflaga for noting this in his answer.
Note that the memory reports are actually incorrect, but that's a separate issue.
The code used for the above is:
int main()
{
while (1)
{
}
}
Some notes:
- You ain't writing a "Sketch" anymore, not that you ever actually do write a sketch. You write programs. Period. I don't care what the Arduino wackos want to say, they don't get to redefine terms.
- All interrupt management is manual. This means no
milis()
or similar. - You can still use the arduino serial libraries and so forth, if you want. You do have to
#include <Arduino.h>
. - You define
main
. You don't ever return frommain
. If you want setup stuff, it goes before thewhile (1)
.
-
-
@Ron-E I don't call it an IDE, Arduino IDE is its name, so I just used its name, even though it is not worth that name. Feb 27, 2014 at 6:02
-
2@FakeName Bad language isn't permitted on Stack Exchange sites (see: stackoverflow.com/help/behavior). I've edited it out in this case, but please try to refrain from using expletives on this site in future. Thanks. Feb 28, 2014 at 23:03
Although it depends on your sketch, you can somewhat decrease the size by reusing code with methods.
Take this code:
int led = 13;
int val;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
val = digitalRead(10);
}
1,322 bytes on Arduino Uno. Now let's shrink it a bit:
int led = 13;
int val;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
for(uint8_t i = 0; i < 8; i++) {
blink(HIGH);
blink(LOW);
}
val = digitalRead(10);
}
void blink(uint8_t state) {
digitalWrite(led, state); // turn the LED to the right state
delay(1000); // wait for a second
}
1,194 bytes. That's about a 10% decrease!
Anyway, although it doesn't greatly shrink a sketch, it sometimes can be the easiest route when you are two bytes over the limit, or just want to make a more compact sketch to begin with without loosing any functionality. It's not for every situation, but I find it useful sometimes.
-
Generally, if you pull code out into functions, the compiler will do the hard work and get the rest right for you. Mar 18, 2014 at 23:44
-
@Cybergibbons Can you define that [for users that aren't familiar with that]? Mar 19, 2014 at 0:11
-
3If you break out code into a function and it isn't efficient, generally the compiler will in-line it for you. However, a compiler will never break code out into functions. Therefore, it's nearly always better to write more functions. Mar 19, 2014 at 8:00
-
1Plus putting the code into functions makes it much more easier to read and understand– user93Mar 19, 2014 at 9:51
-
Using direct port access, the size is decreased to 646 bytes. Using only avr-libc (no Arduino core), it gets down to 220 bytes. Jun 15, 2015 at 15:22
@annonomus penguin, sure we can Although the code compiles into 1180 bytes flash + 13 bytes RAM for an uno on my computer, we can improve on it :) so golf challenge accepted and also a few usefull tips since we are in the business of learning.
Step 1: decrease variable requirements. Using an int for a led port seems a bit overkill, we certainly don't have 65535 addressable IO ports on the arduino :) So we change it to a byte just for the fun of it. We will change it over to a #define later on, but to show the impact of using too large variable types.
byte led = 13;
int val;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
blink();
val = digitalRead(10);
}
void blink() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
Compiles into 1172 bytes + 13 byte RAM. This saves 8 bytes of flash due to fewer needed operations for the byte instead of a integer. I would expect 12 bytes of ram, but okay. Not that much, but every byte saved is good.
Step 2: change over variable into defines when it makes sense. For example, the led byte is not needed, the pin won't unsolder itself.
#define LED 13
int val;
void setup() {
pinMode(LED, OUTPUT);
}
void loop() {
blink();
val = digitalRead(10);
}
void blink() {
digitalWrite(LED, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
Compiles into 1142 bytesflash + 11 bytes ram. Already 38 bytes saved. This is due to fewer register operations needed to fetch the int value. Also we saved 2 bytes from RAM. (still wondering why the byte didn't compile into 1 less byte of ram.....)
Step 3: optimize code. I see 2 delays. I wonder if i change it to 1 delay it would save space, but i have to figure out the value of the LED pin and toggle (invert) it. We can do that with digitalRead(), but will it save space?
#define LED 13
int val;
void setup() {
pinMode(LED, OUTPUT);
}
void loop() {
blink();
val = digitalRead(10);
}
void blink() {
digitalWrite(LED, !digitalRead(LED)); // toggle the led based on read value
delay(1000); // wait for a second and spare yourself the other delay
}
Compiles into 1134 bytes + 11 bytes ram. Yay! another 8 bytes. That makes a total of 46 bytes and 2 fewer lines of code.
Also another general tip on decreasing codesize. Don't use the String class. It's HUGE, learn how to deal with char arrays, strcpy(), strcmp(). If all you have are some basic string operations, the usage of the String class is mostly just wasting space on both flash and RAM.