mikrocontroller.net

Forum: Compiler & IDEs GCC Bug?


Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Versuche ich das SPI Dataregister (SPDR) in einer Funktion zu
beschreiben, ohne es vorher in der main() einmal beschrieben zu haben,
wird nichts auf den SPI Leitungen ausgegeben.

Habe ich schon bei 2 Programmen feststellen können.

Weiß jemand näheres dazu?

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Poste mal den Code der Initialsiserung und der Ausgabe aufs SPDR
Register.

Autor: Detlef A (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was issn mit SPSR, Bit SPIF/WCOL (Mega 128 datasheet S.168), wartest Du
drauf, setzt Du zurück, Fragen über Fragen. Aber Compilerbug, nee!

Cheers
Detlef

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was? wo? nix Interrupt Flag !

Hier mal der Code:
int main(void)
{
       
       AD9832_DDR = (1<<AD9832_CS)|(1<<AD9832_MOSI)|(1<<AD9832_CLK);
       DDRD = (1<<PD1);
       
       SPCR = (1<<SPE)|(1<<MSTR)|(3<<SPR0);
       SPDR = 0xFF;       


       AD9832_PORT &= ~(1<<AD9832_CS);  
    
  AD9832_putc(0b11011000);
  AD9832_putc(0b00000000);
       
       AD9832_putc(0b11000000);
       AD9832_putc(0b00000000);   

            
       AD9832_putc(0b00110011);
       AD9832_putc(0b10100111);
       
       AD9832_putc(0b00100010);
       AD9832_putc(0b11000101);
       
  AD9832_putc(0b00110001);
  AD9832_putc(0b10100000);
  
  AD9832_putc(0b00100000);
  AD9832_putc(0b00000000);
  

       AD9832_PORT |= (1<<AD9832_CS);     

    
       while(1)
  {
  nop();
  }
}



void AD9832_putc(u08 c)
{
       while(!(SPSR & (1<<SPIF))) nop();                 // wait until
SPI transfer is complete
       SPDR = c;   
       while(!(SPSR & (1<<SPIF))) nop();                 // wait until
SPI transfer is complete    
}

Ohne dem SPDR = 0xFF in der Main klappt garnix am SPI.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auf SPIF kannst du erst warten, wenn du etwas auf SPDR
ausgegeben hast, ansonsten ist es eifach erstmal noch nicht
gesetzt.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
müsste ich das while vor dem SPDR in der Funktion einfach weglassen? ;)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, es gehört nach der Ausgabe auf das SPDR hin (es sei denn,
man ist sich sicher, dass bis zur nächsten Ausgabe nach SPDR
sowieso genug Zeit vergeht, dass alle Daten rausgeschoben sind).

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich schreibe beim Init des SPI einmal auf SPDR:
  SPDR      = 0;    // Dummy-Write, damit SPIF gesetzt wird

Dadurch kann ich VOR dem SPI-Transfer fragen und spare mir damit (ein
kleines bischen) Zeit.

Übrigens:
Schreibst Du gcc-Bug nur in den Titel, damit es mehr lesen, oder hast
Du das wirklich geglaubt? Ist wohl nicht Dein Ernst, dass eine so
offensichtliche Sache ein Compiler-Bug sein könnte?

Gruß, Stefan

Autor: Detlef A (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

SPIF wird laut datasheet durch Lesen von SPSR gelöscht. Vermutung:
Schreiben auf SPDR scheint nicht zu gehen, wenn SPIF gesetzt ist,
deswegen dummy-read auf SPSR, selbst wenn man sicher ist, daß das Byte
draussen ist. Nachdem ich das gemacht habe, gings bei mir, habe aber
nich genauer draufgekuckt.

Cheers
Detlef

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Vermutung: Schreiben auf SPDR scheint nicht zu gehen, wenn SPIF gesetzt
ist
Das stimmt teilweise:
Wenn man einen Wert in SPDR schreibt, während ein Transfer läuft, wird
der neue Wert ignoriert. Ob das SPIF gesetzt oder gelöscht ist spielt
dabei aber keine Rolle. Ein dummy Read ist nicht notwendig.

Noch was interessantes:
Wie lange dauert es bis man neue Daten in SPDR schreiben kann, wenn der
Takt auf fclk/2 eingestellt ist ?
Theoretisch 16 CPU Takte.
In der Praxis sind es aber 18, ansonsten funktioniert es nicht. Keine
Ahnung warum, aber es ist so.

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In der Regel benötigen SPI-ICs auf /CS eine 1-0-Flanke nach Ende des
Datentransfers.

Es bringt also überhaupt nichts, vor dem Transfer auf das Ende des
letzten Transfers zu testen.

Daher einfach das Datenbyte ab in den Puffer und dann warten, bis es
raus ist.


Peter

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin eigentlich der Ansicht das AVRGCC nicht mehr betreut wird. was
weiß ich ob da nen bug drin ist oder nicht.

@peter: ahoa, gut zu wissen. ich prüfe das mal bei meinem chip.


@alle: danke, weiß jetzt bescheid!

(danke frau rieger ;))

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich bin eigentlich der Ansicht das AVRGCC nicht mehr betreut wird.

Was bringt dich zu dieser Ansicht?

verwundert guck

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab so den Eindruck, dass das unter die Räder gekommen ist. Wenn ich
schon den "Bug" (ist wohl eher kein feature?), dass als return wert
immer INT genommen wird, auch wenn man nur char brauch. Seh ich ehrlich
gesagt keinen Sinn drin

Aber ich kann mich auch täuschen ;)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ich schon den "Bug" (ist wohl eher kein feature?), dass als
> return wert immer INT genommen wird, auch wenn man nur char brauch.

Ist ein Feature.  Soll die Benutzung von MOVW vereinfachen.  So haben
sich das Marek Michalkiewicz und Denis Chertykov zumindest mal
gedacht.

Da es dieser Art Bestandteil des ABIs geworden ist, dürfte es ziemlich
schwierig sein, dieses Feature wieder los zu werden.

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Simon,

ja, der AVR-GCC ist sehr 16bit lastig. Wenns nur der Returnwert währe,
ginge es ja noch. Aber bei zusammengesetzten Ausdrücken erweitert er
oft erstmal schön umständlich alle Operanden auf 16Bit, rechnet 16Bit
und schmeißt dann das High-Byte wieder weg.
Selbst wenn man jeden einzelnen Ausdruck nach (unsigned char) castet,
läßt ihn das völlig kalt.
Erst wenn man eine Dummy-Variable nimmt, der man immer wieder die
Zwischenergebnisse zuweist, bequemt er sich zu 8-bittigem Rechen. Bloß
dann sieht die Source völlig unübersichtlich aus.


Ich vermute mal diese 16Bit-Umständlichkeit ist ein Zugeständnis an
kommerzielle Compilerhersteller, damit die ihre Produkte loswerden
können. Denn darin liegt mit Abstand das größte Potential, um Code zu
sparen und schneller zu sein.
Daher wird sich daran wohl auch in zukünftigen Versionen des AVR-GCC
leider nichts ändern.


Peter

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na super, naja dafür ists Freeware.

Was sind denn gute Compiler die sowas nicht machen und mindestens
genausogut zu bedienen sind wie ein AVR-GCC ? ;)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich vermute mal diese 16Bit-Umständlichkeit ist ein Zugeständnis an
> kommerzielle Compilerhersteller, damit die ihre Produkte loswerden
> können.

> Daher wird sich daran wohl auch in zukünftigen Versionen des AVR-GCC
> leider nichts ändern.

Peter, meistens finde ich deine Beiträge gut und fundiert, auch wenn
ich viele Dinge anders angehe als du.

Aber hier hast du einfach nur riesigen Blödsinn von dir gegeben,
sorry, anders kann man das nicht ausdrücken.

Die 16Bit-Umständlichkeit ist in erster Linie das Erfordernis des
C-Standards.  Alle Ausdrücke mit ganzen Zahlen müssen erstmal im
Wertebereich von `int' ausgeführt werden (oder mehr, falls ein Term
mehr benötigt).

Wenn du drüber nachdenkst, wo der GCC herkommt (er war ursprünglich
ausschließlich für 32-bit-CPUs entwickelt worden), dann sollte dir
auch sofort klar werden, dass der AVR einer der wenigen vom GCC
unterstützten Prozessoren sein dürfte, bei dem es sich überhaupt
irgendwie lohnen würde, anschließend noch eine Optimierung einzubauen,
die die obere Hälfte des zu berechnenden int-Ausdrucks eliminiert,
sofern aus den übrigen Randbedingungen klar ist, dass man sie
weglassen kann, ohne die Standardkonformität zu gefährden.

Diese Optimierung muss wohl schlicht und ergreifend einfach mal jemand
schreiben -- dabei muss sie so geschrieben werden, dass sie sonst
nichts kaputt macht, d.h. sie muss von ausgiebigen Testscripts
begleitet sein, die nachweisen, dass die Standardkonformität davon
nicht gefährdet wird.  Ohne diese Testscripts bekommst du bei GCC (aus
hoffentlich verständlichem Grund) nichts akzeptiert, was mehr als nur
einen offensichtlichen Tippfehler korrigiert.  Zum Glück, kann ich nur
sagen: meinen 0b-Konstanten-Patch durfte ich nach dem Erstellen der
Testscripts auch nochmal reparieren...

Mit einer Gesamtquantität von vielleicht drei oder vier GCC-Hackern,
die sich mit dem AVR auskennen (Denis Chertykov, Marek Michalkiewicz,
Björn Haase, Svein Seldal fallen mir dabei so ein) ist es schlicht
eine Frage der Manpower und der Prioritäten, wann ein derartiger Patch
mal fertig sein könnte.  Es gibt durchaus Dinge, nach denen viel mehr
Leute rufen als nach den halben 16 bits: die Einführung von memory
spaces (RAM vs. ROM vs. EEPROM vs. ...) zum Beispiel (dafür gibt's
wohl einen standard proposal) oder den Support für ATmega256x.

Rücksichtnahme auf irgendwelche kommerziellen Konkurrenten, noch dazu
für einen Prozessor, der bei GCC eher unter ,,ferner liefen''
rangiert, ist sicher alles andere als ein Entwicklungsziel von GCC.
Ganz davon abgesehen, der IAR schlägt ihn so ziemlich immer
(wenngleich ich merken musste, dass das für die Codegeschwindigkeit zu
meiner Verwunderung schon nicht so völlig gesetzt ist), aber die
anderen Compiler dürften von ihrer Gesamtqualität (Standard-
konformität, generierte Codegröße und -geschwindigkeit) bis auf
pathologische Fälle, die sich natürlich immer konstruieren lassen,
zumindest nicht nennenswert besser als AVR-GCC sein.

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...es gibt da ja noch '-mint8'. Damit verschwinden auch die
überflüssigen 'hi8(x)' konstrukte. Ich habe allerdings noch keinen
blassen schimmer, was das an Nebenwirkungen mit sich bringt. Vielleicht
kannst Du, Jörg, da ganz kurz was zu schreiben. Ich stelle mir das so
vor, daß eben 8Bit berechnungen in einem extra Modul implementiert
werden, welches mit dieser Option übersetzt wird. Natürlich nur, wenn
man das auch wirklich braucht.

Kleines Beispiel?
int
main(void)
{
        unsigned char x = 8;
        volatile unsigned char y = 0;

        y = x * 2;

        return 0;
}

1. Kompiliert mit:

$ avr-gcc -S -gdwarf-2 -Os -omint8.S mint8.c
main:
.LFB2:
.LM1:
/* prologue: frame size=1 */
  ldi r28,lo8(__stack - 1)
  ldi r29,hi8(__stack - 1)
  out __SP_H__,r29
  out __SP_L__,r28
/* prologue end (size=4) */
.LM2:
  std Y+1,__zero_reg__
.LM3:
  ldi r24,lo8(16)
  ldi r25,hi8(16)
  std Y+1,r24
.LM4:
  ldi r24,lo8(0)
  ldi r25,hi8(0)
/* epilogue: frame size=1 */
  rjmp exit
/* epilogue end (size=1) */
/* function main size 11 (6) */

2. Kompiliert mit:

$ avr-gcc -mint8 -S -gdwarf-2 -Os -omint8.S mint8.c
main:
.LFB2:
.LM1:
/* prologue: frame size=1 */
  ldi r28,lo8(__stack - 1)
  ldi r29,hi8(__stack - 1)
  out __SP_H__,r29
  out __SP_L__,r28
/* prologue end (size=4) */
.LM2:
  std Y+1,__zero_reg__
.LM3:
  ldi r24,lo8(16)
  std Y+1,r24
.LM4:
  ldi r24,lo8(0)
/* epilogue: frame size=1 */
  rjmp exit
/* epilogue end (size=1) */
/* function main size 9 (4) */

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jörg,

manchmal provoziere ich gerne ein bischen :)

Hier mal zwei Beispiele für die 16Bit-Umständlichkeit:
00000062 <swap_odd_even>:

unsigned char swap_odd_even( unsigned char a )
{
  a = ((a & 0x55) << 1) | ((a & 0xAA) >> 1);
  62:   99 27           eor     r25, r25
  64:   9c 01           movw    r18, r24
  66:   25 75           andi    r18, 0x55       ; 85
  68:   30 70           andi    r19, 0x00       ; 0
  6a:   22 0f           add     r18, r18
  6c:   33 1f           adc     r19, r19
  6e:   8a 7a           andi    r24, 0xAA       ; 170
  70:   90 70           andi    r25, 0x00       ; 0
  72:   95 95           asr     r25
  74:   87 95           ror     r24

  return a;
}
  76:   82 2b           or      r24, r18
  78:   93 2b           or      r25, r19
  7a:   08 95           ret

0000007c <swap>:


unsigned char swap( unsigned char a )
{
  a = (a >> 4) | (a << 4);
  7c:   28 2f           mov     r18, r24
  7e:   22 95           swap    r18
  80:   2f 70           andi    r18, 0x0F       ; 15
  82:   99 27           eor     r25, r25
  84:   64 e0           ldi     r22, 0x04       ; 4
  86:   88 0f           add     r24, r24
  88:   99 1f           adc     r25, r25
  8a:   6a 95           dec     r22
  8c:   e1 f7           brne    .-8             ; 0x86 <swap+0xa>
  8e:   28 2b           or      r18, r24

  return a;
}
  90:   82 2f           mov     r24, r18
  92:   99 27           eor     r25, r25
  94:   08 95           ret

Daß bei 16Bit ein simples swap in eine Zählschleife mutiert ist
besonders extrem.

Aber das ist nicht immer der Fall, manche Ausdrücke optimiert er
ziemlich gut.
Es ist aber schwer, dahinter ein System zu finden. Ich glaube bei
Schiebeoperationen oder in if-Ausdrücken erweitert er besonders gerne
auf 16Bit.


Peter

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich weiß, dass es die ,,16-Bit-Umständlichkeiten'' gibt.

Ich wollte nur klarstellen, dass deine Verschwörungstheorien
kompletter Unsinn sind.

Wenn du da mit helfen willst, die Optimierung zu verbessern: nur zu.
Nein, ,,ich weiß doch gar nicht, wie Compiler funktionieren!'' ist
keine zugelassene Ausrede.  Zur Geburt wussten wir's alle nicht,
dennoch gibt es Leute, die sich da reingedacht haben -- viel mehr als
die, die den GCC ursprünglich geschrieben haben.  Kann also nicht
undurchdringlich sein.

Wenn es mal ein Dutzend AVR-GCC-Hacker statt einer Hand voll gibt,
wird sich auch die Codeoptimierung verbessern.  Ansonsten
interessieren den größten Teil der GCC-Hacker wohl einfach nur die
`mainstream'-Targets (IA32, AMD64, vielleicht noch UltraSPARC,
PowerPC
und ein bisschen MIPS).  Deren Optimierungen am Compiler werden also
alle nur an diesen Prozessoren gemessen.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
AVR ist als GCC Target insofern eine Besonderheit (ebenso HC12), als die
Zielmaschinen nicht mit Wortbreite arbeitet, sondern mit halber
Wortbreite. Nun sind Shift-Operatoren nicht so leicht wegoptimierbar
wie Und/Oder. So ist byte(irgendwas|1) immer identisch mit
byte(irgendwas)|1, aber bei byte(irgendwas>>1) klappt das eben nicht
mehr.

Sicher, man könnte in den Compiler eine eher maschinenunabhängige
Funktion einbauen, die ausgehend vom Typ des Ergebnisses alle Ausdrücke
auf minimale Breite runterstuft, bei der das ohne Verfälschung vom
Ergebnis geht. Aber diese Stufe wäre auf allen "normalen"
Zielmaschinen bestenfalls überflüssig, oft sogar kontraproduktiv. Ohne
eine solche Stufe sind 8bit-Optimierungen immer nur Einzelaktionen für
bestimmte Fälle und blähen die Code-Templates auf.

Autor: ,,,, (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> GCC Bug?

Ja, GCC ist ein Bug.

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@A.K.

wenn man sich mal diese Zeile ansieht:
  78:   93 2b           or      r25, r19 

dann muß der Compiler aber schon sehr viel mitrechnen, damit er weiß,
daß R25 und R19 unabhängig von a an dieser Stelle immer 0 sind, denn
bei der 16Bit-Erweiterung eines unsigned char muß das High-byte ja
immer 0 sein.

D.h. er muß erkannt haben, daß vor dem Schieben um 1 mit 0x55 maskiert
wurde und so kein High-Byte ungleich 0 ensteht.

Dieser Aufwand erscheint mir viel größer, als sich gleich den Zieltyp
zu merken.


Bei der unteren Routine merkt er aber, daß ein High-Teil ungleich 0
ensteht und schmeißt ihn daher weg:
  92:   99 27           eor     r25, r25 


Peter

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"und schmeißt ihn daher weg"

Das hat nichts mit Analyse zu tun. "a" ist 8bittig deklariert,
return(a) ist per ABI 16bittig, also steht da eine 8->16bit
Konvertierung von R18 nach R25:R24.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.