Forum: Mikrocontroller und Digitale Elektronik STM32L152 uint64_t wird nicht richtig verarbeitet


von Peter F. (peter_da_steht_er)


Lesenswert?

Hallo, habe ich was grob falsch gemacht?
Wenn ich meinen Code debugge, änder sich der Wert von "rom_adress" 
unerwartet und falsch, selbst die Deklaration mit  = 0 hat kein Effekt 
auf den Wert. Die Funktion "one_wire_read" liefert uint8_t.

1
uint64_t onewire_read_rom(void)
2
{  
3
  uint64_t rom_adress = 0;  
4
  uint8_t shift =48;
5
  uint8_t data = 0;
6
  
7
  onewire_reset();
8
  
9
  one_wire_putc(0x33);
10
  
11
  one_wire_read(); // Family 
12
  
13
  while(shift)
14
  {
15
    data=one_wire_read(); 
16
    rom_adress|=(data<<shift);
17
    shift-=8;
18
  };
19
20
  one_wire_read(); // CRC
21
22
    
23
return rom_adress;
24
};

von Rolf M. (rmagnus)


Lesenswert?

Peter F. schrieb:
> Hallo, habe ich was grob falsch gemacht?

Ja.

Peter F. schrieb:
> rom_adress|=(data<<shift);

data ist ein uint8_t. Für die Schiebe-Operation wird der nach int 
konvertiert, und damit ist die maximal Shift-Weite die von int.

von PittyJ (Gast)


Lesenswert?

Was ist genau falsch?
Wie sollte es deiner Meinung nach richtig sein?


Meiner Meinung nach muss data erst auf uint64_t erweitert werden, bevor 
der shift stattfinden darf.

Also sowas wie
rom_adress|=( (( unint64_t)data)<<shift);


Da ich aber deine falsch/richtig-Bewertung nicht kenne, sind das nur 
Vermutungen.

von Peter F. (peter_da_steht_er)


Lesenswert?

Vielen Dank für die schnelle Antwort
wie geh ich dann mit so einem Problem am besten um?

Gruß Peter

von Joe F. (easylife)


Lesenswert?

versuche es mal statt
1
  while(shift)
2
  {
3
    data=one_wire_read(); 
4
    rom_adress|=(data<<shift);
5
    shift-=8;
6
  };

so:
1
    rom_adress =   one_wire_read(); 
2
    rom_adress <<= 8;
3
    rom_adress |=  one_wire_read(); 
4
    rom_adress <<= 8;
5
    rom_adress |=  one_wire_read(); 
6
    rom_adress <<= 8;
7
    rom_adress |=  one_wire_read();

kann man natürlich auch in einer schleife machen...
1
    rom_adress = 0;
2
    for (i=0; i<4; i++) {
3
        rom_adress <<= 8;
4
        rom_adress |=  one_wire_read(); 
5
    }

von Peter F. (peter_da_steht_er)


Lesenswert?

Vielen Dank noch mal. Aber leider Funktioniert das nicht so recht.
@(easylife)
Wenn ich deine Methode mache ist der Wert während der Schleife 
0x800000000.

Ich habe die Funktion onewire_read_rom auf uint32_t abgeändert dann 
treffen alle erwarteten Werte zu ;), aber wo ist dann der Fehler?

von Joe F. (easylife)


Lesenswert?

Peter F. schrieb:
> Wenn ich deine Methode mache ist der Wert während der Schleife
> 0x800000000.

Das verstehe ich dann auch nicht.
Denn wenn in den obersten 8 bit 0x80 steht, heisst das dass im ersten 
Schleifendurchlauf korrekterweise 0x80 mit rom_address ver-odert wurde.
Wenn in den nächsten Schleifendurchläufen dann jeweils 0x00 ver-odert 
wurde, heisst das für mich, dass one_wire_read() 0x00 zurückgeliefert 
hat.
Den cast auf uint64_t beim verodern müsste der Compiler eigentlich 
automatisch machen.

Kannst ja mal ausprobieren, ob ein expliziter cast

rom_adress |=  (uint64_t)(one_wire_read());

innerhalb der Schleife etwas verbessert.

von PittyJ (Gast)


Lesenswert?

Sobald der Shift > 32 ist, geht meiner Meinung nach die Lösung von 
easylife auch nicht.

von Rolf M. (rmagnus)


Lesenswert?

PittyJ schrieb:
> Meiner Meinung nach muss data erst auf uint64_t erweitert werden, bevor
> der shift stattfinden darf.
>
> Also sowas wie
> rom_adress|=( (( unint64_t)data)<<shift);

Ja, richtig.

> Da ich aber deine falsch/richtig-Bewertung nicht kenne, sind das nur
> Vermutungen.

Ich tendiere dazu, nicht gleich die fertige Lösung zu präsentieren, 
sondern einen Hinweis auf den Fehler, damit der Fragesteller die 
Möglichkeit hat, selbst auf die Lösung zu kommem und zu verstehen, warum 
sie nötig ist.

Peter F. schrieb:
> Vielen Dank noch mal. Aber leider Funktioniert das nicht so recht.
> @(easylife)

Dann ist wahrscheinlich wirklich was am Compiler.

> Wenn ich deine Methode mache ist der Wert während der Schleife
> 0x800000000.

Während, oder danach?

Joe F. schrieb:
> Das verstehe ich dann auch nicht.
> Denn wenn in den obersten 8 bit 0x80 steht, heisst das dass im ersten
> Schleifendurchlauf korrekterweise 0x80 mit rom_address ver-odert wurde.

Nein, denn so weit wird bei deinem Code gar nicht geshiftet, daß da 
überhaupt irgendwas ankommen darf. Im Originalcode wird maximal um 48 
Bits geshiftet, aber dein Code shiftet nur um maximal 24 Bits und 
beschreibt damit nur die unteren 32 Bits. 0x800000000 heißt aber, daß 
Bit 35 das einzige ist, das gesetzt wurde.

von Joe F. (easylife)


Lesenswert?

Rolf M. schrieb:
> Joe F. schrieb:
>> Das verstehe ich dann auch nicht.
>> Denn wenn in den obersten 8 bit 0x80 steht, heisst das dass im ersten
>> Schleifendurchlauf korrekterweise 0x80 mit rom_address ver-odert wurde.
>
> Nein, denn so weit wird bei deinem Code gar nicht geshiftet, daß da
> überhaupt irgendwas ankommen darf. Im Originalcode wird maximal um 48
> Bits geshiftet, aber dein Code shiftet nur um maximal 24 Bits und
> beschreibt damit nur die unteren 32 Bits. 0x800000000 heißt aber, daß
> Bit 35 das einzige ist, das gesetzt wurde.

Oops, richtig. Die Schleife müsste korrekterweise 8x durchlaufen werden.
Umso unerklärlicher, dass Bit 35 gesetzt ist.

rom_adress = 0L;

eventuell...

von Peter F. (peter_da_steht_er)


Lesenswert?

Also da haut irgendwas gewaltig nicht hin.
1
uint64_t onewire_read_rom(void)
2
{  
3
  uint64_t rom_adress = 0;
4
  uint8_t i = 0;
5
6
  
7
  onewire_reset();
8
  
9
  one_wire_putc(0x33);
10
  
11
  one_wire_read(); // Family 
12
  
13
    for (i=0; i<4; i++) {
14
        rom_adress <<= 8;
15
        rom_adress |=  one_wire_read(); 
16
    }
17
18
  one_wire_read(); // CRC
19
20
    
21
return rom_adress;
22
};

Die Werte der Schleife von links nach rechts.
1
i                 0x53         0x37           0x37          0x06
2
rom_adress  0x800000053  0x800000037  0x800000037  0x800000006

Software: Keil Arm
Debugger: J-Link EDU

von Joe F. (easylife)


Lesenswert?

Naja, in deiner Ausgabe kann ja auch was nicht stimmen.
i läuft von 0 bis 3, und hat nicht den Wert, den one_wire_read() 
zurückliefert.

Die Schleife sollte auch von 0..7 laufen (den Fehler hat Rolf Magnus ja 
bereits erwähnt).

Es sieht so aus, als ob der Compiler die Anweisung den 64-bit Wert zu 
shiften einfach ignoriert.
Bzw. evtl. mit 64-bit Werten sehr schlecht bis gar nicht umgehen kann.

Du könntest mal nachgucken, wie der Assemblercode aussieht, den der 
Compiler aus den Anweisungen in der Schleife erzeugt.
Vielleicht bringt einen das ja weiter.

Und du solltest mal ausprobieren bei allen 64-bit Operationen long-werte 
zu verwenden. Also

uint64_t rom_adress = 0L;

und

rom_adress <<= 8L;


Ausserdem:
Benötigst du überhaupt eine 64-Bit Adresse?
Mit 32-bit kannst du bereits 4 Gigabytes adressieren...

von Peter F. (peter_da_steht_er)


Lesenswert?

Cool, danke für die Antwort werde ich schnellst möglich testen.

von Joe F. (easylife)


Lesenswert?

Und: mal ausprobieren "unsigned long long" statt "uint64_t" zu 
verwenden, bzw. mal nachgucken, wie "uint64_t" definiert wurde.

von Pete K. (pete77)


Lesenswert?

Ist denn one-wire-read auch als 64 bit Rückgabe definiert?

von Peter F. (peter_da_steht_er)


Lesenswert?

Okey hab den Fehler gefunden es muss heißen (1LL<<shift)

vielen Dank noch mal an alle

von Peter (Gast)


Lesenswert?

Hat es einen besonderen Grund warum Du 1L benutzt?

1L hat nur 32 Bit und nicht 64Bit!

von Joe F. (easylife)


Lesenswert?

Schade, dass du den Beitrag wieder gelöscht hast.
War interessant.

z.B.

25:                         x=0;
0x080001F0 BF00      NOP

Klares Compilerproblem.


Dann probiere doch auch nochmal den anderen code aus...
1
    rom_adress = 0LL;
2
    for (i=0; i<8; i++) {
3
        rom_adress <<= 8LL;
4
        rom_adress |=  (unsigned long long)(one_wire_read()); 
5
    }

von Peter (Gast)


Lesenswert?

Wo ist dein Text hin?

von Rolf M. (rmagnus)


Lesenswert?

Joe F. schrieb:
> Dann probiere doch auch nochmal den anderen code aus...
>     rom_adress = 0LL;
>     for (i=0; i<8; i++) {
>         rom_adress <<= 8LL;
>         rom_adress |=  (unsigned long long)(one_wire_read());
>     }

An sich dürfte das alles nicht nötig sein, also alle "LL" und der Cast 
haben nach C-Definition keine Wirkung. Mag natürlich sein, daß es durch 
einen Compiler-Bug irgendwo notwendig wird.

Nur irgendwie ist der ja auch nicht so was exotisches:

Peter F. schrieb:
> Software: Keil Arm

Ich kann mir nicht so recht vorstellen, daß der so einfache Sachen wie 
Integer Promotion oder Bit-Shifts nicht hinkriegt.

Peter F. schrieb:
> Die Werte der Schleife von links nach rechts.
> i                 0x53          0x37           0x37          0x06
> rom_adress  0x800000053  0x800000037  0x800000037  0x800000006

Bist du dir sicher, daß das die Werte von i sind? Die wären dann nämlich 
völliger Blödsinn.

von (prx) A. K. (prx)


Lesenswert?

Zur Erinnerung: Er schrieb oben, er hätte den Fehler gefunden. Offenbar 
in Code, der hier nicht gezeigt ist: 
Beitrag "Re: STM32L152 uint64_t wird nicht richtig verarbeitet"

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.