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?
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
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).
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
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
>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.
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
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 ;))
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 ;)
> 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.
@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
> 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.
...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?
@Jörg,
manchmal provoziere ich gerne ein bischen :)
Hier mal zwei Beispiele für die 16Bit-Umständlichkeit:
1
00000062<swap_odd_even>:
2
3
unsignedcharswap_odd_even(unsignedchara)
4
{
5
a=((a&0x55)<<1)|((a&0xAA)>>1);
6
62:9927eorr25,r25
7
64:9c01movwr18,r24
8
66:2575andir18,0x55;85
9
68:3070andir19,0x00;0
10
6a:220faddr18,r18
11
6c:331fadcr19,r19
12
6e:8a7aandir24,0xAA;170
13
70:9070andir25,0x00;0
14
72:9595asrr25
15
74:8795rorr24
16
17
returna;
18
}
19
76:822borr24,r18
20
78:932borr25,r19
21
7a:0895ret
22
23
0000007c<swap>:
24
25
26
unsignedcharswap(unsignedchara)
27
{
28
a=(a>>4)|(a<<4);
29
7c:282fmovr18,r24
30
7e:2295swapr18
31
80:2f70andir18,0x0F;15
32
82:9927eorr25,r25
33
84:64e0ldir22,0x04;4
34
86:880faddr24,r24
35
88:991fadcr25,r25
36
8a:6a95decr22
37
8c:e1f7brne.-8;0x86<swap+0xa>
38
8e:282borr18,r24
39
40
returna;
41
}
42
90:822fmovr24,r18
43
92:9927eorr25,r25
44
94:0895ret
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
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.
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.
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:
"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.