mikrocontroller.net

Forum: Compiler & IDEs einzelnen Pin invertieren (nicht ganzen Port)


Autor: weinender Megagott (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Abend liebe Experten!

Ich wollte mal fragen ob mir jemand sagen kann wie man einen einzelnen 
Pin invertiert statt dem gesamten Port wie z.B. so:

PORTD ^= 0xFF;
PORTD = ~PORTD;

Also ich möchte z.B. nur PD0 umkippen.

ich hatte es erst mit
if (PD0) {pin einschalten}else{pin ausschalten} und
if (PD0) {pin ausschalten}else{pin einschalten}
ausprobiert aber das geht so gar nicht.

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

Bewertung
0 lesenswert
nicht lesenswert
Du warst doch schon nahe dran:

PORTD ^= _BV(PD0);

Neuere AVRs können ein Portpin umschalten, indem man eine 1 auf das
(eigentlich nur für die Eingabe sinnvolle) PINx-Register schreibt:

PIND = _BV(PD0);

Idealerweise würde der Compiler aus der ersten Sequenz oben intern
die zweite Sequenz ableiten wenn er weiß, dass der entsprechende AVR
das kann, aber sowas hat dem AVR-GCC noch niemand beigebracht.

Autor: weinender Megagott (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
erste Variante funktionert. Zweite jedoch nicht.
Danke dir für die schnelle Antwort Jörg!

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

Bewertung
0 lesenswert
nicht lesenswert
Wenn die zweite nicht geht, benutzt du keinen der moderneren AVRs, bei
denen das implementiert ist.  Du hast nicht dazu geschrieben, was für
einen Controller du hast.

Autor: weinender Megagott (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
einen Mega8. aber das spielt ja auch keine Rolle denn es funktioniert ja 
so prima :)

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Idealerweise würde der Compiler aus der ersten Sequenz oben intern
die zweite Sequenz ableiten wenn er weiß, dass der entsprechende AVR
das kann, aber sowas hat dem AVR-GCC noch niemand beigebracht."

Lieber nicht. Dazu müsste der Compiler die I/O-Ports soweit 
verinnerlichen, dass für jeden neuen AVR ein neuer Compiler fällig wird.

Statt dessen sind sämtliche Ports nur ganz normale C-Makros, und bei 
denen darf der Compiler so etwas nicht.

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

Bewertung
0 lesenswert
nicht lesenswert
A.K. wrote:

> Lieber nicht. Dazu müsste der Compiler die I/O-Ports soweit
> verinnerlichen, dass für jeden neuen AVR ein neuer Compiler fällig
> wird.

Nicht zwingend.  Alle neuen AVRs scheinen das auf gleiche Weise zu
implementieren, man bräuchte also nur ein Flag "ist ein neuer AVR".

Der ATmega8 ist zu alt dafür, ein ATmega88 könnte es.

> Statt dessen sind sämtliche Ports nur ganz normale C-Makros, und bei
> denen darf der Compiler so etwas nicht.

Die Optimierung von memory-mapped IO auf den separaten IO space macht
er doch auch, genau wie die Optimierung auf SBI/CBI, wenn diese
möglich ist.

Autor: Hannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PD0 toggeln:

PORTD^=(1<<PD0)

73 Hannes

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> "Alle neuen AVRs scheinen das auf gleiche Weise zu implementieren,
> man bräuchte also nur ein Flag "ist ein neuer AVR".

Das ist nicht der Punkt. Woher weiss der Compiler, dass PORTD und PIND 
irgendwie zusammenhängen? Stand heute sind das 2 getrennte #defines in 
einem Include-File, die für den Compiler in keinerlei Zusammenhang 
stehen.

Damit wäre Schluss, man müsste diesem Zusammenhang auf höchst spezielle 
Weite in den Compiler integrieren, per Attribute, Pragma, direkt ins 
config/avr/avr.c, oder so.

> Die Optimierung von memory-mapped IO auf den separaten IO space macht
> er doch auch, genau wie die Optimierung auf SBI/CBI, wenn diese
> möglich ist.

Das ist etwas völlig anderes. Damit wählt der Compiler nur die 
Adressierungsart aus. Das I/O-Register bleibt das gleiche.

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

Bewertung
0 lesenswert
nicht lesenswert
A.K. wrote:

> Damit wäre Schluss, man müsste diesem Zusammenhang auf höchst spezielle
> Weite in den Compiler integrieren, per Attribute, Pragma, direkt ins
> config/avr/avr.c, oder so.

Da müsste man mal recherchieren, welche Möglichkeiten dafür in Frage
kommen.  Solange sich das sauber hinter einem #include <avr/io.h>
verstecken ließe, wäre es komplett transparent für den Benutzer.

> Das ist etwas völlig anderes. Damit wählt der Compiler nur die
> Adressierungsart aus. Das I/O-Register bleibt das gleiche.

Es ist etwas anderes, aber etwas völlig anderes?  Nee.  Liegt im
gleichen Bereich, auch wenn SBI/CBI allgemeiner implementierbar sind
(weil der Adressbereich, für den die Optimierung machbar ist, ein
einfacher großer Block ist).

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist schon was anderes. Denn ebendieser Zusammenhang zwischen den 
Datenadressen steckt ja im Compiler hardcoded drin. Der Zusammenhang 
zwischen PIND und PORTD hingegen (noch) nicht.

Willst du, dass der Compiler bei einem Mega16 im Fall von
   TIMSK ^= 0x40;
einfach 1 auf die Adresse addiert und
   GIFR = 0x40;
daraus macht, weil er die gleiche Regel wie bei I/O-Ports anwendet? 
Stand heute hat der Compiler ja keinerlei Ahnung, ob es sich bei PORTD 
um einen I/O-Port oder um Interrupt-Flags handelt. Genau diese Kenntnis 
müsstest du ihm erst beibringen.

Also: Erweitere dem GCC so, dass man ihm mitteilen kann
   "PORTD ist der Output zu PIND der Input"
und schon geht's. Vorher nicht.

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

Bewertung
0 lesenswert
nicht lesenswert
A.K. wrote:

> Also: Erweitere dem GCC so, dass man ihm mitteilen kann
>    "PORTD ist der Output zu PIND der Input"
> und schon geht's. Vorher nicht.

Genau, auf so etwas müsste es hinauslaufen.  Sei's nun, dass man in
der Definition von PORTD ein _attribute_ dranklebt, das er dann
intern auswertet oder was auch immer.  Kann man im Headerfile ja
bei Bedarf noch von der Compilerversion abhängig machen, damit ist
man rückwärtskompatibel zu einem Compiler, der das noch nicht
versteht.

(Ich glaube, du hast auf mein 30 Sekunden später zurückgezogenes
Posting geantwortet, aber das macht nix. :)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Solche Optimierungen werden doch für gewöhnlich in den
Peephole Optimizer gelegt. Und die sind aus der Natur
der Sache heraus sowieso hardwarespezifisch.

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum den Compiler ändern? 2 Szenarios:

Fall 1:
Der Programmierer weiss was er tut und kennt die neue Option.
Dann benutzt er sie auch und schreibt den Pin-Toggle selbsst so hin.

Fall 2:
Der Programmierer weiss nichts von der neuen Option. Der Compiler macht 
das zukünftig automatisch für ihn.
Beim Debuggen schaut er sich den Assemblercode an und wundert sich. 
Verstehen tut er leider nichts. Danach postet er hier "gcc hat schon 
wieder einen Bug".
Vorteil wäre natürlich:
Da so ein Post sehr gerne gelesen wird, verbreitet sich die neue Option 
viel schneller in den Köpfen als ohne Compileränderung.

Und nun?

Grüße von Stefan

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

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:

> Solche Optimierungen werden doch für gewöhnlich in den
> Peephole Optimizer gelegt. Und die sind aus der Natur
> der Sache heraus sowieso hardwarespezifisch.

Aber bislang eben doch auf höherem Niveau.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Solche Optimierungen werden doch für gewöhnlich in den
> Peephole Optimizer gelegt. Und die sind aus der Natur
> der Sache heraus sowieso hardwarespezifisch.

Auch der Peehole-Optimizer müsste irgendwoher wissen, dass auf 
I/O-Adresse 0x00 je nach Controller-Modell mal TWI-Register, mal 
Portregister stehen. Er ändert also nichts an der Notwendigkeit, dies 
dem Compiler mitzuteilen.

Ein Peephole Optimizier repariert Dinge, die man auf normalem Weg nicht 
so ohne weiteres gebacken kriegt. Die Optimierung hier liesse sich 
problemlos in der normalen Codegenerierung des Compilers unterbringen, 
als gewöhnliches instruction template für XOR, das eben nur unter 
bestimmten Randbedingungen greift.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Er ändert also nichts an der Notwendigkeit, dies
> dem Compiler mitzuteilen.

Das sicherlich nicht.
Aber wenn man dem P-O je nach Prozessortyp eine andere
Tabelle mit Ersetzungsregeln unterjubelt, ist das doch
eine schöne Lösung, ohne dass man allzusehr in die
generelle Compilerlogik eingreifen müsste.


Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verstehst du unter diesem P-O ein separates Tool, das nach dem Compiler 
aber vor dem Assembler des Code "repariert"?  Ja, so kann man das schon 
machen.  Würde ich aber eher als Hack ansehen, im Compiler gefällt mir 
das sehr viel besser, dafür sind die insns ja da.

Nur: Lohnt das wirklich???

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

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:

> Aber wenn man dem P-O je nach Prozessortyp eine andere
> Tabelle mit Ersetzungsregeln unterjubelt, ist das doch
> eine schöne Lösung, ohne dass man allzusehr in die
> generelle Compilerlogik eingreifen müsste.

Doch, es wäre ein ziemlicher Eingriff.  Bisher weiß das AVR-Backend
nichts in diesen Details über den Prozessor, sondern es klassifiziert
die einzelnen AVRs nur nach den Fähigkeiten ihres CPU-Cores.  Man muss
zwar immer noch den GCC für jeden einzelnen AVR patchen, aber das sind
zwei oder drei Tabellen bislang.

Die gesamte Belegung der IO-Ports jedoch ist in den durch <avr/io.h>
hereingezogenen Headerdateien festgelegt.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Verstehst du unter diesem P-O ein separates Tool, das nach dem
> Compiler aber vor dem Assembler des Code "repariert"?

In allen Compilern, die ich bisher gesehen habe, war das so.
Ich muss allerdings gestehen, mich noch nie im Detail mit
dem gcc auseinandergesetzt zu haben.

> Bisher weiß das AVR-Backend nichts in diesen Details über
> den Prozessor

Das ist interessant. Bisher bin ich immer naiv davon ausgegangen
dass die ganze sbi/cbi Umsetzung durch den P-O gemacht würde.
Oder auch die Spezialbehandlung für die Extended Register (die
heissen doch so, oder).

Wenn das natürlich nicht so ist, dann wäre es natürlich Blödsinn
da jetzt einen neuen Mechanismus einzuführen.

Ich ziehe mich zurück und lausche der weiteren Unterhaltung mit
grossem Interesse.

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

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:

> Das ist interessant. Bisher bin ich immer naiv davon ausgegangen
> dass die ganze sbi/cbi Umsetzung durch den P-O gemacht würde.

Ja, sicher.  Aber da braucht's eben auch keinerlei Unterscheidung
zwischen den AVRs.  Wenn die Adresse zwischen 0x20 und 0x5f liegt,
dann kann man sie mittels IN/OUT durch Subtraktion von 0x20
ebenfalls erreichen.  Wenn die Adresse nach dem Subtrahieren zwischen
0 und 0x1f liegt und nur ein einzelnes Bit zu setzen oder zu löschen
ist, kann man CBI/SBI benutzen.

Dafür muss man überhaupt nicht wissen, ob man auf einem uralten
AT90S2333 oder auf dem allerneuesten ATmega644P arbeitet.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> Das ist interessant. Bisher bin ich immer naiv davon ausgegangen
>> dass die ganze sbi/cbi Umsetzung durch den P-O gemacht würde.

> Ja, sicher.

Für mich sieht das eher nach einem ganz normalen instruction template 
für &= aus, mit Randbedingung "I/O-Adressraum" (avr_io_address_p) und 
"Einzelbit".

(define_insn "*cbi"
  [(set (mem:QI (match_operand 0 "const_int_operand" "n"))
  (and:QI (mem:QI (match_dup 0))
    (match_operand 1 "const_int_operand" "n")))]
  "avr_io_address_p (operands[0], 1 + 0x20)
   && exact_log2 (~INTVAL (operands[1]) & 0xff) >= 0"
{
  operands[2] = GEN_INT (exact_log2 (~INTVAL (operands[1]) & 0xff));
  return AS2 (cbi,%0-0x20,%2);
}
  [(set_attr "length" "1")
   (set_attr "cc" "none")])

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaube übrigens nicht, dass es im GCC überhaupt einen P-O gibt, wie 
er oben beschrieben wird. Und was im MD-File "peephole" genannt wird, 
scheint mit eher ein Mechanismus zu sein, bestimmte Sequenzen zu 
erkennen, die im Rahmen von normalen Templates nicht erfasst werden 
können. Insofern nicht direkt vergleichbar zu den oben skizzierten P-Os.

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.