Как уменьшить размер бинарика?
- Войдите на сайт для отправки комментариев
Пнд, 11/03/2013 - 11:42
Я счастливый владелец Seeduino Film со всеми прибабасами. Но у меня проблема в том что 14 кило уже не хватает - как оптимизировать размер ? Может есть упаковщик типа UPX? Поменять IDE ? Отказать от библиотек: только транзакции в только хардкор?
В первую очередь нужно оптимизировать код.
Ну я понял что String дает +2 килобайта
Но без int float и char - вообще никак.
Процедуры делать отдельными - тоже не сильно уменьшает размер, а если процедура используется только в 2х местах то проше - копипаст - меньше обьем дает.
Процедуры делать отдельными - тоже не сильно уменьшает размер, а если процедура используется только в 2х местах то проше - копипаст - меньше обьем дает.
Вызов функции - это пара десятков байтов. Любая нетривиальная функция - это полсоотни байтов как минимум. Так что то, что вы называете копипастом будет иметь скорее обратный эффект.
Хотите действительно сократить объем скетча - переходите от вызовов библиотечных функций (универсальных и поэтому имеющих очень много лишнего) к прямой манипуляции регистрами микроконтроллера - на небольших скетчах можно добиться двух-трехкратного сокращения кода.
А вообще - вопрос ни о чем. Задача оптимизировать код. Сам код - не известен. Какие библиотеки используются - не ведомо (а ведь может к примеру использует шилд какой-то у которого библиотека много жрет и замена шилда на более интелектуальный поможет. Скажем переход од enc28j60 на wiznet). Может используются програмные PWM/SPI/Serial и нужен переход на их hardware вариант.
Может код пилить нужно, может от работы со строками отказыватся (они ой как любят память жрать, особенно если их раскидывать по всему коду), а может реально "предел". Всегда можно нафантазировать фичей больше чем потянет контроллер.
Может от ардуино библиотек прийдется отказыватся (за простоту нужно платить) и переходить на чистый AVR. А может желаний настолько много что только переход на ASM поможет (что-бы контролировать каждый байт).
Если бы существовала методика оптимизации любого произвольного кода, которую можно посоветовать "не глядя на конкретную задачу" - она уже была-бы встроенна в компилятор (и поверте там уже куча такого встроенно, все что можно оптимизировать по формальным признакам - уже есть :)
А еще можно почитать про опции компиляции avr-gcc (его ArduinoIDE использует в качестве компилятора), возможно через них компиляруя руками выйдет "отключить что-нибудь не нужное в вашем случае" и за счет этого уменьшить код.
В моем случае есть 3 библиотеки которые используют wire.h и arduino.h + много вывода в serial - как это оптимизировать?
Не глядя в код, тут ничего не сказать.
Как минимум, покажите код.
В моем случае есть 3 библиотеки которые используют wire.h и arduino.h + много вывода в serial - как это оптимизировать?
Никак.
Вам уже вроде объяснили что "общих рецептов" не бывает. А показывать код - вы не хотите. Значит либо сами что-то придумывайте, либо покупайте более жирный камень.
Покажете код - может кто-то что-то и подскажет. А может и нет. Но без кода - точно шансы нулевые.
#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); }Вот такой код.
Так сколько килобайт не хватает?
14кб , seediono film она как Arduino pro mini w/ AT 168
Так вы можете сказать сколько килобайт НЕ ХВАТАЕТ ? Не сколько килобайт в дуине всего , а какая разница между тем что получается при компиляции и 14-тью килобайтами.
Как минимум, полезно весь статический текст оставить в флэш-памяти,
т.е. вместо:
Serial.print("HEADING:");писать
Serial.print(F("
HEADING:"))На первый взгляд тупым убиранием ненужных println, вместо которых добавляется "\n" dв соответвующую строку Serial.print можно съекономить байт 400. Дальше - нужно смоттреть на скомпилированную программу, настройки компилятора и реализацию библиотек.
Вы меня заинтересовали - выложите, плз, ссылки на все используемые библиотеки, вопрос стал делом спортивного интереса.
Отказатся от бутлодера- занять его место кодом - ещё 2 килобайта...
Поставить 328....
https://github.com/saintbyte/SeeedOLED - SeeedOLED.h
http://code.google.com/p/motionframe/source/browse/#svn%2Ftrunk%2F%20motionframe%2Flibraries - HP03M.h,MMA7660FC,W25Xnn
http://www.seeedstudio.com/wiki/File:Digital_Compass.zip HMC5883L
В общем путем небольших телодвижений у меня на настоящий момент размер скетча уменьшился до 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.
Выложи и я загитую =) Или сразу загитуй а =)
Не, гитовать это не надо. Это в данном случае такие удлвки полезны, а в общем они уменьшают читаемость и структурную целостность.
Вот эту функцию добавил в 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 }