Arduino 1.0 produces 25% larger binary?

I upgraded to 1.0 yesterday. It took me a while to adapt the libraries (e.g. ds1307 clock), but I managed to get it compiled. The sketch used about 25k of flash before, now I can't upload it anymore to the Arduino Uno, because it's blown up to 31,5k.

I make use of Ethernet, SD, Wire, OneWire, DallasTemperature, DS1307 and DHT11 (humidity sensor) libraries. If helpfull, I can post the sketch.

Any help greatly appreciated!

OneWire 2.1 has an option, if you edit OneWire.h, to use a small but slower CRC algorithm. For OneWire 2.0, the slow code was the default. 2.1 defaults to the fast code. The size change should be about 250 bytes.

Unfortunately, some of 1.0's new features, like xyz.print() returning byte counts, simply consume more code space.

If you had posted code, I might have investigated if any one thing was a huge contributor to the size change. But instead, I'm writing this message.. (hint: your chances of more useful help are always better if you post code that demonstrates your problem).

Thanks for your reply! I'd love some expert have a look at the code in any case! :slight_smile: Some of the variable and function names are german, I am afraid. Here it is:

#include <MemoryFree.h>
#include <EEPROM.h>
#include <SD.h> //SD-Karte
#include <SPI.h> //Kommunikation mit Ethernet-Shield
#include <Ethernet.h>
//#include <dht11.h> //Feuchte-Sensor
#include <OneWire.h> //Kommunikation mit Temperatur-Sensoren
#include <DallasTemperature.h> //Temperatur-Sensoren
#include <Wire.h>  //I2C für Uhr
#include <DS1307.h> //Uhr-Chip
//#include <Arduino.h>

#define DHT11PIN 2 //Digitaler Pin, an dem DHT11 angeschlossen ist
#define ONE_WIRE_BUS 3 //Digitaler Pin für 1-Wire

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 
  192,168,1, 177 };

// Initialize the Ethernet server library (port 80 is default for HTTP)
EthernetServer server(80);
//dht11 feuchtesensor;
OneWire oneWire(ONE_WIRE_BUS); //Instanz für 1-Wire-Device
DallasTemperature tempSensors(&oneWire); //Temperatursensor
int uhrzeit[7];
const int relais1 = 5, relais2 = 6; //Relais für Pumpe auf Pins 5, 6
const char eingabeTaste = 13;
const char tabTaste = 9;
//const char refreshString[] = "<meta http-equiv=\"refresh\" content=\"1; URL=/\">";
boolean nichtGespeichert = true; //fuer minuetliches Speichern

void setup()
{
  Serial.begin(9600); //serielle Verbindung über USB starten

  Ethernet.begin(mac, ip); // start the Ethernet connection
  server.begin(); // Ethernet Server starten
  tempSensors.begin(); // 1-Wire-Temperatursensoren starten
  pinMode(10, OUTPUT); //fuer SD-Karte: Chip select pin als OUTPUT setzen
  while (!SD.begin(4)) {  //nur mit SD-Karte geht's weiter!
    Serial.println("SD-Karte?!");
    delay(200);
  };
  DDRC|=_BV(2) |_BV(3);  // POWER:Vcc Gnd  muss was für I2C sein, für die Uhr
  PORTC |=_BV(3);  // VCC PINC3
  //stelleUhr(); //Uhr nur einmal stellen!!

  pinMode(relais1, OUTPUT); //Pin für relais1
  pinMode(relais2, OUTPUT); //Pin für relais2
}


void loop()
{
  RTC.get(uhrzeit,true); //Uhrzeit einlesen
  if (uhrzeit[0]<30 && nichtGespeichert) {  //einmal in der Minute
    //readDHT11(); //DHT11-Feuchtesenser lesen und schreiben
    tempSensors.requestTemperatures();  // 1-Wire lesen
    werteSpeichern(); //Daten mit Zeitstempel speichern
    nichtGespeichert = false;
  }
  else if (uhrzeit[0]>=30) nichtGespeichert = true;
  webServer();
  controlHeater();
}


void controlHeater()
{
  float tempSollTag = changeTemp("h/tetag.htm",'=');
  float tempSollNacht = changeTemp("h/tenac.htm",'=');
  float tempSollWasser = changeTemp("h/tewas.htm",'=');
  DeviceAddress tempHV={ 0x28, 0x99, 0x88, 0x4A, 0x03, 0x00, 0x00, 0xD3 };
  DeviceAddress tempHR={ 0x28, 0x99, 0x87, 0xAD, 0x02, 0x00, 0x00, 0xD8 };
  DeviceAddress tempSpeicherOben ={ 0x28, 0x86, 0x5A, 0x08, 0x03, 0x00, 0x00, 0x96 };
  DeviceAddress tempSpeicherMitte={ 0x28, 0x71, 0x4C, 0x08, 0x03, 0x00, 0x00, 0x81 };
  DeviceAddress tempSpeicherUnten={ 0x28, 0xCA, 0x75, 0x08, 0x03, 0x00, 0x00, 0x09 };
  DeviceAddress tempAussen={ 0x28, 0xD8, 0xC1, 0xAD, 0x02, 0x00, 0x00, 0xEF };

}

void webServer()
{
  EthernetClient client = server.available();   // listen for incoming clients
  if (client) 
  {
    // an http request ends with a blank line
    char* anfrage="h/12345.678";
    int zeichenzaehler=0;
    while (client.available()) {
      char charVomClient = client.read();
      if ((zeichenzaehler++ >= 5) &&(zeichenzaehler <=14)) 
        anfrage[zeichenzaehler-4] = charVomClient;  //Zeichen 12345.678 nach anfrage
      Serial.print(charVomClient);
    }
    Serial.println(); 
    Serial.print("Anfrage: "); 
    Serial.println(anfrage);
    if (anfrage[2]=='_') //"te*"=temperatur or "ta*"=tag
    {
      if (anfrage[3]=='t') //Temperatur
      {
        char upDown=anfrage[6]; //'+' or '-'
        switch (anfrage[4])
        {
        case 't': //Tag
          anfrage="h/tetag.htm";
          break;
        case 'n': //Nacht
          anfrage="h/tenac.htm";
          break;
        case 'w': //Wasser
          anfrage="h/tewas.htm";
        }
        changeTemp(anfrage, upDown);
        sendFile(client, anfrage);
      }//if
      else //Zeiten
      {
        boolean hour = (anfrage[6]=='h' || anfrage[6]=='i'); // !hour == minute
        boolean up = (anfrage[6]=='m' || anfrage[6]=='h'); // !up == down
        boolean startTime = (anfrage[5]=='s');
        char heizzeit = anfrage[4];
        boolean deleteTime = (anfrage[5]=='x');
        switch (anfrage[3])
        {
        case '1':
          anfrage="h/tamoX.htm";
          break;
        case '2':
          anfrage="h/tadiX.htm";
          break;
        case '3':
          anfrage="h/tamiX.htm";
          break;
        case '4':
          anfrage="h/tadoX.htm";
          break;
        case '5':
          anfrage="h/tafrX.htm";
          break;
        case '6':
          anfrage="h/tasaX.htm";
          break;
        case '7':
          anfrage="h/tasoX.htm";
        }
        anfrage[6]=heizzeit;
        if (deleteTime) setTimeToND(anfrage);
        else changeTime(anfrage, startTime, hour, up);
        sendFile(client, anfrage);
      }
    }
    else 
    {
      if (anfrage[2]==' ') anfrage="h/index.htm";
      if (anfrage[8]=='t') anfrage="log.txt";
      sendFile(client, anfrage); //alle sonstigen Anfragen
    };
    delay(1); //Zeit für die TCP-Übermittlung
    client.stop(); // close the connection
  }
}

/*void readDHT11(void)
{
  int chk = feuchtesensor.read(DHT11PIN); //liest DHT11
  switch (chk) //Fehlerbehandlung für DHT11
  {
  case 0: 
    break;
  case -1: 
    Serial.println("DHT11: C err"); //checksum
    break;
  case -2: 
    Serial.println("DHT11: T err"); //timeout
    break;
  default: 
    Serial.println("DHT11: err"); 
    break;
  }
}*/

Second half of the code (didn't fit in one message):

void werteSpeichern(void) //sichert alle Sensordaten in "log.txt"
{
  Serial.print("werteS RAM: ");
  Serial.println(freeMemory());
  File logFile = SD.open("LOG.TXT", FILE_WRITE);
  if (logFile) {
    logFile.print(uhrzeit[4]);  //Datum und Uhrzeit
    logFile.print( ".");
    logFile.print( uhrzeit[5]);
    logFile.print( "."); 
    logFile.print( uhrzeit[6]);
    logFile.print( " ");
    logFile.print( uhrzeit[2]);
    logFile.print( ":");
    logFile.print( uhrzeit[1]);
    logFile.print( ":");
    logFile.print( uhrzeit[0]);
    logFile.print( tabTaste);

/*    logFile.print( feuchtesensor.humidity);
    logFile.print( tabTaste);
    logFile.print( feuchtesensor.temperature);
    logFile.print( tabTaste); */

    logFile.print( (int)(tempSensors.getTempCByIndex(0)*100));
    logFile.print( tabTaste);
    logFile.println( (int)(tempSensors.getTempCByIndex(1)*100));

    delay(10);
    logFile.close();
  }
  else Serial.println("Op file err"); 
}

boolean sendFile(Client& client, char* filename)
{
  File file = SD.open(filename);
  if (file)
  {
    char c=file.read();
    while (c != -1)
    {
      client.write(c);
      c = file.read();
    }
    file.close();
    return true;
  }  
  else return false;
}

float changeTemp(char* filename, const char upDown)
{
  float temperature=0.0;
  File file = SD.open(filename, FILE_WRITE);
  if (file)
  {
    int positionInFile=0;
    char* last="     "; //length 5
    file.seek(0);
    last[4]=file.read();
    while (last[4] != -1)
    {
      if (last[4]=='>' && last[2]=='v' && last[3]=='"') 
        positionInFile=file.position();//Start der Var
      //      Serial.print("last: "); Serial.println(last);
      if (positionInFile!=0 && last[4]=='<') //weiterlesen, bis '<' erreicht
      {
        last[4]=0;
        temperature= (last[0]-48)*10 + (last[1]-48) + (last[3]-48)/10.0;
        //        Serial.print("Temperatur: "); Serial.println(temperature);
        if (upDown=='+') temperature += 0.5; 
        else if (upDown=='-') temperature -= 0.5;
        last[0]=temperature/10+48;
        last[1]=(int)(temperature-(int)(temperature/10)*10)+48;
        last[2]='.';
        if ((int)(temperature*10) % 10 != 0) last[3]='5'; 
        else last[3]='0';
        //        Serial.print("last: "); Serial.println(last);
        file.seek(positionInFile);
        for (int i=0;i<=3;i++) file.write(last[i]);
        last[4]=-1;
      }
      else
      {
        for (int i=0;i<4;i++) last[i]=last[i+1];
        last[4] = file.read();
      };
    }
    file.close();
    return temperature;
  }  
  else return -1.0;
}

int getTime(File& file, int& hour, int& minute)
{
  char* last="   "; //length 3
  last[2]=file.read();
  while (last[2] != -1)
  {
    if (last[2]=='>' && last[0]=='v' && last[1]=='"') last[2]=-1;
    else
    {
      for (int i=0;i<2;i++) last[i]=last[i+1];
      last[2] = file.read();
    }
  }
  for (int i=1;i<=2;i++) last[i] = file.read();
  if (last[1]=='N' && last[2]=='D')
  {
    hour=-1;
    minute=-1;
  }
  else
  {
    hour= (last[1]-48)*10 + (last[2]-48);
    for (int i=0;i<=2;i++) last[i] = file.read();
    minute= (last[1]-48)*10 + (last[2]-48);     
  };
  return file.position();
}

boolean setTimeToND(char* filename)
{  
  File file = SD.open(filename, FILE_WRITE);
  if (file)
  {
    file.seek(0);
    for(int i=0; i <= 2; i++)
    {
      int hour, minute;
      int positionInFile=getTime(file, hour, minute);
      if (hour >= 0)
      {
        file.seek(positionInFile-5);
        file.print("ND   ");
        Serial.println("ND geschrieben.");
      }
      else i=3;
    };
    file.close();
    return true;
  }
  else return false;
}


boolean changeTime(char* filename, boolean startTime, boolean isHour, boolean up)
{  
  File file = SD.open(filename, FILE_WRITE);
  if (file)
  {
    int hour, minute;
    file.seek(0);
    int positionInFile=getTime(file, hour, minute);
    if (hour < 0)
    {
      file.seek(file.position()-2);
       file.print('00:00');
      while(file.read()!='N');
      file.seek(file.position()-1);
      file.print('00:00');
    }
    else
    {
      if (!startTime) positionInFile=getTime(file,hour,minute);
      char* timeString="00:00";
      if (isHour)
      {
        if (up) hour += 1; 
        else hour -=1;
        if (hour==-1) hour=23;
        if (hour==24) hour=0;
      }
      else 
      {
        if (up) minute += 10; 
        else minute -= 10;
        if (minute < 0) minute=50;
        if (minute >50) minute=0;
      };
      timeString[0]=hour/10+48;
      timeString[1]=(int)(hour-(int)(hour/10)*10)+48;
      timeString[3]=minute/10+48;
      timeString[4]=(int)(minute-(int)(minute/10)*10)+48;
      file.seek(positionInFile-5);
      for (int i=0;i<=4;i++) file.write(timeString[i]);
    };
    file.close();
    return true;
  }  
  else return false;
}

So why upgrade?
Unless you need the new features of 1.0, it really isn't worth
the work to use it and as you have seen, it breaks literally 100% of the existing libraries
and can cause your code to no longer fit.

Since 1.0 was not well published during the beta/RC period prior to its release, I predict that
many issues will crop up and you will see a flury of updates. So I'd hold off on using it
for a while.

If you still want to use 1.0 there are few easy things that might work in your specific case.

If you are using a pre "uno" board,

You can also save several hundred bytes of code by changing the head and tail pointers
in HardwareSerial to use unsigned chars instead of ints. This is an easy change and should
have been done in the official code. (but we all know how hard it is to get any patches into Arduino)
Simple go edit
hardware/cores/arduino/HardwareSerial.cpp
and change:

struct ring_buffer
{
  unsigned char buffer[RX_BUFFER_SIZE];
  int head;
  int tail;
};

to

struct ring_buffer
{
  unsigned char buffer[RX_BUFFER_SIZE];
  unsigned char head;
  unsigned char tail;
};

You can also shave off a few bytes (50-100), if you use your own main() function.

Instead of:

void setup(void) {
  // setup-code
}

void loop(void) {
 // loop-code
}

you'd just use:

int main(void) {

  init(); // this initializes all the timers and so forth

  // your setup() code goes here

 while(1) {
   // your loop() code goes inside the while loop
 }

}

This also disables the 'serial event' code btw.

bperrybap:
Unless you need the new features of 1.0, it really isn't worth
the work to use it and as you have seen, it breaks literally 100% of the existing libraries
and can cause your code to no longer fit.

I come to believe that that's the way to go... Why invest lots of work without the need for new features? Thanks also for the helpful hints! Same to you, madworm! I guess I will need these hints later anyhow, when I'll get to the limits. There's still a lot to do for my little Arduino! :wink:

I can do some analysis, but... nearly every library you're using is giving me compile errors. Do you happen to have pointers to the 1-compatible versions of onewire, ds1370, dallastemperature, and etc? (Yeah, I can probably fix them, but then I wouldn't know for sure whether I'm using the same code that you're using. PM me a zip file if you want.)

I also might investigate, but at the risk of repeating myself, it's pointless without having the code to reproduce the problem.

@barish - you posted your sketch, but that is not enough. Imagine, if you will, that you some random person who might help, but has nothing other that a clean copy of the Arduino IDE. Try downloading a fresh copies of Arduino, both 1.0 and 0023. Can you reproduce the exact result in both using only fresh downloads of both Arduino IDEs, and the files you've provided? If not, you haven't posted enough to reproduce the problem!

Paul, I wasn't aware that you'd like to compile the code and reproduce the problem. Instead I thought you would look over my sketch to see if there was obvious memory waste. I will see if I can upload the modified libraries I use to make them available to you guys. Thanks for your effort so far!

Edit: Here's the zip-file of my "libraries" folder: http://goo.gl/BMGYs

SD.h has grown by almost 2KB for a simple example. The SD/examples/ReadWrite sketch is 13580 bytes on 1.0 and it is 11686 bytes on 0022.

Most of this is due to new features added to the SD.h wrapper in 1.0. The base code for SdFat has not been changed much from 0022.

Part is due to something else in 1.0. For my new version of SdFat a similar example, SdFatReadWrite, is 12098 bytes on 1.0 and 11682 on 0022. So there is a 416 byte increase in this example with the same code on both systems.

look over my sketch to see if there was obvious memory waste.

I'm afraid the "interesting question" is not "how can we fix your sketch?", but rather "why did the sketch get 25% bigger?", so we don't particularly want to look at the source for your sketch, but the size of the binaries of everything involved...

fat16lib:
Part is due to something else in 1.0. For my new version of SdFat a similar example, SdFatReadWrite, is 12098 bytes on 1.0 and 11682 on 0022. So there is a 416 byte increase in this example with the same code on both systems.

If I understand there's something about 1.0 you don't know yet the cause. Well I hope someone will find out.

@westfw: nothing to be afraid for, I hope you can compile and fix something now. All I want is a smaller binary after all, no matter where the problem lies.

Looks like most of the increase is in Ethernet. The Ethernet WebServer example is 10146 bytes on 1.0 but only 5446 bytes on 0022. That's 4,700 bytes more.

I didn't look at the library code for Ethernet but the example was not changed much. Here is the diff for the example in 1.0 and 0022:

24c24
< IPAddress ip(192,168,1, 177);
---
> byte ip[] = { 192,168,1, 177 };
29c29
< EthernetServer server(80);
---
> Server server(80);
41c41
<   EthernetClient client = server.available();
---
>   Client client = server.available();

The SD library is about 1,500 bytes larger due to new features. These two libraries add about 6,200 bytes.

Thanks, fat16lib, so that must be the biggest chunk of my memory increase. But shouldn't there be some options for the lib to use less space? E.g. I don't need to open multiple files. I mean, 5k more or less, that must be important to many users (I imagine).

First, most of the increase, 4700 bytes, appears to be due to the Ethernet library.

Second, I wrote the SdFat base library for SD.h but I was not involved with the Arduino group's wrapper for SdFat. The extra 1500 bytes is due to features in the wrapper for SdFat. A very old version of SdFat is used as the base for SD.h so the wrapper takes extra memory.

The current version of SdFat has all the features of SD.h and is smaller by around 1500 bytes. The problem is that the SD.h wrapper implements a different API than SdFat so you can't just use to the new version of SdFat without a lot of program changes.

If you could live with FAT16 on standard SD cards with 2 GB or less, you could use my Fat16 library. It is much smaller than SD.h or SdFat.

A beta of the SdFat and Fat16 libraries that work with Arduino 1.0 is here Google Code Archive - Long-term storage for Google Code Project Hosting..

I will soon post the a non-beta version of both libraries here Google Code Archive - Long-term storage for Google Code Project Hosting. and here Google Code Archive - Long-term storage for Google Code Project Hosting..

most of the increase, 4700 bytes, appears to be due to the Ethernet library.

It looks to me like a big part of this is because 1.0 has a DNS client, which is apparently included in your sketch even though you're not using it. This causes UDP to be included as well. This is at least a couple thousand bytes of code that didn't exist at all in 0022...

BTW, on my system, your sketch compiles to 30682 bytes, which still fits in a 32k AVR...
(I did generate a trivial memoryfree.c from the postings in the forums, rather than digging up an actual library, but other than that I should have the same code...)

I commented out the humidity sensor to get below 31k, but it still didn't upload to the board. So maybe another error I got with 1.0? I'll see if I can fix it, thanks for your help!

It seems the infamous 'round' issue is back again... at least code-size wise. This time in 'Arduino.h'. They have done something to the compile process, so at least I don't get any errors from that anymore. BUT if I comment out the '#define round...' line, the code-size goes down by 190 bytes!

void setup(void) {
}

void loop(void) {
 volatile long a = round(digitalRead(0)); 
}

compiled with '#define round...' in 'Arduino.h': 1412 bytes
compiled without '#define round...' in 'Arduino.h': 1222 bytes

This should affect linux users with avr-libc version 1.7.1 I think. It comes with a internal version of round() and doesn't need the '#define round...' anymore. I think there is a patch for this, but somehow it got ignored for 1.0.

BTW, I did not check if the produced code actually is working. I just removed the define out of old habit and was rewarded with almost 200 bytes less file size.

barish:
I commented out the humidity sensor to get below 31k, but it still didn't upload to the board. So maybe another error I got with 1.0? I'll see if I can fix it, thanks for your help!

If you have code under 31k and you have a m328 based board and it isn't fitting, then it
sounds like you are not using optiboot.

Switching to the optiboot bootloader will get you more space so that images up to 32256 bytes will fit
vs 30720 with the older bootloader.

--- bill