Liebe Kollegen,
ich bin ein "Controller Anfänger". Ich habe mit Bascom begonnen und bin
jetzt bei C gelandet.
Ich versuche gerade ein Programm für die Arduino IDE in C zu übersetzen.
Folgende Befehlszeile funktioniert in C allerdings nicht.
asm(" sbi %0,%1" : : "I" (_SFR_IO_ADDR(PINB)), "I" (5));
sollte ein der Schleifengeschwindigkeit entsprechendes Signal ausgeben !
Auch mit Recherche im Internet für mich nicht lösbar )-:
Andreas S. schrieb:> aber das war mir schon bekannt.> Anbei der Buchauszug warum der Author das so gelöst hat !
Der Compiler ist nicht blöd.
Der C-Code wird in den entsprechenden sbi und cbi Befehle resultieren.
Ansonsten, Compiler wegschmeissen!
Da es anscheinend um Arduino geht:
Ein DigitalWrite kann natürlich nicht derart optimiert werden.
Ich hab den Buchtext mal überflogen und würde es immer noch mit C-Code
schreiben
1
PINB|=1<<5;
Daraus sollte der compiler einen "sbi"-Befehl generieren, sonst, wie
bereits erwähnt, den compiler in die tonne treten!
Wenn du aber weiter an deiner ASM-Lösung festhalten möchtest, so poste
doch mal den genauen wortlaut der Fehlermeldung.
Andreas S. schrieb:> Vielen Dank,>> aber das war mir schon bekannt.> Anbei der Buchauszug warum der Author das so gelöst hat !
keine Ahnung was der Autor sich da einbildet,
schreib doch einfach mal
PINA |= 1;
und schau nach was danach im Assemblerlisting steht
SBI ist da sowieso Unsinn, verplempert nur einen zusätzlichen
Taktzyklus.
1
PINB=1<<5;
ist doppelt so schnell.
Andererseits: ist natürlich völlig schnuppe, da die Arduino-Umgebung
sowieso einen langweiligen CALL für loop() machen muss. Maximale
Geschwindigkeit würde man so bekommen:
@Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
>SBI ist da sowieso Unsinn, verplempert nur einen zusätzlichen>Taktzyklus.>PINB = 1<<5;>ist doppelt so schnell.
Aber nur, wenn zufällig schon eine 0x20 in einem Register steht ;-)
Geht aber alles am Ursprungsproblem vorbei.
@OP
Lass diese Assemblertricks weg, die brauchst du nicht. Programmier
ordentlich in C und alles wird gut. Schnelle Takte erzeugt man so oder
so mit einem Timer und der Output Compare Funktion.
Das ist ein schönes Beispiel, wie nah man bei Assembler am spezifischen
Silizium ist. Und wie wichtig bei solchen Fragen die genaue
Spezifikation der Randbedingungen ist.
Dieser "Toggle-Trick" funktioniert z.B. beim mega328, der auch im
Arduino Uno sitzt. Bei vielen anderen AVRs funktioniert das nicht.
Wenn man durch Inline-Assembler noch besser sein will als der
Compiler-/Bibliothekenbauer, so ist die Lektüre der entsprechenden
MCU-Datenblätter Pflicht. Beim AVR ist das zum Glück recht
übersichtlich.
Marcus H. schrieb:> Bei vielen anderen AVRs funktioniert das nicht.
Naja, bei allen neueren Datums geht er.
Ist aber unabhängig von Assembler oder C: der C-Compiler ersetzt
einen Pintoggle nicht automatisch durch die Ausgabe auf das zugehörige
PINx-Register.
Marcus H. schrieb:> Wenn man durch Inline-Assembler noch besser sein will als der> Compiler-/Bibliothekenbauer, so ist die Lektüre der entsprechenden> MCU-Datenblätter Pflicht. Beim AVR ist das zum Glück recht> übersichtlich.
Ob der µC die genannte Funktionalität bei PINx bietet, muss man so oder
so wissen. Ohne das Verhalten des µC zu kennen kann das nicht optimial
codiert werden — in C nicht und in Assembler auch nicht.
Jörg Wunsch schrieb:> PINB = 1<<5;>> ist doppelt so schnell.
Was für ein Quatsch! Diese Instruktion macht was völlig anderes als
gewünscht. Sie setzt alle anderen Bits im Register auf NULL.
Axiom schrieb:> Jörg Wunsch schrieb:>> PINB = 1<<5;>>>> ist doppelt so schnell.>> Was für ein Quatsch! Diese Instruktion macht was völlig anderes als> gewünscht. Sie setzt alle anderen Bits im Register auf NULL.
Schau mal ins Manual was das genau macht bevor du hier Peinlichkeiten
loslässt.
Laut o.g. PDF geht es darum, ein Pin (Port B5) zu toggeln, und neuere
Devices wie bei Arduino im Einsatz implementieren das u.a. indem eine 1
nach PINx (sic!) geschrieben wird.
@ Axiom (Gast)
>> PINB = 1<<5;>Was für ein Quatsch! Diese Instruktion macht was völlig anderes als>gewünscht. Sie setzt alle anderen Bits im Register auf NULL.
PINB != PORTB
Johann L. schrieb:> Schau mal ins Manual was das genau macht bevor du hier Peinlichkeiten> loslässt.>> Laut o.g. PDF geht es darum, ein Pin (Port B5) zu toggeln, und neuere> Devices wie bei Arduino im Einsatz implementieren das u.a. indem eine 1> nach PINx (sic!) geschrieben wird.
Trotzdem Quatsch!
Weil der GCC selbst bei (-OS) aus einer Zuweisung mittels "=" immer mit
einem "immediate register load" reagiert, wie bei dem vorgeschlagenen
1
PINB=1<<5;
hier wird immer folgendes gemacht
1
00000023 LDI R24,0x20 Load immediate
2
00000024 OUT 0x03,R24 Out to I/O location
und das sind immer noch zwei Takte genau so viel wie eine sbi
instruction. Wo das doppelt so schnell sein soll muss Herr Wunsch erst
mal erklären.
Lediglich das von Little Basdart vorgeschlagene C-Äquivalent
Thomas Holmes schrieb:> und das sind immer noch zwei Takte genau so viel wie eine sbi> instruction. Wo das doppelt so schnell sein soll muss Herr Wunsch erst> mal erklären.
Schon, aber...
Der Compiler wird einfach vor der Schleife (dem Sprung) das Register
laden. Damit entsteht einmal ein Takt laden und danach dauert es immer
nur einen anstatt 2 Takten.
Also
Marcus H. schrieb:> Das ist ein schönes Beispiel, wie nah man bei Assembler am spezifischen> Silizium ist.
Und auch, wie unnötig solche Mikrooptimierungen in der Praxis sind.
Thomas Holmes schrieb:> Weil der GCC selbst bei (-OS) aus einer Zuweisung mittels "=" immer mit> einem "immediate register load" reagiert, wie bei dem vorgeschlagenenThomas Holmes schrieb:> Die benötigten Prozessortakte sind die selben.
weisst du zufällig wie die Arduino IDE das handhabt?
Die Compiler Optimierung -OS ist mir da nie begegnet oder wo ich sie
einstellen kann, komme vom AVR Studio 4.18 da konnte ich diese noch
wählen.
Es goibt mehrere Möglichkeiten ein Rechtecksignal zu erzeugen.
1. PINB != PORTB
2. if PINB == high {
PORTB = low
}else
PORTB = high
}
3. PINB = high
delay_ms(1)
PINB = low
Falk Brunner schrieb:> DIESE Worte vom Chefmikrooptimierer himself? ;-)
Ich gebe zu, meine Entprellroutine ist ziemlich optimiert.
Aber es ist kein Inlineassemblerkauderwelsch drin, keine Instruktionen,
die targetabhängig sind und keine Instruktionen, die was völlig anderes
machen, als sie implizieren.
Ich fand dieses Togglen bei Input zuerst auch ganz lustig, aber keine
sinnvolle Anwendung dafür.
Ich habe es daher noch nie benutzt, sondern immer nur:
1
PORTB^=1<<PB0;
Wenn die Lesbarkeit oder Portierbarkeit drastisch leidet, hat bei mir
die Optimierung ihre Grenzen.
N. G. schrieb:> Schon, aber...> Der Compiler wird einfach vor der Schleife (dem Sprung) das Register> laden. Damit entsteht einmal ein Takt laden und danach dauert es immer> nur einen anstatt 2 Takten.
Für diesen Sonderfall trifft das zu. Generell kann aber die Aussage
nicht gemacht werden.