Forum: Compiler & IDEs Assembler Code in Cprogramm


von Andreas S. (define_andreas)


Lesenswert?

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 )-:

von Little B. (lil-b)


Lesenswert?

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

von Andreas S. (define_andreas)


Angehängte Dateien:

Lesenswert?

Vielen Dank,

aber das war mir schon bekannt.
Anbei der Buchauszug warum der Author das so gelöst hat !

von Le X. (lex_91)


Lesenswert?

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.

von Little B. (lil-b)


Lesenswert?

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.

von Walter (Gast)


Lesenswert?

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

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

vielleicht liegt es an der Leerstelle in " sbi..."
:-)

von Kaj (Gast)


Lesenswert?

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!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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
von Falk B. (falk)


Lesenswert?

@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.

von Andreas S. (define_andreas)


Lesenswert?

Vielen, vielen Dank an alle !

Es ist mir auch lieber das in C zu lösen !

von Marcus H. (Firma: www.harerod.de) (lungfish) Benutzerseite


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Axiom (Gast)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@ 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

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

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.

von N. G. (newgeneration) Benutzerseite


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@ Peter Dannegger (peda)

>Und auch, wie unnötig solche Mikrooptimierungen in der Praxis sind.

DIESE Worte vom Chefmikrooptimierer himself? ;-)

von Joachim B. (jar)


Lesenswert?

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.

von Konrad S. (maybee)


Lesenswert?

Joachim B. schrieb:
> Die Compiler Optimierung -OS ist mir da nie begegnet oder wo ich sie
> einstellen kann

-Os ist standandmäßig aktiv.

von Kenner (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

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
Noch kein Account? Hier anmelden.