Mehrere uint8_t in uint32_t

Gast #3080225
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
#3080366
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);
Gast #3080385
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...
Persönliche Seite #3080399
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
Gast #3080401
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.
Gast #3080416
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren