Forum: Compiler & IDEs Mehrere uint8_t in uint32_t


von Stefan (Gast)


Lesenswert?

Hallo Forengemeinde!
Ich verstehe den AVR-GCC nicht so recht, es geht um folgendes Problem:
Ich habe eine uint32_t-Variable und hole über den UART 4 Byte Daten ab, 
welche mir jeweils als uint8_t zur Verfügung stehen. Ich will diese nun 
verketten, sodass das zuerst empfangene Byte ganz links (am MSB 
sozusagen) in der 32-Bit-Variable steht und von da an abwärts die 
Folgebytes.

Das ganze gestaltet sich ungefähr so:
1
uint32_t registerValue = 0;
2
dataLen = 4;
3
while(dataLen--) 
4
{
5
   registerValue = registerValue << 8;
6
   registerValue |= fifo_get_wait(&FIFO.infifo);
7
}
Die fifo_get_wait ist definiert als:
1
uint8_t fifo_get_wait(fifo_t *f)
Gibt also korrekt einen uint8_t zurück.

Das Problem äußert sich darin, dass immer nur das zuletzt gelesene Byte 
in registerValue steht, nachdem die Schleife durchlaufen wurde. Die 24 
Bit links davon sind 0.
Einzeln kann ich alle 4 Byte empfangen - kann es sein dass ich auf einen 
Bug im AVR-GCC gestoßen bin, und der das shiften von 32-Bit-Variablen 
nicht richtigmacht?

Ein dazu analoges Programm für x86 auf Windows kompiliert funktioniert:
1
#include <stdio.h>
2
#include <inttypes.h>
3
4
uint8_t irgendwas(void) {
5
    return 1;
6
}
7
8
int main(void)
9
{
10
    uint32_t test = 0;
11
    uint8_t ctr = 2;
12
    while (ctr--) {
13
        test = test << 8;
14
        test |= irgendwas();
15
    }
16
17
    printf("%d", test);
18
    return 0;
19
}
Ergibt wie zu erwarten 257 (0000000100000001).

Hoffe, ihr könnt mir helfen, ich verzweifle hier noch. Was ich schon 
versucht habe:
- Den fifo_get_wait-Aufruf auf uint32_t casten
- += statt |= benutzen
- Statt der Shift-Operation *256 rechnen

Was ich ausschließen kann als Fehlerquelle:
- die FIFO funktioniert (alle 4 Byte einzeln empfangen ist kein Problem)
- der UART ist korrekt eingestellt (empfangene Bytes kann ich korrekt 
wieder zurücksenden)
- die Hardware (UART-Signale beobachte ich dauerhaft am Logikanalysator 
mit)...

Danke für die Hilfe,
Stefan

von Ingo (Gast)


Lesenswert?

Warum verwendest du keine Union?

von Stefan (Gast)


Lesenswert?

Vielleicht keine schlechte Idee und ist wohl auch stilistisch besser - 
trotzdem interessiert mich brennend, wo hier das Problem liegt... Kann 
es irgendjemand bei sich verifizieren?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Daß ne Union schlecht ist wurde nun schon zum 1000 mal diskutiert...

Was den Originalcode angahr, wäre ein reproduzierbarer Testfall 
hilfreich, d.h. irgendein compilierbares Modülchen.

Oben das ist kein gültiger C-Code, z.b. steht die while-SChleife 
ausserhalb einer Funktion oder dataLen wird nicht deklariert.

von Coder (Gast)


Lesenswert?

Verwende doch mal den AVR-Simulator und anstatt deiner FIFO-Funktion 
nimm ein Array mit Test-Daten.

von Fabian O. (xfr)


Lesenswert?

Besonders effizient ists übrigens nicht, den uint32_t in der Schleife 
rumzushiften. Schreib die Bytes lieber gleich an die richtige Stelle:
1
uint32_t registerValue = 0;
2
registerValue |= (uint32_t) fifo_get_wait(&FIFO.infifo) << 24;
3
registerValue |= (uint32_t) fifo_get_wait(&FIFO.infifo) << 16;
4
registerValue |= (uint32_t) fifo_get_wait(&FIFO.infifo) << 8;
5
registerValue |= (uint32_t) fifo_get_wait(&FIFO.infifo);

von Stefan (Gast)


Lesenswert?

@Johann: Ich versuche mal, was durchkompilierbares hinzubekommen. mein 
Versuch, den PC-Code aus dem OP auf dem MCU auszuführen, wurde wohl 
wegoptimiert. Damit kam das erwartete Ergebnis heraus...

@Fabian: Leider funktioniert diese Lösung genausowenig. Habe gerade 
sogar den Weg gewählt, die 4 Reads in 4 Variablen machen zu lassen, die 
ich mir dann nochmal einzeln hab ausgeben lassen - die werden 100% 
richtig belegt. Nur das verketten mit dem Shiften will einfach nicht 
gehen - ich werde blöde hier.

Compilerupdate von 4.3.3 aus WinAVR auf 4.7.0 hat nichts gebracht...

von Stefan E. (sternst)


Lesenswert?

Wie stellst du überhaupt fest, was hinterher im uint32_t drin steht?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan schrieb:
> @Johann: Ich versuche mal, was durchkompilierbares hinzubekommen. mein
> Versuch, den PC-Code aus dem OP auf dem MCU auszuführen, wurde wohl
> wegoptimiert. Damit kam das erwartete Ergebnis heraus...

Da dann ist fifo_get_wait vermutlich inline.  Wirf die Implementierung 
raus und mach es extern, dann kann nix mehr optimiert werden.

> Compilerupdate von 4.3.3 aus WinAVR auf 4.7.0 hat nichts gebracht...

Die 4.7.0 willst du definitiv nicht verwenden :-)

Nimm die 4.7.2, wenn es denn eine 4.7 sein soll!  Siehe etwa

http://lists.gnu.org/archive/html/avr-gcc-list/2012-09/msg00024.html

von Stefan (Gast)


Lesenswert?

Einerseits durch ein itoa und Ausgabe auf dem OSD am Fernseher, 
andererseits durch
1
uint32_t fraglich;
2
uint8_t test1 = fraglich;
3
uint8_t test2 = fraglich>>8;
4
uint8_t test3 = fraglich>>8;
5
uint8_t test4 = fraglich>>8;
6
uart_putc(test1);
7
uart_putc(test2);
8
uart_putc(test3);
9
uart_putc(test4);

Beide zeigen mir das gleiche. Mit einem bekannten, festen 32Bit-Wert in 
"fraglich" sehe ich via UART die korrekten Daten.

von Stefan (Gast)


Lesenswert?

Sry, 8, 16, 24 natürlich..

von Stefan (Gast)


Lesenswert?

Bitte vergebt mir, ich habe den Fehler an anderer Stelle gefunden. Die 
übergeordnete Funktion hatte nur ein uint8_t als Rückgabewert, das muss 
beim umherkopieren passiert sein...

So kann man sich das Leben schwer machen. Hier kann dichtgemacht werden.

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.