Как уменьшить размер бинарика?

saintbyte
Offline
Зарегистрирован: 11.03.2013

Я счастливый владелец Seeduino Film со всеми прибабасами. Но у меня проблема в том что 14 кило уже не хватает -  как оптимизировать размер ? Может есть упаковщик типа UPX? Поменять IDE ? Отказать от библиотек: только транзакции в только хардкор?

maksim
Offline
Зарегистрирован: 12.02.2012

В первую очередь нужно оптимизировать код.

saintbyte
Offline
Зарегистрирован: 11.03.2013

Ну я понял что String дает +2 килобайта 

Но без int float и char - вообще никак. 

Процедуры делать отдельными  - тоже не сильно уменьшает размер, а если процедура используется только в 2х местах то проше - копипаст - меньше обьем дает.

step962
Offline
Зарегистрирован: 23.05.2011

saintbyte пишет:

Процедуры делать отдельными  - тоже не сильно уменьшает размер, а если процедура используется только в 2х местах то проше - копипаст - меньше обьем дает.

Вызов функции - это пара десятков байтов. Любая нетривиальная функция - это полсоотни байтов как минимум. Так что то, что вы называете копипастом будет иметь скорее обратный эффект.

Хотите действительно сократить объем скетча - переходите от вызовов библиотечных функций (универсальных и поэтому имеющих очень много лишнего) к прямой манипуляции регистрами микроконтроллера - на небольших скетчах можно добиться двух-трехкратного сокращения кода.

leshak
Offline
Зарегистрирован: 29.09.2011

А вообще - вопрос ни о чем. Задача оптимизировать код. Сам код - не известен. Какие библиотеки используются - не ведомо (а ведь может к примеру использует шилд какой-то у которого библиотека много жрет и замена шилда на более интелектуальный поможет. Скажем переход од enc28j60 на wiznet). Может используются програмные PWM/SPI/Serial и нужен переход на их hardware вариант.

Может код пилить нужно, может от работы со строками отказыватся (они ой как любят память жрать, особенно если их раскидывать по всему коду), а может реально "предел". Всегда можно нафантазировать фичей больше чем потянет контроллер.
Может от ардуино библиотек прийдется отказыватся (за простоту нужно платить) и переходить на чистый AVR. А может желаний настолько много что только переход на ASM поможет (что-бы контролировать каждый байт).

Если бы существовала методика оптимизации любого произвольного кода, которую можно посоветовать "не глядя на конкретную задачу" - она уже была-бы встроенна в компилятор (и поверте там уже куча такого встроенно, все что можно оптимизировать по формальным признакам - уже есть :) 

А еще можно почитать про опции компиляции avr-gcc  (его ArduinoIDE использует в качестве компилятора), возможно через них компиляруя руками выйдет "отключить что-нибудь не нужное в вашем случае" и за счет этого уменьшить код.

saintbyte
Offline
Зарегистрирован: 11.03.2013

В моем случае есть 3 библиотеки которые используют wire.h и arduino.h + много вывода в serial   - как это оптимизировать?

tsostik
Offline
Зарегистрирован: 28.02.2013

Не глядя в код, тут ничего не сказать.

Как минимум, покажите код.

leshak
Offline
Зарегистрирован: 29.09.2011

saintbyte пишет:

В моем случае есть 3 библиотеки которые используют wire.h и arduino.h + много вывода в serial   - как это оптимизировать?

Никак.

Вам уже вроде объяснили что "общих рецептов" не бывает. А показывать код - вы не хотите. Значит либо сами что-то придумывайте, либо покупайте более жирный камень.

Покажете код - может кто-то что-то и подскажет. А может и нет. Но без кода - точно шансы нулевые.

saintbyte
Offline
Зарегистрирован: 11.03.2013

#include <Arduino.h>
#include <Wire.h>
#include <HP03M.h>
#include <MMA7660FC.h>
//#include <W25Xnn.h>
#include <SeeedOLED.h>
#include <HMC5883L.h>

// Store our compass as a variable.
HMC5883L compass;
// Record any errors that may occur in the compass.
int compass_error = 0;
float compass_scale;
void sendBlueToothCommand(char command[])
{
    Serial.println();
    delay(200);
    Serial.print(command);
    delay(200);
    Serial.println();
    delay(1000);   
    Serial.flush();
}

void setup()  
{
    Wire.begin();
    SeeedOled.init();  //initialze SEEED OLED display
    SeeedOled.clearDisplay();           //clear the screen and set start position to top left corner
    SeeedOled.setNormalDisplay();       //Set display to Normal mode
    SeeedOled.setHorizontalMode();      //Set addressing mode to Horizontal Mode
    SeeedOled.setTextXY(0,0); 
    SeeedOled.putString("DMA-1b 1"); 
    Serial.begin(38400); //Set BluetoothFrame BaudRate to default baud rate 38400
    delay(1000);
    SeeedOled.putString("2");
    Mma7660fc.init();
    Hp03m.init();      //Initialize Hp03m  
    SeeedOled.putString("3");
    sendBlueToothCommand("+STNA=DMA1b");
    delay(3000);
    SeeedOled.putString("4");
    sendBlueToothCommand("+STWMOD=0");
    sendBlueToothCommand("+STAUTO=0");
    sendBlueToothCommand("+STOAUT=1");
    sendBlueToothCommand("+STPIN=1234");
    delay(3000); // This delay is required.
    sendBlueToothCommand("+INQ=1");
    SeeedOled.putString("5");
    delay(3000); // This delay is required.
    SeeedOled.putString("8");
    //-----------------------------
    compass = HMC5883L(); 
    compass_scale = 1.3;
    compass_error = compass.SetScale(compass_scale);
    if(compass_error != 0)
    { // If there is an error, print it out.
        Serial.println(compass.GetErrorText(compass_error));  
        SeeedOled.putString("10ce");
    }
    compass_error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
      
    if(compass_error != 0) { // If there is an error, print it out.
        Serial.println(compass.GetErrorText(compass_error)); 
        SeeedOled.putString("11ce");
    }
    //--------------------------------------------
    //-----------------------------
    DDRB|=0x21;        //digital pin 8, LED glow indicates Film properly Connected .
    PORTB |= 0x21;
    SeeedOled.clearDisplay(); 
}

void loop()
{
    char Acc_x = 0;
    char Acc_y = 0;
    char Acc_z = 0;
    Hp03m.read();  // Read temperature, pressure and altitude
    Mma7660fc.accelarationRead();  // Read accelaration X, Y and Z
    MagnetometerRaw raw = compass.ReadRawAxis();
    MagnetometerScaled scaled = compass.ReadScaledAxis();
    Acc_x = ((char)(Mma7660fc.accelarationData[0]<<2))/4 ;
    Acc_y = ((char)(Mma7660fc.accelarationData[1]<<2))/4 ;
    Acc_z = ((char)(Mma7660fc.accelarationData[2]<<2))/4 ;
    delay(200);
    
    Serial.println();
    Serial.print("<seq>");
    Serial.println();
    
    Serial.print("T:");
    Serial.println(Hp03m.Temperature);
    SeeedOled.setTextXY(0,0);            
    SeeedOled.putString("T:"); 
    SeeedOled.setTextXY(0,2);  
    SeeedOled.putNumber(Hp03m.Temperature);  
    
    Serial.print("P:");
    Serial.println(Hp03m.Pressure);
    SeeedOled.setTextXY(0,6);            
    SeeedOled.putString("P:"); 
    SeeedOled.setTextXY(0,8);  
    SeeedOled.putNumber(Hp03m.Pressure); 
      
    Serial.print("A:");
    Serial.println(Hp03m.Altitude);
    SeeedOled.setTextXY(1,0); 
    SeeedOled.putString("A:"); 
    SeeedOled.setTextXY(1,2);  
    SeeedOled.putNumber(Hp03m.Altitude); 
    
    Serial.print("X:");
    Serial.println(Acc_x,DEC);
    SeeedOled.setTextXY(2,0); 
    SeeedOled.putString("X:"); 
    SeeedOled.setTextXY(2,2);  
    SeeedOled.putNumber(Acc_x); 
    
    Serial.print("Y:");
    Serial.println(Acc_y,DEC);
    SeeedOled.setTextXY(2,5); 
    SeeedOled.putString("Y:"); 
    SeeedOled.setTextXY(2,7);  
    SeeedOled.putNumber(Acc_y);
   
    Serial.print("Z:");
    Serial.println(Acc_z,DEC);
    SeeedOled.setTextXY(2,10); 
    SeeedOled.putString("Z:"); 
    SeeedOled.setTextXY(2,12);  
    SeeedOled.putNumber(Acc_z);
    SeeedOled.setTextXY(3,0); 
    SeeedOled.putString("____________"); 
    //if (compass_error == 0) {
    int MilliGauss_OnThe_XAxis = scaled.XAxis;
    float heading = atan2(scaled.YAxis, scaled.XAxis);
    float declinationAngle = -0.0457;
    heading += declinationAngle;
    if(heading < 0) heading += 2*PI;
    if(heading > 2*PI) heading -= 2*PI;
    float headingDegrees = heading * 180/M_PI; 
    
    Serial.print("RAW_X:");
    Serial.println(raw.XAxis);
    Serial.print("RAW_Y:");
    Serial.println(raw.YAxis);
    Serial.print("RAW_Z:");  
    Serial.println(raw.ZAxis);
    SeeedOled.setTextXY(4,0); 
    SeeedOled.putNumber(raw.XAxis);
    SeeedOled.setTextXY(4,6); 
    SeeedOled.putNumber(raw.YAxis);
    SeeedOled.setTextXY(4,12); 
    SeeedOled.putNumber(raw.ZAxis);
    
    Serial.print("SCAL_X:");
    Serial.println(scaled.XAxis);
    Serial.print("SCAL_Y:");
    Serial.println(scaled.YAxis);
    Serial.print("SCAL_Z:");  
    Serial.println(scaled.ZAxis);
  
    Serial.print("HEADING:");
    Serial.println(heading);
    Serial.print("RADIAND:");
    Serial.println(headingDegrees);
    Serial.print("DEGRESS:");
    Serial.println(headingDegrees);
    Serial.print("SCALE:");
    Serial.println(compass_scale);
    SeeedOled.setTextXY(5,0); 
    SeeedOled.putNumber(heading);
    SeeedOled.setTextXY(5,6); 
    SeeedOled.putNumber(headingDegrees);   
    //}
    
    

    Serial.println();
    Serial.print("</seq>");
    Serial.println();

    delay(1000);
}  

Вот такой код.

maksim
Offline
Зарегистрирован: 12.02.2012

Так сколько килобайт не хватает?

saintbyte
Offline
Зарегистрирован: 11.03.2013

14кб , seediono film она как Arduino pro mini w/ AT 168 

maksim
Offline
Зарегистрирован: 12.02.2012

Так вы можете сказать сколько килобайт НЕ ХВАТАЕТ ? Не сколько килобайт в дуине всего , а какая разница между тем что получается при компиляции и 14-тью килобайтами.

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Как минимум, полезно весь статический текст оставить в флэш-памяти,

т.е. вместо:

Serial.print("HEADING:");

писать

Serial.print(F("HEADING:"))

tsostik
Offline
Зарегистрирован: 28.02.2013

На первый взгляд тупым убиранием ненужных println, вместо которых добавляется "\n" dв соответвующую строку Serial.print можно съекономить байт 400. Дальше - нужно смоттреть на скомпилированную программу, настройки компилятора и реализацию библиотек.

Вы меня заинтересовали - выложите, плз, ссылки на все используемые библиотеки, вопрос стал делом спортивного интереса.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Отказатся от бутлодера- занять его место кодом - ещё 2 килобайта...

Поставить 328....

saintbyte
Offline
Зарегистрирован: 11.03.2013
tsostik
Offline
Зарегистрирован: 28.02.2013

В общем путем небольших телодвижений у меня на настоящий момент размер скетча уменьшился до 13696 байт.

Вот текст:


#include <Arduino.h>
#include <Wire.h>
#include <HP03M.h>
#include <MMA7660FC.h>
//#include <W25Xnn.h>
#include <SeeedOLED.h>
#include <HMC5883L.h>

// Store our compass as a variable.
HMC5883L compass;
    MagnetometerRaw raw;// = compass.readRawAxis();
    MagnetometerScaled scaled;// = compass.readScaledAxis();

// Record any errors that may occur in the compass.
int compass_error = 0;
#define COMPASS_SCALE 1.3
void sendBlueToothCommand(char command[])
{
    Serial.println();
    delay(200);
    Serial.print(command);
    delay(200);
    Serial.println();
    delay(1000);   
    Serial.flush();
}

void setup()  
{
    Wire.begin();
    SeeedOled.init();  //initialze SEEED OLED display
    SeeedOled.clearDisplay();           //clear the screen and set start position to top left corner
//    SeeedOled.setNormalDisplay();       //Set display to Normal mode
    SeeedOled.setHorizontalMode();      //Set addressing mode to Horizontal Mode
//    SeeedOled.setTextXY(0,0); 
    SeeedOled.putString("DMA-1b 1"); 
    Serial.begin(38400); //Set BluetoothFrame BaudRate to default baud rate 38400
    delay(1000);
    SeeedOled.putString("2");
    Mma7660fc.init();
    Hp03m.init();      //Initialize Hp03m  
    SeeedOled.putString("3");
    sendBlueToothCommand("+STNA=DMA1b");
    delay(3000);
    SeeedOled.putString("4");
    sendBlueToothCommand("+STWMOD=0");
    sendBlueToothCommand("+STAUTO=0");
    sendBlueToothCommand("+STOAUT=1");
    sendBlueToothCommand("+STPIN=1234");
    delay(3000); // This delay is required.
    sendBlueToothCommand("+INQ=1");
    SeeedOled.putString("5");
    delay(3000); // This delay is required.
    SeeedOled.putString("8");
    //-----------------------------
    compass = HMC5883L(); 
    //compass_scale = 1.3;
    compass_error = compass.setScale(COMPASS_SCALE);
    if(compass_error != 0)
    { // If there is an error, print it out.
        Serial.println(compass.getErrorText(compass_error));  
        SeeedOled.putString("10ce");
    }
    compass_error = compass.setMeasurementMode(MEASUREMENT_CONTINUOUS); // Set the measurement mode to Continuous
      
    if(compass_error != 0) { // If there is an error, print it out.
        Serial.println(compass.getErrorText(compass_error)); 
        SeeedOled.putString("11ce0");
    }
    //--------------------------------------------
    //-----------------------------
    DDRB|=0x21;        //digital pin 8, LED glow indicates Film properly Connected .
    PORTB |= 0x21;
    SeeedOled.clearDisplay(); 
}

void loop()
{
    char Acc_x = 0;
    char Acc_y = 0;
    char Acc_z = 0;
    Hp03m.read();  // Read temperature, pressure and altitude
    Mma7660fc.accelarationRead();  // Read accelaration X, Y and Z
    compass.readRowAndScaledAxis(&raw, &scaled);
    Acc_x = ((char)(Mma7660fc.accelarationData[0]<<2))/4 ;
    Acc_y = ((char)(Mma7660fc.accelarationData[1]<<2))/4 ;
    Acc_z = ((char)(Mma7660fc.accelarationData[2]<<2))/4 ;
    delay(200);
    
//    Serial.println();
//    Serial.print("<seq>");
//    Serial.println();
    Serial.println("\n<seq>");
    
    Serial.print("T:");
    Serial.println(Hp03m.Temperature);
    SeeedOled.setTextXY(0,0);            
    SeeedOled.putString("T:"); 
    SeeedOled.setTextXY(0,2);  
    SeeedOled.putNumber(Hp03m.Temperature);  
    
    Serial.print("P:");
    Serial.println(Hp03m.Pressure);
    SeeedOled.setTextXY(0,6);            
    SeeedOled.putString("P:"); 
    SeeedOled.setTextXY(0,8);  
    SeeedOled.putNumber(Hp03m.Pressure); 
      
    Serial.print("A:");
    Serial.println(Hp03m.Altitude);
    SeeedOled.setTextXY(1,0); 
    SeeedOled.putString("A:"); 
    SeeedOled.setTextXY(1,2);  
    SeeedOled.putNumber(Hp03m.Altitude); 
    
    Serial.print("X:");
    Serial.println(Acc_x,DEC);
    SeeedOled.setTextXY(2,0); 
    SeeedOled.putString("X:"); 
    SeeedOled.setTextXY(2,2);  
    SeeedOled.putNumber(Acc_x); 
    
    Serial.print("Y:");
    Serial.println(Acc_y,DEC);
    SeeedOled.setTextXY(2,5); 
    SeeedOled.putString("Y:"); 
    SeeedOled.setTextXY(2,7);  
    SeeedOled.putNumber(Acc_y);
   
    Serial.print("Z:");
    Serial.println(Acc_z,DEC);
    SeeedOled.setTextXY(2,10); 
    SeeedOled.putString("Z:"); 
    SeeedOled.setTextXY(2,12);  
    SeeedOled.putNumber(Acc_z);
    SeeedOled.setTextXY(3,0); 
    SeeedOled.putString("____________"); 
    //if (compass_error == 0) {
    int MilliGauss_OnThe_XAxis = scaled.XAxis;
    float heading = atan2(scaled.YAxis, scaled.XAxis);
 //   float declinationAngle = -0.0457;
 //   heading += declinationAngle;
    heading -= 0.0457;
    if(heading < 0) heading += 2*PI;
    if(heading > 2*PI) heading -= 2*PI;
    float headingDegrees = heading * 180/M_PI; 
    
    Serial.print("RAW_X:");
    Serial.println(raw.XAxis);
    Serial.print("RAW_Y:");
    Serial.println(raw.YAxis);
    Serial.print("RAW_Z:");  
    Serial.println(raw.ZAxis);
    SeeedOled.setTextXY(4,0); 
    SeeedOled.putNumber(raw.XAxis);
    SeeedOled.setTextXY(4,6); 
    SeeedOled.putNumber(raw.YAxis);
    SeeedOled.setTextXY(4,12); 
    SeeedOled.putNumber(raw.ZAxis);
    
    Serial.print("SCAL_X:");
    Serial.println(scaled.XAxis);
    Serial.print("SCAL_Y:");
    Serial.println(scaled.YAxis);
    Serial.print("SCAL_Z:");  
    Serial.println(scaled.ZAxis);
  
    Serial.print("HEADING:");
    Serial.println(heading);
    Serial.print("RADIAND:");
    Serial.println(headingDegrees);
    Serial.print("DEGRESS:");
    Serial.println(headingDegrees);
    Serial.print("SCALE:");
    Serial.println(COMPASS_SCALE);
    SeeedOled.setTextXY(5,0); 
    SeeedOled.putNumber(heading);
    SeeedOled.setTextXY(5,6); 
    SeeedOled.putNumber(headingDegrees);   
    //}
    
    

//    Serial.println();
//    Serial.print("</seq>");
//    Serial.println();
    Serial.println("\n</seq>");
    delay(1000);
}  

Правда пришлось немного исправить библиотеки компаса (добавил функцию, которая за один раз читает и Raw и Scaled данные, подправил функцию setScale, убрав неиспользуемые ветки кода) и OLED (подправил функцию putChar так, чтобы она все писала сразу в Wire, не зовя промежуточную функцию writeData).

Это явно не предел, но мне дальше стало лень.

Например, можно повыкидывать нафиг все библиотеки и работать напрямую с девайсами, благо в данном случае все ограничивается записьмю-чтением одной-двух команд через Wire.

saintbyte
Offline
Зарегистрирован: 11.03.2013

Выложи и я загитую =) Или сразу загитуй а =)

tsostik
Offline
Зарегистрирован: 28.02.2013

Не, гитовать это не надо. Это в данном случае такие удлвки полезны, а в общем они уменьшают читаемость и структурную целостность.

Вот эту функцию добавил в HMC5883L.cpp (ну и в хедер, конечно, добавил):

void HMC5883L::readRawAndScaledAxis(MagnetometerRaw * raw, MagnetometerScaled *scaled)
{
  uint8_t* buffer = read(DATA_REGISTER_BEGIN, 6);
  raw->XAxis = (buffer[0] << 8) | buffer[1];
  raw->YAxis = (buffer[2] << 8) | buffer[3];
  raw->ZAxis = (buffer[4] << 8) | buffer[5];
  scaled->XAxis = raw->XAxis * m_Scale;
  scaled->ZAxis = raw->ZAxis * m_Scale;
  scaled->YAxis = raw->YAxis * m_Scale;

};

А вот тут грязными руками покопался в SeeedOLED.cpp (предварительно убрав модификатор PROGMEM у массиваBasicFont):

void SeeedOLED::putChar(unsigned char C)
{
    if(C < 32 || C > 127) //Ignore non-printable ASCII characters. This can be modified for multilingual font.
    {
    C=' '; //Space
    }        
     Wire.beginTransmission(SeeedOLED_Address); // begin I2C transmission
     Wire.write(SeeedOLED_Data_Mode);            // data mode
     unsigned char i=0;
     for(i=0;i<8;i++)
     {
         Wire.write(BasicFont[C-32][i]);
     }
     Wire.endTransmission();                    // stop I2C transmission

}