Forum: Mikrocontroller und Digitale Elektronik ATMega Flash wird langsam knapp. Upgrade o. Plattformwechsel?


von Felix N. (felix_n888)


Lesenswert?

Hallo liebe Community,

Ich würde gerne mal eure Meinung hören. Ich programmiere seit letzten 
Jahr Oktober 2018 ein Aquarium Controller.


Da mein Projekt ständig weiter entwickelt wird, wird nun auch langsam 
der Programmspeicher meines Mikrocontrollers knapp. Hatte damals schon 
den ATMega644 gegen ein ATMega1284P ausgetauscht. Da die 64K des 644 
voll waren, nun der ATMega1284P hat 128K Flash und 16K SRAM.

Im Moment sieht es bei mir so aus das ich 100K Flash benutze und 7Kb 
SRAM. Von den 128K gehen noch 4K für den Bootloader runter. Mein Projekt 
ist jedoch noch nicht fertig und ich habe noch einige Sachen die ich 
umsetzten möchte.

Nun für ein Funktionsfähiges Menü verbrauche ich ungefähr 10-15KB Flash, 
RAM ist immer Unterschiedlich. Ein großer Teil des Flash Speicher geht 
für die Text drauf die ich auf dem ILI9341 TFT Display darstelle.

Ich stelle mir nun aber die Frage was mache ich wenn der Speicher 
endgültig voll ist? Es gibt noch den ATMega2560 der den doppeln Speicher 
aufweist jedoch dafür nur den halben RAM von ATMega1284P. Naja und ist 
halt SMD aber das wäre das kleinste Problem.

Oder vielleicht ein kompletter Umstieg auf ein ganzen anderen Prozessor 
wie zum Beispiel den STM32 den gibt es ja bis 2MB Flash und 512kB RAM. 
Aber mal ganz abgesehen das ich noch keinerlei Erfahrung mit dem STM32 
habe.

Das habe ich so im Moment an Peripherie angeschlossen:
- TFT Display(ILI9341)
- SD Karte(FatFs)
- Netzwerkchip ENC28J60
- Externes EEPROM
- RTC(MCP7940M)
- Rotary Encoder(Bedienung)

Geplant ist noch:
- Akustischer Signalgeber
- Fehlerspeicher(SD Karte)
- SMTP(nicht sicher)
- USV(nicht sicher)

Was würdet ihr machen wenn es bei euch so wäre. Upgrade auf ATMega2560 
oder kompletter Wechsel auf einen Prozessor zb. STM32?

Schönen Sonntag noch
Lg

von micha (Gast)


Lesenswert?

Wenn du eh eine SD-Karte planst eventuell Texte auslagern?  (Oder extern 
flash) Kannst dann immerhin auf der bekannten Plattform bleiben

von Georg A. (georga)


Lesenswert?

Ist denn der Stromverbrauch oder besondere Echtzeitfähigkeit ein 
wichtiges Kriterium? Falls nicht, hätte ich da schon einen Raspi Zero W 
genommen ;)

von Philipp K. (philipp_k59)


Lesenswert?

Da müsste man den Code sehen.. wenn das so schnell voll ist für so eine 
einfache Aufgabe muss da wohl die Arduino IDE am Werk sein?

Bei Arduino und anderen normalen Librarys kann man eine Menge 
optimieren/abspecken..

EDIT: das meisste müsste der ENC28J60 ausmachen.. da sollte man 
heutzutage lieber den W5100 oder nen ESP8266 nehmen. ( beim ENC baust Du 
die kommunikation im Atmega zusammen, beim w5100 macht das der w5100 
schon selbst)

Welche IDE wird denn benutzt?

: Bearbeitet durch User
von Frank K. (fchk)


Lesenswert?

Mein Vorschlag:

https://www.olimex.com/Products/OLinuXino/A64/A64-OLinuXino/open-source-hardware

Das erschlägt sehr viel von dem, was Du selber mühselig programmieren 
musstest:
- TFT Display, wahlweise mit Touch direkt anschließbar, z.B. das hier
https://www.olimex.com/Products/OLinuXino/LCD/LCD-OLinuXino-7/open-source-hardware

- SD-Karte wird direkt vom Linux unterstützt
- Gigabit Ethernet ist direkt da.
- EEPROM brauchst Du wahrscheinlich nicht mehr, ist aber leicht 
anschließbar
- RTC ist bereits drin
- Encoder sollte kein Problem sein, aber den könntest Du eventuell mit 
Toucheingabe besser in Software implementieren
- Akustischer Signalgeber: Audio 3.5" Stereo-Klinke vorhanden, Beeper 
kann einfach über GPIO angeschlossen werden
- SMTP: installier einfach einen postfix auf dem Linux, und gut ist.
- USV: LiPo-Akku anschließbar.

Du wirst das meiste sofort da haben, ohne groß basteln zu müssen.

fchk

PS: Einen Pi würde ich nicht nehmen, da verlierst Du einfach zu viele 
IOs, wenn Du ein RGB-TFT anschließen willst. Die Peripherie ist beim PI 
viel schlechter als bei Alternativprodukten.

: Bearbeitet durch User
von Ver Wunderter (Gast)


Lesenswert?

Frank K. schrieb:
> Mein Vorschlag:

Booaaahhhh, einen Quad Core für die Aquariumsteuerung.

Das ist wirklich die optimale Lösung!

von Frank K. (fchk)


Lesenswert?

Ver Wunderter schrieb:
> Frank K. schrieb:
>> Mein Vorschlag:
>
> Booaaahhhh, einen Quad Core für die Aquariumsteuerung.
>
> Das ist wirklich die optimale Lösung!

Ja und? Für die AVR-Lösung wird der Fragesteller sicher insgesamt mehr 
bezahlt haben als die 36 Oiro, die Olimex für das Board aufruft.

fchk

von Crazy Harry (crazy_h)


Lesenswert?

Wie wäre denn ein XMega384? Neben mehr Flash gibt dazu bis zu 60MHz 
(inoffiziell 64MHz) und zusätzliche Ports, SPIs, I2Cs, UARTs, .....

von Felix N. (felix_n888)


Lesenswert?

Hallo,

micha schrieb:
> Wenn du eh eine SD-Karte planst eventuell Texte auslagern?

SD Karte ist schon drin, habe ich auch schon gedacht jedoch kann man die 
SD Karte aus dem System entfernen um zb. den Fehlermeldungen am PC 
auslesen zu können. Die Grundfunktionen sollen erhalten bleiben. Daher 
fiel diese Auswahl weg.

Philipp K. schrieb:
> Arduino IDE am Werk sein?

Nein, programmiere das Ding in Atmel Studio 7 in C.

Philipp K. schrieb:
> Bei Arduino und anderen normalen Librarys kann man eine Menge
> optimieren/abspecken..

ENC28J60 -> Eine Library von Tuxgraphics welche vom Inhalt her größten 
Teils auf der Arduino EtherShield und EtherCard Lib basiert.

ILI9341 -> Hat Ähnlichkeit mit der Adafruit Lib

SD Karte -> FatFs von ELM ChaN

Rotary Encoder -> kommt aus diesen Forum.

Andere Sachen wie Kommunikation wie I2C, SPI, USART, EEPROM sind selbst 
geschrieben

Philipp K. schrieb:
> das meisste müsste der ENC28J60 ausmachen

Ja ein großen Anteil macht der ENC aus mit der SD Karte zusammen. Der 
ENC28J60 ist halt im rohen zustand Dumm wie Brot. TCP/IP HTTP ist halt 
in Software gelöst.

Philipp K. schrieb:
> lieber den W5100 oder nen ESP8266 nehmen.

Muss mal schauen ob es den W5100 in einzel Ausführung gibt ohne Arduino 
Shield.

Frank K. schrieb:
> Das erschlägt sehr viel von dem, was Du selber mühselig programmieren
> musstest:

Ich hatte am Anfang ein PI in der Hand gehabt, habe mich letzte endlich 
aber für den AVR entschieden da dich das ganze gerne selber "klassisch" 
programmieren wollte.

Lg

von W5100Usa (Gast)


Lesenswert?

Felix N. schrieb:
> Muss mal schauen ob es den W5100 in einzel Ausführung gibt ohne Arduino
> Shield.

Gibt es. Ganz handlich ...

https://www.ebay.de/itm/Mini-W5100-Arduino-LAN-Ethernet-Shield-Network-Module-Board-TCP-IP/223614689695?hash=item341079619f:g:6~wAAOSw241YXMLw

von Felix N. (felix_n888)


Lesenswert?

W5100Usa schrieb:
> Gibt es. Ganz handlich ...
>
> Ebay-Artikel Nr. 223614689695

Ah okay du warst schneller als ich :) Danke

Werde ich mal bestellen und ausprobieren.

Crazy H. schrieb:
> Wie wäre denn ein XMega384?

Hmm, hörst sich ja auf im ersten Moment nicht schlecht an, weißt du ob 
es möglich ist mit bestehen ATMega Kenntnissen den XMega programmieren 
zu können. Oder ist der von der Struktur komplett anderes?

Mfg

von Stefan F. (Gast)


Lesenswert?

Eventuell macht hier ein Wechsel auf ein ganz anderes Kaliber Sinn: 
Raspberry Pi

Wobei ich mich schon frage, wie man 128kB für ein Aquarium voll bekommt. 
Das muss man erstmal schaffen.

von W5100Usa (Gast)


Lesenswert?

Felix N. schrieb:
> Ah okay du warst schneller als ich :) Danke

Wenn du erst mal die Last des Ethernet- und TCP-Handling vom
ENC weg hast wirst du schon mal eine ganze Menge Speicher
gewonnen haben.

Und falls du bis jetzt Arduino-Klassen verwendet hast und
auf "normale" Programmierung umsteigst noch mal eine ganze
Menge.

ATXmegas sind meines Wissens nach nicht vom Arduino
Environment unterstützt.

von W5100Usa (Gast)


Lesenswert?

Felix N. schrieb:
> ob
> es möglich ist mit bestehen ATMega Kenntnissen den XMega programmieren
> zu können. Oder ist der von der Struktur komplett anderes?

Die Register heissen ein bisschen anders und es sind viel
mehr, aber sonst kein grosser Umschwung.

von Felix N. (felix_n888)


Lesenswert?

W5100Usa schrieb:
> Wenn du erst mal die Last des Ethernet- und TCP-Handling vom
> ENC weg hast wirst du schon mal eine ganze Menge Speicher
> gewonnen haben.

Ich habe kurz die Netzwerk Initialisierung und Anfragen auskommentiert.

Mit ENC verwende ich Aktuell:
Program Memory Usage   :  99750 bytes   76,1 % Full
Data Memory Usage   :  7001 bytes   42,7 % Full

Und ohne:
Program Memory Usage   :  85646 bytes   65,3 % Full
Data Memory Usage   :  5746 bytes   35,1 % Full

W5100Usa schrieb:
> Und falls du bis jetzt Arduino-Klassen verwendet hast und
> auf "normale" Programmierung umsteigst noch mal eine ganze
> Menge.

Ich nutze kein Arduino IDE, Ich habe mit Header und C Dateien.

W5100Usa schrieb:
> ATXmegas sind meines Wissens nach nicht vom Arduino
> Environment unterstützt.

Muss es ja auch nicht. Ich kann den ATXMega in Atmel Studio ja als 
Prozessor auswählen.

Lg

von Stefan F. (Gast)


Lesenswert?

Wenn du auf einen ESP8266 oder ESP32 wechselst, hast du Flash ohne Ende 
und das Netzwerk Interface auch schon dabei. Allerdings sind deren I/O 
Pins nicht ganz so flexibel einsetzbar, wie du es von deinem AVR gewohnt 
bist.

Eine Kombination aus einem AVR für die eigentliche Steuerung + einem ESP 
8266 für das Benutzerinterface wäre vielleicht eine praktikable Option 
für Dich, wenn du bei Mikrocontrollern bleiben möchtest.

von W5100Usa (Gast)


Lesenswert?

Felix N. schrieb:
> Ich habe kurz die Netzwerk Initialisierung und Anfragen auskommentiert.

Ob du damt alles wegbekommst? Dazu müsste dein Linker schon
sehr intelligent sein alle unbenutzten Funktionen zu detektieren
und herauszunehmen.

Ich denke um zu einem genaueren Ergebnis zu kommen müsstest du
wirklich die Ethernet- und TCP Lib voll herausnehmen.

Aber es käme auch Code dazu: die W5100 Einbindung kostet
natürlich trotzdem was an Programm-Speicher und RAM ....

von Peter D. (peda)


Lesenswert?

Felix N. schrieb:
> Ein großer Teil des Flash Speicher geht
> für die Text drauf die ich auf dem ILI9341 TFT Display darstelle.

Dann machst Du irgendwas grundlegend falsch.
Mußt Du wirklich ganze Romane an Text anzeigen?
Was belegen denn die vielen Zeichensätze allein?
In der Regel reicht ein Font in 3 Größen völlig aus.

von BerAVRter (Gast)


Lesenswert?

> Ich habe kurz die Netzwerk Initialisierung und Anfragen auskommentiert.
>
> Mit ENC verwende ich Aktuell:
> Program Memory Usage   :  99750 bytes   76,1 % Full
> Data Memory Usage   :  7001 bytes   42,7 % Full
>
> Und ohne:
> Program Memory Usage   :  85646 bytes   65,3 % Full
> Data Memory Usage   :  5746 bytes   35,1 % Full

Sehr gut. Nun machst die selbe Datenerhebung für jeden anderen 
Teilbereich deines Aquariumprogramms auch und führst Buch.

(wenn deine FW sauber modularisiert ist, solltest du bis runter auf eine 
"leere" main(..)-Funktion gelangen. Wobei: man kann alles 
übertreiben...)

Dann steckst Du Hirnschmalz erstmal in die 3 Speicherintensivsten 
Bereiche, mit Fokus auf Verkleinerung.

Danach vergleichst Du die Bereiche untereinander und suchst 
Code-Doppelspurigkeiten. Da wo's nur ähnlich ist arbeitest solange daran 
rum bis es gleich wird. Dann ausfaktorieren .

Wenn Du echt viele Präsentationstexte (Anzeige) hast, überlege ob ALLE 
diese in was anderem als ASCII codierbar wären. Schliesslich belegt 1 
Buchstabe 1Byte, ASCII hat aber nur 127 wovon du auch nicht alle 
benötigst.
Code welcher das dann handhaben würde, müsste dann aber die 
Platzersparnis nicht auffressen...
(ich habe in Konditional geschrieben...)

Viel Erfolg!

von Rudolph R. (rudolph)


Lesenswert?

Wenn Du ein intelligentes Display verwendest hast Du plötzlich eine 
Menge Speicher über, Touch läuft dann nebenbei und Anzeige und Bedienung 
werden viel flüssiger, weil die Bildrate sehr viel höher sein kann bei 
einem
Bruchteil an zu übertragenden Daten.

Sowas wie das hier:
https://www.matrixorbital.com/ftdi-eve/eve-bt815-bt816/eve3-43g

Das hat Zeichensätze eingebaut und einen FLASH Chip den man mit u.a. 
Bildern, UTF-8 Zeichensätzen und Texten füllen kann.

Die Kapazitiv-Touch Version habe ich ausgewählt, weil Resistiv-Touch im 
Vergleich einfach nur eklig ist.
Resistiv-Touch werde ich mir hoffentlich nie wieder antun müssen.

Die haben eine SPI Schnittstelle die mit 3,3V Pegeln läuft und benötigen 
ein 3,3V Netzteil, je größer das Display, desto mehr Strom.
Das sind so ~200mA bei 3,5", ~300mA bei 4,3", ~500mA bei 5" und ~750mA 
bei 7".

Ja, die Größen habe ich alle schon mit AVR benutzt, bei 40+ Bildern pro 
Sekunde hat der Controller auch noch nicht wirklich was zu tun.
Aber sowas wie eine Animation für z.B. eine Pumpe läuft schön flüssig, 
so mit Drehung des Bildes durch den Grafik-Chip.

von Peter D. (peda)


Lesenswert?

BerAVRter schrieb:
> Sehr gut. Nun machst die selbe Datenerhebung für jeden anderen
> Teilbereich deines Aquariumprogramms auch und führst Buch.

Man könnte aber auch die Größe der einzelnen Programmteile im MAP-File 
ablesen.

von Stefan F. (Gast)


Lesenswert?

Ein Klassiker: Wenn du Strings einfach "normal" (wie beim PC) in 
Anführungsstriche schreibst, dann belegen sie doppelt Speicher, nämlich 
Flash und RAM. Wenn du die gleichen Strings in mehreren 
Quelltext-Dateien hast, dann wird auch Speicherplatz vergeudet.

Kennst du die Makros PSTR und PROGMEM?

von Frank K. (fchk)


Lesenswert?

Felix N. schrieb:

> Frank K. schrieb:
>> Das erschlägt sehr viel von dem, was Du selber mühselig programmieren
>> musstest:
>
> Ich hatte am Anfang ein PI in der Hand gehabt, habe mich letzte endlich
> aber für den AVR entschieden da dich das ganze gerne selber "klassisch"
> programmieren wollte.

Was heißt für Dich "klassisch"? Unter Unix haben schon Generationen vor 
Dir in C und C++ entwickelt. Und solche Sachen wie TCP/IP, USB, 
Filesysteme usw. muss man heute nicht mehr selber entwickeln, das kann 
man ruhig einem Betriebssystem überlassen. Das ist jedenfalls der Weg, 
über den Du mit minimaler Arbeit das Maximum an Möglichkeiten bekommst.

Alternativ:
http://www.ti.com/tool/EK-TM4C1294XL

Da bekommst Du auch eine ganze Menge an Rechenleistung und Speicher, 
dazu 10/100 MBit Ethernet MAC+PHY im Chip, USB und was man sonst noch 
alles so braucht. Und dazu gibts ein schönes RTOS und eine umfangreiche 
Treiberbibliothek.

fchk

von Theor (Gast)


Lesenswert?

Hm. Wieviel Speicher belegen denn die Texte?

Es gibt Techniken um den Speicher dafür zu verringern. Angefangen von 
Kompression bis zur Zerlegung in kleinere Textbautsteine.
Ob sich das im konkreten Fall lohnt, hängt natürlich von der Menge an 
Text ab, denn im Austausch ist Code für die Dekompression bzw. das 
zusammensetzen der Textbausteine nötig.

Eine etwas schwieriger zu realisierende Möglichkeit ist, die Texte zu 
kürzen bzw. entfallen zu lassen. Schwieriger, weil es dazu nötig ist, 
gewisse Wünsche und Vorstellungen zu verändern. Dabei steht man sich 
mitunter selbst im Weg. :-)

von m.n. (Gast)


Lesenswert?

Theor schrieb:
> Eine etwas schwieriger zu realisierende Möglichkeit ist, die Texte zu
> kürzen bzw. entfallen zu lassen.

Werden denn überhaupt so viele Texte verwendet, bzw. können Deine Fische 
lesen?
Ich vermute eher, ungeschickte Programmierung uneinheitlicher Menüs 
benötigt zu viel Speicher.

Um nicht den µC komplett zu wechseln, würde ich Funktionen in einen 2. 
AVR auslagern und über IIC ankoppeln. Der Hauptprozessor erledigt dabei 
die Bedienung.
Genaueres kann man nur sagen, wenn man sieht, was jetzt vorhanden und 
wie es umgesetzt ist.

von Marco H. (damarco)


Lesenswert?

Es gibt auch neuere AVRs mit deutlich mehr Speicher. Sie lösen das 
Problem der Optimierung nur bedingt ;).

Im wirklichen Leben wäre das der Gau, da man sich im Vorfeld keine 
Gedanken über die richtige Plattform für sein Projekt gemacht hat.

Der ESP32 wäre die Lösung allerdings muss dein Code auch für ein OS 
geeignet sein. Das heißt sich mit Threads und einem völlig anderen 
Framework beschäftigen zu müssen.

Wie viel Aufwand es ist den Code auf einer anderen Plattform zum laufen 
zu bringen hängt von deinem Programmierstil ab.

von Erfahrener Entwickler (Gast)


Lesenswert?

Felix N. schrieb:
> Da mein Projekt ständig weiter entwickelt wird,

   [...]

> Das habe ich so im Moment an Peripherie angeschlossen:
> - TFT Display(ILI9341)
> - SD Karte(FatFs)
> - Netzwerkchip ENC28J60

Schau nach vorne, mach einen Plattformwechsel, aber richtig.

Vermutlich tust Du Daten loggen und die Daten irgendwie mit Netzwerk 
abrufbar machen oder irgendwohin speichern etc.

Es wird nicht lang gehen, und Du willst evtl. schöne Webseiten mit 
Messwerten etc. darstellen. Vielleicht soll das auch per MQTT etc. an 
einen Cloud-Hoster angebunden werden etc.

Tu' Dir den Gefallen und rüste auf. Ich vermute, es wird Dir weiterhin 
viel Spaß machen neue Funktionen einzubauen und auszuprobieren. Lass Dir 
den Tag von Kleingeistern nicht versauern. Die Zeit ist zu Schade, um 
sich mit Beschränkungen der Plattform rumärgern zu müssen.

  - Willst Du mehr in Richtung Netzwerk und Daten machen, nimm etwas
   in der Raspi-Klasse.

  - Wenn das Netzwerk wirklich nur ganz trivial bleiben soll, nimm
    einen richtig fetten Controller mit viel RAM und richtig Flash
    und mehr Bits.

Das Aquarium selbst benötigt so sehr viel mehr Energie und Wartung, da 
brauchst Du nicht am Controller sparen.

Nicht kleckern, sondern klotzen.

von Erfahrener Entwickler (Gast)


Lesenswert?

Felix N. schrieb:
> - SMTP(nicht sicher)

Ach, das hatte ich überlesen. Nimm einen Raspi. Die Wahrscheinlichkeit 
dass Du zwingend TLS brauchst, ist hoch.

von m.n. (Gast)


Lesenswert?

Erfahrener Entwickler schrieb:
> Das Aquarium selbst benötigt so sehr viel mehr Energie und Wartung, da
> brauchst Du nicht am Controller sparen.

Als ob der Preis des µC das Problem wäre ;-)

> Tu' Dir den Gefallen und rüste auf.

Ja was denn nun: aufrüsten oder umrüsten?

von Roland P. (pram)


Lesenswert?

Durch geschickte Programmoptimierungen kann man immer ein paar Bytes 
heraus schinden (z. B fixed point statt floating point nutzen)

Kann man die Texte oder Fonts komprimiert abspeichern? (z. B. nur 7 bit 
statt 8 verwenden, würde schon 12,5% sparen)

Hast du denn schon heraus gefunden, was den meisten Speicher braucht?

Gruß Roland

von Stefan F. (Gast)


Lesenswert?

Vielleicht hat er die Texte alle als Bitmap abgelegt.

Felix, bist du noch da? Ich glaube es wäre Sinnvoll, wenn du dich an der 
Diskussion beteiligen würdest.

Ansonsten können wir unser Urteil gegen Dich in Abwesenheit sofort 
fällen :-)

von c-hater (Gast)


Lesenswert?

Felix N. schrieb:

> Da mein Projekt ständig weiter entwickelt wird, wird nun auch langsam
> der Programmspeicher meines Mikrocontrollers knapp. Hatte damals schon
> den ATMega644 gegen ein ATMega1284P ausgetauscht.

Hossa, du schaffst es, 128k Flash und 16k SRAM mit der Steuerung eines 
Aquariums zu füllen?

Das ist doch nicht etwa ein Aquarium mit der Komplexität etwa von dem in 
Manly Beach, Sydney, NSW, Australia? Weil: ich kann mir kaum vorstellen, 
dass man sich SOWAS mal eben zu Hause hinstellen kann...

Wie auch immer: die Jungs dort kommen jedenfalls mit ca. 4k SRAM und 48K 
ROM klar. SPS und HMI zusammengezählt...

Mir scheint, du musst ein wenig an deiner Programmierkompetenz arbeiten, 
statt nach mehr Hardware zu schreien...

von Felix N. (felix_n888)


Angehängte Dateien:

Lesenswert?

W5100Usa schrieb:
> Ob du damt alles wegbekommst?

Nein ich habe die #includes ja nicht auskommentiert. Es sollte ja auch 
nur verdeutlichen das der ENC28J60 circa. 20Kbyte an Speicher frisst.

W5100Usa schrieb:
> die W5100 Einbindung kostet
> natürlich trotzdem was an Programm-Speicher und RAM ....

logisch.

Peter D. schrieb:
> Mußt Du wirklich ganze Romane an Text anzeigen?

Sorry, habe mich vertan ich die Texte liegen im RAM und nicht im Flash. 
Ich habe im Moment ja nur die Grundlegende Menüs fertig(Hauptmenü, 
Uhrzeit, Co2, pH Elektrode, SD Karte, Netzwerk und Lichtsteuerung) die 
Texte die da drin sind brauche ich so wie sie sind.

BerAVRter schrieb:
> Dann steckst Du Hirnschmalz erstmal in die 3 Speicherintensivsten
> Bereiche, mit Fokus auf Verkleinerung.

Ich weiß zb. das die ENC Lib auch UDP und NTP vorhanden sind und auch 
benutzt werde diese Funktionen mal entfernen da ich diese nicht verwende 
und auch nicht vor habe zu verwenden.

Rudolph R. schrieb:
> intelligentes Display

Hört sich auf jeden Fall interessant an, gut die FPS bei dem ILI9341 mit 
8 MHz Clock Speed sind jetzt nicht sonderlich hoch aber ich hatte bis 
jetzt noch nicht vor Grafiken zu verwenden. Aber werde ich auf jeden 
Fall im Hinterkopf behalten.

m.n. schrieb:
> Ich vermute eher, ungeschickte Programmierung uneinheitlicher Menüs
> benötigt zu viel Speicher.

Ich habe jetzt mal mein letztes Menü angehängt in diesem wird die 
Lichtsteuerung gehandelt.

m.n. schrieb:
> Um nicht den µC komplett zu wechseln, würde ich Funktionen in einen 2.
> AVR auslagern und über IIC ankoppeln. Der Hauptprozessor erledigt dabei
> die Bedienung.

Also würde ein Prozessor als Externer Speicher arbeiten? Würde SPI nicht 
besser sein weil dort höhere Geschwindigkeiten erreicht werden als max. 
400KHz bei I2C?

Erfahrener Entwickler schrieb:
> Die Wahrscheinlichkeit
> dass Du zwingend TLS brauchst

Ja deswegen steht da auch hinter (nicht sicher) ...

Roland P. schrieb:
> Hast du denn schon heraus gefunden, was den meisten Speicher braucht?

Ja der ENC und die SD Karte. Der ENC ca. 20Kb die SD ca. 15kb. Und der 
Rest geht wahrscheinlich auf die sprintf's drauf, habe gehört die sollen 
auch nicht so speicher Schonend sein.

Mfg

von Theor (Gast)


Lesenswert?

Ui.

Menues zu Fuß programmiert, wie es aussieht.
Das braucht natürlich Code noch und nöcher.

Und häufig doppelter Code. (Vermutlich z.T. durch die Optimierung 
abgefangen).

Und, wie zu vermuten war, reichlich mehrfache Kopieen von Texten.

Das sowas sich so (aus-)wächst ist bei einem Anfänger der dann noch 
dieses oder jenes Feature haben will normal (und auch nichts Schlimmes),
Aber, das macht die Entwicklung auf die Dauer immer schwieriger und 
schwieriger.


Also, falls Dein einziges großes Projekt (im Leben) überhaupt sein soll, 
dann lass es so und hör auf, wenn der FLASH-Speicher voll ist.

Ansonsten, gehe den nächsten Schritt zur Meisterschaft und überarbeite 
den Code gründlich.

von Stefan F. (Gast)


Lesenswert?

Felix N. schrieb:
> die Texte liegen im RAM und nicht im Flash

Warum? Schau Dir mal in der Doku der AVR C Library die Beschreibung der 
PSTR und PROGMEM Makros an. Ich habe dafür zwar ein -1 bekommen, aber 
ich bin zuversichtlich, dass du damit eine große Menge RAM frei bekommen 
wirst. Statt sprintf nutzt du dann sprintf_P.

Beitrag #5966040 wurde von einem Moderator gelöscht.
von Joachim B. (jar)


Lesenswert?

Felix N. schrieb:
> Von den 128K gehen noch 4K für den Bootloader runter.

Optiboot 512 Byte
https://github.com/Optiboot/optiboot

woher kommen deine 4K?

von Felix N. (felix_n888)


Angehängte Dateien:

Lesenswert?

Theor schrieb:
> Das sowas sich so (aus-)wächst ist bei einem Anfänger der dann noch
> dieses oder jenes Feature haben will normal (und auch nichts Schlimmes),
> Aber, das macht die Entwicklung auf die Dauer immer schwieriger und
> schwieriger.

Hallo,

Gut das ich ein guter Programmier bin habe ich nie gesagt, ich habe mir 
mein gesamtes Programmier wissen aus YouTube Videos, Code Schnippels, 
teilweise Bücher und Foren zusammen gesammelt. Habe Beruflich nix damit 
zutun. Nur Hobby.

Das was funktioniert hat habe ich am Anfang erst mal auch nicht mehr 
verändert. Warum? Es hat ja funktioniert da habe ich mir kein Kopf 
gemacht ob dieses nun maximal Optimiert ist oder nicht. Gut das mag 
vielleicht nach einer schlechten Einstellung klingen. So soll es aber 
nicht rüber kommen.

Ich bin jeder Zeit bereit aus meinen Fehlern zu lernen und diese zu dann 
zu verhindern/verbessern. Schließlich siehst Du den Code ja ganz anderen 
Augen als Ich, mag vielleicht an deiner Erfahrung liegen.

Stefanus F. schrieb:
> Warum? Schau Dir mal in der Doku der AVR C Library die Beschreibung der
> PSTR und PROGMEM Makros an. Ich habe dafür zwar ein -1 bekommen, aber
> ich bin zuversichtlich, dass du damit eine große Menge RAM frei bekommen
> wirst. Statt sprintf nutzt du dann sprintf_P.

Hi,

Wenn ich mich nicht irre werden Texts die man direkt übergibt im RAM 
ausgelagert. Ich kenne die PSTR und PROGMEM Makros. Ich weiß auch das 
Sie Texte in den Flash auslagern und so Platz im RAM Schaffen. Nur ich 
habe 16K RAM und belege 7K zurzeit. Wenn die die ganzen Texte in den 
Flash Schiebe wird mein Programmspeicher doch noch weniger. Und gerade 
der Flash Speicher ist ja mein Problem. Oder habe ich jetzt da was 
falsch verstanden?

MaWin schrieb im Beitrag #5966040:
> Poste mal bitte deinen Sourcecode

Hi, ich habe jetzt mal eine rar Datei angehängt wo mein ganzer Source 
Code drin ist.

Mfg

von leo (Gast)


Lesenswert?

Felix N. schrieb:
> Ich bin jeder Zeit bereit aus meinen Fehlern zu lernen

Ich hab nur kurz in den Anzeigecode geschaut, aber was mir sofort 
auffaellt ist der Mangel an Abstraktion bzw. die Wiederholung von (fast 
oder) identem Code, e.g.
1
  ili9341_fillrect(87, 138, 120, 20, BLACK);
2
  ili9341_combo(87, 140, WHITE, BLACK, 2, 3, 0, 0, "pH Stabil");

Das wird dann noch gemacht mit nur anderem Text. Du findest sowas zuhauf 
im Code.

Da kannst du genug einsparen.

leo

von Frank K. (fchk)


Lesenswert?

Und Du benutzt float. Das ist meistens vermeidbar.

Wenn ich Bruchteile von Volt messen will, dann nehme ich einfach die 
passende Einheit. Nicht Volt, sondern mV oder uV. Zack, schon kann ich 
mit Ganzzahlen rechnen. Floats brauchst DU nur, wenn Du einen hohen 
Dynamikbereich brauchst, d.h. gleichzeitig sehr kleine und sehr große 
Zahlen und dazwischen 10 oder mehr Zehnerpotenzen.

Ohne float wird auch stdio sehr viel kleiner.

Das ist mir nach 30s aufgefallen.

Auf dem vomn mir vorgeschlagenen Olimex-Board wäre das völlig egal. Da 
brauchst Du Dich auch nicht um Menüs oder Strings im ROM zu kümmern. Als 
Programmierumgebung nimmst Du Qt, das nimmt Dir alles ab.

In der richtigen Welt würde niemand mehr den von Dir gewählten Weg 
nehmen. Zu viele Einschränkungen, zu aufwändig zu programmieren, zu 
aufwändig zu warten. Schlicht zu teuer in der Entwicklung.

fchk

von Frank K. (fchk)


Lesenswert?

Felix N. schrieb:

> Wenn ich mich nicht irre werden Texts die man direkt übergibt im RAM
> ausgelagert. Ich kenne die PSTR und PROGMEM Makros. Ich weiß auch das
> Sie Texte in den Flash auslagern und so Platz im RAM Schaffen. Nur ich
> habe 16K RAM und belege 7K zurzeit. Wenn die die ganzen Texte in den
> Flash Schiebe wird mein Programmspeicher doch noch weniger. Und gerade
> der Flash Speicher ist ja mein Problem. Oder habe ich jetzt da was
> falsch verstanden?

Die Texte sind doch sowieso im Flash. Müssen sie auch. Von wo anders als 
auch dem Flash sollen sie denn nach dem Einschalten herkommen? Klar, aus 
einem .data-Segment, das von der Compiler-Runtime noch vor main() ins 
RAM kopiert wird. Und DAS ist vermeidbar.

Ja, nun hast DU auch eine Architektur (AVR) gewählt, wo Programm- und 
Daten in getrennten Adressräumen liegen. Bei anderen Architekturen wie 
ARM oder MIPS (PIC32) oder x86 ist das nicht so. Bei AVR, 8051 und 8-Bit 
PIC muss halt der Programmierer entsprechend Grips in der Birne haben.

fchk

von leo (Gast)


Lesenswert?

Frank K. schrieb:
> Und Du benutzt float. Das ist meistens vermeidbar.

Ja, das stimmt. Aber es ist nur ein Funktionsaufruf, traegt kaum zur 
Codegroesse bei, nur viel zur Laufzeit.

leo

von leo (Gast)


Lesenswert?

leo schrieb:
> Mangel an Abstraktion

Rein zufaellig, aber wohl exemplarisch:
1
$ grep "ili9341_fillrect(87, 138," Co2Menu.c 
2
    ili9341_fillrect(87, 138, 120, 20, BLACK);
3
      ili9341_fillrect(87, 138, 120, 20, BLACK);
4
      ili9341_fillrect(87, 138, 120, 20, BLACK);
5
      ili9341_fillrect(87, 138, 120, 20, BLACK);
6
      ili9341_fillrect(87, 138, 135, 20, BLACK);
7
      ili9341_fillrect(87, 138, 135, 20, BLACK);
8
      ili9341_fillrect(87, 138, 135, 20, BLACK);
9
      ili9341_fillrect(87, 138, 135, 20, BLACK);

leo

von Joachim B. (jar)


Lesenswert?

Frank K. schrieb:
> Nicht Volt, sondern mV oder uV

ich nehme cV centi Volt oder dV dezi Volt als Ganzzahl und füge das 
Komma per Stringmanipulation ein.

von Philipp K. (philipp_k59)


Lesenswert?

mal als Beispiel..
im code sind 34 mal "ili9341_drawRect(277, 17, 36, 32,BLABLA); und auch 
andere doppelt und dreifach..


dann lieber komprimieren mit:

void RechteckBLA(uint32_t color){
ili9341_drawRect(277, 17, 36, 32,color)
}

an der richtigen stelle dann ersetzen rechteckBLA(ORANGE);

von W5100Usa (Gast)


Lesenswert?

leo schrieb:
> Rein zufaellig, aber wohl exemplarisch:
> ......

Exemplarische Korinthenkackerei.

von Theor (Gast)


Lesenswert?

Felix N. schrieb:
> Theor schrieb:
>> Das sowas sich so (aus-)wächst ist bei einem Anfänger der dann noch
>> dieses oder jenes Feature haben will normal (und auch nichts Schlimmes),
>> Aber, das macht die Entwicklung auf die Dauer immer schwieriger und
>> schwieriger.
>
> Hallo,
>
> Gut das ich ein guter Programmier bin habe ich nie gesagt,
> [...]

Und ich habe auch nicht behauptet, dass Du das von Dir gesagt hättest. 
:-)

Darum ging es mir nicht. Du brauchst Dich auch nicht zu rechtfertigen.
Es geht darum, wie bestimmte Dinge entstehen. Es geht um Erklärungen, 
nicht um Vorwürfe. Es darum, was die Folge bestimmter Vorgehensweisen 
ist und wie man, meiner Ansicht nach, reagieren sollte, wenn einem diese 
Folgen auf die Füsse fallen. Mehr nicht.

> Das was funktioniert hat habe ich am Anfang erst mal auch nicht mehr
> verändert. Warum?
> Es hat ja funktioniert da habe ich mir kein Kopf
> gemacht ob dieses nun maximal Optimiert ist oder nicht. Gut das mag
> vielleicht nach einer schlechten Einstellung klingen. So soll es aber
> nicht rüber kommen.

Im Prinzip ist das sinnvoll. Aber es macht doch einen Unterschied, ob 
man weiß, dass es bestimmte Entwurfsmuster gibt und ob man zur rechten 
Zeit das Entwurfsmuster wechselt oder ob man das nicht weiß oder nicht 
wechselt.

> Ich bin jeder Zeit bereit aus meinen Fehlern zu lernen und diese zu dann
> zu verhindern/verbessern. Schließlich siehst Du den Code ja ganz anderen
> Augen als Ich, mag vielleicht an deiner Erfahrung liegen.

Gerade so möchte ich von Dir verstanden werden. Ich gebe Dir Urteile 
über Deinen Code ab - nicht über den Wert Deiner Person. (Von Deiner 
Einstellung habe ich ja auch garnichts geschrieben. Das mag aber in 
manchen Fällen durchaus ein sinnvolles Thema sein. Sagt aber immer noch 
nichts über den Wert Deiner Person).

Also nochmal in Kürze, da Du darauf nicht eingangen bist:

1. Benutze datengetriebene Menuesysteme, wenn der explizite Code für 
jeden Menuepunkt groß wird. Ab, über den Daumen gepeilt, mal so 5 bis 8 
Menupunkten sind datengetriebene Systeme meist kleiner als "zu Fuß" 
programmierte. Das äussert sich auch darin, dass Du häufig gleiche 
Sequenzen von Funktionsaufrufen hast. Siehe: 
Beitrag "Re: ATMega Flash wird langsam knapp. Upgrade o. Plattformwechsel?"

2. Da Du sehr häufig gleiche Texte oder Textteile verwendest, kannst Du 
Speicher sparen, wenn Du diese Texte nicht als Literale im Code 
verwendest, sondern nur einmal hinschreibst und anschliessend Zeiger 
darauf verwendest.
In diesem Zusammenhang solltest Du wissen, dass Texte in jedem Fall im 
Flash gespeichert werden, denn von irgendwo müssen sie ja auch dann 
herkommen, wenn sie in das RAM geschrieben werden (also kopiert werden). 
Insofern ist PSTR resp. PROGMEM sinnvoll.

Zusätzlich: Ich habe das vorher nicht erwähnt.

3. Vermeide die Verwendung von Literalen, insbesondere von 
Zahlenliteralen im Code. Halte sie lieber an einer zentralen Stelle, 
falls möglich.
Gleiches gilt für String-Literale (mal unabhängig davon, ob Du nun ein 
Menuesystem verwendest). So sind Änderungen, insbesondere wenn wegen der 
Änderung eines Wertes auch andere Werte geändert werden müssen, 
einfacher.

Ich hoffe ich habe meine Absichten und Haltung Dir gegenüber klarer 
gemacht und Du entscheidest Dich dafür, meine Einwände zu überdenken. 
Jedenfalls, auch wenn Du es nicht tust, wünsche ich Dir Erfolg.

von Manfred (Gast)


Lesenswert?

Stefanus F. schrieb:
> Wenn du auf einen ESP8266 oder ESP32 wechselst, hast du Flash ohne Ende
> und das Netzwerk Interface auch schon dabei.

Ich habe einen Aufbau mit Arduino AT328 und ENC28J60, der im Prinzip 
läuft, aber das RAM nicht mehr ausreicht. Die Idee war, auf den ESP32 zu 
wechesln. Aber: Jegliche Suche nach Libraries für Ethernet als 
UDP-Server endete ohne Erfolg. Du schreibst immer, wie toll Ethernet vom 
ESP unterstützt würde, nachvollziehen kann ich das nicht.

von Philipp K. (philipp_k59)


Lesenswert?

Manfred schrieb:
> wie toll Ethernet vom
> ESP unterstützt würde, nachvollziehen kann ich das nicht.

mindestens jede ENC oder W5100 Arduino library kann das.. 
praktischerweise ist das bestimmt Via WLAN gemeint.

von leo (Gast)


Lesenswert?

W5100Usa schrieb:
> Exemplarische Korinthenkackerei.

Aha, du hast dir den Code also angeschaut?

leo

von Peter D. (peda)


Lesenswert?

Frank K. schrieb:
> Und Du benutzt float. Das ist meistens vermeidbar.

Diese Angst ist unbegründet, die float Lib kostet nur einmal Flash (~1kB 
ohne printf, scanf).
Bei einem AVR mit 4kB Flash würde ich überlegen, aber nicht bei 128kB.

von Stefan F. (Gast)


Lesenswert?

Felix N. schrieb:
> Wenn die die ganzen Texte in den
> Flash Schiebe wird mein Programmspeicher doch noch weniger.

Nein. Denn ohne PSTR und PROGMEM müssen sie beim Start vom Flash ins RAM 
kopiert werden. Wo sollen die Texte sonst liegen, in den Elkos?

von Andreas K. (andreasmc)


Lesenswert?

Felix N. schrieb:

> SD Karte ist schon drin, habe ich auch schon gedacht jedoch kann man die
> SD Karte aus dem System entfernen um zb. den Fehlermeldungen am PC
> auslesen zu können. Die Grundfunktionen sollen erhalten bleiben. Daher
> fiel diese Auswahl weg.

Dann schliess parallel am SPI noch einen kleinen SPI-Flash-Baustein an. 
Kein Grund für reine Daten einen uC mit größerem Flash zu nehmen. Gibts 
für wenig Geld bis in MByte-Größen und kannst du einfach im Programm von 
der SD-Karte aus befüllen.

von Peter D. (peda)


Lesenswert?

PSTR wird doch schon benutzt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Theor schrieb:

> Zusätzlich: Ich habe das vorher nicht erwähnt.
>
> 3. Vermeide die Verwendung von Literalen, insbesondere von
> Zahlenliteralen im Code. Halte sie lieber an einer zentralen Stelle,
> falls möglich.

Das ist Quatsch bzw. stimmt nur für C-Strings (bei AVR). Zahlliterale 
(als core-constant) werden vom Compiler immer direkt in den generierten 
Code eingebaut.

von Andreas B. (bitverdreher)


Lesenswert?

Wenn Du doch sowieso schon ein externes Eeprom hast: Warum nicht dort 
die Strings ablegen?

von m.n. (Gast)


Lesenswert?

Andreas B. schrieb:
> Wenn Du doch sowieso schon ein externes Eeprom hast: Warum nicht dort
> die Strings ablegen?

Die paar Texte sind doch überhaupt nicht das Problem, zumal der Compiler 
gleiche Texte in der Regel erkennt und nur einmal anlegt.

Die wiederholten, nahezu gleichen Abläufe fressen Platz. Geschickter ist 
es, mit Strukturen für die Bedienfelder zu arbeiten. Das ist einmaliger 
Aufwand aber danach sehr effizient und transparent.

Für einen Anfänger ist das aber zunächst ein mächtiger Happen, der zu 
schlucken ist, zumal es auch anfangs an der Einsicht dafür fehlen wird. 
Und auch nur so, behält man bei unkommentiertem Code den Überblick.
Aber da muß man durch, egal wie "fett" der verwendete µC ist.

von Andreas B. (bitverdreher)


Lesenswert?

m.n. schrieb:
> Andreas B. schrieb:
>> Wenn Du doch sowieso schon ein externes Eeprom hast: Warum nicht dort
>> die Strings ablegen?
>
> Die paar Texte sind doch überhaupt nicht das Problem, zumal der Compiler
> gleiche Texte in der Regel erkennt und nur einmal anlegt.

Ich sehe eine ganze Menge Strings. 10% Einsparung würde ich schätzen.

>
> Die wiederholten, nahezu gleichen Abläufe fressen Platz. Geschickter ist
> es, mit Strukturen für die Bedienfelder zu arbeiten. Das ist einmaliger
> Aufwand aber danach sehr effizient und transparent.

Das ist allerdings wahr. Das ganze Bediengedöns sieht recht ineffektiv 
aus.

von gdgddfgdfd (Gast)


Lesenswert?

ich vermisse eine Angabe der Compileroptimierung
Stand das schon irgendwo?

Ansonst ja ... man kann immer etwas einsparen


alternativ die Discovery boards ...
gibt ja welche mit LCD + touch + ethernet + sdCard

von W5100Usa (Gast)


Lesenswert?

Ich plädiere nochmal für diese Lösung:

Frank K. schrieb:
> Mein Vorschlag:
>
> https://www.olimex.com/Products/OLinuXino/A64/A64-OLinuXino/open-source-hardware

Mann kann ja nie genug Cores haben. Und die Megaherz sind auch
ganz wichtig, besonders beim Aquarium-Steuern.

von M. K. (sylaina)


Lesenswert?

Felix N. schrieb:
> Ich weiß auch das
> Sie Texte in den Flash auslagern und so Platz im RAM Schaffen.

Nein, sie werden nicht ins Flash ausgelagert. Da stehen sie sowieso. Sie 
werden mit Progmen/PSTR nur nicht ins RAM geschoben beim Start des uCs.

Ich hab mir den Thread jetzt nicht genau durchgelesen, nur überflogen. 
Aber generell würde ich mir über Optimierungen mal Gedanken machen wenn 
ich sehe, dass 128 kB Flash nicht reichen.

von Falk B. (falk)


Lesenswert?

Felix N. schrieb:
> Hallo,
>
> Gut das ich ein guter Programmier bin habe ich nie gesagt, ich habe mir
> mein gesamtes Programmier wissen aus YouTube Videos, Code Schnippels,
> teilweise Bücher und Foren zusammen gesammelt. Habe Beruflich nix damit
> zutun. Nur Hobby.

Naja, da haben wir schon deutlich schlimmere Dinge gesehen ;-)
1
void getTempCompensation(void) {
2
  if(temperature >= 20 && temperature <= 21) {
3
    reAmpDiff = TEMP_20 * 3;
4
  }

Diese Funktion ist maximal albern, wenn gleich sie sicher nicht 
wahnsinnig viel Flash braucht.
1
void getpHValue(uint8_t withTemperatureMeasuring) {
2
...
3
voltageOnPin = (avgVolt[0] + avgVolt[1] + avgVolt[2] + avgVolt[3] + avgVolt[4] + avgVolt[5] + avgVolt[6] + avgVolt[7] + avgVolt[8] + avgVolt[9] + avgVolt[10] + avgVolt[11] + avgVolt[12] + avgVolt[13] + avgVolt[14] + avgVolt[15] + avgVolt[16] + avgVolt[17] + avgVolt[18] + avgVolt[19]) / 20;

Schon mal was von einer Schleife gehört?
1
void init_EEPROM(void) {

Au weia! Sieht du in den Massen an Schreibzugriffen selber noch durch? 
Schon mal was von einem struct gehört?
1
char * stringReplace(char *search, char *replace, char *string) {
2
  // Speicher reservieren
3
  tempString = (char*) malloc(strlen(string) * sizeof(char));

Naja, theoretisch korrekt, praktisch eher ungünstig. Du hast so oder so 
nur wenig Speicher, da reicht es, eine lokale, temporäre Variable 
(Array) anzulegen. Mit ein wenig Nachdenken kommt diese Funktion sogar 
ohne Zwischenspeicher aus, wenn man einfach die Lücke im Originalstring 
vor dem Austausch passend zurecht schiebt.
1
void ili9341_init(void)//set up display using predefined command sequence

Auch hier wieder sinnlose, endlose Funktionsaufrufe, die nur einen 
anderen Parameter haben! Sowas macht man mit einem Array, idealerweise 
liegt der im Flash (PROGMEM) und einer Schleife. Das ergibt nicht nur 
deutlich weniger Quelltext, der deutlich übersichtlicher ist, sondern 
auch deutlich weniger Flashverbrauch.
1
sprintf(buffer, "pH: %-.2f", phValue);

Du hast viele sprintf() Funtkionen drin. Nimm sprintf_P, dann liegt der 
Formatstring direkt im FLASH und verbraucht keinen RAM!

Denk dran, konstante Strings und Array, welche "normal" benutzt werden, 
verbrauchen beim AVR Flash UND RAM in gleicher Größe. Erst wenn man sie 
mittels der passenden Funktionen in den Flash schiebt und entsprechend 
anspricht, entfällt der RAM-Verbrauch.
1
  ili9341_combo(5, 105, WHITE, BLACK, 2, 3, 0, 0, "Karbonathaerte:");

Auch hier das Gleiche. Du musst deine Funktion auf PROGMEM-Strings 
umbauen. Dann sparst du massiv RAM.
1
void getTimeBasedInformation(void) {
2
  ontime_co2_hour  = readEEPROM(0x0F);
3
  ontime_co2_min   = readEEPROM(0x10);
4
  offtime_co2_hour = readEEPROM(0x11);
5
  offtime_co2_min  = readEEPROM(0x12);

Gleiches Problem wie oben. Du spricht direkte, absolute Adressen im 
EERPOM an. Das ist Low Level Programmierung, wie man sie nicht mal in 
Assembler machen will. Man will Variablen mit gescheitem Namen 
ansprechen! Denn sonst sieht man irgendwann nicht mehr durch.
1
uint8_t compare_float(float f1, float f2){
2
  float precision = 0.00001;

Hier hast du schon eines der Probleme bei Fließkommazahlen erkannt. Ein 
direkter Vergleich auf Gleichheit geht meist schief. Vermutlich ist für 
deine Anwendung Festkommaarithmetik ausreichend und macht dir nicht 
solche Probleme.
1
 strcpy(smallBuffer, "Manuell")

Auch hier bringt die Funktion strcpy_P RAM-Ersparnis.

Allgemein sieht man in deinem Ansatz zum Menuaufbau tonnenweise 
Funktionsaufrufe zum Zeichnen. Vermutlich ist da sehr viel doppelt und 
dreifach drin, das kostet schon einiges an Flash. Das kann man mit einem 
besseren Ansatz lösen. Man muss ja nicht gleich eine GUI-Menu-Bibliothek 
programmieren. Aber man sollte mit deutlich mehr Datenstrukturen 
arbeiten, welche die einzelnen Menus beschreiben. Ein kleine, kompakte 
Funktion kann diese dann auswerten und ja nach Menu zeichnen. Außerdem 
sollte man mehr mit universellen Hilffunktionen arbeiten, damit 
wiederholende Aufgaben nicht mehrfach aufgedröselt hingeschrieben werden 
müssen. Das spart FLASH, Tipparbeit und minimiert Fehlerquellen.

Strukturierte Programmierung auf Mikrocontrollern
1
  switch(dayOfTheWeek()) {
2
    case 1:
3
      strcpy(buffer, "Mo.");
4
      break;
5
    case 2:

Ist auch maximaler Unsinn. Das macht man mit einem PROGMEM-Array!
Etwa so
1
const char DoW[][4] = PROGMEM {"Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa.", "So.", };
2
strcpy_P(buffer, DoW[dayOfTheWeek()]);

von M. K. (sylaina)


Lesenswert?

Falk B. schrieb:
> Ist auch maximaler Unsinn. Das macht man mit einem PROGMEM-Array!

Das zum einem, es zeigt aber noch etwas weiteres: So eine Woche hat ja 
nur 7 Tage: Ein Case hätte man sich auch hier sparen können.
Auch ein ENUM hätte hier wahrscheinlich besser gepasst als das 
Switch-Statement.

Aber es wurde ja schon festgestellt, dass in dem Code enorm viel 
Optimierungspotential steckt.

von m.n. (Gast)


Lesenswert?

W5100Usa schrieb:
> Mann kann ja nie genug Cores haben.

Völlig richtig.
Es soll jetzt einen neuen ATtiny885 geben mit sagenhaften 8 Kernen!

von Falk B. (falk)


Lesenswert?

Noch was
1
void encode_init(void){
2
  int8_t new;
3
4
  CODER_DDR |= (0<<CODER_PINA) | (0<<CODER_PINB) | (0<<CODER_BUTTON);

Das ist Unsinn und macht im Extremfall nicht das, was du willst. Eine 0 
durch die Gegend schieben ist sinnlos. Das funktioniert hier nur, weil 
die Bits im Register nach dem Reset sowieso schon auf Null stehen. Wenn 
man sicherstellen will, daß diese Pins Eingänge werden, dann eher so, 
siehe Bitmanipulation.
1
void encode_init(void){
2
  int8_t new;
3
4
  CODER_DDR &= ~((1<<CODER_PINA) | (1<<CODER_PINB) | (1<<CODER_BUTTON));

von MaWin (Gast)


Lesenswert?

> Autor: MaWin (Gast)
> Datum: 08.09.2019 20:47

Noch so ein Trollbeitrag vom Psychopathen...

von Falk B. (falk)


Lesenswert?

MaWin schrieb:
>> Autor: MaWin (Gast)
>> Datum: 08.09.2019 20:47
>
> Noch so ein Trollbeitrag vom Psychopathen...

Und du Plinse schaffst es seit Jahren nicht, dir einen Login zuzulegen. 
Selber Schuld! Aber was wäre die Welt ohne Paranoia?

von Falk B. (falk)


Lesenswert?

Noch was
1
ISR(TIMER1_COMPA_vect){            // 1ms for manual movement
2
  int8_t new, diff;
3
4
  static uint8_t cnt_10ms;
5
  cnt_10ms++;
6
  if (cnt_10ms==10 && useSD) { //needed for sd card
7
    cnt_10ms=0;
8
    disk_timerproc();
9
  }
10
11
  new = 0;
12
  if( PHASE_A ) new = 3;
13
  if( PHASE_B ) new ^= 1;          // convert gray to binary
14
  diff = last - new;               // difference last - new
15
  if( diff & 1 ) {                 // bit 0 = value (1)
16
    last = new;                    // store new as next last
17
    enc_delta += (diff & 2) - 1;   // bit 1 = direction (+/-)
18
  }
19
20
  encoder_position += encode_read4();
21
}
Genau SO macht man das eben nicht! Der Witz der Funktion encode_read4() 
ist es ja, daß man sie relativ langsam und selten in einer Schleife im 
Hauptprogramm aufrufen kann und als Ergebnis die Anzahl der Schritte 
seit dem letzten Aufruf nach links oder rechts bekommt. Ein Aufruf in 
der ISR ist sinnlos und kontraproduktiv! Die Beispiele hier im Wiki 
machen das auch nicht!

von Stefan F. (Gast)


Lesenswert?

Falk B. schrieb:
> CODER_DDR |= (0<<CODER_PINA) | (0<<CODER_PINB) | (0<<CODER_BUTTON);
> Eine 0 durch die Gegend schieben ist sinnlos.

Kostet allerdings auch keinen Speicherplatz. Der Compiler reduziert das 
auf eine simple Zuweisung: CODER_DDR |=0

von Andreas B. (bitverdreher)


Lesenswert?

Stefanus F. schrieb:
> Falk B. schrieb:
>> CODER_DDR |= (0<<CODER_PINA) | (0<<CODER_PINB) | (0<<CODER_BUTTON);
>> Eine 0 durch die Gegend schieben ist sinnlos.
>
> Kostet allerdings auch keinen Speicherplatz. Der Compiler reduziert das
> auf eine simple Zuweisung: CODER_DDR |=0

Wenn der Compiler schlau ist, macht er dabei gar nichts (was ich mal 
stark vermute). Mit 0 verodern gibt immer noch das gleiche wie vorher.

von Stefan F. (Gast)


Lesenswert?

Andreas B. schrieb:
> Wenn der Compiler schlau ist, macht er dabei gar nichts (was ich mal
> stark vermute). Mit 0 verodern gibt immer noch das gleiche wie vorher.

Alle Register sind volatile, ich glaube dass der Compiler die Zugriffe 
daher nicht weg optimieren darf.

von Theor (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Theor schrieb:
>
>> Zusätzlich: Ich habe das vorher nicht erwähnt.
>>
>> 3. Vermeide die Verwendung von Literalen, insbesondere von
>> Zahlenliteralen im Code. Halte sie lieber an einer zentralen Stelle,
>> falls möglich.
>
> Das ist Quatsch bzw. stimmt nur für C-Strings (bei AVR). Zahlliterale
> (als core-constant) werden vom Compiler immer direkt in den generierten
> Code eingebaut.

Lieber Wilhelm. du zitierst nur einen Teil meines Textes und 
unterstellst dann, ohne dass ich dafür einen vernüfntigen Grund erkennen 
kann, dass ich den von Dir zitierten Teil geschrieben habe, weil ich 
annehme, dass damit Speicherplatz gespart wird.

Ich zitiere mich selbst und hebde der Deutlichkeit halber die von mir 
genannte Begründung für meine Aussage, die zu zitieren Du unterlassen 
hast.
(Die Hervorherbung geschieht hier, in dem die Zitatzeichen '>' von dem 
Satz entfernt wurden. Eine andere Möglichkeit, den Satz etwa mit 
Unterstreichung hervorzuheben und ihn dabei weiter als Zitat zu 
kennezeichen, habe ich leider nicht gefunden). Das Original kann hier 
Beitrag "Re: ATMega Flash wird langsam knapp. Upgrade o. Plattformwechsel?" nachgelesen werden.

Theor schrieb:
>[...]
> 3. Vermeide die Verwendung von Literalen, insbesondere von
> Zahlenliteralen im Code. Halte sie lieber an einer zentralen Stelle,
> falls möglich.
> Gleiches gilt für String-Literale (mal unabhängig davon, ob Du nun ein
> Menuesystem verwendest).
_So sind Änderungen, insbesondere wenn wegen der
Änderung eines Wertes auch andere Werte geändert werden müssen,
einfacher._
> [...]

Es mag sein, dass Du das nicht gesehen hast. Dann ist das sicher nur ein 
Mißverständnis. Ich hoffe, nun ist klarer, was ich sagen wollte.

von MaWin (Gast)


Lesenswert?

Falk B. schrieb:
> MaWin schrieb:
>>> Autor: MaWin (Gast)
>>> Datum: 08.09.2019 20:47
>>
>> Noch so ein Trollbeitrag vom Psychopathen...
>
> Und du Plinse schaffst es seit Jahren nicht, dir einen Login zuzulegen.
> Selber Schuld! Aber was wäre die Welt ohne Paranoia?

Lasst uns einen MaWin-Day einführen an dem alle mit seinem Namen posten 
:)

von Thomas E. (thomase)


Lesenswert?

Stefanus F. schrieb:
> Alle Register sind volatile, ich glaube dass der Compiler die Zugriffe
> daher nicht weg optimieren darf.

Macht er auch nicht:
1
  TCCR2A |= 0;
2
  d2:  e0 eb         ldi  r30, 0xB0  ; 176
3
  d4:  f0 e0         ldi  r31, 0x00  ; 0
4
  d6:  80 81         ld  r24, Z
5
  d8:  80 83         st  Z, r24

von Felix N. (felix_n888)


Angehängte Dateien:

Lesenswert?

Hallo,

Theor schrieb:
>> Hallo,
>>
>> Gut das ich ein guter Programmier bin habe ich nie gesagt,
>> [...]
>
> Und ich habe auch nicht behauptet, dass Du das von Dir gesagt hättest.
> :-)
>
> Darum ging es mir nicht.

Okay, dann hatte ich das falsch aufnehmen. Sorry!

leo schrieb:
> Das wird dann noch gemacht mit nur anderem Text. Du findest sowas zuhauf
> im Code.

Ja weil ich zuvor den bestehen Text überschreiben muss mit einem 
schwarzen Rechteck um da sonst wildes Zeug raus kommt wenn ich es weg 
lasse.

Andreas K. schrieb:
> Dann schliess parallel am SPI noch einen kleinen SPI-Flash-Baustein an.

Andreas K. schrieb:
> kannst du einfach im Programm von
> der SD-Karte aus befüllen.

Das heißt wenn ich das richtig verstehe ich schreibe 1x die meine ganzen 
Strings auf die SD Karte und schreibe sie dann in den SPI Flash und dort 
bleiben sie ja bis ich sie wieder lösche.

Muss ich dann nicht massig Zugriffe machen, um die Strings dort wieder 
raus zubekommen?

M. K. schrieb:
> Sie
> werden mit Progmen/PSTR nur nicht ins RAM geschoben beim Start des uCs.

Achso.

Falk B. schrieb:
> Diese Funktion ist maximal albern, wenn gleich sie sicher nicht
> wahnsinnig viel Flash braucht.

500 Bytes hat Sie verbraucht. War noch eine alte Funktion um die 
Temperatur Korrektur zu machen für die pH Elektrode ist aber 
Mittlerweile nicht mehr in Gebrauch.

Falk B. schrieb:
> Schon mal was von einer Schleife gehört?

Ja habe. Ich habe jetzt eine for Schleife eingefügt.

Falk B. schrieb:
> Auch hier wieder sinnlose, endlose Funktionsaufrufe, die nur einen
> anderen Parameter haben! Sowas macht man mit einem Array, idealerweise
> liegt der im Flash (PROGMEM) und einer Schleife. Das ergibt nicht nur
> deutlich weniger Quelltext, der deutlich übersichtlicher ist, sondern
> auch deutlich weniger Flashverbrauch.

Also ich habe das mal versucht umzusetzen, doch ist der Flash verbrauch 
nicht gesunken sondern um 0,2%(256Bytes) gestiegen. Möglicherweiße habe 
ich es auch falsch gemacht, habe den Quellcode von ili9341_init() als 
Datei angehängt.

Falk B. schrieb:
> Nimm sprintf_P

Falk B. schrieb:
> direkt im FLASH und verbraucht keinen RAM!

Falk B. schrieb:
> Du musst deine Funktion auf PROGMEM-Strings
> umbauen. Dann sparst du massiv RAM.

Irgendwie stehe ich gerade auf den Schlauch. Es wurde ja bereits öfters 
geschrieben das ich mit PSTR und PROGMEM oder _P Strings aus dem RAM ins 
Flash lege.

Aber erhöhe ich nicht zwangsweise dadurch den Flash Verbrauch? RAM habe 
ich ja 16K wovon ich nicht mal 50 % im Moment benutze oder habe ich da 
was falsch verstanden?

Falk B. schrieb:
> Du spricht direkte, absolute Adressen im
> EERPOM an. Das ist Low Level Programmierung
> Man will Variablen mit gescheitem Namen
> ansprechen!

Was heißt den jetzt Low Level? Und wieso ist es schlecht das ich der 
Variable direkt den Wert aus dem EEPROM zuweiße? Wüsste jetzt nicht wie 
ich es sonst machen sollte.

Was meinst du genau mit gescheitem Namen? Ich mein ich weiß ja warum die 
Variable zb. ontime_co2_hour heißt oder ist damit gemeint das ich besser 
ein Array erstelle wie zb.
1
uint8_t co2ONTime[4];
Und dann dem Array 0 bis 4 die Adressen zuweiße?

Falk B. schrieb:
> Sieht du in den Massen an Schreibzugriffen selber noch durch

Falk B. schrieb:
> Denn sonst sieht man irgendwann nicht mehr durch.

Naja manchmal ist es schon ein bisschen speziell. Aber ich habe ein 
Excel Dokument wo ich Eintragen habe wie und wo welche Adresse und Wert 
abgespeichert ist und was das macht.

Falk B. schrieb:
> Schon mal was von einem struct gehört?

Gehört schon aber noch nie benutzt.

Falk B. schrieb:
> Allgemein sieht man in deinem Ansatz zum Menuaufbau tonnenweise
> Funktionsaufrufe zum Zeichnen.

Ich rufe die Menüs ja schon in der buttonpressed() Funktion auf die in 
der Menu Funktion vorhanden ist. Somit lade ich ja die Menüs schon vor. 
Wäre es besser wenn ich dort zb. ein Integer als Menü Index setze und 
ein Wechsel Boolean so das in der Menu geschaut wird ob gerade ein 
Wechsel erforderlich ist zb. vom Hauptmenü aufs RTC Menu und wenn das 
der Fall dann wechseln. Somit würde ich die Menüs ja unter ein anderer 
nicht mehr aufrufen sondern nur noch 1x Zentral von der main.c

Falk B. schrieb:
> Das ist Unsinn und macht im Extremfall nicht das, was du willst.

Ah gut zu wissen das nicht alles gewonnenes wissen richtig ist habe das 
mal so aufgeschnappt in einem Online Artikel über die AVR Programmierung 
... Deswegen habe ich das so gemacht. Bis jetzt hat es mich auch noch 
nicht im Stich gelassen.

Falk B. schrieb:
> Genau SO macht man das eben nicht!

Falk B. schrieb:
> Die Beispiele hier im Wiki
> machen das auch nicht!

Da war mal irgendwas warum ich das gemacht habe. Werde mir nochmal den 
Wiki Artikel durchlesen.

Lg

von leo (Gast)


Lesenswert?

Felix N. schrieb:
> leo schrieb:
>> Das wird dann noch gemacht mit nur anderem Text. Du findest sowas zuhauf
>> im Code.
>
> Ja weil ich zuvor den bestehen Text überschreiben muss mit einem
> schwarzen Rechteck um da sonst wildes Zeug raus kommt wenn ich es weg
> lasse.

Du verstehst offensichtlich das Problem nicht. Du hast die selben 3 
Zeilen Code x mal, nur mit anderem Text anstatt den Code genau 1 mal in 
einer Funktion zu haben, der du den unterschiedlichen Text uebergibst.

leo

von Stefan F. (Gast)


Lesenswert?

Felix N. schrieb:
> Aber erhöhe ich nicht zwangsweise dadurch den Flash Verbrauch?

Nochmal: Nein

Ich kann das auch gerne 100 mal schrieben, wenn es Dir hilft:

Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, 
Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, 
Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, 
Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, 
Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, 
Nein, Nein, Nein, Nein, Nein, Nein, Nein, Nein, ...

von Felix N. (felix_n888)


Lesenswert?

leo schrieb:
> Du hast die selben 3
> Zeilen Code x mal, nur mit anderem Text anstatt den Code genau 1 mal in
> einer Funktion zu haben, der du den unterschiedlichen Text uebergibst.

Hallo, ich glaube ich weiß jetzt wie du das meinst. Ich beziehe mich mal 
auf ein Code Schnippel aus der Co2Menu.c Datei Zeile 118-119 dort habe 
ich zwei Zeilen Code
1
ili9341_fillrect(87, 138, 120, 20, BLACK);
2
ili9341_combo(87, 140, WHITE, BLACK, 2, 3, 0, 0, "pH Stabil");

In Zeile 126-127 und 133-134 wiederholt sich der Code nur mit einem 
anderen Text. Ich habe mir jetzt folgende Funktion überlegt die halt das 
fillrect macht und den Text mittels PSTR übergibt:
1
void drawSelectedModus(const char *progmem_s) {
2
  ili9341_fillrect(87, 138, 120, 20, BLACK);
3
  ili9341_combo_flash(87, 140, WHITE, BLACK, 2, 3, 0, 0, progmem_s);  
4
}

Wenn ich die Zeilen die ich oben genannt habe durch die Funktion ersetze 
habe ich 46 Bytes Flash wieder frei.

Stefanus F. schrieb:
> Ich kann das auch gerne 100 mal schrieben, wenn es Dir hilft:

Nein. Aber ich glaube ich habe es jetzt verstanden. Ich habe mir den 
Link mal durchgelesen und mal mich erkundigt wie das mit dem RAM und 
Flash ungefähr funktioniert.

https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Speicherzugriffe

Wenn ich das nun richtig verstanden habe belegt ein normaler String 
Flash und RAM. Wobei der String beim Start zusätzlich in den RAM kopiert 
wird. Das ist der Grund warum ich direkt drauf zugreifen kann. richtig?


Wenn ich jetzt den String mit PSTR oder PROGMEM anlege je nach dem, wird 
er erst gar nicht in den RAM kopiert. Er wird also nur im Flash anlegt. 
Wenn ich jetzt ein direkten Zugriffe drauf mache versucht das Programm 
die Adresse der Variable im RAM zu finden, wird es aber nicht da sie mit 
PSTR oder PROGMEM gar nicht erst ins RAM geladen wurde und ich bekomme 
irgendwas zurück.


Daher muss ich mit den Makros pgm_read_byte/word/... arbeiten damit das 
Programm nicht die Adresse des Strings aus dem RAM ließt sondern nach 
der Adresse im Flash.

Somit würde ich den doppelten Speicher belegen wenn ich ein String ohne 
PROGMEM anlege, das würde ja auch bedeuten das wenn ich einen normalen 
String anlege ohne PROGMEM das im RAM zwar eine Kopie liegt aber sie 
jedoch nur auf die Adresse des Strings im Flash verweist oder?

Lg

von leo (Gast)


Lesenswert?

Felix N. schrieb:
> Wenn ich die Zeilen die ich oben genannt habe durch die Funktion ersetze
> habe ich 46 Bytes Flash wieder frei.

Sehr gut. Ich denke da sind noch viel mehr Wiederholungen, auch mit 
leicht anderen Koordinaten oder anderen Texten. Du kannst noch viel mehr 
in Funktionen zusammenfassen.

leo

von Frank K. (fchk)


Lesenswert?

Felix N. schrieb:

> Somit würde ich den doppelten Speicher belegen wenn ich ein String ohne
> PROGMEM anlege, das würde ja auch bedeuten das wenn ich einen normalen
> String anlege ohne PROGMEM das im RAM zwar eine Kopie liegt aber sie
> jedoch nur auf die Adresse des Strings im Flash verweist oder?

Eine Kopie ist genau das: eine Kopie und kein Zeiger/Verweis. Ein Zeiger 
würde bei einem 16 Bit Adressraum nur 2 Byte brauchen, egal wie groß das 
Original ist. Eine Kopie braucht exakt so viel Platz wie das Original.

Das Problem bei AVR ist, dass Du einmal Adressen von 0...65535 fürs 
Flash hast und einmal Adressen von 0...65535 fürs RAM. Diese beiden 
Adressen sind nicht miteinander kompatibel, d.h. Du hast einmal eine wie 
strcpy für RAM-Adressen und einmal eine Spezialversion strcpy_P für 
Flash-Adressen. Bei ARM, MIPS und den meisten anderen Architekturen hast 
Du diese Unterscheidung nicht. Da hast Du nur einen Satz von Adressen 
von 0 bis 4G-1, und da ist alles drin: Flash, RAM, IO-Ports usw. Ist 
damit einfacher zu programmieren und ermöglicht es auch, Code aus dem 
RAM ablaufen zu lassen. Das ist auch etwas, was bei AVR grundsätzlich 
nicht geht.

fchk

von Stefan F. (Gast)


Lesenswert?

Felix N. schrieb:
> Wenn ich das nun richtig verstanden habe belegt ein normaler String
> Flash und RAM. Wobei der String beim Start zusätzlich in den RAM kopiert
> wird. Das ist der Grund warum ich direkt drauf zugreifen kann. richtig?

... und was du danach geschrieben hast

ja alles richtig.

pgm_read_byte/word/...nutze ich nur sehr selten.

Denn für viele String Funktionen gibt es noch die _P Varianten, die aus 
dem Flash lesen, anstatt aus dem RAM. Zum Beispiel sprintf_P().

von Torsten S. (tse)


Lesenswert?

Was Falk geschrieben hat ist richtig auch wenns nicht besonders 
diplomatisch war. Lass Dich nicht von diesen Helden mit den ESP- oder 
WIZ-Zeugs beeindrucken. Damit schaffts Du nur neue Baustellen.

Mein eigenes Projekt nutzt fast die gleiche Peripherie aber als 
FBH-Steuerung. Auch bei mir ist Speicher irgendwann knapp geworden. Habe 
dann auf den 2560 + 64k XMEM aufgerüstet - damit lebt es sich ganz 
entspannt. Das läuft 24/7 seit ein paar Jahren äußerst zuverlässig.

von Theor (Gast)


Lesenswert?

Felix N. schrieb:
> > [...]

> Falk B. schrieb:
>> Du musst deine Funktion auf PROGMEM-Strings
>> umbauen. Dann sparst du massiv RAM.
>
> Irgendwie stehe ich gerade auf den Schlauch. Es wurde ja bereits öfters
> geschrieben das ich mit PSTR und PROGMEM oder _P Strings aus dem RAM ins
> Flash lege.

Es ist vielleicht noch nicht klar genug beschrieben worden:
Nach dem Reset des Prozessors geschieht in Bezug auf literale, also 
konstante, Strings, u.A. Folgendes:

1. Der FLASH-Speicher enthält grundsätzlich Dein gesamtes Programm 
inklusive aller in Deinem Programm verwendeten konstanten Strings 
(Zeichenketten), egal ob Du nun PSTR verwendest oder nicht.

2. Das RAM enthält nach dem Reset (sozusagen) Nichts. Soweit es Dich im 
Moment angeht, enthält es keine sinnvollen Werte, keine Strings oder 
Zahlen aus Deinem Programm.
(Genau genommen stimmt das nur, falls zuvor der Strom ausgeschaltet war, 
aber zunächst mal kommt es für Dich auf das selbe hinaus, ob der Strom 
vor dem Reset an war oder nicht).

3. Ein Teil der ersten Befehle nach dem Reset, kopiert Deine Strings, 
die Du in dem Programmtext hingeschrieben hast, aus dem FLASH-Speicher 
in das RAM. Das geschieht, weil Zugriffe auf das RAM schneller gehen als 
Zugriffe auf Daten im FLASH-Speicher. D.h. wird auf Strings im Programm 
mehr als zwei- oder dreimal zugegriffen, dann geht das aus dem RAM 
insgesamt schneller als aus dem FLASH. Dieser Vorgang des kopierens wird 
durch Programmcode beschrieben, den Du normalerweise nicht zu sehen 
bekommst. Man nennt das den "Startup-Code".

D.h. mit der Verwendung von PSTR und PROGRMEM (usw.) legst Du nicht 
Strings aus dem RAM ins FLASH! Nicht so, wie Du das vermutlich meinst. 
Die Strings sind eben nicht von vorne herein (beim Reset) im RAM. Wie 
sollten sie da hinkommen?

Es ist wichtig, dass Dir klar wird, was Du im Programmtext eigentlich 
beschreibst und zu welchem Zeitpunkt es eine Wirkung hat.

Wenn Du im Programmtext PSTR hinschreibst und das Programm kompilierst, 
dann erzeugt der Compiler für diese Variable, vor der PSTR steht, 
keinen Code, der sie in das RAM kopiert. PSTR wirkt sich auf den Code 
aus und der Code tut gewisse Dinge dann nicht.


In Deinem Fall ist nun eine Maßnahme (von mehreren, die Dir hier 
vorgeschlagen wurden), dass Du (fast) alle Strings ausschliesslich im 
FLASH-Speicher vorhälst. Deswegen sollst Du PSTR vor (fast) alle Strings 
schreiben.

> Aber erhöhe ich nicht zwangsweise dadurch den Flash Verbrauch? RAM habe
> ich ja 16K wovon ich nicht mal 50 % im Moment benutze oder habe ich da
> was falsch verstanden?

Nein. Eben nicht.
Wie oben beschrieben, sind Strings immer_ und _grundsätzlich im FLASH 
Speicher enthalten. Denn das ist der Speicher, der auch nach dem 
Abschalten des Stroms erhalten bleibt. RAM verliert seinen Inhalt.

Du bewirkst also mit PSTR nicht, das der FLASH-Speicher voller wird, 
denn die Strings stehen da auch dann drin, falls Du PSTR nicht 
verwendest. Woher sollen sie sonst kommen, wenn sie ins RAM kopiert 
werden?

Mit der Verwendung von PSTR bewirkst Du aber, dass die Strings nicht 
ins RAM kopiert werden und sparst dadurch, weil Du soviel Text hast, 
viel RAM.

Eine Folge der Verwendung von PSTR ist aber, dass sich die 
Ausführungszeit des Programmes insgesamt etwas erhöht, denn wie gesagt, 
dauert es länger, die Strings aus dem FLASH zu laden, als aus dem RAM. 
Nur macht das in Deinem Fall nicht viel aus, da die Anzeige nicht 
zeitkritisch ist. Du würdest nur bei extrem langen Texten (vielleicht ab 
etwa 100Bytes oder mehr etwas davon merken.

Klar? Oder hast Du noch Fragen?

von Theor (Gast)


Lesenswert?

Na toll. Da war ich zu langsam. :-)

von eku (Gast)


Lesenswert?

Schon mal Ethersex angeschaut?

von Falk B. (falk)


Lesenswert?

Felix N. schrieb:
> Das heißt wenn ich das richtig verstehe ich schreibe 1x die meine ganzen
> Strings auf die SD Karte und schreibe sie dann in den SPI Flash und dort
> bleiben sie ja bis ich sie wieder lösche.
>
> Muss ich dann nicht massig Zugriffe machen, um die Strings dort wieder
> raus zubekommen?

Naja, soo viel ist das nicht, kann man relativ einfach in eine Funktion 
packen. Aber soweit musst du gar nicht gehen, du hast noch VIEL Luft 
nach oben. Erstens durch eine gescheite Umstruktuerierung deines Codes 
(neudeutsch Refactoring) und 2. durch den großen Bruder mit 256kB Flash.

>Also ich habe das mal versucht umzusetzen, doch ist der Flash verbrauch
>nicht gesunken sondern um 0,2%(256Bytes) gestiegen.

Darf nicht sein.

> Möglicherweiße habe
>ich es auch falsch gemacht, habe den Quellcode von ili9341_init() als
>Datei angehängt.

Naja, schon mal besser, wenn gleich noch ausbaufähig. Vor allem schreibt 
man nicht eine supermegalange Zeile! Viel mehr als 100-120 Zeichen 
gehören nicht in eine Zeile. Ein Array darf problemlos über mehrere 
Zeilen gehen.
Ich hätte aber aber anders, gemacht, damit wird es kompakter. Kodiere 
die Befehle mit 16 Bit und nutze die oberen Bits zur Unterscheidung von 
Befehl und Daten. Das verschwendet zwar 7 Bit, macht das in Summe aber 
wieder wett (ein Maschinenbefehlt hat beim AVR auch 16 Bit). Siehe 
Anhang, ist aber nur beispielhaft, den Rest must du ergänzen.

>Aber erhöhe ich nicht zwangsweise dadurch den Flash Verbrauch? RAM habe
>ich ja 16K wovon ich nicht mal 50 % im Moment benutze oder habe ich da
>was falsch verstanden?

Ja hast du, immer noch.

Wenn man beim AVR "normale", konstante Strings benutzt, liegen die im 
Flash und werden vor dem Start von main() in den RAM kopiert. Mit denen 
arbeitet dann dein Programm. Die Strings im Flash werden danach nie 
wieder angesprochen.

Mit dem _P Funktionen etc. entfällt die Kopie in den RAM und die Strings 
werden DIREKT aus dem Flash gelesen und verarbeitet. Capice?

>Was heißt den jetzt Low Level?

Du kriechst im IT-Urschleim!

> Und wieso ist es schlecht das ich der
>Variable direkt den Wert aus dem EEPROM zuweiße?

Weil das Hacker und Amateurmurks ist und du ganz schnell nicht mehr 
durchsiehst. Warum wohl wurden selbst beim Assembler Namen für Variablen 
verwendet und keine Adressen? Weil der Mensch mit NAMEN deutlich besser 
klar kommt!

> Wüsste jetzt nicht wie
>ich es sonst machen sollte.

Richtig? Solche Sache packt man in ein struct.
1
typedef struct {
2
  uint16_t: max_temperature;
3
  uint16_t: min_temperature;
4
  long: Fish_counter
5
} my_setting_t;    // Datentyp als struct definieren
6
7
my_setting_t my_settings EEMEM; // Variable vom Typ my_setting_t im EEPROM anlegen.
8
9
eeprom_write_word(&my_settings.max_temperature, max);
10
min = eeprom_read_word(&my_settings.min_temperature);

Ist das nicht DEUTLICH lesbarer und vor allem selbsterklärend?

>Naja manchmal ist es schon ein bisschen speziell. Aber ich habe ein
>Excel Dokument wo ich Eintragen habe wie und wo welche Adresse und Wert
>abgespeichert ist und was das macht.

AUA! Genau SO macht man es NICHT! Denn dieser Job gehört dem COMPILER! 
Der verwaltet die Adressen! Du legst Variablen mit gescheiten Namen an, 
ggf. als Struct zusammengefaßt.

>Wäre es besser wenn ich dort zb. ein Integer als Menü Index setze und
>ein Wechsel Boolean so das in der Menu geschaut wird ob gerade ein
>Wechsel erforderlich ist zb. vom Hauptmenü aufs RTC Menu und wenn das
>der Fall dann wechseln.

JA!

> Somit würde ich die Menüs ja unter ein anderer
> nicht mehr aufrufen sondern nur noch 1x Zentral von der main.c

Das ist der Witz der Sache!

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Hier der Anhang.

von gdgddfgdfd (Gast)


Lesenswert?

Felix N. schrieb:
> Wenn ich die Zeilen die ich oben genannt habe durch die Funktion ersetze
> habe ich 46 Bytes Flash wieder frei.

hi

und so geht das durch den gesammten code weiter.

ABER ...
Alle haben mal angefangen und gelernt das jede Architektur  seine eigene 
Programmierweise hat...
siehe AVR mit PROGMEM und das er nunmal variablen > 8bit nicht so mag

Ich selbst arbeite momentan viel mit Cortex M7
Da dieser Cache hat und immer 32byte aligned arbeitet muss man auch 
"komisch" programmieren.
Ebenso der "ART" ist ein 128byte Cache für den Flashzugriff. Alle 
Funktionen >128bytes brauchen deutlich mehr Zeit.
Ergo... alles zerhackstücken das man lieber viele viele kleine 
funktionen hat.  8bit ist hier eher kontraproduktiv weil trotzdem 32bit 
verbraucht werden... usw ...


Wenn ich manchmal code durchschaue den ich vor 2-3 Jahren mal 
geschrieben habe erkenne ich sofort optimierungspotenzial.
Das wird mir in 2-3 Jahren bei einem aktuellen Projekt sicher auch so 
gehen ^^
Aber zumindest macht man keine grunsätzlichen fehler mehr... nicht mehr 
so doll ^^  Man muss halt nur immer dazulernen.


Habe selbst ein Aquarium ( meerwasser ) und mir damals was gebaut.
funktioniert bis heute.  Habe dazu aber kein LCD eingebaut und nur den 
Netzwerkanschluss genutzt.

Das Ding hat eine Webseite die alle Daten liefert und ggf. auch von 
"Außen" Zugriff gewährt.
Vieleicht als Idee für dich ...
Da ein Handy ja auch ein LCD ist ..
und man mit CSS / HTML sicherlich mehr grafische Möglichkeiten hat als 
auf dem ILI ..
Encoderbedienung brauch man auch nicht mehr.. gibt ja 
Eingabemöglichkeiten auf der Seite.

Die webseite wird komplizierter... dafür wird die Blackbox einfacher 
:-)

von Falk B. (falk)


Lesenswert?

gdgddfgdfd schrieb:
> hi
>
> und so geht das durch den gesammten code weiter.
>
> ABER ...
> Alle haben mal angefangen und gelernt das jede Architektur  seine eigene
> Programmierweise hat...
> siehe AVR mit PROGMEM

Sicher, ist halt eine Besonderheit. Wenn man sie kennt ist es aber kein 
echtes Problem, nur ein wenig mehr Aufwand.

> und das er nunmal variablen > 8bit nicht so mag

UNSINN!!!

> Ich selbst arbeite momentan viel mit Cortex M7
> Da dieser Cache hat und immer 32byte aligned arbeitet muss man auch
> "komisch" programmieren.
> Ebenso der "ART" ist ein 128byte Cache für den Flashzugriff. Alle
> Funktionen >128bytes brauchen deutlich mehr Zeit.
> Ergo... alles zerhackstücken das man lieber viele viele kleine
> funktionen hat.  8bit ist hier eher kontraproduktiv weil trotzdem 32bit
> verbraucht werden... usw ...

Quark^3. Kein Mensch optimiert C-Funktionen, damit sie in den Cache der 
CPU passen. Das macht man, wenn überhaupt, in Assembler, und auch nur 
dort, wo es ULTIMATIV nötig ist.

https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung

Die Grundlagen gelten ganz allgmein.

https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Was

von gdgddfgdfd (Gast)


Lesenswert?

Falk B. schrieb:
>> und das er nunmal variablen > 8bit nicht so mag
>
> UNSINN!!!

Zugriffe auf 16/32bit sind also weiter in einem Takt möglich?
Ich glaube nicht ...
Es geht auch nicht darum das man jetzt bei einer Tasateneingabe 
optimiert.
Aber , wenn man in der summe etwas darauf achtet ist so ein AVR lange 
nicht am limit .. auch wenn hier oft solche threads erscheinen.
Oft werden "int" oder "short" sogar "float" variablen genutzt ohne das 
diese sinn machen.  da werden dann zahlen im bereich 0-10 übergeben.
Die funktion wird im code 100x aufgerufen und jedesmal speicher 
verbraten.

Sowas meine ich damit.
Das man beim programmieren etwas auf die architektur achtet.
Auch wenn die compiler recht intelligent sind.



Falk B. schrieb:
> Quark^3. Kein Mensch optimiert C-Funktionen, damit sie in den Cache der
> CPU passen. Das macht man, wenn überhaupt, in Assembler, und auch nur
> dort, wo es ULTIMATIV nötig ist.

Ich habe ein Projekt mit einem M7 der (nebenbei) mjpeg decodiert.
Ohne diese Anpassung auf 32bit alianing oder kleinere Funktionen liegt 
die Bildrate bei QVGA bei ca 10-13fps , mit dieser Optimierung bei ca 
22-25fps.
Die Anpassung ist im C code und damit auch wieder für andere M7 
portabel.
(getestet auf STM F7 H7 und NXP RT1060 )

Generell ist der M7 etwas tricky. durch die diversen Speicherbereiche 
und deren verhalten ( caching , BUSse )

von Peter D. (peda)


Lesenswert?

Man kann es ruhig auf die Spitze treiben. Alle ähnlichen Codesequenzen, 
die an 2 oder mehr Stellen auftreten, macht man zu einer Funktion, der 
nur die Unterschiede übergeben werden.
Es schaded auch nicht, wenn diese Funktionen nur aus 1 oder 2 Zeilen 
bestehen.

Der große Vorteil neben der Codeersparnis ist, man macht auch alle 
Fehler immer nur an einer Stelle, muß also nur eine Stelle korrigieren.

: Bearbeitet durch User
von gdgddfgdfd (Gast)


Lesenswert?

Falk B. schrieb:
>> siehe AVR mit PROGMEM
>
> Sicher, ist halt eine Besonderheit. Wenn man sie kennt ist es aber kein
> echtes Problem, nur ein wenig mehr Aufwand.

richtig.
Bezieht sich darauf das der TE den Unterschied zwischen RAM und Flash 
Nutzung bei Strings jetzt ja kennt.
Wenn er in zukunft darauf achtet .. ist das kein thema mehr.

Wenn er mal mit Cortex M zu tun hat wird er der einfachheit halber auf
1
const char *string = "test";
zurückgreifen.

von Wilhelm M. (wimalopaan)


Lesenswert?

gdgddfgdfd schrieb:

> Wenn er mal mit Cortex M zu tun hat wird er der einfachheit halber auf
>
1
> const char *string = "test";
2
>
> zurückgreifen.

Oder auch für AVR
1
const auto s1 = "abc"_pgm;

schreiben. Damit sind gleiche Strings auch nur einmal im Flash, der 
Zugriff ist gekapselt, man kann kein _P mehr bei irgendeiner Funktion 
vergessen.

Daher der Ratschlag: bevor er die Plattform wechselt, was sicher bei der 
Auquariensteuerung völlig unnötig ist, erstmal mit dem Thema 
Softwareentwicklung intensiv befassen. Und das nicht auf dem µC, sondern 
in einer komfortableren Umgebung, etwa ein PC mit geeigneter IDE.

von Falk B. (falk)


Lesenswert?

gdgddfgdfd schrieb:
> Falk B. schrieb:
>>> und das er nunmal variablen > 8bit nicht so mag
>>
>> UNSINN!!!
>
> Zugriffe auf 16/32bit sind also weiter in einem Takt möglich?
> Ich glaube nicht ...

War das die Frage? Ist das für einen Aquariumcontroller wichtig?

> Aber , wenn man in der summe etwas darauf achtet ist so ein AVR lange
> nicht am limit .. auch wenn hier oft solche threads erscheinen.

EBEN!

>> Quark^3. Kein Mensch optimiert C-Funktionen, damit sie in den Cache der
>> CPU passen. Das macht man, wenn überhaupt, in Assembler, und auch nur
>> dort, wo es ULTIMATIV nötig ist.
>
> Ich habe ein Projekt mit einem M7 der (nebenbei) mjpeg decodiert.
> Ohne diese Anpassung auf 32bit alianing oder kleinere Funktionen liegt
> die Bildrate bei QVGA bei ca 10-13fps , mit dieser Optimierung bei ca
> 22-25fps.

Eben DAS ist so eine Anwendung, wo sich so eine Optimierung lohnt. Das 
sollte man aber schon dazu sagen!

von Stefan F. (Gast)


Lesenswert?

Peter D. schrieb:
> Es schaded auch nicht, wenn diese Funktionen nur aus 1 oder 2 Zeilen
> bestehen.

Das ist ein Punkt, der mich anfangs überraschte, da ich vor 
Mikrocontroller überwiegend PC's programmierte.

Beim PC sind Funktionsaufrufe oft (nicht immer) wesentlich teurer, als 
beim AVR. Insbesondere dann, wenn die angesprungene Funktion in einem 
anderen Speicherberbereich liegt, der sich gerade nicht im CPU Cache 
befindet.

Bei AVR kosten Funktionsaufrufe hingegen fast keinen Overhead. Dazu 
kommt, dass der Compiler einige Funktionen durch inline-Code ersetzt, 
wenn er das für vorteilhaft hält.

von gdgddfgdfd (Gast)


Lesenswert?

Das alles in summe betrachtet führt dazu das der flash nicht so schnell 
voll ist.

auch funktionen mit vielen übergabeparametern frisst nicht nur zeit und 
ram .. sondern auch flash.

Die sichtweise wie man sachen verallgemeinert oder modularisiert ohne 
groß aufzublähen fehlt oft am anfang.

Aber nur durch fehler lernen wir , oder?

von Falk B. (falk)


Lesenswert?

gdgddfgdfd schrieb:
> Aber nur durch fehler lernen wir , oder?

Viele nicht mal dadurch. Das geht schon bei der Groß/Kleinschreibung los 
. . .

von gdgddfgdfd (Gast)


Lesenswert?

Falk B. schrieb:
> gdgddfgdfd schrieb:
>> Aber nur durch fehler lernen wir , oder?
>
> Viele nicht mal dadurch. Das geht schon bei der Groß/Kleinschreibung los
> . . .

Stimmt.
Bei mir liegts nur an der Faulheit.
Hat sich seit 30 Jahren nicht gebessert.

von svensson (Gast)


Lesenswert?

Peter D. schrieb:
> Der große Vorteil neben der Codeersparnis ist, man macht auch alle
> Fehler immer nur an einer Stelle, muß also nur eine Stelle korrigieren.

Und die positive Kehrseite ist, daß Änderungen nur an einer zentralen 
Stelle vorgenommen werden müssen. Wenn man viele Änderungen vornimmt, 
dann wirkt sich das enorm zeitsparend aus.

Ich muß aber gestehen, daß ich manchmal auch Programmteile kopiere, 
wodurch sich dann zwangsläufig redundante Codeteile ergeben, weil das 
einfacher ist als eine Funktion zu schreiben. Wenn genügend Speicher da 
ist, kann ich mir diesen Luxus erlauben...

von Arno (Gast)


Lesenswert?

gdgddfgdfd schrieb:
> ich vermisse eine Angabe der Compileroptimierung
> Stand das schon irgendwo?

Ich möchte nochmal auf diese Frage hinweisen - ob mit -O0 oder -Os 
kompiliert wird, dürfte die Programmgröße massiv beeinflussen.

Genauso die Linker-Optionen überprüfen, ob zum Beispiel LTO aktiv ist. 
Und diese andere Option, deren Name mir gerade nicht einfällt, dass 
nicht die ganze Bibliothek dazu gelinkt wird, wenn nur eine einzelne 
Funktion daraus benötigt wird. Sollte zwar standardmäßig aktiv sein, 
aber besser mal nachsehen...

Falk B. schrieb:
>>Also ich habe das mal versucht umzusetzen, doch ist der Flash verbrauch
>>nicht gesunken sondern um 0,2%(256Bytes) gestiegen.
>
> Darf nicht sein.

Vielleicht, weil durch die Änderung eine/mehrere der _P-Funktionen mit 
gelinkt wird, die vorher nicht benötigt wurde(n)? Die "normalen" 
Funktionen (ohne _P) werden ja für die ungeänderten Teile nach wie vor 
gebraucht.

MfG, Arno

von gdgddfgdfd (Gast)


Lesenswert?

Ich habe gerade gesehen das er in seiner main.c ganz viele Infos zum 
Start ausgibt. Das ist als Anfänger schön wenn da was steht , ist aber 
oft auch totaler nonsins^^...
Es belegt Speicher und man baut künstliche delays ein damit man Zeit hat 
das zu lesen.

Ich hab beim AVR damals immer eine eigene Datei für alle Strings 
angelegt.
Diese war entsprechend formatiert.

texte_de.txt
1
"Hauptmenü",
2
"Submenü1",
3
"Version",
4
.....

im quelltext dann irgendwo:
1
const char *strings_de[] PROGMEM={ 
2
   #include "texte_de.txt"
3
};

im source gab es dazu passend eine liste
1
typedef enum{
2
   TXT_MAIN = 0,
3
   TXT_SUB1,
4
   TXT_VERSION,
5
....
6
}texte_e ;

damit lies sich verhindern das texte vlt doppelt im flash landen.
und bei mehreren Sprachen brauch man nur den pointer (strings_de) 
verändern.
1
void foo ( texte_e text ){
2
       sprintf_P( buffer , strings_de[text]);
3
}

auch Lesbarkeit:
1
if(menuSelector == 2)
ist nichtssagend.

mach dir dafür defines

#define MAIN_MENUE  1
#define RTC_MENUE   2

oder eine enumeration
enum{
  MENUE_NONE = 0,
  MENUE_MAIN,
  MENUE_RTC,
...
};

von Falk B. (falk)


Lesenswert?

Noch was.

Die One Wire Kommunikation ist NICHT solide, denn während der 
Übertragung eines Bits müssen die Interrupts gesperrt sein, damit das 
Timing wasserdicht ist! Außerdem braucht man auch hier für die 
Temperatur keine Fließkommazahlen. Außerdem fehlt die CRC-Prüfung, das 
kann bisweilen auch mal daneben gehen. Was macht deine Steuerung dann? 
So geht es sicher und besser.

Beitrag "Onewire + DS18x20 Library"
1
#include "MCP7940M.h"
2
#include "../Communication/usart.h"
3
4
const uint8_t daysInMonth [] PROGMEM = {31,28,31,30,31,30,31,31,30,31,30,31};
5
6
uint8_t  MCP7940_ADDRESS          =       0x6F;                       // Device address, fixed value      //
7
uint8_t  MCP7940_RTCSEC           =       0x00;                       // Section 1: timekeeping           //
8
uint8_t  MCP7940_RTCMIN           =       0x01;                       //                                  //
9
uint8_t  MCP7940_RTCHOUR          =       0x02;                       //                                  //

Auch das hier ist Unsinn. Hier werden echte Variablen angelegt, die 
echten RAM verbrauchen. Das braucht keiner, denn das sind alles 
Konstanten. In C nutzt man hier eher #define
1
#define  MCP7940_ADDRESS 0x6F // Device address
2
#define  MCP7940_RTCSEC  0x00 // Section 1: timekeeping

von Frank K. (fchk)


Lesenswert?

Falk B. schrieb:

> uint8_t  MCP7940_ADDRESS          =       0x6F;                       //
> Device address, fixed value      //
> uint8_t  MCP7940_RTCSEC           =       0x00;                       //
> Section 1: timekeeping           //
> uint8_t  MCP7940_RTCMIN           =       0x01;                       //
> //
> uint8_t  MCP7940_RTCHOUR          =       0x02;                       //
> //
> [/c]
>
> Auch das hier ist Unsinn. Hier werden echte Variablen angelegt, die
> echten RAM verbrauchen. Das braucht keiner, denn das sind alles
> Konstanten. In C nutzt man hier eher #define
>
>
1
> #define  MCP7940_ADDRESS 0x6F // Device address
2
> #define  MCP7940_RTCSEC  0x00 // Section 1: timekeeping
3
>

Oder static const uint8_t, wenn es typsicher sein soll.

fchk

von Falk B. (falk)


Lesenswert?

Frank K. schrieb:
> Oder static const uint8_t, wenn es typsicher sein soll.
>
> fchk

Das wird dann aber in C auch eine echte Variabel mit RAM-Verbrauch, 
oder?

von Wilhelm M. (wimalopaan)


Lesenswert?

Frank K. schrieb:
> Falk B. schrieb:
>
>> uint8_t  MCP7940_ADDRESS          =       0x6F;                       //
>> Device address, fixed value      //
>> uint8_t  MCP7940_RTCSEC           =       0x00;                       //
>> Section 1: timekeeping           //
>> uint8_t  MCP7940_RTCMIN           =       0x01;                       //
>> //
>> uint8_t  MCP7940_RTCHOUR          =       0x02;                       //
>> //
>> [/c]
>>
>> Auch das hier ist Unsinn. Hier werden echte Variablen angelegt, die
>> echten RAM verbrauchen. Das braucht keiner, denn das sind alles
>> Konstanten. In C nutzt man hier eher #define
>>
>>
1
>> #define  MCP7940_ADDRESS 0x6F // Device address
2
>> #define  MCP7940_RTCSEC  0x00 // Section 1: timekeeping
3
>>
>
> Oder static const uint8_t, wenn es typsicher sein soll.

Mmh, und
1
MCP7940_RTCSEC * MCP7940_RTCMIN

ist ein sinnvoller Ausdruck?

Also, typsicher bedeutet etwas anderes!

von Wilhelm M. (wimalopaan)


Lesenswert?

Falk B. schrieb:
> Frank K. schrieb:
>> Oder static const uint8_t, wenn es typsicher sein soll.
>>
>> fchk
>
> Das wird dann aber in C auch eine echte Variabel mit RAM-Verbrauch,
> oder?

Das ist eine read-only Variable (constexpr gibt es nur in C++), die auch 
ein schlechter Compiler sicher gut wegoptimieren kann.

von Armin K. (-donald-) Benutzerseite


Lesenswert?

Falk B. schrieb:
> Die One Wire Kommunikation ist NICHT solide, denn während der
> Übertragung eines Bits müssen die Interrupts gesperrt sein, damit das
> Timing wasserdicht ist!

Das muss nicht Wasserdicht sein, da der AVR nicht im Aquarium ist ;-)

von W5100Usa (Gast)


Lesenswert?

Armin K. schrieb:
> Das muss nicht Wasserdicht sein, da der AVR nicht im Aquarium ist ;-)

Aber die Quad-Core Lösung mit 64-Bit ARM ist nach heutigem
Diskussions-Stand Pflicht!

Frank K. schrieb:
> Mein Vorschlag:
>
> https://www.olimex.com/Products/OLinuXino/A64/A64-OLinuXino/open-source-hardware

von Theor (Gast)


Lesenswert?

W5100Usa schrieb:
> Armin K. schrieb:
>> Das muss nicht Wasserdicht sein, da der AVR nicht im Aquarium ist ;-)
>
> Aber die Quad-Core Lösung mit 64-Bit ARM ist nach heutigem
> Diskussions-Stand Pflicht!

Der Zweck des Forums und dieser Diskussion ist meiner Ansicht nach, 
Empfehlungen zu ggeben und vernünftige Gründe dafür zu nennen. 
Ausserdem, nach Möglichkeit konkrete Informationen darüber, wie diese 
Empfehlungen realisiert werden können.


Welche Diskussion zwischen welchen Diskussionsteilnehmern meinst Du?

Die Diskussion hier fokussiert sich, meiner Meinung nach zu Recht, auf 
eine Überarbeitung des Codes und hat, wiederum meiner Meinung nach zu 
Recht, die Voraussetzung, dass bei Umsetzung der Ratschläge der AVR (der 
vom TO genannte Typ resp. der nächstgrössere) völlig ausreicht.


Wer oder was verpflichtet hier den TO oder sonstwen und mit welcher 
Rechtfertigung tut er oder es das?

"Pflicht" ist hier gar Nichts.
Der TO hat das Recht jede Lösung zu nehmen, die er möchte - sogar wenn 
dies von Anderen als unvernünftig betrachtet wird.

von Felix N. (felix_n888)


Lesenswert?

Hallo,

Arno schrieb:
> Ich möchte nochmal auf diese Frage hinweisen - ob mit -O0 oder -Os
> kompiliert wird, dürfte die Programmgröße massiv beeinflussen.

Habe mal unter AVR/GNU C Compiler -> Optimization nach geschaut dort 
steht drin: Optimization Level: Optimize(-O1).

Ich habe es mal testweise umstellt bei -O0 kann ich erst gar nicht 
kompilieren dort kommt der Fehler: "region `text' overflowed by 14018 
bytes"

Ja -O1 wird ja benutzt dort habe ich im Moment 98952 Bytes an Flash und 
6853 Bytes an SRAM. Mit -Os habe ich 89932 Bytes Flash und 6893 Bytes an 
SRAM.

Habe ich dadurch irgendwelche Nachteile wenn ich das auf -Os umstelle?

Arno schrieb:
> Genauso die Linker-Optionen überprüfen, ob zum Beispiel LTO aktiv ist.

Kann ich nicht finden. Weder als Checkbox noch in der Command Zeile.

Falk B. schrieb:
> gescheite Umstruktuerierung deines Codes

Ja da bin ich im Moment noch am Überlegen was mehr Sinn macht. Das 
Projekt neu Anlegen und den alten Code Schritt weiße übernehmen und 
dabei überarbeiten. Zb. Floats weg lassen ... oder im bestehenden Code 
überarbeiten.

Falk B. schrieb:
> Capice?

Frank K. schrieb:
> Eine Kopie ist genau das: eine Kopie und kein Zeiger/Verweis.

Stefanus F. schrieb:
> ja alles richtig.

Theor schrieb:
> Klar? Oder hast Du noch Fragen?

Habe es mittlerweile kapiert^^. Danke euch :)

Falk B. schrieb:
> Weil der Mensch mit NAMEN deutlich besser
> klar kommt!

Falk B. schrieb:
> Denn dieser Job gehört dem COMPILER!
> Der verwaltet die Adressen!

Moment mal. Das heißt ich definiere gar nicht die Adressen fürs EEPROM, 
sondern die werden dann Zufällig zugewiesen, oder wie muss ich das 
verstehen?

In deinem Struct Beispiel bezieht sich die 16 Bit 
Variable(min_temperature) ja nicht auf den gelesen Wert vom EE sondern 
auf die Adresse im EE wo der Wert liegt.

Oder muss ich die Variablen einmal mit einer Adresse definieren?
1
my_struct.irgendwas = eeprom_adresse;

Falk B. schrieb:
> Ist das nicht DEUTLICH lesbarer und vor allem selbsterklärend?

Ja auf jeden Fall. Aber eine Frage habe ich dazu noch du legt ja eine 
Variable von der Struktur im EEMEM an wobei sich EEMEM wahrscheinlich 
auf das Interne EEPROM des uC bezieht. Ich benutze ja ein externes 
EEPROM, reicht es dann wenn ich es nur mit
1
my_struct my_ee;
initialisiere?

Falk B. schrieb:
> Hier der Anhang.

Clever auf jeden Fall. Wäre ich aber im Leben nie drauf gekommen mit Bit 
Operatoren da zu arbeiten ...

Falk B. schrieb:
> Ist das für einen Aquariumcontroller wichtig?

Zeitkritisches habe ich eigentlich nix in meinem Projekt drin und wenn 
der pH Wert mal unter 6.80 sinken wird werden meine Fischis auch nicht 
davon sterben.

Das einzige wovor ich immer Angst hatte war das sich mein Controller 
aufhängt während gerade das Magnetventil für die Co2 Zufuhr geöffnet 
ist, konnte ich aber relativ einfach mit dem Watchdog Timer beheben. 
Zudem hat er sich bis jetzt auch noch nie aufgehängt.

gdgddfgdfd schrieb:
> Das ist als Anfänger schön wenn da was steht , ist aber
> oft auch totaler nonsins^^

Es hatte am Anfang wirklich mal ein Sinn gehabt, mein Controller hatte 
sich durch nicht ganz korrekte Verdrahtung und scheinbar Kapazitive 
Einkopplung der SCL und SCK Leitungen zu System Hängen geführt hat. Habe 
ich ein Start Up Bildschirm gemacht um zu sehen wo er sich aufhängt, es 
war auch mal eine Startzeit Messung drin aber das ist alles mittlerweile 
nicht mehr nötig.

Hatte die Texte damals dennoch drin gelassen, können aber raus. Muss die 
main eh mal aufräumen und ein paar Funkionen entfernen und auslagern.

gdgddfgdfd schrieb:
> auch Lesbarkeit:if(menuSelector == 2)
> ist nichtssagend.

Ja ich weiß menuSelector, menuPointer, menuInlinePointer ... mir war 
damals nix besseres eingefallen.

Falk B. schrieb:
> Außerdem fehlt die CRC-Prüfung, das
> kann bisweilen auch mal daneben gehen. Was macht deine Steuerung dann?

Die sollte weiterlaufen liefert mir nur dann eine Temperatur von 
-0.06°C. Den Link werde ich mir mal anschauen.

Falk B. schrieb:
> In C nutzt man hier eher #define

Ah ok. Ja die Lib kommt aus dem I-Net. Werde ich abändern. Schaue mir 
dann auch gleich mal die anderen Libs an ob es da noch sowas gibt.

Theor schrieb:
> Die Diskussion hier fokussiert sich

Theor schrieb:
> auf
> eine Überarbeitung des Codes und hat

Jor das wahr zwar eigentlich nicht mein Ziel. Aber der Richtung wechsel 
in die Code Optimierung finde gut. Bin gar nicht erst auf die Idee 
gekommen. Das der Flash wegen vielleicht falscher Programmierung voll 
ist.

Da habe ich am Ende mehr von als wenn ich mir jedesmal ein neuen uC 
kaufen mit mehr flash/ram etc.

Lg

von svensson (Gast)


Lesenswert?

Armin K. schrieb:
> as muss nicht Wasserdicht sein, da der AVR nicht im Aquarium ist ;-)

Wäre aber möglich. Wir haben schon einen µC in Epoxyd eingegossen und 
unter Wasser betrieben. (Meine Idee war das nicht!) Wegen der 
Wärmeentwicklung (läuft an 24V) wurde aber ein Schaltregler eingesetzt.
Funktioniert tatsächlich. ;-)

von Stefan F. (Gast)


Lesenswert?

Felix N. schrieb:
>> Genauso die Linker-Optionen überprüfen, ob zum Beispiel LTO aktiv ist.
> kann ich nicht finden. Weder als Checkbox noch in der Command Zeile.

Ich empfehle diese Optionen:

FLAGS = -Wall -O1 -fshort-enums -ffunction-sections -fdata-sections
CFLAGS = -std=c99
CPPFLAGS = -fno-exceptions
LDFLAGS = -lm -Wl,--gc-sections

Zum Compilieren für *.c Dateien: FLAGS und CFLAGS
Zum Compilieren für *.cpp Dateien: FLAGS und CPPFLAGS
Zum Linken: FLAGS und LDFLAGS

von Stefan F. (Gast)


Lesenswert?

Erklärung:

-Wall Aktiviert alle empfohlenen Warnungen (es gibt noch mehr, deswegen 
ist das Wort "all" irreführend).

-O0 Optimiert gar nicht
-O1 Optimiert auf Performance, geringfügig zu Lasten der Größe
-O2 Optimiert auf Performance, mehr zu Lasten der Größe
-O3 Optimiert auf Performance, ohne Rücksicht auf die Größe
-Os Optimiert auf Größe, geringfügig zu Lasten der Performance
-Og optimiert ein bisschen, soweit es den Debugger nicht stört

-fshort-enums Die numerischen Werte von enums sind 8bit groß - Normal 
wären es 16bit

-ffunction-sections -fdata-sections Diese beiden Optionen ermöglichen es 
dem Linker (nach dem Compilieren), den Code auseinander zu nehmen und 
unbenutzte Funktionen zu entfernen.

-std=c99 Aktiviert Erweiterungen der Sprache C, die ich gerne benutze

-fno-exceptions Deaktiviert das Exception-Handling in C++, was 
kompakteren Code ergibt. Dann kann man aber eben keine Exceptions mehr 
nutzen. Macht man auf µC eh nur selten.

-lm Bindet die Math Library ein, für Fließkommazahlen

--gc-sections Diese Optionen sagen dem Linker, dass er nicht verwendeten 
Code weg schmeißen soll.

Wenn du in printf() Fließkommazahlen brauchst, dann brauchst du noch die 
LDFLAGS += -Wl,-u,vfprintf -lprintf_flt

Für Fließkommazahlen in scanf(): LDFLAGS += -Wl,-u,vscanf -lscanf_flt

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefanus F. schrieb:
> Ich empfehle diese Optionen:
>
> FLAGS = -Wall -O1 -fshort-enums -ffunction-sections -fdata-sections
> CFLAGS = -std=c99

zusätzlich:

-mrelax -mcall-prologues

und natürlich -Os statt -O1.

Stefanus F. schrieb:
> -fshort-enums Die numerischen Werte von enums sind 8bit groß - Normal
> wären es 16bit

Das ist allerdings keine Optimieruns-Option, sonder wählt ein anderes 
ABI.

> -lm Bindet die Math Library ein, für Fließkommazahlen

Braucht man schon seit X Jahren nicht mehr.

: Bearbeitet durch User
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Felix N. schrieb:
> Ja da bin ich im Moment noch am Überlegen was mehr Sinn macht. Das
> Projekt neu Anlegen und den alten Code Schritt weiße übernehmen und
> dabei überarbeiten.

Ja! neu anlegen und gründlich überarbeiten, da sind locker 30% code 
reduction drin, hinweise gab es hier doch reichlich und mal klartext - 
dein code ist sehr "bescheiden" so im sinne von level two auf einer 
scala von 1-10. mit 128k kannst du bei dem project lange bis ewig leben, 
wenn du sinnig programmierst.

und wenn noch nicht geschehen tausche auch die gcc version, gute 
erfahrung habe ich mit v8.3 bzgl. optimization.

und für die ferne zukunft würde ich vielleicht mal esp32 mit micropython 
andenken, python macht richtig spass braucht aber auch einige zeit bis 
man das halbwegs drauf hat und pythonkenntnisse kann man immer 
gebrauchen auf allen plattformen als schweizer-messer oder als die 
eierlegende wollmilchsau!


mt

von Falk B. (falk)


Lesenswert?

Felix N. schrieb:

> Habe ich dadurch irgendwelche Nachteile wenn ich das auf -Os umstelle?

Nein.

> Falk B. schrieb:
>> Denn dieser Job gehört dem COMPILER!
>> Der verwaltet die Adressen!
>
> Moment mal. Das heißt ich definiere gar nicht die Adressen fürs EEPROM,

Ja.

> sondern die werden dann Zufällig zugewiesen,

Nicht ganz, aber im Normalfall ist die exakte Adresse einer Variable 
vollkommen egal. Das kann der Compiler zusammenbasteln wie er will. Es 
gibt Ausnahmen, logisch.

> oder wie muss ich das
> verstehen?

Bei Structs legt der Compiler die Daten exakt so in der Reihenfolge an, 
wie sie aufgeschrieben sind. Aber er darf bisweilen Lücken einfügen, 
wenn es die Architektur verlangt oder es Vorteile bringt.

> In deinem Struct Beispiel bezieht sich die 16 Bit
> Variable(min_temperature) ja nicht auf den gelesen Wert vom EE

Aber sicher!

> sondern
> auf die Adresse im EE wo der Wert liegt.
>
> Oder muss ich die Variablen einmal mit einer Adresse definieren?
> my_struct.irgendwas = eeprom_adresse;

NEIN!

Ok, hier gibt es ein Mißverständnis. Beim internen EEPROM übernimmt der 
Compiler die Adressverwaltung, genauso wie im RAM oder ROM (Flash). Bei 
externem, seriellen Speicher ist der Compiler nicht beteiligt, dort muss 
man alles "zu Fuß" organisieren. Aber auch dort ist man gut beraten, 
zumindest teilweise die Funktionen des Compilers zu nutzen. Eben indem 
man einen Struct definiert und die Daten struc(block) weise in den 
externen Speicher schreibt bzw. von dort liest.

> Falk B. schrieb:
>> Ist das nicht DEUTLICH lesbarer und vor allem selbsterklärend?
>
> Ja auf jeden Fall. Aber eine Frage habe ich dazu noch du legt ja eine
> Variable von der Struktur im EEMEM an wobei sich EEMEM wahrscheinlich
> auf das Interne EEPROM des uC bezieht. Ich benutze ja ein externes
> EEPROM, reicht es dann wenn ich es nur mitmy_struct my_ee;initialisiere?

Nein, das geht leider nicht, siehe oben. Aber auch dann arbeitet man 
nicht derartig mit absoluten Adressen.

> Falk B. schrieb:
>> Ist das für einen Aquariumcontroller wichtig?
>
> Zeitkritisches habe ich eigentlich nix in meinem Projekt drin und wenn
> der pH Wert mal unter 6.80 sinken wird werden meine Fischis auch nicht
> davon sterben.

Deine CPU wird so oder so tödlich gelangweilt sein, ganz egal wie 
ineffizient dein Programm ist.

> Jor das wahr zwar eigentlich nicht mein Ziel. Aber der Richtung wechsel
> in die Code Optimierung finde gut. Bin gar nicht erst auf die Idee
> gekommen. Das der Flash wegen vielleicht falscher Programmierung voll
> ist.

Vor allem. Wenn du sie meisten (alle?) konstanten Strings in den Flash 
verlagerst (PROGMEM und so), dann wird massiv RAM frei und du kanst 
problemlos mit dem großen Bruder 2561 (aka Arduino Mega) mit 256kB Flash 
und 8kB RAM arbeiten, ohne ins Schwitzen zu kommen.

von Joachim B. (jar)


Lesenswert?

Felix N. schrieb:
> Ja -O1 wird ja benutzt dort habe ich im Moment 98952 Bytes an Flash

und warum 4K für den Bootloader wo 512 Byte reichen?

von Felix N. (felix_n888)


Lesenswert?

Apollo M. schrieb:
> Ja! neu anlegen und gründlich überarbeiten

Ja glaubig auch. Werde ich auch machen.

Apollo M. schrieb:
> nd wenn noch nicht geschehen tausche auch die gcc version, gute
> erfahrung habe ich mit v8.3 bzgl. optimization.

Nein ich benutze die GCC Version 5.4.0 die Version 8.3.0 kann ich nicht 
finden habe nur die AVR-GCC 9.2.0 gefunden zum Downloaden:

http://blog.zakkemble.net/avr-gcc-builds/

Jedoch scheint da irgendwas faul zu sein. Beim Kompilieren meckerte er 
erst bei der Zusatz Option "unrecognized debug output level 
'c-sections'" habe dann -gc-sections entfernt dann konnte ich 
Kompilieren jedoch habe ich nun 0 Bytes Flash und 0 Bytes RAM Belegung. 
Yeah! Oder auch irgendwie nicht. Er lädt zumindest immer mein altes 
Programm hoch welches ich mit GCC 5.4.0 Kompiliert habe.

Habe nur die neuen Daten der Toolchain in den bestehen Ordner der 
Toolchain im Atmel Studio Ordner geschoben und halt 5.4.0(Ordner) 
gelöscht.

Falk B. schrieb:
> Aber sicher!

OK?

Falk B. schrieb:
> eeprom_write_word(&my_settings.max_temperature, max);

Da ich die interen EEPROM Funktion des AVRs nicht nutze habe ich mir mal 
kurz die Funktion angeschaut und der erste Parameter ist die Adresse im 
EEPROM der zweite Parameter der Wert.


Das heißt doch folglich dann wenn du als erstes die Variable aus der 
Struktur(max_temperature) übergibt als 1en Paramter das in dieser 
Variable(max_temperature) nicht Wert steht sondern nur die EEPROM 
Adresse die vom Kompiler vergeben wird steht. Und das der zweite 
Parameter(max) die Variable ist welchen den eigentlichen Wert enthält 
der ins EEPROM geschrieben werden soll. Oder nicht?

Falk B. schrieb:
> Ok, hier gibt es ein Mißverständnis. Beim internen EEPROM übernimmt der
> Compiler die Adressverwaltung, genauso wie im RAM oder ROM (Flash). Bei
> externem, seriellen Speicher ist der Compiler nicht beteiligt, dort muss
> man alles "zu Fuß" organisieren.

Sorry habe mit diesen Strukturen noch nie gearbeitet. Absolutes Neuland 
für mich.

Wenn ich das Interne EEPROM nutze brauch ich mir keine Gedanken machen 
um die Adressen im EEPROM. Nutze ich(wie jetzt) ein externes EEPROM muss 
ich diese ihm einmal Mitteilen. Würde das jetzt so machen:
1
typedef struct { //Struktur definieren
2
  uint8_t: karbonathaerte;
3
  uint8_t: benutzeDimmung;
4
  uint8_t: pHSoll;
5
  ...
6
} my_eepromAddress;
7
8
void setEEEPROMAddress(void) { //EEPROM Adressen einmal während des Startup laden
9
  my_eepromAddress.karbonathaerte = 0x01;
10
  my_eepromAddress.benutzeDimmung = 0x02;
11
  my_eepromAddress.phSoll    = 0x03;
12
  ...
13
}

Falk B. schrieb:
> Nein, das geht leider nicht

Muss ich dieses Struktur überhaupt initialisieren, ich meine du hast 
dort ja ein Datentyp im EEPROM anlegt. Kann ich dann direkt damit 
arbeiten sprich wie im meinem Beispiel oben?

Joachim B. schrieb:
> und warum 4K für den Bootloader wo 512 Byte reichen?

Der Controller liegt schon seit ein paar Jahren bei mir(so 2016) den 
habe ich damals fertig mit Bootloader bei unserem ehemaligen 
Elektronikshop um der Ecke gekauft, für glaubig 10 Eur. Dort sagte man 
mir es ist schon ein Bootloader drauf der würde ca. 4 Kb vom Flash in 
Anspruch nehmen. Aber gut zu wissen dann kann ich den neuen ja mal bei 
Gelegenheit drauf brennen.

Mfg

von Falk B. (falk)


Lesenswert?

Felix N. schrieb:


> Nein ich benutze die GCC Version 5.4.0 die Version 8.3.0 kann ich nicht
> finden habe nur die AVR-GCC 9.2.0 gefunden zum Downloaden:

Warum nimmst du nicht einfach Atmelstudio? Dort ist alles fix und fertig 
drin. Dieses Rumgehacke mit Kommandozeile und Dutzenden Parametern ist 
gerade für Anfänger wie du schlicht Unsinn.

>> eeprom_write_word(&my_settings.max_temperature, max);
>
> Da ich die interen EEPROM Funktion des AVRs nicht nutze habe ich mir mal
> kurz die Funktion angeschaut und der erste Parameter ist die Adresse im
> EEPROM der zweite Parameter der Wert.

Ja.

> Das heißt doch folglich dann wenn du als erstes die Variable aus der
> Struktur(max_temperature) übergibt als 1en Paramter das in dieser
> Variable(max_temperature) nicht Wert steht sondern nur die EEPROM
> Adresse die vom Kompiler vergeben wird steht. Und das der zweite
> Parameter(max) die Variable ist welchen den eigentlichen Wert enthält
> der ins EEPROM geschrieben werden soll.

Ja sicher. Wo liegt das Problem?

> Wenn ich das Interne EEPROM nutze brauch ich mir keine Gedanken machen
> um die Adressen im EEPROM. Nutze ich(wie jetzt) ein externes EEPROM muss
> ich diese ihm einmal Mitteilen.

So einfach ist es nicht. Weig gesagt, bei externem EEPROM muss man 
vieles manuell machen. Man kann es nur dahingehend vereinfachen bzw. dem 
"Normalfall" angleichen, indem man z.B. beim Start einen Datenblock aus 
dem externen EEPROM in ein struct vom gleichen Typ in den RAM kopiert. 
Dann hat man alle Einstellungen im RAM und kann dort beliebige 
Schreib/Lesezugriffe machen. Irgendwann muss man dann aber die Daten vom 
RAM wieder in den EEPROM kopieren, damit sie dauerhaft erhalten bleiben.
Auch das macht man meist sinnvoll als Datenblock und nicht mit 
Einzeldaten.

 Würde das jetzt so machen:
> typedef struct { //Struktur definieren
>   uint8_t: karbonathaerte;
>   uint8_t: benutzeDimmung;
>   uint8_t: pHSoll;
>   ...
> } my_eepromAddress;

Das ist nicht ganz richtig. typedef definiert einen Datentyp, keine 
Variable. Und schon gar nicht eine Adresse! Solche Namen sind maximal 
irreführend! Die Variable muss dann im 2. Schritt normal definiert 
werden, wie in meinem Beispiel. Man kann zwar auch direkt eine Variable 
als struc anlegen, ohne einen Typ zu definieren, das ist aber meistens 
ungünstig. Näheres erklärt dir ein C-Buch.

> void setEEEPROMAddress(void) { //EEPROM Adressen einmal während des
> Startup laden

Falsch. Adressen werden nicht geladen. Gewöhn dir eine klare, saubere 
Sprache bzw. Beschreibung/Namensgebung an, sonst wurschtelst du nur rum.

Strukturierte Programmierung auf Mikrocontrollern

>   my_eepromAddress.karbonathaerte = 0x01;
>   my_eepromAddress.benutzeDimmung = 0x02;
>   my_eepromAddress.phSoll    = 0x03;

Was du meinst ist das Laden der EEPROM-Werte mit einem Startwert oder 
Standardwert. Das kann der Compiler selber.

struct my_settings EEMEM = {1, 2, 3};

Damit wird vom Compiler ein .eep File (Intel-HEX) erzeugt, daß ebenso 
wie der Flash einfach in den AVR programmiert wird. Damit hast du im 
internen EEPROM initialisierte Daten stehen. Beim externen EEPROM geht 
das freilich nicht. Da ist wieder Handarbeit angesagt.

von Peter D. (peda)


Lesenswert?

Falk B. schrieb:
> struct my_settings EEMEM = {1, 2, 3};

Die bessere Schreibweise ist:
1
struct my_settings EEMEM = {
2
  .karbonathaerte = 0x01,
3
  .benutzeDimmung = 0x02,
4
  .phSoll         = 0x03,
5
};
Es müssen auch nicht alle Elemente initialisiert werden, die nicht 
aufgefürten werden mit 0 initialisiert.

von gdgddfgdfd (Gast)


Lesenswert?

Felix N. schrieb:
> Da ich die interen EEPROM Funktion des AVRs nicht nutze habe ich mir mal
> kurz die Funktion angeschaut und der erste Parameter ist die Adresse im
> EEPROM der zweite Parameter der Wert.

ich greife das nochmal auf.

Wenn er immer den externen nutzt. muss er es eh anders machen.
der compiler kennt den externen nicht
hier muss man dieses struct bei der init auf die startadresse des 
externen eeprom setzen.

bei einem neugerät kann man am anfang des struct ein flag setzen

default sind die externen auf 0xFF gesetzt.
wenn 0xFF im ersten byte an adresse 0x0000 steht kann der µC seine 
default werte in den externen EEPROM schreiben

also auch das erste byte auf einen anderen wert setzen

von Arno (Gast)


Lesenswert?

Felix N. schrieb:
> Arno schrieb:
>> Ich möchte nochmal auf diese Frage hinweisen - ob mit -O0 oder -Os
>> kompiliert wird, dürfte die Programmgröße massiv beeinflussen.
>
> Habe mal unter AVR/GNU C Compiler -> Optimization nach geschaut dort
> steht drin: Optimization Level: Optimize(-O1).
>
> Ich habe es mal testweise umstellt bei -O0 kann ich erst gar nicht
> kompilieren dort kommt der Fehler: "region `text' overflowed by 14018
> bytes"

Also statt 98kB 142kB (128kB plus 14kB, die nicht mehr in den Speicher 
passen).

> Ja -O1 wird ja benutzt dort habe ich im Moment 98952 Bytes an Flash und
> 6853 Bytes an SRAM. Mit -Os habe ich 89932 Bytes Flash und 6893 Bytes an
> SRAM.
>
> Habe ich dadurch irgendwelche Nachteile wenn ich das auf -Os umstelle?

Es wird an der einen oder anderen Stelle ein bisschen langsamer sein. 
Hast du gerade ein Zeit- oder ein Speicherplatzproblem? (rhetorische 
Frage)

> Arno schrieb:
>> Genauso die Linker-Optionen überprüfen, ob zum Beispiel LTO aktiv ist.
>
> Kann ich nicht finden. Weder als Checkbox noch in der Command Zeile.

Das, was ich meinte, ist:

Stefanus F. schrieb:
> Erklärung:
>
> -ffunction-sections -fdata-sections Diese beiden Optionen ermöglichen es
> dem Linker (nach dem Compilieren), den Code auseinander zu nehmen und
> unbenutzte Funktionen zu entfernen.
>
> --gc-sections Diese Optionen sagen dem Linker, dass er nicht verwendeten
> Code weg schmeißen soll.

Wichtig bei --gc-sections: Das muss direkt nach -Wl, stehen, ohne 
Leerzeichen. Denn damit weiß der Compiler, dass er das einfach so an den 
Linker weiterreichen soll (sonst kommt die Fehlermeldung, die du gesehen 
hast, denn der Compiler versteht --gc-sections nicht).

Also genau wie von Stefan geschrieben:

-Wl,--gc-sections

MfG, Arno

von temp (Gast)


Lesenswert?

Hab das bei mir mal durchlaufen lassen mit meinen Standardoptionen 
(-Os):

avr-size release/aqutest.elf
   text    data     bss     dec     hex filename
  86024    3410    3597   93031   16b67 release/aqutest.elf

Ist natürlich komplett ungetestet. Arbeitest du mit Debugger und 
Debuginfos im Code? Ich helfe mir da immer so, dass ich in meinem 
makefiles den Code in 2 Gruppen teile. Einmal den der mit -Os optimiert 
bleibt und der andere der mit -O0 zum Debuggen von der Optimierung 
befreit ist. Aber schon Ewigkeiten nicht mehr mit AVRs sondern mit 
Cotexen. Höchstens mal noch einen tiny841.

Das meiste im bss dürften deine Strings belegen wie schon gesagt wurde, 
in soweit hast du da noch Optimierungsmöglichkeiten wenn du auf den 
größeren AVR umsteigst. Auf den Flash hat das kaum Auswirkung. Wenn du 
den RAM nicht anderweitig brauchst ist es verschenkte Lebenszeit das nur 
zur Optik anders zu machen. Ob du mit Änderungen am eigenen Code 30% 
sparen kannst wie hier behauptet wird, wage ich zu bezweifeln da der 
Verhältnis zu den Libs schon nicht mehr als 30% ist. Wenn du 10 Leute 
fragst wie guter Code aussieht kriegst du 10 Meinungen und jeder findet 
seinen Stil am besten. Traue auch keinen der großspurige Behauptunge in 
der Form: "das macht man doch nicht!" von sich gibt. Das ist in der 
Regel nur nachgeplappertes Geschwätz.

Für ein komplettes Redesign würde ich dir den Umstieg auf einen Cortex 
Mx empfehlen. Allerdings nur wenn dir die Lernphase einen Zusatznutzen 
bringt. Die Zeit die du bis jetzt darauf verwendet hast dürfte nochmal 
draufgehen. Auf alle Fälle gibt es in diesem Bereich mehr fertige Boards 
als für große AVRs. z.B.
https://www.hotmcu.com/lpc1768minidk2-development-board-28-tft-lcd-p-12.html?cPath=1_21&zenid=tdo7s5kaoj499q667hl9du1rl7


Auch wenn die ESPxxxx Controller massiv Flash und Ram haben und auch 
schnell sind, die bescheidenen Debugmöglichkeiten wären für mich ein 
NoGo für größere Projekte. Höchstens als Interface für BLE oder WLAN in 
einer Mehrcontrollerumgebeung.

von svensson (Gast)


Lesenswert?

Moin,

also ICH würde zunächst einige der Verbesserungsvorschläge einarbeiten, 
z.B. Texte ins EE, Menüstruktur, Funktionen und Unterprogramme mehr 
nutzen.
Dann ergibt sich wahrscheinlich eine deutliche Reduktion der Codegröße, 
zumindest für das RAM, aber wahrscheinlich auch für das Flash.

Und zu lernen, wie man effizienter programmiert, kann grundsätzlich 
nicht schädlich sein, egal für welches System.
Der Ruf nach stärkerer Hardware ist immer die Nullösung für schlechte 
Programmierung.

Und wenn es wirklich zu knapp werden sollte, dann umsteigen auf eine Art 
"Mega256 als Nano", der sich auch in eigene Platinen per THT einlöten 
läßt:
https://www.mikrocontroller-elektronik.de/mini-controllerboard-mit-atmel-atmega2560-und-usb/

Und wenn 256 kB für eine Aquariensteuerung nicht ausreichen, dann sollte 
man das wirklich ganz lassen, denn dann muß die dermaßen mit Funktionen 
oder Gimmicks überfrachtet sein, daß die Regelung vermutlich viel zu 
unzuverlässig wird... ;-))

von Falk B. (falk)


Lesenswert?

svensson schrieb:
> Und wenn es wirklich zu knapp werden sollte, dann umsteigen auf eine Art
> "Mega256 als Nano", der sich auch in eigene Platinen per THT einlöten
> läßt:
> 
https://www.mikrocontroller-elektronik.de/mini-controllerboard-mit-atmel-atmega2560-und-usb/

Schönes Marketinggefasel!

>Leistungsstarker Controller ATMega2560 (einer der wohl leistungsfähigsten
> 8 Bit AVR-Controller überhaupt), 100 Pins am Gehäuse,

BlaBla. Der CPU-Kern ist bei allen AVRs praktisch gleich und damit 
gleich leistungsfähig. Nur die Speichergröße sowie IO-Module variieren

>256.000 Bytes Flash Speicher

Jaja, große Zahlen braucht das Land! Warum nicht gleich 2048000 Bit? 
Außerdem sind es 256KiB, was 262144 Bytes entspricht.

https://de.wikipedia.org/wiki/Binärpräfix

>8000 Byte RAM
>4000 Bytes EEPROM

Dito.

von temp (Gast)


Lesenswert?

svensson schrieb:
> Und wenn 256 kB für eine Aquariensteuerung nicht ausreichen, dann sollte
> man das wirklich ganz lassen, denn dann muß die dermaßen mit Funktionen
> oder Gimmicks überfrachtet sein, daß die Regelung vermutlich viel zu
> unzuverlässig wird... ;-))

Bevor du weiter faselt, lade dir das Programm mal runter. Bei ihm machen 
im Moment die Libs den meisten Teil aus. Ethernet, Filesystem, Grafik 
und Kommunikation belegen da schon eine ganze Menge. Und was er für sich 
für Funktionen und Gimmicks einbaut war weder die Frage noch geht es 
dich was an.   Und wieso sollte der Flashverbrauch irgendwelchen 
Einfluss auf die Geschwindigkeit einer Temperaturregelung haben?

von svensson (Gast)


Lesenswert?

@Falk

Mir ging es auch nicht um den Inhalt der Seite (den habe ich mir gar 
nicht angesehen), sondern um die Bauform (Bilder). Das einzig 
entscheidende Kriterium ist, daß der Mega256 eben 256 kB Flash hat, was 
einer Verdoppelung zur jetzigen Situation gleichkäme.

Wenn ich es richtig verstanden habe, nutzt der TE jetzt die DIL-Bauform, 
d.h. er lötet das Dingens irgendwo ein oder nutzt ein Steckbrett. Bei 
dem gezeigten Beispiel wäre das eben, sogar relativ einfach, auch so 
möglich.

@temp
Nun aus langjähriger Erfahrung kann ich sagen, KISS (keep it simple and 
stupid) gilt immer, läßt sich sogar mathematisch beweisen.

Es gäbe auch noch die Möglichkeit, das ganze Projekt in Teilbereiche 
aufzuteilen, z.B. Regelaufgaben und Datenlogging/Aufbereitung der 
Meßwerte zu trennen.

von gdgddfgdfd (Gast)


Lesenswert?

habe was gefunden  wo er sparen kann

aus der main.c folgende zeilen vor der loop entfernen:
1
  ili9341_combo_flash(5, tftline, WHITE, BLACK, 1, 3, 0, 0, PSTR("Initialized SPI Bus at Duplex Speed: 8 MHz"));
2
    ili9341_combo_flash(5, tftline += 10, WHITE, BLACK, 1, 3, 0, 0, PSTR("ILI9341 TFT Driver successfully initialized!"));
3
    
4
    ili9341_combo_flash(5, tftline += 10, WHITE, BLACK, 1, 3, 0, 0, PSTR("I2C Interface initialized. Speed is 400KHz"));
5
6
    ili9341_combo_flash(5, tftline += 10, WHITE, BLACK, 1, 3, 0, 0, PSTR("ADS1115 16 Bit ADC initialized over I2C(0x48)"));  
7
  
8
   ili9341_combo_flash(5, tftline += 10, WHITE, BLACK, 1, 3, 0, 0, PSTR("MCP7940M Real Time Clock Initialized"));
9
10
      ili9341_combo_flash(5, tftline += 10, YELLOW, BLACK, 1, 3, 0, 0, PSTR("Try to start the Oscillator"));
11
      
12
        ili9341_combo_flash(5, tftline += 10, RED, BLACK, 1, 3, 0, 0, PSTR("Oscillator did not start!"));
13
14
    ili9341_combo_flash(5, tftline += 10, GREEN, BLACK, 1, 3, 0, 0, PSTR("Oscillator running on Crystal: 32.768KHz!"));
15
  
16
    sprintf(buffer, "Getting Time from RTC: %d-%d-%d | %d:%d:%d", year(), month(), day(), hour(), minute(), second());
17
   ili9341_combo(5, tftline += 10, WHITE, BLACK, 1, 3, 0, 0, buffer);
18
    
19
    ili9341_combo_flash(5, tftline += 10, WHITE, BLACK, 1, 3, 0, 0, PSTR("Usart initialized. Baud=9600 Data=8 Pty:none Stp:1"));
20
    
21
   ili9341_combo_flash(5, tftline += 10, WHITE, BLACK, 1, 3, 0, 0, PSTR("Rotary Encoder(4step) initialized!"));
22
   
23
    ili9341_combo_flash(5, tftline += 10, WHITE, BLACK, 1, 3, 0, 0, PSTR("EEPROM initialized. Addr=0xA1 InitCode on 0x00"));
24
    
25
     ili9341_combo_flash(5, tftline += 10, WHITE, BLACK, 1, 3, 0, 0, PSTR("Initialized Timers/Counters and Enable Interrputs!"));
26
     ili9341_combo_flash(5, tftline += 30, ORANGE, BLACK, 1, 3, 0, 0, PSTR("Startup done. Took 405ms"));
dann kann er die _delay_ms(1500);  auch entfernen

Das sind infos zum start die anfangs zum debugging vlt brauchbar sind .. 
aber am gerät später keinen nutzen haben

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Felix N. schrieb:
> Nein ich benutze die GCC Version 5.4.0 die Version 8.3.0 kann ich nicht
> finden habe nur die AVR-GCC 9.2.0 gefunden zum Downloaden:
>
> http://blog.zakkemble.net/avr-gcc-builds/

... die gcc v8.3 findest du auch bei zakkemble, du nimmst den link der 
9.2 und ersetzt entsprechend auf 8.3.0.

ich benutze atmelstudio und kann bei mir via script mit einem klick 
zwischen den versioen 5.4-9.2 wechseln.

ABER! ... du musst immer die 5.4 avr_size.exe nehmen sonst wird dir 
bzgl. used code size müll angezeigt.

UND! ... zum debuggen eher auch die 5.4 nehmen, weil atmel studio sonst 
ein problem hat beim anzeigen mit den variables/symboles.


mt

temp schrieb:
> Auch wenn die ESPxxxx Controller massiv Flash und Ram haben und auch
> schnell sind, die bescheidenen Debugmöglichkeiten wären für mich ein
> NoGo für größere Projekte.

der esp32 lässt sich z.b. unter vsc einfach/vollständig debuggen, also 
kein problem, wenn man ahnung hat!

von Carl D. (jcw2)


Lesenswert?

Der AVR-GCC hat eine CommandLineOption
-mcall-prologues
mit der er (gegen minimalste Extralaufzeit) die Push/Pop-Orgien am 
Anfang/Ende von Funktionen optimiert.
Wenn man also die 128k Flash nicht nur mit Bitnaps, sondern auch mit 
ausführbarem Code belegt hat, dann spart das eventuell die 
entscheidenden 5%.

Oder man versucht mal mit
-flto
in der Compiler-CommandLine Link-Time-Optimization. Dabei wird der ganze 
Code über alle C-Files hinweg optimiert.

Letzteres muß nicht auf Anhieb funktionieren, aber das deutet dann eher 
auf Ungereimtheiten im Code hin, ganz so wie "das Programm läuft nur mit 
-O0".

"Call-Prologs" ist aber völlig transparent und dürfte keine Probleme 
machen.
Wenn man LTO nicht probieren will/kann, dann auf alle Fälle alle 
Funktionen die nicht von außerhalb ihres Source-Files gerufen werden, 
als "static" definieren. Dann spart sich der Compiler den Call eventuell 
ganz. Schneller und kleiner!

von Felix N. (felix_n888)


Angehängte Dateien:

Lesenswert?

Hallo alle miteinander,

Falk B. schrieb:
> Warum nimmst du nicht einfach Atmelstudio?

Nutze ich doch. Ich habe mal ein Bild angehängt um nun die Frage zgl. 
welche IDE ich benutze hochgeladen.

Falk B. schrieb:
> Ja sicher. Wo liegt das Problem?

Weil ich oben gefragt ob sich die Variable(min_temperature) nicht auf 
den gelesen Wert vom EE bezieht sondern nur auf die Adresse.

Falk B. schrieb:
>> In deinem Struct Beispiel bezieht sich die 16 Bit
>> Variable(min_temperature) ja nicht auf den gelesen Wert vom EE
>
> Aber sicher!

Ich habe jetzt unter "Aber sicher" verstanden, das sie doch den gelesen 
Wert enthält und nicht die Adresse. Aber das hat sich ja nun geklärt.

Falk B. schrieb:
> Näheres erklärt dir ein C-Buch.

Irgendwie check das immer noch nicht mit den Strukturen. Aber ich habe 
mal in mein Buch rein geschaut dort wird es so erklärt:
1
struct person {     //Struktur definieren
2
  char name[50];    //Inhalt der Struktur
3
  int alter;
4
} peter;        //Variable der Struktur anlegen
5
6
//Alternativ ohne direkt eine Variable der Struktur anzulegen:
7
struct person dieter;   //Variable der Struktur anlegen. 
8
9
int main() {
10
  
11
  peter.alter = 50;  //Person 'peter' das Alter 50 zuweisen
12
  dieter.alter = 25;  //Person 'dieter' das Alter 25 zuweisen
13
  
14
  printf("Peter ist: %d Jahre alt", peter.alter);
15
  printf("Dieter ist: %d Jahre alt", dieter.alter);
16
  
17
  return 0;
18
}

Falk B. schrieb:
> Gewöhn dir eine klare, saubere
> Sprache bzw. Beschreibung/Namensgebung an

Werde ich versuchen.

gdgddfgdfd schrieb:
> muss er es eh anders machen.
> der compiler kennt den externen nicht

Das heißt ich muss einmal beim Programmstart die Variablen in der 
Struktur die passenden EEPROM Adressen zuweisen, zb. im EEPROM steht 
unter der Adresse  0x0A der Wert der Karbonathärte also muss ich einmal 
struktur.karbonathaerte = 0x0A machen?

Arno schrieb:
> Wichtig bei --gc-sections: Das muss direkt nach -Wl, stehen, ohne
> Leerzeichen.

Ah danke jetzt tut es.

svensson schrieb:
> Wenn ich es richtig verstanden habe, nutzt der TE jetzt die DIL-Bauform,
> d.h. er lötet das Dingens irgendwo ein oder nutzt ein Steckbrett.

Früher Steckbrett hat aber zu viele Probleme mit Kapazitive 
Einkopplungen gemacht habe mir dann eine Platine ätzen lassen.

Wenn ich wirklich auf den 2560 umsteige mache ich eh wieder eine neue 
Platine da teile der jetzigen Platine nicht mehr gebraucht werden. Dann 
kann ich auch gleich den IC in SMD drauf löten.

gdgddfgdfd schrieb:
> Das sind infos zum start die anfangs zum debugging vlt brauchbar sind ..
> aber am gerät später keinen nutzen haben

Es war mal zum Debuggen nötig:

Felix N. schrieb:
> Es hatte am Anfang wirklich mal ein Sinn gehabt, mein Controller hatte
> sich durch nicht ganz korrekte Verdrahtung und scheinbar Kapazitive
> Einkopplung der SCL und SCK Leitungen zu System Hängen geführt hat. Habe
> ich ein Start Up Bildschirm gemacht um zu sehen wo er sich aufhängt, es
> war auch mal eine Startzeit Messung drin aber das ist alles mittlerweile
> nicht mehr nötig.

Ist aber nun entfernt.

Apollo M. schrieb:
> ... die gcc v8.3 findest du auch bei zakkemble, du nimmst den link der
> 9.2 und ersetzt entsprechend auf 8.3.0.

Habe es gefunden.

Apollo M. schrieb:
> ABER!

Apollo M. schrieb:
> UND!

Ich lasse es erstmal bei 5.4.0 und werde mich erstmal um mein Programm 
kümmern. Das wird mir sonst alles zu kompliziert.

Mfg

von tschut tschut (Gast)


Lesenswert?

Ich würde dir empfehlen:
Code optimieren, aber nicht komplett neu anlegen, auch nur die 
wichtigsten Sachen optimieren, keine riesigen Sachen, dann auf den mit 
256kb umsteigen. Auf gar keinen Fall würde ich die Plattform wechseln, 
da investierst du locker mal 100h nur fürs umprogrammieren, einlesen, 
Entwicklungsumgebung aufsetzen, etc. musst du noch draufrechnen.
Wirklich hübschen Code würde ich beim nächsten Projekt von Anfang an 
schreiben, das jetzt groß umändern, kostet einfach viel Zeit.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Falk B. schrieb:
> So einfach ist es nicht. Weig gesagt, bei externem EEPROM muss man
> vieles manuell machen.

... eigentlich nicht, wenn man es sinnig angeht. z.b.

- zuerst mal die extEEprom read/write byte/word/block functionen 
schreiben, die i2c oder spi oder parallel angetrieben sind.

- dann ein struct z.b. extEE definieren wo ALLE anderen struct's , 
variablen drin sind. also die struct extEE ist ein "data container"

- nun einen ptr pExtEE mit z.b. addr=0 (ext eeprom start addr) auf die 
extEE struct definieren und dann entsprechend mit pExtEE-> und den extEE 
read/write functions drauf zugreifen.


so what?

von Falk B. (falk)


Lesenswert?

Felix N. schrieb:
> Irgendwie check das immer noch nicht mit den Strukturen. Aber ich habe
> mal in mein Buch rein geschaut dort wird es so erklärt:

Ist OK.

>> muss er es eh anders machen.
>> der compiler kennt den externen nicht
>
> Das heißt ich muss einmal beim Programmstart die Variablen in der
> Struktur die passenden EEPROM Adressen zuweisen,

Nein! Du musst die Daten vom externen EEPROM in eine Kopie im RAM laden. 
Man könnte auch immer direkt mit dem Zugriff auf den externen EEPROM 
arbeiten, aber das ist meist deutlich ungünstiger.

> zb. im EEPROM steht
> unter der Adresse  0x0A der Wert der Karbonathärte also muss ich einmal
> struktur.karbonathaerte = 0x0A machen?

Du verwechselt irgendwie permanent die Adresse mit dem Inhalt einer 
Variablen.

> Wenn ich wirklich auf den 2560 umsteige mache ich eh wieder eine neue
> Platine da teile der jetzigen Platine nicht mehr gebraucht werden. Dann
> kann ich auch gleich den IC in SMD drauf löten.

Naja, kauf dir lieber einen Arduino Mega und bastel dir einen passenden 
"Shield" dafür.

> Ich lasse es erstmal bei 5.4.0 und werde mich erstmal um mein Programm
> kümmern. Das wird mir sonst alles zu kompliziert.

Gute Wahl! Einen Vielfrontenkrieg gewinnt man nicht! (Urdeutsche 
Erkenntnis . . .)

von Alfred von Schlieffen (Gast)


Lesenswert?

Falk B. schrieb:
> Einen Vielfrontenkrieg gewinnt man nicht! (Urdeutsche
> Erkenntnis . . .)

Doch, ich weiß wie das geht.

von Frank K. (fchk)


Lesenswert?

Felix N. schrieb:
> svensson schrieb:
>> Wenn ich es richtig verstanden habe, nutzt der TE jetzt die DIL-Bauform,
>> d.h. er lötet das Dingens irgendwo ein oder nutzt ein Steckbrett.
>
> Früher Steckbrett hat aber zu viele Probleme mit Kapazitive
> Einkopplungen gemacht habe mir dann eine Platine ätzen lassen.
>
> Wenn ich wirklich auf den 2560 umsteige mache ich eh wieder eine neue
> Platine da teile der jetzigen Platine nicht mehr gebraucht werden. Dann
> kann ich auch gleich den IC in SMD drauf löten.

Der 2560 hat ein External Bus Interface. Da kannst Du z.B. extern noch 
ein 32kb RAM anschließen. Z.B.

https://www.reichelt.de/sram-32-kb-4-k-x-8-4-5-5-5-v-tsop-28-62256-70-m-p40086.html?r=1

Das liegt dann direkt im Adressraum des Prozessors wie das interne RAM 
auch, und für 1.45€ kann man das ruhig auf Vorrat verbauen.

Und Du kannst zusätzlich ein TFT-Display daran anschließen, z.B.:

https://www.buydisplay.com/default/serial-spi-3-2-inch-tft-lcd-module-display-ili9341-power-than-sainsmart

Das könnte zwar auch SPI, aber die Ansteuerung über das External Bus 
Interface geht VIEL schneller (Faktor 5 und mehr), weil jeder 
TFT-Registerzugriff nur ein einziger Speicherzugriff ist. Schneller kann 
man keine Daten in das Display reinbekommen.

fchk

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

tschut tschut schrieb:
> Wirklich hübschen Code würde ich beim nächsten Projekt von Anfang an
> schreiben, das jetzt groß umändern, kostet einfach viel Zeit.

... das klingt nach blümchen sex!

wir reden hier über neudeutsch refactoring! und das ist immer sinnvoll.

coding ist art ... ich habe kein project/program wo ich nicht gefüllt 
den code 2-3mal fast neugeschrieben habe - in teilen sogar x-mal neu.

und da ging es nicht darum wie z.b. in c sinnig programmiert wird, 
sondern wie ein problem/aufgabe sinnvoll abgebildet wird bzgl. 
structure, algorithm, data abstruction, use of rtos, ...

mit jeder itteration lernt man dann fett was dazu (hoffentlich).


mt

von Frank K. (fchk)


Lesenswert?

tschut tschut schrieb:
> Auf gar keinen Fall würde ich die Plattform wechseln,
> da investierst du locker mal 100h nur fürs umprogrammieren, einlesen,
> Entwicklungsumgebung aufsetzen, etc. musst du noch draufrechnen.

Autsch. Da könnte man ja was bei lernen. Das Denken ist zwar allen 
Menschen erlaubt, aber vielen bleibt es erspart.

Mal ein Schwank aus meiner Kindheit: Ich habe 1981 mit Z80 Assembler 
angefangen (C existierte zwar, war aber wenig verbreitet). Nach 6 
Monaten war ich soweit, dass ich die wichtigsten der 300 Opcodes im Kopf 
hatte und meine Programme direkt als hexdumps eingeben konnte. An der 
Wand hingen seitenweise Spickzettel mit Befehlslisten und Codierungen. 
Mein Rechner hatte keinen Assembler, nur einen Disassembler. Als ich 
dann einige Jahre später 6502 angefangen hhabe, brauchte ich nur noch 6 
Wochen, um genauso produktiv zu sein.

Genauso ist es hier: Kennst Du einen, kennst Du alle. Ja, Register, 
Bitbelegungen und andere Details sind zwar anders, aber Technik, 
Vorgehensweise und Grundlagen bleiben. Und bei Dir wird sogar noch die 
Programmiersprache die gleiche bleiben. Mann, hast Du es heute gut. Wir 
früher...

fchk

von m.n. (Gast)


Lesenswert?

Frank K. schrieb:
> Mal ein Schwank aus meiner Kindheit:

Im Sandkasten habe ich eine kleine Schaufel gehabt. Heute nehme ich zum 
Blumenumtopfen einen Bagger. Meintest Du das?

Die Tage hat hier jemand eine Möglichkeit gesucht, eine LED mit einem I7 
blinken zu lassen:Beitrag "LED blinken mit Intel core i7"
Hattest Du ihm dazu geraten?

von Carl D. (jcw2)


Lesenswert?

Mal (eine) ganz simple Frage(n) an den TO:
Gibt es einen Grund den Debug-Build zu benutzen?
Wird ein Sourcecode-Debugger benutzt?

Falls die letze Frage nicht mit eindeutigem JA beantwortet werden kann:
Ein Release-Build mit -Os kommt auf 97017 Byte Flash. Da ist noch Luft.

Und es ist nicht erkennbar, daß irgend ein Code vom Makro "DEBUG" 
abhängen würde. Wie auch immer man so einen Berg Code zu laufen bekommt, 
ohne irgendwie zu debuggen. Ich könnte es nicht.

Nachtrag:
Die SD-Lib braucht viel Flash für die Benutzung langer Filenamen 
inclusive Unterstützung der Codepage 1250. Wird das wirklich gebraucht?
WCHAR (16bit) Zeichenverarbeitung paßt einfach besser zum i7 als zum 
AVR.

: Bearbeitet durch User
von Theor (Gast)


Lesenswert?

Carl D. schrieb:
> [...]
> Wie auch immer man so einen Berg Code zu laufen bekommt,
> ohne irgendwie zu debuggen. Ich könnte es nicht.


Was man mal lobend hervorheben könnte.
Es muss ungeheure Energie dazu gehören, mit den verwendeten 
unzureichenden Methoden und geringen Kenntnissen so weit zu kommen. Ein 
Paradebeispiel für "die harte Tour".

Hut ab und alle Achtung. Auch wenn es doch etwas tragisch ist.

von Frank K. (fchk)


Lesenswert?

m.n. schrieb:
> Frank K. schrieb:
>> Mal ein Schwank aus meiner Kindheit:
>
> Im Sandkasten habe ich eine kleine Schaufel gehabt. Heute nehme ich zum
> Blumenumtopfen einen Bagger. Meintest Du das?
>
> Die Tage hat hier jemand eine Möglichkeit gesucht, eine LED mit einem I7
> blinken zu lassen:Beitrag "LED blinken mit Intel core i7"
> Hattest Du ihm dazu geraten?

Nein, davon distanziere ich mich.

Ich bin kein Bastler, ich mach das beruflich. Und ich nehme dazu das, 
was am besten für die jeweilige Aufgabe geeignet ist, was 
Rechenleistung, Verlustleistung, Platzbedarf, Bauteilekosten, 
Leiterplattenkosten, Entwicklungsaufwand, Kundenwünsche usw usw angeht.

Bei einem Bastler ist der Weg das Ziel. Von mir werden Ergebnisse 
erwartet, und meine Zeit ist teuer. Sehr teuer. Da ist es oft unterm 
Strich sinnvoller, bei der Hardware etwas größer als unbedingt notwendig 
zu dimensionieren, um dafür Entwicklungs-Zeit und damit -Kosten zu 
sparen. Ja, in diesem Forum gibts auch Spezialisten, die am liebsten 
alles in Assembler machen würden, um alles optimal und auf der 
kleinstmöglichen Hardware erledigen zu können. Im Echten Leben™ würde 
die gefeuert werden, weil die ihre Abgabetermine nicht einhalten würden 
und das kein Kunde bezahlen wollen würde.

Dazu kommt: Ein 8-Bit Controller wie z.B. der ATMEGA2561-16AU für 10.83€ 
(aktueller Digikey-Preis) ist heutzutage kommerziell nur noch 
interessant, wenn man an die Architektur gebunden ist. Selbst wenn 5V 
VCC und 5V IO gefordert sind, gibts beispielsweise den 16 Bit 
DSPIC33EV256GM106-I/PT mit mehr und besserer Peripherie, mehr RAM und 
wesentlich mehr Rechenleistung im gleiche Gehäuse (TQFP64 im 0.5mm 
Raster) für 3.82€.

Jetzt erklär mir mal jemand, warum ich unbedingt eine technisch 
schlechtere Alternative zum 3-fachen Preis nehmen soll, wenn 
Binärkompatibilität keinerlei Rolle spielt.

Die Aquariumsteuerung hätte ich mit dem von mir anfangs erwähnten 
Olimex-Board und einem passenden TFT-Touch-Display und einer 
Implementation in Phython in ein paar Tagen fertig gehabt. Das mal als 
Vergleich, was die Produktivität angeht. Klar, Webservice, Mail, 
SD-Karten-Unterstützung und das Malen von Pixeln auf ein Display sind 
Sachen, die dann einfach da sind und funktionieren. Um schnell zu 
Ergebnissen zu kommen, ist das der bessere Weg. Ja, ich weiß, dass es 
viele Leute gibt, die da anderer Meinung sind, aber das ist halt so.

fchk

PS: Irgendwelche Argumente von wegen Open Source, GPL, Community sind 
mir egal. Ich habe es nicht so mit Ideologien, und GPL-Code darf ich in 
meinen beruflichen Projekten eh im Allgemeinen nicht verwenden.

: Bearbeitet durch User
von Manfred (Gast)


Lesenswert?

Frank K. schrieb:
> Ich bin kein Bastler, ich mach das beruflich. Und ich nehme dazu das,
> was am besten für die jeweilige Aufgabe geeignet ist, was
> Rechenleistung, Verlustleistung, Platzbedarf, Bauteilekosten,
> Leiterplattenkosten, Entwicklungsaufwand, Kundenwünsche usw usw angeht.

Das klingt sinnvoll.

> Bei einem Bastler ist der Weg das Ziel.

Das ist Unsinn. Meine Hobbyprojekte verfolgen ein Ziel: Ich habe eine 
Idee und ich will ein funktionierendes Gerät mit überschaubarem Aufwand. 
Es ist sicher nicht in meinem Sinne, möglichst lange daran zu pruckeln. 
Da es Einzelstücke sind, jucken mich ein paar Euro mehr an 
Bauteilekosten meist nicht.

> Von mir werden Ergebnisse
> erwartet, und meine Zeit ist teuer. Sehr teuer. Da ist es oft unterm
> Strich sinnvoller, bei der Hardware etwas größer als unbedingt notwendig
> zu dimensionieren, um dafür Entwicklungs-Zeit und damit -Kosten zu
> sparen.

So pauschal klingt das falsch: Ich habe früher Prüf- und Meßtechnik 
gemacht, individuelle Einzelstücke, da waren Materialkosten kein Thema.

Geht man aber in die Entwicklung von Serienprodukten, sieht das deutlich 
anders aus. Da darf der Entwicklungsaufwand gerne ein paar Mannwochen 
größer werden, wenn die Hardware bei xxxxxx-Stück pro Jahr ein paar cent 
billiger zu fertigen ist.

von svensson (Gast)


Lesenswert?

Frank K. schrieb:
> Der 2560 hat ein External Bus Interface. Da kannst Du z.B. extern noch
> ein 32kb RAM anschließen.

Das hätte der Mega1280-V auch, aber der dürfte nicht auf die vorhandene 
Platine passen ohne Anpassungsarbeiten.

Frank K. schrieb:
> Dazu kommt: Ein 8-Bit Controller wie z.B. der ATMEGA2561-16AU für 10.83€
> (aktueller Digikey-Preis) ist heutzutage kommerziell nur noch
> interessant ...

Den Arduino 2560 PRO MINI bekommt man schon für ca. 7,50 und braucht 
nicht einmal SMD-Teile zu löten.
Außerdem handelt es sich um ein privates Hobbyprojekt, also ein 
Einzelstück, an dem jetzt schon fast ein Jahr programmiert wird. Da 
spielt diese Summe doch nun wirklich keine Rolle.

Wahrscheinlich wird das alles aber gar nicht notwendig werden, sofern 
der TE nicht noch weitere große Libs einbindet, denn 20kB sind ja noch 
frei. Und nach Optimierung wahrscheinlich eher 30-40kB.

von Frank K. (fchk)


Lesenswert?

Manfred schrieb:

> So pauschal klingt das falsch: Ich habe früher Prüf- und Meßtechnik
> gemacht, individuelle Einzelstücke, da waren Materialkosten kein Thema.
>
> Geht man aber in die Entwicklung von Serienprodukten, sieht das deutlich
> anders aus. Da darf der Entwicklungsaufwand gerne ein paar Mannwochen
> größer werden, wenn die Hardware bei xxxxxx-Stück pro Jahr ein paar cent
> billiger zu fertigen ist.

Klar, bei den Stückzahlen ist das klar. Bei meinem aktuellen Arbytegeber 
sind das aber nie mehr als xxx-Stück für etwa xxxxxx€ pro Stück.

fchk

von Frank K. (fchk)


Lesenswert?

svensson schrieb:

> Außerdem handelt es sich um ein privates Hobbyprojekt, also ein
> Einzelstück, an dem jetzt schon fast ein Jahr programmiert wird. Da
> spielt diese Summe doch nun wirklich keine Rolle.

Siehst Du. Mir der gleichen Begründung hätte ich selber zu dem 
Olimex-Board für 36€ gegriffen und wäre innerhalb weniger Tage fertig 
gewesen.

fchk

von m.n. (Gast)


Lesenswert?

Frank K. schrieb:
> svensson schrieb:
>
>> Außerdem handelt es sich um ein privates Hobbyprojekt, also ein
>> Einzelstück, an dem jetzt schon fast ein Jahr programmiert wird. Da
>> spielt diese Summe doch nun wirklich keine Rolle.
>
> Siehst Du. Mir der gleichen Begründung hätte ich selber zu dem
> Olimex-Board für 36€ gegriffen und wäre innerhalb weniger Tage fertig
> gewesen.

Es geht aber nicht um Dich oder einen anderen erfahrenen Entwickler 
hier, sondern allein um den TO.
Mancheiner hätte sich auch jede weitere Anschaffung sparen können und 
die Hardware einfach aus der Schublade gekramt - LIBs für den Rest 
inklusive.

Frank K. schrieb:
> Von mir werden Ergebnisse
> erwartet, und meine Zeit ist teuer. Sehr teuer.

Eventuell zu teuer?
;-)

von Felix N. (felix_n888)


Lesenswert?

Hallo nochmal,

Apollo M. schrieb:
> so what?

Ich werde es mal versuchen umzusetzen.

Falk B. schrieb:
> Du verwechselt irgendwie permanent die Adresse mit dem Inhalt einer
> Variablen.

Ich werde es mir versuchen abzugewöhnen.

Frank K. schrieb:
> Der 2560 hat ein External Bus Interface. Da kannst Du z.B. extern noch
> ein 32kb RAM anschließen. Z.B.

Das ist dieses XMEM Interface. Für 1,45 Euro kann ich das wohl mit in 
einbauen. Anschlüsse habe ich ja so oder so genug am Ende.

Muss nach der Code Optimierung mal einen neuen Schaltplan erstellen für 
den 2560.

Carl D. schrieb:
> Gibt es einen Grund den Debug-Build zu benutzen?
> Wird ein Sourcecode-Debugger benutzt?

Der Debug Build wahr voreingestellt und habe ihn auch nie umstellt. Nein 
es wird auch kein Sourcecode Debugger benutzt. Das einzige was ich mal 
zum "Debuggen" nutze sind Textnachrichten die ich an den UART sende.

Carl D. schrieb:
> Ein Release-Build mit -Os kommt auf 97017 Byte Flash. Da ist noch Luft.

Ich habe mal das ganze auf Release umstellt jedoch habe ich keine 
vergrößern von Flash/RAM im Vergleich zu dem Debug Build. Habe alles im 
Release Build wieder eingestellt(-Wl,-gcc-section, -Os ...).

Oder muss ich da noch was einstellen?

Theor schrieb:
> Hut ab und alle Achtung. Auch wenn es doch etwas tragisch ist.

Soll ich das jetzt positiv oder negativ verstehen?

Theor schrieb:
> Es muss ungeheure Energie dazu gehören, mit den verwendeten
> unzureichenden Methoden und geringen Kenntnissen so weit zu kommen.

Puff naja, ich arbeite an diesem Projekt halt dann wann ich Lust und 
Laue dazu habe. Ja es steckt viel Arbeit drin jedoch kam es auch schon 
vor das ich am meinem Aquarium Controller Wochenlang nicht weiter 
programmiert habe.


Und mit den geringen Kenntnissen naja je nach dem mit wem man mich nun 
vergleich oder? Ich habe 2014 das Programmieren in Java angefangen für 
ein Jahr habe ich mich mit Bukkit Plugins(Minecraft) versucht später 
dann ein bisschen Java an sich ohne Bezug auf Plugins. Seit 2016 habe 
ich mit den Mikrocontrollern angefangen.


Kann mir gut vorstellen das wenn sich ein richtiger Programmier der eine 
Ausbildung gemacht hat und Beruflich damit zutun, sich mein Code 
anschaut das er fast vom Stuhl fällt. Habe mir halt alles selber erlernt 
das einzige Buch was ich über C habe ist "Grundlagen C von Jürgen Wolf".

svensson schrieb:
> ofern
> der TE nicht noch weitere große Libs einbindet, denn 20kB sind ja noch
> frei. Und nach Optimierung wahrscheinlich eher 30-40kB.

Neue Libs sind erstmal nicht geplant. Ich werde jetzt die nächsten Tagen 
mein Projekt neu anlegen und den Code überarbeiten. Werde auf jeden Fall 
die ganzen Strings mit PSTR und PROGMEM überarbeiten. Floats entfernen 
und mit Integers arbeiten und mal schauen was ich noch verbessern kann.

Frank K. schrieb:
> wäre innerhalb weniger Tage fertig
> gewesen.

Das Ziel war für mich natürlich auch klar das es am Ende funktionieren 
soll. Ich habe dieses jedoch als langes Projekt geplant. Am Anfang war 
es nur ein Temperatur Messgerät mit Serieller Ausgabe dann kam ein 16x2 
LC Display dann eine pH Messer wo man die Kalibrierten Spannung in den 
Code direkt eintragen musste. Und so hat sich das dann weiter 
entwickelt. ...


Es war nicht Ziel dieses Projekt innerhalb von wenigen Tagen 
abzuschließen. Spaß an diesem Projekt habe ich besonders an der Software 
Entwicklung und auch an der Konstruktion an sich(Gehäuse, Bauteile, 
Platine, Kühlung etc..)


Möchte mich aber bei euch allen bedanken für eure Hilfe und euren vielen 
Tipp und Ratschläge. Werde es die nächsten Tage angehen!

Vielen Dank :)!

Mfg

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Felix N. schrieb:
> das einzige Buch was ich über C habe ist "Grundlagen C von Jürgen Wolf".

kannst du halbwegs in english was lesen/verstehen, dann schick ich dir 
ein "pdf-buchpacket" mit guten bookz zu C und mehr drumrum. wenn 
interesse pm an mich mit email.

mt

von Carl D. (jcw2)


Lesenswert?

Felix N. schrieb:
> Hallo nochmal,
>
> Apollo M. schrieb:
>> so what?
>
> Ich werde es mal versuchen umzusetzen.
>
> Falk B. schrieb:
>> Du verwechselt irgendwie permanent die Adresse mit dem Inhalt einer
>> Variablen.
>
> Ich werde es mir versuchen abzugewöhnen.
>
> Frank K. schrieb:
>> Der 2560 hat ein External Bus Interface. Da kannst Du z.B. extern noch
>> ein 32kb RAM anschließen. Z.B.
>
> Das ist dieses XMEM Interface. Für 1,45 Euro kann ich das wohl mit in
> einbauen. Anschlüsse habe ich ja so oder so genug am Ende.
>
> Muss nach der Code Optimierung mal einen neuen Schaltplan erstellen für
> den 2560.
>
> Carl D. schrieb:
>> Gibt es einen Grund den Debug-Build zu benutzen?
>> Wird ein Sourcecode-Debugger benutzt?
>
> Der Debug Build wahr voreingestellt und habe ihn auch nie umstellt. Nein
> es wird auch kein Sourcecode Debugger benutzt. Das einzige was ich mal
> zum "Debuggen" nutze sind Textnachrichten die ich an den UART sende.
>
> Carl D. schrieb:
>> Ein Release-Build mit -Os kommt auf 97017 Byte Flash. Da ist noch Luft.
>
> Ich habe mal das ganze auf Release umstellt jedoch habe ich keine
> vergrößern von Flash/RAM im Vergleich zu dem Debug Build. Habe alles im
> Release Build wieder eingestellt(-Wl,-gcc-section, -Os ...).
>
> Oder muss ich da noch was einstellen?
>

Release-Build bedeutet hauptsächlich, daß nicht -O0,
sondern -Os oder -O1/2/3
Größer als Debug-Builds werden die Release-Build (praktisch) nie.
Wie schon geschrieben, im konkreten Fall ca. 97kB statt 142kB.


>
> Es war nicht Ziel dieses Projekt innerhalb von wenigen Tagen
> abzuschließen. Spaß an diesem Projekt habe ich besonders an der Software
> Entwicklung und auch an der Konstruktion an sich(Gehäuse, Bauteile,
> Platine, Kühlung etc..)

Wenn man die "extremen" Realtime-Anforderungen der aktuellen Version 
anschaut, nämlich praktisch keine, dann könnte man natürlich schon auf 
die Idee kommen, eine Raspi-Zero zu verwenden. Der hat Disk/Filesystem, 
Netzwerk, WLAN (wenn aktuelle Version), unmengen Speicher und 
Rechenleistung, komfortables OS, Python als relative einfache und doch 
mächtige Implementierungssprache, Webinterface inclusive und seinen 
Pinheader lassen sich die benutzten IO-Bausteine auch betreiben, wobei 
auf ein EEPROM nicht nötig ist, die Daten schreibt man einfach in ein 
File. Man braucht auch beim Rechnen keine Klimmzüge machen, denn das 
Ding kann Floatingpoint mit double Genauigkeit berechnen. AVR kann das 
nicht.

Wenn also "Spaß" ein wesentlicher Faktor ist, dann kann man was anderes 
ausprobieren. Wobei so Raspi-Zero mit WLAN und Flas-Karte wenn überhaupt 
kaum mehr kostet, als ein Mega256n-Board mit ENC, ...
Von fehlenden Nervenkitzel eines "selbstgeschriebenen" Filesystems oder 
Netzwerkstacks mal ganz abgesehen.

von Christopher J. (christopher_j23)


Lesenswert?

Carl D. schrieb:
> Wenn man die "extremen" Realtime-Anforderungen der aktuellen Version
> anschaut, nämlich praktisch keine, dann könnte man natürlich schon auf
> die Idee kommen, eine Raspi-Zero zu verwenden.

... und selbst wenn man "Realtime-Anforderungen" hat, dann flanscht man 
per UART, SPI, etc. irgendeinen 08/15 Controller à la ATTiny dran und 
fertig.

von Carl D. (jcw2)


Lesenswert?

Christopher J. schrieb:
> Carl D. schrieb:
>> Wenn man die "extremen" Realtime-Anforderungen der aktuellen Version
>> anschaut, nämlich praktisch keine, dann könnte man natürlich schon auf
>> die Idee kommen, eine Raspi-Zero zu verwenden.
>
> ... und selbst wenn man "Realtime-Anforderungen" hat, dann flanscht man
> per UART, SPI, etc. irgendeinen 08/15 Controller à la ATTiny dran und
> fertig.

Notfalls, aber nachdem ich den aktuellen AVR-Code gesehen hab: etwas 
Zeitsteuerung, das man locker mit cron machen kann und was schneller 
reagieren muß, wie z.B. der Drehgeber, ist im Python machbar. Es gibt 
das sogar fertig auf 
https://thepihut.com/blogs/raspberry-pi-tutorials/how-to-use-a-rotary-encoder-with-the-raspberry-pi.

BTW, habe ich weiter oben ganz vergessen: ein ordentliches Display kann 
man natürlich per HDMI auch dran hängen. Und sollte man keine Lust/Zeit 
für Frischfisch haben, kann ein größerer Monitor auch gleich eine 
Aquqrium-Simulation anzeigen. ;-)

von svensson (Gast)


Lesenswert?

Wenn das Projekt auch eine Regelung des Aquariums ist, also Pumpen, 
Heizungen, Beleuchtung, Belüftung, Filtration, Denitrifikation usw. 
betreibt, dann würde ich unbedingt beim µC bleiben, weil das alles 
absolut zuverlässig funktionieren muß, sonst gehen die Tiere hops.

Wenn es sich lediglich um die Darstellung von Meßwerten handelt, dann 
ist man natürlich völlig frei. Für animierte Grafiken per WLAN aufs 
Smartphone wäre ein Kleinstcomputer wie Raspi&Co sicherlich die bessere 
Wahl.

von Frank K. (fchk)


Lesenswert?

svensson schrieb:
> Wenn das Projekt auch eine Regelung des Aquariums ist, also Pumpen,
> Heizungen, Beleuchtung, Belüftung, Filtration, Denitrifikation usw.
> betreibt, dann würde ich unbedingt beim µC bleiben, weil das alles
> absolut zuverlässig funktionieren muß, sonst gehen die Tiere hops.

Auch Unix-/Linux-System können jahrelang störungsfrei funktionieren, 
wenn Hardware, Betriebssystem und Anwendungssoftware von Leuten mit 
Ahnung entwickelt wurden. Das ist kein Entscheidungskriterium, sondern 
universelle Grundvoraussetzung.

Andersrum: Der Linux-Code ist inzwischen so gut getestet und debuggt, 
dass die Wahrscheinlichkeit für Bugs um Zehnerpotenzen geringer ist als 
Code, den irgend so ein Anfänger aus Bruchstücken aus dem Netz 
zusammengerührt hat. Das gilt vor allem, wenn Fehler auftreten und 
beispielsweise die SD-Karte keine Lust mehr hat. Eine richtige 
Fehlerbehandlung hab ich in DEM Code hier nicht gesehen. Oder 
beispielsweise ein Watchdog. Nee, so wird das nix mit SIL.

Und die zugrunde liegenden physikalischen Prozesse sind so träge, dass 
die Echtzeitanforderungen sehr gering sind. 1000 Liter Wasser haben so 
viel thermische Kapazität, da ändert sich die Temperatur nicht eben mal 
von einer Sekunde zur anderen. Solltest Du auch nur einen Hauch von 
physikalischem Verständnis haben, kannst Du gerne mal die kWh 
ausrechnen, die Du brauchst, um das Becken von 18°C auf 28°C aufzuheizen 
und dann mal schauen, wie lange Du dafür mit einem normalen Heizstab 
brauchst. Und als Bonus kannst Du dann noch ausrechnen, wie viel Reboots 
Du in dieser Zeit machen kannst.

fchk

von temp (Gast)


Lesenswert?

Frank K. schrieb:
> Andersrum: Der Linux-Code ist inzwischen so gut getestet und debuggt,
> dass die Wahrscheinlichkeit für Bugs um Zehnerpotenzen geringer ist als
> Code, den irgend so ein Anfänger aus Bruchstücken aus dem Netz
> zusammengerührt hat. Das gilt vor allem, wenn Fehler auftreten und
> beispielsweise die SD-Karte keine Lust mehr hat. Eine richtige
> Fehlerbehandlung hab ich in DEM Code hier nicht gesehen. Oder
> beispielsweise ein Watchdog. Nee, so wird das nix mit SIL.

Dafür ist es in der Summe Zehnerpotenzen mehr Code der für das 
zusammenspielen aller Teile dazugehört. Aus der Sicht also Patt. Viele 
Libs und gerade die von ChaN für das Filesystem sind wenigstens genauso 
gut oder besser getestet wie Treiber für exotische Hardware in Linux. 
Code ohne Fehlerbehandlung kann man in Linux auch schreiben. Raspberry 
Zero scheidet ja wohl aus weil Ethernet fehlt. 5W rund um die Uhr sind 
auch fast 45kWh im Jahr. Ne, dann lieber beim Avr o.ä. bleiben.

von Stefan F. (Gast)


Lesenswert?

svensson schrieb:
> würde ich unbedingt beim µC bleiben, weil das alles
> absolut zuverlässig funktionieren muß

Mein Raspberry Pi läuft genau so stabil, wie meine AVR und ESP8266 
Projekte. Jahrelang ohne Aussetzer halt ich für vollkommen normal.

Gut, ich habe nur Welse und Gildfische im Aquarium, daher brauche ich 
mir um die nicht vorhandene Heizung keinen Kopf machen. Aber wenn da 
eine wäre, würde ich zumindest die Heizung durch eine unabhängige 
Schaltung (nämlich dem darin eingebauten Thermostaten) absichern.

Die Pumpe darf ruhig mal einen halben Tag ausfallen, davon geht die Welt 
nicht unter.

von Carl D. (jcw2)


Lesenswert?

temp schrieb:
> Raspberry Zero scheidet ja wohl aus weil Ethernet fehlt.

Stimmt, die WLAN-Kabel sind zu teuer.

> 5W rund um die Uhr sind
> auch fast 45kWh im Jahr. Ne, dann lieber beim Avr o.ä. bleiben.

Dann am besten auf Kaltwasserfische umstellen.

von Stefan F. (Gast)


Lesenswert?

> 5W rund um die Uhr sind sind auch fast 45kWh im Jahr

Im Ruhezustand nimmt der Raspberry Pi weniger Strom auf, rechne mal mit 
ca. 2W + 1W Verlust im Netzteil.

Klar, das ist immer noch mehr, als ein AVR. Die Frage ist, wo man sonst 
noch so kleine Leistungen vergeudet ohne darüber nachzudenken.

> Dann am besten auf Kaltwasserfische umstellen.

Eben, deswegen habe ich zwei Goldfische, wo früher 15 andere kleinere 
waren.

von S. R. (svenska)


Lesenswert?

Felix N. schrieb:
> Werde auf jeden Fall die ganzen Strings mit PSTR und PROGMEM
> überarbeiten.

Ja, und am besten sich wiederholende Sequenzen nach Möglichkeit 
datengetrieben aufbauen. Wenn du bestimmte Dinge in einer Tabelle 
organisieren kannst, dann brauchst du keinen zusätzlichen Code.

> Floats entfernen und mit Integers arbeiten und mal schauen
> was ich noch verbessern kann.

Das ist nicht unbedingt nötig. Die Kosten für float (den Bibliothekscode 
für die Funktionen) bezahlst du nur einmal, ab dann sind das nur normale 
Funktionsaufrufe. Da das nicht zeitkritisch ist, ist die Rechenzeit 
nicht so wichtig - aber mit Float kannst du natürliche Einheiten ohne 
Skalierung benutzen. Das macht es einfacher, Werte auf Plausibilität zu 
prüfen.

Ansonsten: Übung macht den Meister. Hier wurden viele gute Ideen 
genannt, und wenn du jetzt das Projekt passend umstrukturierst, wirst du 
hoffentlich genug gelernt haben, um die Fehler zu vermeiden. Du wirst 
dafür viele neue Fehler machen, aber genau dadurch lernt man. Viel 
Erfolg und Spaß!

von Joachim B. (jar)


Lesenswert?

Stefanus F. schrieb:
> Mein Raspberry Pi läuft genau so stabil, wie meine AVR und ESP8266
> Projekte. Jahrelang ohne Aussetzer halt ich für vollkommen normal.

hahaha,
mir sind schon 3 SD und µSD Karten im PI gestorben, die werden durch das 
swap oder cache Dateien einfach kaputtgeschrieben.

Ohne Nennung von OS und wie du Schreibvorgänge auf der SD abschaltest 
ist deine Aussage wertlos.

Die 2 Transcend microSD wollten nicht mal am PI2 und PI3 laufen, 
einigermaßen durchgehalten haben Samsung SD Karten, aber 2 hat das Kodi 
auf dem PI auch kaputtgeschrieben, eine steht kurz vor dem Lebensende 
mit raspbian jessiePIXEL. Mittlerweile habe ich swap und chromium cache 
auf das NAS ausgelagert, wie gesagt um die Schreibvorgänge auf die SD zu 
minimieren.

von S. R. (svenska)


Lesenswert?

Joachim B. schrieb:
> Ohne Nennung von OS und wie du Schreibvorgänge
> auf der SD abschaltest ist deine Aussage wertlos.

Ich wüsste jetzt nicht, warum deine Inkompetenz die Aussage von 
Stefanus ungültig machen sollte.

Aber fürs Topic:
Mein Raspberry Pi hat auch noch keine SD-Karte gefressen.

von Joachim B. (jar)


Lesenswert?

S. R. schrieb:
> warum deine Inkompetenz

wieder nur Geschwafel

S. R. schrieb:
> Mein Raspberry Pi hat auch noch keine SD-Karte gefressen.

schaffe ich auch, wenn man den PI im Schrank liegen lässt :)

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Joachim B. schrieb:
> Ohne Nennung von OS und wie du Schreibvorgänge auf der SD abschaltest
> ist deine Aussage wertlos.

Rasbian ohne GUI ansonsten in Standard-Konfiguration.
Anwendungen: Fileserver samba (kaum genutzt), sowie ein Shell-Script das 
alle 10 Sekunden eine Logmeldung ausgibt.

Wenn die SD Karte frühzeitig ablegt, dann entweder wegen schlechter 
Qualität oder ein Anwendungsprogramm hat sie überfordert.

von Joachim B. (jar)


Lesenswert?

Stefanus F. schrieb:
> Rasbian ohne GUI

installiert raspbian jetzt nicht mehr serienmäßig eine SWAP Partition 
oder macht das nur die mit GUI?

von Stefan F. (Gast)


Lesenswert?

Joachim B. schrieb:
> Stefanus F. schrieb:
>> Rasbian ohne GUI
>
> installiert raspbian jetzt nicht mehr serienmäßig eine SWAP Partition
> oder macht das nur die mit GUI?

Ich weiß nicht was es "jetzt" macht, denn meiner ist ja schon über 2 
Jahre alt. Der hat jedenfalls eine swap Partition. Da sie kaum verwendet 
wird, habe ich mir keinen Kopf darum gemacht.

von Joachim B. (jar)


Lesenswert?

Stefanus F. schrieb:
> Ich weiß nicht was es "jetzt" macht, denn meiner ist ja schon über 2
> Jahre alt.

na denn.....
2 Jahre mit wenig Schreiben ist eine recht kurze Zeit.
ich nutze den PI seit 6 Jahren und habe 5 PIs und Kodi sowie Chromium 
schreiben recht viel auf die SD Karten und Kartenausfall gab es nicht 
nur bei mir, auch im PI Forum waren einige betroffen.
Die Karten gehen in den write protect Modus, da ist dann nichts mehr zu 
"löten" die lassen sich nicht mehr löschen oder initialisieren.

Mein Webserver auf AVR 1284p Basis läuft seit 2008

: Bearbeitet durch User
von E. H. (emax)


Lesenswert?

Hallo Felix,

ich habe nicht den ganzen Thread Wort für Wort gelesen, aber das 
Problem, denke ich, verstanden.

Erst mal Hut ab für Deinen unbedarften Einstieg in die Sache. Genau so 
habe ich vor Jaaaahren (80er) gelernt, Software zu schreiben. Die vielen 
Fehler und Ungelenkigkeiten in meinen Entwicklungen waren der 
gründlichste Weg, dazu zu lernen.

Deine Sources habe ich überflogen. Wenn Du hier so etwas postest, 
bekommst Du von 20 Softwerkern natürlich mindestens 30 andere Lösungen 
für jedes Einzelproblem. Hinzu kommt, dass manche Protagonisten sich 
gegenseitig mit "noch besseren" Lösungen überhäufen, was Dir aber am 
Ende wenig nützt. Also lass Dich nicht entmutigen, das ist normal. ;-)

Ich möchte mich nicht unbedingt dazu gesellen, weil es einfach Dutzende 
Ansätze gibt, den Code übersichtlicher zu strukturieren und weniger 
redundant zu machen.

Um aber Deine Eingangsfrage zu beantworten:

- Wenn Du einfach nur mehr reinpacken willst, und die Dir die 
Optimierung Deines Werks nicht so wichtig ist, nimm was Größeres. Dann 
hast Du vermutlich schneller Ergebnisse. Allerdings ist der Umstieg auf 
(z.B.) einen STM32 nicht trivial. Der ATMEGA2560 hätte vermutlich genug 
Flash für das, was Du noch machen möchtest. Und hinsichtlich der 
Optimierung des SRAMs dürfte es auch noch genügend Raum geben.
- Wenn Du aber dazu lernen möchtest und es Dir nicht primär auf "viel 
drin, schnell fertig" ankommt, rate ich Dir zu einer grundlegenden 
Reorganisation Deines Projektes, einschließlich der damit verbundenen 
Erarbeitung der entsprechenden Grundlagen. Dann hast Du alles richtig 
gemacht, klassisches "learning by doing".

Ich persönlich bin am Ende immer den zweiten Weg gegangen. Zuweilen war 
aber auch mir das "viel drin/schnell fertig" wichtig. Nur endete das 
dann in aller Regel in schwer wartbaren und final neu zu schreibenden 
Programmen. Fehlersuche, Optimierung und Erweiterung der Software waren 
am Schluss aufwändiger als es die Neuorgansiation bzw. ein Neustart 
gewesen wäre.

Letztlich eine Frage der Geduld.

Ernsthafte Software-Entwicklung ist nach meiner Erfahrung immer ein 
iterativer Prozess, der häufig ein gründliches Refactoring verlangt, 
und, wenn man einfach so hineingestolpert ist, i.d.R. auch ein 
umfassendes Neudesign. Siehe majortom: "ich habe kein project/program wo 
ich nicht gefüllt den code 2-3mal fast neugeschrieben habe - in teilen 
sogar x-mal neu.". Kann ich unterschreiben. Und auch das hier "und da 
ging es nicht darum wie z.b. in c sinnig programmiert wird, sondern wie 
ein problem/aufgabe sinnvoll abgebildet wird".

Da offenbart sich der Unterschied zwischen Design und Koden. Du hast 
kodiert. Das ist nichts Schlimmes, aber auf Dauer reicht das eben nicht, 
jedenfalls nicht bei nicht-trivialen Aufgaben, Und das, was Du da 
machst, ist durchaus nicht trivial. Vor dem Koden steht daher die 
Isolierung und Formulierung des Problems bzw. der Aufgabe und verbunden 
damit der Einzelprobleme und -aufgaben. Ist das geschafft, lassen sich 
solche Blöcke viel einfacher handhaben.

Was ich machen würde: Viel Papier auf den Tisch legen, die einzelnen 
Aufgaben definieren und als Meta-Code aufschreiben, den Code 
reorganisieren (sowohl "physisch", also in Einzeldateien zerlegen, als 
auch logisch) und dann mit einem klaren Konzept neu aufsetzen. Zu diesem 
Zeitpunkt sollten dann neben den aktuellen Features auch die für die 
Zukunft angedachten bekannt und eingeplant sein.

So sollte Dein vorhandener Prozessor noch für einiges mehr tauglich 
sein, als Du vermutest.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.