AVR Shl mit Konstante

Antworten
Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

AVR Shl mit Konstante

Beitrag von Mathias »

Dieses Miniprogramm spuckt auf dem PC wie erwartet 14 True aus.

Code: Alles auswählen

procedure sendIntValueSPI(Value: uint16);
var
  dw: boolean;
  i: int8;
begin
  Value := $FFFF;
  for i := 11 downto 0 do begin
    dw := (Value and (1 shl i)) > 0;
    Write(dw, ' ');
  end;
end;
 
begin
  sendIntValueSPI(0);
end.


Auf dem Arduino fast der gleiche Code. Aber hier blinkt die LED, welche an PortC Pin3 angeschlossen ist.
Eigentlich müsste sie konstant leuchten, da dw eigentlich immer true sein müsste.

Ersetze ich in der Schleife WritePortB(3, dw); auf WritePortB(3, true); dann leuchtet die LED konstant.
Somit wird die Auswertung von dw auf dem PC anders gehandhabt wie auf dem AVR.

Wo liegt das Problem ? :roll:

Code: Alles auswählen

program Project1;
 
{$O-}
 
  procedure mysleep(t: int32);
  var
    i: Int32;
  begin
    for i := 0 to t do begin
      asm
               Nop;
      end;
    end;
  end;
 
  procedure ModePortB(Pin: byte; Value: boolean);
  begin
    if Value then begin
      DDRC := DDRC or (1 shl Pin);
    end else begin
      DDRC := DDRC and not (1 shl Pin);
    end;
  end;
 
  procedure WritePortB(Pin: byte; Value: boolean);
  begin
    if Value then begin
      PORTC := PORTC or (1 shl Pin);
    end else begin
      PORTC := PORTC and not (1 shl Pin);
    end;
  end;
 
  procedure sendIntValueSPI(Value: uint16);
  var
    dw: boolean;
    i: int8;
  begin
    Value := $FFFF;
 
    for i := 11 downto 0 do begin
      dw := (Value and (1 shl i)) > 0;
      mysleep(10000);
      WritePortB(3, dw);
    end;
  end;
 
begin
  ModePortB(3, True);
  repeat
    sendIntValueSPI(0);
  until 1 = 2;
end.
Zuletzt geändert von Mathias am Di 24. Jul 2018, 21:28, insgesamt 1-mal geändert.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR For-To Falsch

Beitrag von Mathias »

Fehler gefunden, wen ich die Konstante 1 auf UInt16 erzwinge, dann geht es.

Code: Alles auswählen

      dw := (Value and (UInt16(1) shl i)) <> 0;

Anscheinend werden Konstanten von 0-255 auf dem AVR auf 8Bit gesetzt.

Nachtrag:
Ist auf dem PC auch so, aber auf dem PC wird dann shl anders ausgewertet.

Code: Alles auswählen

  WriteLn(SizeOf(1));       // --> 1
  WriteLn(SizeOf(1000));    // --> 2
  WriteLn(SizeOf(100000))// --> 4


Ist dies ein Bug bei AVR oder ist dies so gewollt ?

Noch auf dem AVR getestet, die Kontanten sind gleich gross wie auf dem PC.

Code: Alles auswählen

    b := SizeOf(1);
    str(b, s);
    UARTSendString(s + '  '); // --> 1
 
    b := SizeOf(1000);
    str(b, s);
    UARTSendString(s + '  '); // --> 2
 
    b := SizeOf(100000);
    str(b, s);
    UARTSendString(s + '  '); // --> 4
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR Shl mit Konstante

Beitrag von Mathias »

Mit folgendem Mini-Beispiel, sieht man den Fehler gut.

Code: Alles auswählen

var
  i, ii: UInt16;
  s: string;
begin
  UARTInit;
 
  for i := 0 to 15 do begin
    ii := (1 shl i); // einfach
    str(ii:8, s);
    UARTSendString(s);
    ii := (UInt16(1) shl i)// mit UInt16
    str(ii:8, s);
    UARTSendString(s);
 
    UARTSendString(#13#10);
  end;
 
  repeat
    if UARTReadChar = #32 then begin
      UARTSendString('Hello World !'#13#10);
    end;
  until 1 = 2;
end.

Ausgabe:

Code: Alles auswählen

       1       1
       2       2
       4       4
       8       8
      16      16
      32      32
      64      64
   65408     128
       0     256
       0     512
       0    1024
       0    2048
       0    4096
       0    8192
       0   16384
       0   32768
So wie es aussieht wird ein ShortInt (int8) verwendet.
Bei der achten Zeile passiert sowieso was komisches. Irgendwie bringt er noch das Vorzeichen durcheinander.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: AVR Shl mit Konstante

Beitrag von Timm Thaler »

Wie sieht denn das Assembler-Listing aus? Mit welcher Optimierung kompilierst Du für Avr?

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR Shl mit Konstante

Beitrag von Mathias »

{O-} Ist im obigen Code sichtbar.
Den Assemblercode muss ich morgen mal angucken.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: AVR Shl mit Konstante

Beitrag von kupferstecher »

Im englischen Forum gab es eine aehnliche Diskussion (Link unten), Problem ist das Vorzeichen welches in i steckt. Nach der verlinkten Diskussion ist shl immer eine logische Operation, nimmt auf das Vorzeichen keine Ruecksicht.

In der 8ten Zeile ist ja i=7, also
(1 shl int8(7) ) das ergibt %10000000, was -128 ist. Wie der Compiler jetzt auf das ausgedruckte Ergebnis kommt, ist mir nicht ganz klar. So wie es aussieht erweitert er das Vorzeichen auf die 16 bit und interpretiert die Zahl dann als unsigned.


http://forum.lazarus.freepascal.org/ind ... 88697.html

Nachtrag: Das ist natuerlich Mist. Der Compiler sollte da nicht signed-Variablen annehmen, wenn die shl-Operation sowieso das Vorzeichen ignoriert.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: AVR Shl mit Konstante

Beitrag von Timm Thaler »

kupferstecher hat geschrieben:Im englischen Forum gab es eine aehnliche Diskussion (Link unten), Problem ist das Vorzeichen welches in i steckt. Nach der verlinkten Diskussion ist shl immer eine logische Operation, nimmt auf das Vorzeichen keine Ruecksicht.


Nee, in i steckt kein Vorzeichen. Das erste "Problem" ist, dass wie in Pascal üblich, 1 nur ein Byte belegt. Wird das geschiftet, geht das solange gut, bis es bei shl 8 überläuft. Dann ist das Lowbyte nur noch Null, das Highbyte wird nicht beachtet. Aber das ist immer bei Operationen so.

Code: Alles auswählen

# [14] ii := (1 shl i); // einfach
   ldi   r19,1
   lds   r18,(U_sPsTEST_ss_I)
   tst   r18
   breq   .Lj7
.Lj6:
   lsl   r19
   dec   r18
   brne   .Lj6
.Lj7:


Wird die 1 vor dem shl auf 2 Byte erweitert, klappt auch das Shift.

Code: Alles auswählen

# [17] ii := (UInt16(1) shl i)// mit UInt16
   ldi   r19,1
   mov   r18,r1
   lds   r20,(U_sPsTEST_ss_I)
   tst   r20
   breq   .Lj9


Das Vorzeichen-Problem ist dann später bei der Zuweisung auf den String. Hier wird fpc_shortstr_word aufgerufen. Allerdings wird hier ii mit Vorzeichen erweitert, obwohl ii unsigned ist. Das ist ein Fall für einen Bugreport, würde ich sagen.

Code: Alles auswählen

   mov   r20,r19
   mov   r18,r1
   sbrc   r19,7
   com   r18
   sts   (U_sPsTEST_ss_II),r20
   sts   (U_sPsTEST_ss_II+1),r18

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: AVR Shl mit Konstante

Beitrag von kupferstecher »

Mathias hat geschrieben:Mit folgendem Mini-Beispiel, sieht man den Fehler gut.

Habs jetzt selber probiert, bei mir funktionierts erwartungsgemäß, d.h. richtig. Ich verwende die FPC-Version 3.1.1 [2018/03/01], getestet mit -O0 , -O1, -O4. Ergebnis jeweils gleich. Die Frage ist jetzt ob du eine neuere oder ältere Version verwendest.

Das ist die Ausgabe:

Code: Alles auswählen

       1       1
       2       2
       4       4
       8       8
      16      16
      32      32
      64      64
     128     128
       0     256
       0     512
       0    1024
       0    2048
       0    4096
       0    8192
       0   16384
       0   32768


Timm Thaler hat geschrieben:Nee, in i steckt kein Vorzeichen.

Doch schon, aber du hast wahrscheinlich recht, dass das Problem hier an der Konstanten liegt, die vorzeichenbehaftet verarbeitet wird.


Das erste "Problem" ist, dass wie in Pascal üblich, 1 nur ein Byte belegt. Wird das geschiftet, geht das solange gut, bis es bei shl 8 überläuft. Dann ist das Lowbyte nur noch Null, das Highbyte wird nicht beachtet. Aber das ist immer bei Operationen so.

Ja, das ist soweit klar. Man kann sicher damit leben, schön ist es aber nicht.

Das Vorzeichen-Problem ist dann später bei der Zuweisung auf den String. Hier wird fpc_shortstr_word aufgerufen. Allerdings wird hier ii mit Vorzeichen erweitert, obwohl ii unsigned ist. Das ist ein Fall für einen Bugreport, würde ich sagen.

Die Variable ii ist doch schon vor der Zuweisung auf den String vom Typ uInt16. Die Vorzeichenerweiterung muss also zur Zeile ii := (1 shl i); gehören. Aber wie gesagt, bei mir funktioniert es, wäre die Frage, ob es ein neuer Bug ist, oder bereits gelöst.

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR Shl mit Konstante

Beitrag von Mathias »

Könnte ein neuer Bug sein, da dein fpc vom März ist. Meines ist keine 14 Tage alt.

Ich sehe gerade, du hast eine 128, aber mit den grösseren Werte hast du aber auch Probleme.
Somit ist eine Typenumwandlung sowieso nötig ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: AVR Shl mit Konstante

Beitrag von Timm Thaler »

kupferstecher hat geschrieben:Die Variable ii ist doch schon vor der Zuweisung auf den String vom Typ uInt16. Die Vorzeichenerweiterung muss also zur Zeile ii := (1 shl i); gehören. Aber wie gesagt, bei mir funktioniert es, wäre die Frage, ob es ein neuer Bug ist, oder bereits gelöst.


Ja, bei der Zuweisung in ii wird erweitert. Meiner Meinung nach ist das falsch, da auf ein unsigned int nicht mit signed erweitert werden darf.

Meine Version ist "FPC 3.1.1-r38520 [2018/03/13] for avr - embedded", jaja, ich müsste mal updaten.

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR Shl mit Konstante

Beitrag von Mathias »

Meine Version ist "FPC 3.1.1-r38520 [2018/03/13] for avr - embedded", jaja, ich müsste mal updaten.
Momentan ist dies sehr ungünstig, habe gerade meinen AVR-Compiler zerschossen. :twisted:

Ich hatte den ganzen Atmega328 Ordner mal vor längerer Zeit als Backup gezippt. Diesen habe ich entpackt, dafür habe ich folgenden Fehler:

Code: Alles auswählen

Project1.pas(103,28) Error: Assembler avr-as not found, switching to external assembling
:evil:

Der ATTiny-Ordner den ich noch habe, der funktioniert noch, obwohl der eigentlich den av-as auch nicht finden dürfte. :roll:

Wo steckt dieser Assembler ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR Shl mit Konstante

Beitrag von Mathias »

Ja, bei der Zuweisung in ii wird erweitert. Meiner Meinung nach ist das falsch, da auf ein unsigned int nicht mit signed erweitert werden darf.

Irgendwie blicke ich nicht mehr durch,

Es sind 2 Fehler vorhanden.
1. Das Vorzeichen.
2. 8Bit Überlauf von shl.

Sind jetzt nun beides Bug, oder nur dies mit dem Vorzeichen ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: AVR Shl mit Konstante

Beitrag von kupferstecher »

Timm Thaler hat geschrieben:jaja, ich müsste mal updaten.

"Never ruin a running system" oder so ähnlich :wink:
Bei mir haben neue Versionen oft auch nicht kompiliert, da bin ich mittlerweile vorsichtig, bzw. behalte immer die letzte funktionierende Version auf der Platte.

Mathias hat geschrieben:Es sind 2 Fehler vorhanden.
1. Das Vorzeichen.
2. 8Bit Überlauf von shl.
Sind jetzt nun beides Bug, oder nur dies mit dem Vorzeichen ?

Der erste definitiv. Zum zweiten kann ich auch nichts sagen. Ich finde es unschön (gelinde gesagt), aber ob es ein Bug ist ist die andere Frage. In der Doku (Reference Guide) hab ich nichts genaueres zu impliziten Umwandlungen gefunden, nur dass FPC das tut, aber nicht wie.

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: AVR Shl mit Konstante

Beitrag von kupferstecher »

Mathias hat geschrieben:

Code: Alles auswählen

Project1.pas(103,28) Error: Assembler avr-as not found, switching to external assembling

Wo steckt dieser Assembler ?

Ja, das ist immer ärgerlich...
kann es sein dass die Binutils mit dem falschen Prefix auf deiner Platte sind? Sollte doch avr-embedded-as heißen.

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR Shl mit Konstante

Beitrag von Mathias »

Anscheinend werden Konstanten von 0-255 auf dem AVR auf 8Bit gesetzt.

Ich habe dies im Wiki vermerkt: http://wiki.freepascal.org/AVR_Programming/de#Shiften

Wen man voll auf Speicheroptimierung ab ist ist es eigentlich gut, das kleine Konstanten nur 8Bit gross sind.
Aber hier sollte der Compiler eigentlich wissen, das 16Bit erwünscht sind, weil i 16Bit ist.

Code: Alles auswählen

var
  i: UInt16;
  b: UInt8;
begin
  b := 8;
  i := 1 shl b;
Würde man es so schreiben,

Code: Alles auswählen

i := 1 shl b;
sieht es anders aus, weil Werte in Klammern immer zuerst gerechnet werden.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten