Forum: Compiler & IDEs avr-gcc 5.3.1: lto Problem mit Flash > 64k


von N. G. (newgeneration) Benutzerseite


Lesenswert?

Hallo Forum,

ich habe ein meiner Meinung nach seltsames und (für mich) unerklärbares 
Problem.
Ausgangssituation: Ein ATmega2560 (mit eben 256k Flash-Speicher) hat ein 
etwas größeres Display angeschlossen. In seinem Flash liegen die Bilder 
(im RGB-Format), die der AVR dann anzeigen soll.

Das kopieren geschieht mittels
1
extern uint8_t frame_name[FRAME_SIZE] PROGMEM = { ... };
2
3
uint8_t frame_buffer[FRAME_SIZE];
4
5
memcpy_P(frame_buffer, frame_name, sizeof(frame_name));
6
update_display(frame_buffer);

Das funktioniert bis 64k auch ganz normal mit dem PROGMEM-Attribut.
Über der 64k-Grenze sind die Daten ja nicht mehr mit 16bit adressierbar, 
was einen anderen Zugriff erfordert. Die avr-libc bietet dafür 
folgendes:
1
extern uint8_t frame_name[FRAME_SIZE] PROGMEM = { ... };
2
3
uint8_t frame_buffer[FRAME_SIZE];
4
5
memcpy_PF(frame_buffer, pgm_get_far_address(frame_name), sizeof(frame_name));
6
update_display(frame_buffer);

Das funktioniert auch so weit, ABER:

Nur ohne -flto, also ohne link-time-optimizations
Wenn man lto aktiviert werden zwar immer noch die richtigen Daten 
adressiert, aber wohl falsch gelesen.

Das äußert sich darin, dass das Display falsche RGB Werte anzeigt. Grün 
wird beispielsweise blau.
Ein Blick ins Disassembly verät aber, dass die Daten korrekt im Flash 
stehen.

Also muss der Zugriff irgendwie fehlerhaft sein.

Gibt es irgendwas, was man bei dem Zugriff auf Daten im Flash > 64k 
beachten muss?
Oder könnte das etwa ein Bug im Compiler sein?

Mit freundlichen Grüßen,
N.G.

Eckdaten: avr-gcc-5.3.1, binutils 2.25

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

N. G. schrieb:
> Gibt es irgendwas, was man bei dem Zugriff auf Daten im Flash > 64k
> beachten muss?

Wenn deine Daten nicht in die ersten 64 KiB passten, dann gilt das 
womöglich auch für andere Daten im .progmem.  Als erstes würd ich also 
mal das Map-File checken, ob noch andere Daten nicht mehr per LPM 
erreichbar sind.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

...und prinzipiell hast du auch die Möglichkeit, __flash1, __flash2 oder 
__flash3 zu verwenden, was auch 16-Bit Zeiger erzeugt; eben im 
entsprechenden Segment.

Allerdings brauchst du dann ein passendes Linker Description File, weil 
es keine "one fits all" Lösung gibt und die standard-Beschreibung 
.progmem1.data etc. nicht adäquat behandelt.

von N. G. (newgeneration) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Wenn deine Daten nicht in die ersten 64 KiB passten,

Tun sie nicht, sind bisher 200kB.

> dann gilt das
> womöglich auch für andere Daten im .progmem.  Als erstes würd ich also
> mal das Map-File checken, ob noch andere Daten nicht mehr per LPM
> erreichbar sind.

Ich greife generell auf alle PROGMEM-Daten mittels dem _PF, also den 
far-pointer-Funktionen zu. Das sollte doch eigentlich immer gehen.
pgm_get_far_address() erzeugt ja einen 32bit Pointer (wovon aber glaube 
ich nur 24 benutzt werden, weil das oberste Register immer auf 0 gesetzt 
wird).

Johann L. schrieb:
> ...und prinzipiell hast du auch die Möglichkeit, __flash1, __flash2 oder
> __flash3 zu verwenden, was auch 16-Bit Zeiger erzeugt; eben im
> entsprechenden Segment.

Ja, diese Möglichkeit ist mir bekannt, aber ich möchte die Daten 
eigentlich nicht in ein bestimmtes Segment verweisen (außer es geht 
nicht anders). Das müsste ich ja dann tun, mittels
> passendem Linker Description File



Bleibt aber die Frage, warum es ohne LTO geht, mit aber nicht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

N. G. schrieb:
> Johann L. schrieb:
>> Wenn deine Daten nicht in die ersten 64 KiB passten,
>
> Tun sie nicht, sind bisher 200kB.

Zu beachten ist auch, dass Zeiger immer noch 16 Bits breit sind, d.h. 
jegliche zeiger-Arithmetik zu vermeiden ist und stattdessen händische 
Adressberechnung angezeigt ist.

> Ich greife generell auf alle PROGMEM-Daten mittels dem _PF, also den
> far-pointer-Funktionen zu. Das sollte doch eigentlich immer gehen.

Das war nicht die Frage.  Auch der Compiler oder Bibliotheken können 
Daten in .progmem erzeugen, und für deren Zugriff wird eben kein _PF 
verwandt.

> Bleibt aber die Frage, warum es ohne LTO geht, mit aber nicht.

Möglich ist auch, dass es garnix mit progemem zu tun hat, sondern ein 
Bug in deiner Anwendung, der erst durch LTO offengelegt wird.  Ums 
Debuggen wirst du also schwerlich rumkommen.

von N. G. (newgeneration) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Zu beachten ist auch, dass Zeiger immer noch 16 Bits breit sind, d.h.
> jegliche zeiger-Arithmetik zu vermeiden ist und stattdessen händische
> Adressberechnung angezeigt ist.

Das hätte ich jetzt tatsächlich übersehen, aber ich verwende das sowieso 
nicht. Aber gut zu wissen und eigentlich sollte es ja klar sein...

Johann L. schrieb:
> Auch der Compiler oder Bibliotheken können
> Daten in .progmem erzeugen, und für deren Zugriff wird eben kein _PF
> verwandt.

Okay, auch wieder klar, aber habe ich vernachlässigt.
Woran erkenne ich denn die Objekte mit dem falschen Zugriff? An der 
Objektadresse > 64k?

Johann L. schrieb:
> Möglich ist auch, dass es garnix mit progemem zu tun hat, sondern ein
> Bug in deiner Anwendung, der erst durch LTO offengelegt wird.

Das ist das woran ich als erstes gedacht habe. Ich vermute generell nie 
Fehler beim Compiler, erst wenn es einen seehr begründeten Verdacht 
gibt.
Allerdings fallen mir auf Anhieb keine Gründe für ein solches Verhalten 
ein.
Aber das einfachste wäre zu Debuggen, wie du schon gesagt hast.

Leider ist mein Board ein Arduino mega ADK Board (wird aber ohne 
Arduino-Umgebung mittels Eclipse+Makefile programmiert), und ich muss 
erst mal einen Debugger organisieren und irgendwie anschließen (das ist 
aber das kleinere Problem).

Danke schon mal für deine Hilfe bis jetzt.
N.G.

von holger (Gast)


Lesenswert?

>und ich muss
>erst mal einen Debugger organisieren und irgendwie anschließen

Du könntest dir auch ein STM32 Discovery Board besorgen.
Bei ARMs gibt es diese nervigen Verrenkungen mit PROGMEM nicht.

SCNR;)

von N.G. (Gast)


Lesenswert?

holger schrieb:
>>und ich muss
>>erst mal einen Debugger organisieren und irgendwie anschließen
>
> Du könntest dir auch ein STM32 Discovery Board besorgen.

Habe ich, nutzt mir jedoch nichts. Man kann nicht immer einfach das 
machen, was einem am liebsten wäre. Und wenn schon ARM, dann eher von 
NXP, die finde ich persönlich besser.

> Bei ARMs gibt es diese nervigen Verrenkungen mit PROGMEM nicht.

Nervig finde ich es jetzt nicht, man muss halt wissen was man tut. Und 
in dem Fall liegt das "Problem" ja nicht an den getrennten Adressräumen, 
sondern an den zu kleinen Pointern (was natürlich auf nem ARM mit 32bit 
Pointern auch wieder nicht so ist, ich weiß).

Trotzdem muss ich beim AVR bleiben, schon alleine wegen der Zeit.

Debugger habe ich Privat schon, aber natürlich zur Zeit verliehen. Und 
in der Firma habe ich bis jetzt noch keinen gesehen, aber da sind AVRs 
(abgesehen von Arduino) eine Seltenheit, ich glaube es gibt hier 
(Bootloader sei Dank) nicht mal einen normalen ISP-Programmer.

Ich melde mich dann nächste Woche wieder, wenn das Debuggen brauchbare 
Ergebnisse liefert.

N.G. (nicht angemeldet)

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.