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 )-:
ein Bit setzen in C geht so:
1 | val |= 1<<BitNr; |
ein Bit zurücksetzen so:
1 | val &= ~(1<<BitNr); |
Der compiler sollte das verstehen und in die entsprechenden ASM-Befehle umsetzen
Vielen Dank, aber das war mir schon bekannt. Anbei der Buchauszug warum der Author das so gelöst hat !
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
Mal auf dem Bild unten rechts geschaut?
1 | Dieses (...) Verfahren ist nötig um Kompilierungsfehler zu vermeiden. |
Was für Fehler sollen das sein? Schmeiß das Buch weg!
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:
1 | void loop(void) { |
2 | for(;;) PINB = 1<<5; |
3 | }
|
:
Bearbeitet durch Moderator
@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.
Vielen, vielen Dank an alle ! Es ist mir auch lieber das in C zu lösen !
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
1 | PINB |= 1<<5; |
führt zu einem
1 | 00000023 SBI 0x03,5 Set bit in I/O register |
Die benötigten Prozessortakte sind die selben.
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
1 | LDI... |
2 | label: OUT ... |
3 | RJMP label |
und nicht
1 | label: |
2 | LDI... |
3 | OUT... |
4 | RJMP label |
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.
@ Peter Dannegger (peda)
>Und auch, wie unnötig solche Mikrooptimierungen in der Praxis sind.
DIESE Worte vom Chefmikrooptimierer himself? ;-)
Thomas Holmes schrieb: > Weil der GCC selbst bei (-OS) aus einer Zuweisung mittels "=" immer mit > einem "immediate register load" reagiert, wie bei dem vorgeschlagenen Thomas 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.
Joachim B. schrieb: > Die Compiler Optimierung -OS ist mir da nie begegnet oder wo ich sie > einstellen kann -Os ist standandmäßig aktiv.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.