Forum: Mikrocontroller und Digitale Elektronik Identischer Befehl liefert in for-Schleife falschen Wert


von Johannes (menschenskind)


Angehängte Dateien:

Lesenswert?

Hallo,

Im Flash eines AVR ist ein Image abgelegt, mit dem dann ein anderer AVR 
geflasht werden soll --> siehe .cpp
1
typedef struct image {
2
    char image_name[30];         /* Ie "optiboot_diecimila.hex" */
3
    char image_chipname[12];         /* ie "atmega168" */
4
    uint16_t image_chipsig;         /* Low two bytes of signature */
5
    byte image_progfuses[4];         /* fuses to set during programming */
6
    byte image_normfuses[4];         /* fuses to set after programming */
7
    byte fusemask[4];
8
    uint16_t chipsize;
9
    byte image_pagesize;         /* page size for flash programming */
10
    byte image_hexcode[12000];         /* intel hex format image (text) */
11
} image_t;

Nun wollte ich simpel über diese For-Schleife den Inhalt von 
"image_progfuses" ausgeben:
1
for ( uint8_t index = 0; index < sizeof ( targetimage->image_progfuses ); index++ ){
2
showHex ( targetimage->image_progfuses[index], true, true );
3
}
was aber falsche Werte zurück gibt. Wenn ich es aber ohne die Schleife 
mache, stimmen die Werte, --> siehe Screenshot.
1
showHex ( targetimage->image_progfuses[0], true,true );
2
showHex ( targetimage->image_progfuses[1], true,true );
3
showHex ( targetimage->image_progfuses[2], true,true );
4
showHex ( targetimage->image_progfuses[3], true,true );

Ich habe auch überprüft, ob die Indizes stimmen und ob sizeof() den 
richtigen Wert zurück gibt, beides positiv.
Nun bin ich mit meinem Latein am Ende und hoffe auf eure Hilfe.

Gruß
Hannes

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Ich sehe keine for-Schleife in Deinem Quelltext.

von Johannes (menschenskind)


Lesenswert?

Walter T. schrieb:
> Ich sehe keine for-Schleife in Deinem Quelltext.

Hast Du den Text komplett gelesen? 🤔

von (prx) A. K. (prx)


Lesenswert?

Da targetimage aufs Flash zeigt: Kann es sein, dass der Compiler den 
Wert von targetimage->image_progfuses[0] aus dem Kontext heraus direkt 
kennt, bei targetimage->image_progfuses[index] aber nicht weiss, dass er 
auf ROM statt RAM zugreifen muss?

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Ja. Und Text und Bild passen nicht zusammen. Im Text sind vier HEX-Werte 
zu sehen, im Bild 8.

Edit: prx wird wohl die richtige Spur gefunden haben. Welchen Datentyp 
hat showHex() ?

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Bei AVR zeigen alle Pointer standardmäßig auf RAM.

Die CPU Befehle, die normalerweise zum Einsatz kommen, können nicht auf 
FLASH zugreifen. Um auf FLASH zuzugreifen, müssen die Funktionen aus 
https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html 
verwendet werden, dann wird Code mit den richtigen Befehlen erzeugt.

von (prx) A. K. (prx)


Lesenswert?

Oder __flash verwenden.

: Bearbeitet durch User
von Johannes (menschenskind)


Lesenswert?

Hallo,
Danke für die schnelle Hilfe.
1
showHex ( pgm_read_byte ( &targetimage->image_progfuses[index] ), true, true );
 muss es also lauten.

D.h. solange die entsprechenden Anweisungen zur Compile-Zeit eindeutig 
sind, weiß das Programm, welches die korrekten Adressen der Daten sind?
Denn die meisten anderen Zugriffe auf die weiteren Elemente dieses 
target_image erfolgen in dem Code (aus einem Adafruit-Projekt) ohne 
dieses Makro.

showHex() ist eine void-Funktion für die Ausgabe auf der seriellen 
Schnittstelle, die ein Byte erwartet.

von Stefan F. (Gast)


Lesenswert?

Weil sie ein "normales" byte erwartet, geht der Compiler davon aus, dass 
das im RAM liegt.

Aus diesem Grund gibt es auch printf() versus printf_p(), sowie puts() 
versus puts_p() und viele weitere. Diese Funktionen erwarten einen 
Zeiger auf eine Zeichenkette. Am Zeiger alleine kann der Compiler nicht 
erkennen, ob RAM oder FLASH gemeint ist. Die Adressen 0, 1, 2, 3, 4, 
usw. gibt es in beiden Speichern. Außerdem kann eine Funktion nicht 
beide Speicher abdecken, denn zum Zugriff auf diese Speicher werden 
unterschiedliche CPU-Befehle benötigt. Du brauchst also zwangsläufig 
zwei unterschiedliche Varianten dieser Funktionen.

Bei PC und ARM Controllern ist das anders. Die haben einen 
Segmentierten Adressraum, in dem RAM und FLASH hintereinander liegen. 
Alle Adressen zeigen dort eindeutig auf eine bestimmten Speicher (z.B. 
0-32768 ist FLASH und 1048510-1068990 ist RAM), deswegen brauchen sie 
dazu auch keine unterschiedlichen Befehle.

Ich weiß nicht, ob du __flash benutzt hast. Das wurde erst relativ spät 
nachträglich zum Compiler hinzugefügt und seine Funktionsweise ist 
zumindest mir immer etwas unklar. Deswegen nutze ich es nicht.

Siehe 
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Flash_mit_flash_und_Embedded-C

von Oliver S. (oliverso)


Lesenswert?

Johannes H. schrieb:
> D.h. solange die entsprechenden Anweisungen zur Compile-Zeit eindeutig
> sind, weiß das Programm, welches die korrekten Adressen der Daten sind?

Nein. Ohne pgm_read_ / write wird immer nur das SRAM angesprochen. Der 
gcc kennt das Konzept „Flash/SRAM“ überhaupt nicht.

Er berechnet zur Compilezeit die Werte, und dabei spielt es dann keine 
Rolle, ob die konstanten Werte zur Laufzeit im Flash oder im SRAM 
liegen.

Oliver

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Oliver S. schrieb:
> Der gcc kennt das Konzept „Flash/SRAM“ überhaupt nicht.

Doch. Seit einigen Versionen kennt er Adressräume und damit __flash.
https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html

Progmem aus der avrlibc stammt aus der Zeit davor.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

(prx) A. K. schrieb:
> Doch. Seit einigen Versionen kennt er Adressräume und damit __flash.

Johannes H. schrieb:
> .cpp

Der g++ kennts noch nicht.

Oliver

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.