Speicher wird knapp, Optimierungen gesucht

Hallo,

nach dem ich mich nun schon ewig mit meinen Programm rumquäle und versuche Speicher zu sparen, komme ich nun nicht weiter.

Das angehängte Programm ist in sich vollständig und wird fehlerfrei kompiliert und auch ausgeführt.

Allerdings bin ich bei 31966 / 32256 byte - für Arduino Uno kompiliert, und das soll auch aus Platzgründen so bleiben, am liebsten wäre es mir, am Ende passt es in einen Nano (328).
Es müss(t) aber noch einige Sachen rein, dafür ist nur im Moment kein Platz.

Nun die Frage an die Profis unter euch, wer hat noch Tipps für mich?

  • Die enthaltenen Funktionen sollten erhalten bleiben
  • Der Code sollte hinterher nicht aussehen wie eine ASCII-Tabelle (für so einen Anfänger wie mich)

An alle, der Code darf frei verwendet werden, vielleicht findet ja jemand noch was nützliches darin.

Primär sind hier Funktionen drin für Onewire-Temperatur, MQTT, Ethernet, I2C - die mit openHAB und Mosquitto als MQTT-Broker zusammenspielen.

Vielen lieben Dank, an jeden der mal drüber schaut und konstruktiv helfen kann.

arduino_forum_source_01.ino (29.5 KB)

Was spricht gegen einen anderen Prozessor?
Wieviel Speicher bräuchtest du denn noch?

FlyingEagle:
... und versuche Speicher zu sparen, ....

Mir ist die Serial.print()-Orgie ab Zeile 431 aufgefallen(Du hast nach meinem Eindruck auch sonst viele Serial.print()s drin).

Meiner Erfahrung nach kosten viele Serial.print()s reichlich Speicher kosten. Kannst Du evtl. die Texte von dort in den Flash verlagern und durch ein passendes Konstrukt mit einer Serial.print()-Anweisung zurecht kommen?

Gruß

Gregor

Der Code sieht sehr schön aus, stilistisch und inhaltlich, viel Optimierungspotential kann ich da leider nicht finden, abgesehen von Kleinigkeiten (switches, String) :frowning:

Vermutlich wird der meiste Speicher von den Bibliotheken verbraten?

Was spricht gegen einen anderen Prozessor?
Wieviel Speicher bräuchtest du denn noch?

Ich habe Halterungen sowohl für das angesprochene i2c-Zeugs als auch den Uno, die sind gleich groß und sollen als Stapel übereinander montiert werden. Die i2c-Platinen hätten nen Steckplatz für einen Nano :wink:
Aber mit dem Uno könnte ich zur Not leben.
Größer wäre nicht so optimal.

Meiner Erfahrung nach kosten viele Serial.print()s reichlich Speicher kosten.

Die Serials raus bringen "nur" 1K. Und ein wenig Debug, wenn irgendwas nicht geht wäre schon nicht schlecht. Hatte schon überlegt nur mit ner Art Kennziffern zu arbeiten, dann müsste ich mir aber einen Parser auf PC-Seite bauen, der mir das dann wieder "übersetzt".
Allerdings blieben die Serials dennoch und nur die zeichenketten würden ggfs. kleiner.

Kannst Du evtl. die Texte von dort in den Flash verlagern und durch ein passendes Konstrukt mit einer Serial.print()-Anweisung zurecht kommen?

Ich dachte mit F() und PROGMEM das getan zu haben.

Der Code sieht sehr schön aus, stilistisch und inhaltlich, viel Optimierungspotential kann ich da leider nicht finden,

Das ist schön zu hören, aber auch schade :slight_smile:

Vermutlich wird der meiste Speicher von den Bibliotheken verbraten?

Das mag sein, aber ich bin leider nicht in der Lage die vielleicht für mich nur relevanten Sachen rauszunehmen und ggfs. durch Assembler oder durch eigene Konstrukte zu ersetzen. :confused:

Ich hatte angenommen, bei den strcat z.b. noch ein wenig sparen zu können, hatte das zwar weitgehend mal gegen s(n)printf ersetzt, das machte es nur noch größer.

Mir ist auch etwas aufgefallen, um Zeile 173 rum. dort steht:

MAC2String(ethernet_mac, cStringMac);
 Ethernet.begin(ethernet_mac); // DHCP // , ethernet_lip, ethernet_dns, ethernet_gateway, ethernet_netmask);

Sketch kompiliert:
Program size: 31.966 bytes (used 99% of a 32.256 byte maximum) (5,16 secs)
Minimum Memory Usage: 1736 bytes (85% of a 2048 byte maximum)

ändere ich das in:

Ethernet.begin(ethernet_mac); // DHCP // , ethernet_lip, ethernet_dns, ethernet_gateway, ethernet_netmask);
 MAC2String(ethernet_mac, cStringMac);

Sketch kompiliert:
Program size: 31.978 bytes (used 99% of a 32.256 byte maximum) (5,21 secs)
Minimum Memory Usage: 1736 bytes (85% of a 2048 byte maximum)

Das ist bspw. etwas, was ich so gar nicht verstehen kann.

Oder bei den Vergleichen in der mqtt_callback, da stehen recht lange Zeichenketten, da dachte ich evtl. auch an Pointer auf diese und Mehrfachverwendung der Zeichenketten, aber habe dafür keine Lösung gefunden.

Zum Thema Switches: Alternative?

Zum String: Ich habe sie weitgehend draußen, habe aber noch eine Function drin als String, da Serial mir sonst mein Byte-Array nicht als ASCII-Werte anzeigt.

Überhaupt so bei den Konvertierungsfunktionen im Pragma Allgemeine Funktionen, da hoffte ich auf ein wenig Potenzial.

Bezügl. noch erforderlichem Speicherplatz, sagen kann ich das nicht, wollen würde ich gern in etwa das.
(Das ist nur eine Brain-flash-liste, die mir so während des Codens in den Sinn kam. Über Sinn und Unsinn der einzelnen Punkte habe ich noch nicht abschließend entschieden.):

  • Abfrage via MQTT von GPIO-Ports und einzelnen Pins ==> PININ
  • LED-Status überarbeiten
  • LED 13 auf anderen GPIO setzen mit eigener LED?
  • ext. Taster am Arduino als Testknopf, ggfs. mit long-press-erkennung oder über 2. button
  • per mqtt kompletten reboot auslösen
  • Idee: DHCP o. feste ip "irgendwie" von außen konfigurierbar machen
  • via mqtt einstellungen schicken, ins eeprom speichern
  • wenn dort daten da sind entsprechend starten, ggfs. über o.g. buttons die werte setzen
  • wenn der button gedrückt, dann dhcp bspw.
  • ggfs auf mac erweitern, starten mit einheitlicher standard-mac, dann wechseln via mqtt und eeprom
  • ggfs. konfigurationsoptionen auch via serial coden
  • Broker IP + Zugangsdaten müsste man auch tauschen können
  • zumindest via serial

ja, du hast alle Serial.print Texte mit F() ins Flash verschoben, aber das Flash ist ja nun auch voll.
Wenn du mit den Serial.print 1k einsparen kannst, dann ist das 1k mehr Platz...
Mir fiel auch auf, dass du viele Textstrings im Flash hast, wie "AAAA/BBBB/CC/ARDUNO/pub/" wenn du die geschickt aus einzelnen Fragmenten zusammenbastelst, kannst du auch nochmal 100byte sparen.
Dein Programm ist ja schon recht kompakt aufgebaut. Den einen Punkt, an dem du plötzlich ein paar kbyte Flash freibekommst, gibts nicht.

Ausser, du gehst an die Bibliotheken ran.

Ja genau die Textstrings sind es, die ich meine, wie genau stellst du dir das vor?
Ich habe keine Idee wie man da noch optimieren könnte.
Ich hatte anfangs, oben bei den Topic-Variablen bspw. die in gemeinsam genutzte Elemente und zusätzliche Elemente unterschieden und in entsprechenden Variablen gespeichert:
bspw:
topicAll = "AAAA/BBBB/CC"
topic2 = "ARDUNO/"
topic3 = "pub"
und dann den Quatsch per weiteren strcat vor Ort der Verwendung zusammengebaut.
Das habe ich dann rausgemacht und gegen längere Textstrings getauscht, mit dem Erfolg etwas Speicher zu gewonnen zu haben.

Hab mal Spaßenshalber nun alle Serials (107 Stk.) rausgenommen:
Program size: 29.032 bytes (used 90% of a 32.256 byte maximum) (4,97 secs)
Minimum Memory Usage: 1557 bytes (76% of a 2048 byte maximum)
gegenüber mit Serials:
Program size: 31.966 bytes (used 99% of a 32.256 byte maximum) (5,16 secs)
Minimum Memory Usage: 1736 bytes (85% of a 2048 byte maximum)

Keine Frage, da ist Potenzial, aber ich würde nur zu ungern drauf verzichten.
Würde es etwas bringen die Serials weitgehend durch nen Funktionsaufruf zu ersetzen und in einer Methode zu kapseln? Wie würde dann die Parameter-Definition aussehen? Wie könnte man Formatangaben mit übermitteln (BIN, HEX, DEC)?

hi,

alternativ:

ich hab' schon mal einen 2560er auf einer uno-platine verbaut gesehen. hat vielleicht jemand einen link, finde ihn auf die schnelle nicht.

schau Dir mal die wemos d1 an. ist ein esp8266 auf einer uno-platine. keine ahnung, ob Du da Deinen sketch anpassen müßtest.

gruß stefan

Ein paar Bytes bringt es auf alle Float-Variablen und Berechnungen zu verzichten. Du kannst auf den Nano den Uno-Bootloader spielen oder gleich per ISP programmieren.

Jeder Aufruf eines Unterprogramms kostet Speicher. Deshalb dürfte das Zerlegen längerer Strings eher mehr Speicher kosten (beim Aneinanderhängen der Teile), als an Literalen eingespart werden kann.

Zu den Switches: in get_ethernet_main_states() und i2c_error_to_string() könnte stattdessen ein Array verwendet werden - das könnte sogar die ganze Funktion ersetzen.

Es gibt einen kleinen 1284p Arduino.

http://www.ebay.de/itm/Mighty-Mini-ATMega1284p-compatible-with-Arduino

DrDiettrich:
Jeder Aufruf eines Unterprogramms kostet Speicher. Deshalb dürfte das Zerlegen längerer Strings eher mehr Speicher kosten (beim Aneinanderhängen der Teile), als an Literalen eingespart werden kann.

Das war/ist ja das was ich meinte mit den Textstrings, eigentlich, so verstehe ich es zumindest, dürfte das jeweilige Serial.print ja doch auch nur ein Funktionsaufruf sein. Es wird ja wohl nicht an jeder Stelle der komplette Ausgabe-code eingefügt. D.h. es würde nur bedingt Speicher sparen.

DrDiettrich:
Zu den Switches: in get_ethernet_main_states() und i2c_error_to_string() könnte stattdessen ein Array verwendet werden - das könnte sogar die ganze Funktion ersetzen.

Ich habe 4 switches im Code, mir ist nur gerade schleierhaft wie ich das in Arrays packen soll, zumal die nicht immer akurat fortlaufend sind die Werte.

Whandall:
Es gibt einen kleinen 1284p Arduino.

Definitiv nicht uninteressant, aber auch preislich ne kleine Nummer, da ich mehrere davon bräuchte.
Pinkompatibel zum Nano ist er auch nicht, daher auch keine z.B. Ethernet-Shield-Nutzung.
Vielleicht lasse ich meinen Wunschzettel, auch Wunschzettel sein und mache erstmal so weiter, die Hauptfunktionen gehen ja erstmal.
Wäre aber dennoch schade :slight_smile:

hi,

und der wemos wäre nichts? 6,75 versandkostenfrei. läuft mit 10facher taktfrequenz des arduino und hat 4M flash. ist pinkompatibel.

gruß stefan

Eisebaer:
...

Interessante Eckdaten, aber, ich brauche kein WLAN, und das wichtigste, die Dinger laufen mit 3.3V.
Der Rest meiner Materie aussenrum läuft mit Standard 5V.

hi,

ja, das ist ein kriterium (3,3V, nicht das wlan, das wär' egal).

den 2560 auf dem uno-großen board find' ich nirgends mehr, aber ich glaube mich zu erinnern, daß der schweineteuer war...

gruß stefan

... und ich werde wohl ein paar davon brauchen ...

kann man das WLAN hardwareseitig im zweifel deaktivieren, das der nichts funkt?

Du meinst bestimmt den "Mega2560-CORE mini" bzw "Meduino".
Sieht auf jeden Fall interessant aus, auch wenn etwas teurer, müsste ich im Zweifel eine neue Aufnahme 3D-Drucken lassen. Aber so wie es aussieht, gehen Standardshields nicht, Ethernet bräuchte ich auf jeden Fall.

Aber erstmal schauen was mit dem Uno noch geht.

Schau dir doch mal den Teensy 3.x an.
256k Flash, 64k Ram.
Und dabei etwas kleiner als ein Nano.

guntherb:
Schau dir doch mal den Teensy 3.x an.

Auch interessant, aber nur 5V "tolerant" für INPUT, OUTPUT ist weiterhin nur 3,3V ... dann müsste man noch was 'Levelshiftiges' dazu stricken ...

Wie schwierig ist es denn, auf dem Uno Board den Controller auszutauschen?

Ich könnte mir ein Adapter-Platinchen vorstellen, das in den IC-Sockel eingesteckt wird. Die überzähligen Pins müssen ja nicht unbedingt herausgeführt werden, wenn es nur um Speicher geht.