Forum: Mikrocontroller und Digitale Elektronik Bibliotheken streiten sich um Daten im Flash / PROGMEM


von S. G. (goeck)


Lesenswert?

Hallo zusammen,

Ich glaube,ich muss mal wieder auf eure Fachkompetenz zurückgreifen.
Ich habe auf einem ATMega328P ein größeres Projekt, in dem ich auch die 
Linsin Bibliothek von Johann L. (gjlayde) nutze 
(http://www.mikrocontroller.net/articles/AVR_Arithmetik/Sinus_und_Cosinus_%28Lineare_Interpolation%29).
Außerdem nutze ich ein LCD Display, das über I2C angesprochen wird, 
dafür habe ich die GLCDL-AVR Bibliothek von Christophe Lorenz 
(https://sites.google.com/site/donutscience/programming-hacks/graphic-lcd-library-for-avr-barton-and-other).
Die GLCDL Bibliothek nutzt ASCII Tabellen, die im Flash abgelegt werden 
für die String Ausgabe auf dem LCD. Die Linsin Bibliothek nutzt Lookup 
Tables, die ebenfalls im Flash abgelegt werden, um die 
Stütztstelleninterpolation zu rechnen.

Mein Problem ist, sobald ich die Linsin Bib einbinde, bekomme ich 
anstatt der Buchstaben auf dem LCD nur zufällig verteilt aussehende 
Pixelbereiche (keinerlei Buchstaben erkennbar), die widerum aber immer 
konstant sind, d.h. es sind nicht zufällige Muster, sondern konstant 
erzeugte Muster. Grafische Elemente, wie Kreise und Rechtecke, können 
mit und ohne Linsin Bib immer einwandfrei angezeigt werden.
Entferne ich die Linsin Bib wieder, funktioniert die String Darstellung 
auf dem LCD einwandfrei.

Ich vermute daher, dass es ein Problem mit den Daten im Flash gibt. 
Allerdings reicht über das Speichern und Lesen, wie es bspw. hier 
beschrieben ist 
(http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=38003&start=all&postdays=0&postorder=asc) 
mein Wissen nicht hinaus. Atmel Studio sagt zur Speicherbelegung 
folgendes nach dem Kompilieren:
1
Program Memory Usage   :  18546 bytes   56.6 % Full
2
Data Memory Usage     :  901 bytes      44.0 % Full

Ich hoffe, ihr habt noch einen Tipp für mich.

Danke und
Grüße
Stefan

von S. G. (goeck)


Lesenswert?

Hat niemand einen Hinweis?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

In meiner Glaskugel schneits leider grade nur...
Und du hast dein Code nicht gepostet!

von Karl H. (kbuchegg)


Lesenswert?

Helfen kann ich dir so nicht, weil dein konkreter Code bzw. das Projekt 
nicht vorliegt.

Aber ich weiß, was ich tun würde.
Nichts gegen Johann, aber als erstes würde ich mal von der linsin die 
Funktionen rauswerfen und nachsehen ob der Effekt auch dann noch 
besteht, wenn ich nur die Sin/Cos Tabelle im Programm hab.

Wenn geklärt ist, das die Tabelle alleine das Programm nicht 
beeinflusst, würde ich mal die Assembler-Versionen der Funktionen durch 
normale C-Funktionen ersetzen.

Wenn allerdings das blosse Vorhandensein der Tabelle die Font-Ausgabe 
schon durcheinander bringt, dann muss man eben die Graphic-Funktionen 
auseinander nehmen.

von Peter D. (peda)


Lesenswert?

Bevor man Assembler in einem C-Programm benutzt, sollte man sich diese 3 
Fragen stellen:

Ist es wirklich wirklich wirklich nötig?
Ist es wirklich wirklich wirklich nötig?
Ist es wirklich wirklich wirklich nötig?

Und sie auch wahrheitsgemäß beantworten!

Peter

von S. G. (goeck)


Lesenswert?

Hihi, Peter das gefällt mir.
Naja, Johann hat die Bibliothek nun mal so geschrieben und sie (allein) 
funktioniert auch hervorragend, vor allem schnell...worauf ich 
angewiesen bin, da ich in einem iterativen Algoritmus ständig sin/cos 
rechnen muss.
Habe schon in erwägung gezogen CORDIC zu nutzen, allerdings war mir das 
für quick'n'dirty etwas zu umständlich gestern.

Bin jetzt dabei Karl Heinz' Ratschläge zu testen und bekomme merkwürdige 
Ergebnisse. Anscheinend ist die bloße Anwesenheit der Lookup Table schon 
nicht erwünscht. Mehr später...

Danke euch für eure Meinungen.

Grüße
Stefan

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Inline Assembler wurde eh vom Dunkellord personlich erfunden.
Wenns schon asm sein muss, dann in ein extra File packen und sich an die 
konventionen halten.

von Karl H. (kbuchegg)


Lesenswert?

Martin Wende schrieb:
> Inline Assembler wurde eh vom Dunkellord personlich erfunden.

Na dann passts ja.
Johann könnte man durchaus als den DuWeißtSchonWer beim AVR-gcc ansehen 
:-)

(Soll heißen: Johann weiß schon was er tut - dem vertrau ich 
normalerweise blind. Aber im vorliegenden Fall ist sein Code nun mal der 
kürzere gegenüber dieser GLCD-Lib)

von S. G. (goeck)


Lesenswert?

Hallo zusammen,

also meinen bisherigen Versuchen zufolge liegt unter anderem es an 
folgendem Makro aus linsin.c:
1
// Ein Word per post-Increment aus dem Flash lesen.
2
// Dies ist besser als  pgm_read_word (p++)
3
#define pgm_read_word_inc(addr)             \
4
(__extension__({                            \
5
uint16_t __result;                      \
6
__asm__                                 \
7
(                                       \
8
"lpm %A0, Z+"   "\n\t"              \
9
"lpm %B0, Z+"                       \
10
: "=r" (__result), "+z" (addr)      \
11
);                                      \
12
__result;                               \
13
}))
Der gesamte restliche Code aus linsin.h und linsin.c kann eingebunden 
werden, ohne das es Probleme bei den LCD Routinen gibt. Sobald ich 
allerdings dieses pgm_read_word_inc Makro und auch das pgm_read_word aus 
pgmspace.h Makro einbinde, bekomme ich Müll auf dem Display.

Mein aktuelles Workaround ist die Auskommentierung dieses Blocks und 
folgende Defines
1
#define pgm_read_word_inc(a)  1
2
#define pgm_read_word(a)      1

Damit lässt sich alles einwandfrei kompillieren, allerdings macht dies 
natürlich die sin/cos Funktionen unbrauchbar...

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Na danns chreib die Lib eben um zu:
1
// Ein Word per post-Increment aus dem Flash lesen.
2
// Dies ist besser als  pgm_read_word (p++)

Dann sollte die wieder laufen, nur eben etwas langsamer.
Oder du exportierst diese Funktion in ein extra Assemblerfile.
Inlineassembler macht jeder Compiler nen bissel anders.

von Peter D. (peda)


Lesenswert?

Man kennt ja Dein Programm nicht, ob es wirklich auf 2 Zyklen mehr 
ankommt.

In der Regel sollte man bei nem RISC nicht so pingelig sein müssen, da 
sind 2 Zyklen Pinats.
Erst wenns um >=100 Zyklen geht, dann kann man mal versuchen, dran zu 
drehen.

Man darf auch nicht vergessen, daß der AVR keine Interruptlevel hat. Es 
nützt also nichts, einen Interrupt mit viel Mühe auf 50 Zyklen 
einzudampfen, wenn eine anderer 500 Zyklen dauert. Die worst case Latenz 
ist immer der das Maximum, also die 500 Zyklen.

Am besten, man schreibt erstmal alles komplett in C. Und erst, wenn es 
klemmt, kann man analysieren, ob Assembler überhaupt was rausreißen 
würde.


Peter

von S. G. (goeck)


Lesenswert?

Werde euren Tipp wahrnehmen und das Ganze in C implementieren...
Allerdings was mir grad auffällt, auch der Aufruf des Makros 
pgm_read_word führt ja schon zum Problem. Und dieses ist ja in 
pgmspace.h, also einer generischen Header Datei definiert. Die Nutzung 
von pgmspace.h ist die einzige Möglichkeit, die ich kenne für Flash 
Zugriff. Dort wird auch alles mit inline Assembler gemacht...
Gibt es Alternativen?

Grüße
und viel Spaß im Schnee

von Karl H. (kbuchegg)


Lesenswert?

S. G. schrieb:
> Werde euren Tipp wahrnehmen und das Ganze in C implementieren...
> Allerdings was mir grad auffällt, auch der Aufruf des Makros
> pgm_read_word führt ja schon zum Problem.

Das kann/sollte allerdings nicht sein.

Wie hast du denn die pgm_read_word_inc ersetzt?

Ein ...
1
#define pgm_read_word_inc(addr)   pgm_read_word (addr++)
... anstelle der ursprünglichen Definition sollte eigentlich das Kind 
geschaukelt haben.


wobei.
So ganz klar ist mir ehrlich gesagt nicht, wie da die Zusammenhänge 
sind/sein sollen, die zum Fehler führen. Ich denke eher, wir sind auf 
einer ganz kalten Spur. Wir versuchen hier Symptome zu behandeln und 
nicht Ursachen.

von Peter D. (peda)


Lesenswert?

S. G. schrieb:
> Und dieses ist ja in
> pgmspace.h, also einer generischen Header Datei definiert.

Die Compiler-Libs sollten eigentlich kugelsicher sein.
Daß sich ein Fehler auswirkt, wenn man sie benutzt, muß ja nicht heißen, 
daß sie fehlerhaft sind. Der Fehler wird wohl woanders sein.


Peter

von S. G. (goeck)


Lesenswert?

hm...da habt ihr Recht. Ich baue mal ein Minimalbeispiel zusammen und 
poste es.

von S. G. (goeck)


Lesenswert?

Hallo zusammen,

jetzt habe ich gleich keine Lust mehr. Wollte euch gerade ein 
Minimalbsp. zusammenstöpseln, da lege ich mir ein neues Projekt an in 
ATmelStudio 6.0 und füge meine kopierten Dateien (aus dem 
Originalprojekt) hinzu, kompiliere direkt und alles funktioniert 
einwandfrei mit inkludierter Linsin und GLCDL Bilbiothek. Versuche ich 
daraufhin wiederholt das gleiche mit den Originaldateien im 
Originalprojekt entstehen wieder die Fehler auf dem Display. Abhilfe 
schafft immer noch der Verzicht auf pgm_read_byte() und Konsorten.
Ich habe mir die erzeugten Makefiles angeschaut, sind identisch, wie 
auch die erzeiten cproj Dateien. Löschen alle erstellter *.o Dateien und 
wiederholtes Erzeugen brachte im originalprojekt auch keine Änderung.

Das Originalprojekt wurde mit AtmelStudio 5.1 angelegt und dann in 
AtmelStudio 6.0 importiert. Bisher gab es keinerlei Probleme, bis auf 
dieses merkwürdige Verhalten.

Am Code scheint es wohl demnach nciht zu liegen...
Kennt ihr diesen Effekt von AtmelStudio?

Viele Grüße
Stefan

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hab den Thread eben erst gefunden...

Hat sich ds Problem eigentlich gelöst? Ich kann mit kaum vorstellen, daß 
das Macro pgm_read_byte_inc aus dem linsin Modul Schuld an den Problemen 
sein soll — zumal das Problem nach Kopieren des gesamten Projekts 
verschwindet.

von S. G. (goeck)


Lesenswert?

Hey,

das Problem hat sich insofern erledigt, als dass es ja mit dem 
angelegten AtmelStudio 6.0 Projekt verschwundenn war und insofern, als 
dass ich mittlerweile zwecks besserer Performance auf einen STM32F0 
umgestiegen bin (Kann das DevKit für 7€ nur empfehlen :-) ) und eine 
RTOS darauf laufen habe (ChibiOS). Alles funktioniert schnell und 
einwandfrei.

Also wiegesagt, letzlich klären ließ sich das Ganze nicht. Mit Anlegen 
eines neuen Projektes in AtmelStudio war es behoben, aber eben nicht 
geklärt...

Grüße

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.