Forum: Compiler & IDEs Kleine Bitmanipulationsfrage


von N. G. (newgeneration) Benutzerseite


Lesenswert?

Hallo Leute,

ich hab mal ne Frage. Ich habe gesehen, dass Registerzugriffe als 
volatile deklariert sind, also werden diese nicht vom avr-gcc optimiert, 
oder?
Also wird das mehr Befehle brauchen
1
PORTD |= (1 << PD4);
2
PORTD &= ~(1 << PD5);
, als eine andere Version, bei der nur einmal auf den Port zugegriffen 
wird.
Ich habs mal so versucht
1
PORTD |= (1 << PD4) & ~(1 << PD5);
, es scheint aber so nicht zu funktionieren...
Ich steh wohl ganz schön auf den Schlauch...
Wie müsste der Befehl mit nur einem Portzugriff aussehen?

Danke im Vorraus
N.G.

von Max H. (hartl192)


Lesenswert?

> Wie müsste der Befehl mit nur einem Portzugriff aussehen?
1
PORTD = (PORTD & ~(1 << PD5)) | (1 << PD4);

: Bearbeitet durch User
von Bitflüsterer (Gast)


Lesenswert?

Und warum ist das die richtige Lösung?

von Loocee L. (loocee)


Lesenswert?

Zwei Portzugriffe bleiben es aber trotzdem

von Mike A. (Gast)


Lesenswert?

N. G. schrieb:
> Ich habs mal so versuchtPORTD |= (1 << PD4) & ~(1 << PD5);, es scheint
> aber so nicht zu funktionieren...

Wie sollte es auch. Mit "|" ein Bit zu löschen, geht nun mal nicht.

von (prx) A. K. (prx)


Lesenswert?

N. G. schrieb:
> Also wird das mehr Befehle brauchen
> , als eine andere Version, bei der nur einmal auf den Port zugegriffen
> wird.

Geht es um das Tempo oder um gleichzeitige Veränderung der Pins?

von Bernd K. (prof7bit)


Lesenswert?

N. G. schrieb:

> Also wird das mehr Befehle brauchen
> PORTD |= (1 << PD4);
> PORTD &= ~(1 << PD5);
> , als eine andere Version, bei der nur einmal auf den Port zugegriffen
> wird.

Das wird nur 2 Befehle brauchen, also schneller als alle anderen 
Varianten, Zeit und Codegröße sind hier also nicht das Problem, jedoch 
werden bei dieser Variante die beiden Portpins nicht mehr zur selben 
Zeit geschaltet werden, PD5 wird hier einen Taktzyklus später geschaltet 
als PD4.

von Max H. (hartl192)


Lesenswert?

Eberhard F. schrieb:
> Zwei Portzugriffe bleiben es aber trotzdem
Ein PORTD |= x; sind auch schon zwei Portzugriffe. Das ist nur die 
Kurzform für:
PORTD = PORTD | x;

von (prx) A. K. (prx)


Lesenswert?

Bernd K. schrieb:
> Das wird nur 2 Befehle brauchen

Zumindest solange es sich um einen AVR handelt und der Port im passenden 
Bereich liegt.

> also schneller als alle anderen Varianten

Nicht auf den Standard-AVRs. Die Einzelbitbefehle brauchen 2 Takte, die 
4 Ersatzbefehle (IN,2xLogik,OUT) jeweils einen.

von Thomas E. (thomase)


Lesenswert?

Max H. schrieb:
> Ein PORTD |= x; sind auch schon zwei Portzugriffe.
Sofern der Port im Adressbereich von 0 - 0x1F liegt,  ist das ein 
Zugriff, weil der Compiler hier ein 'SBI' einsetzt, bzw. zum Löschen ein 
'CBI'.  Erst wenn mehrere Bits gleichzeitig bearbeitet werden, wird ein 
Read-Modify-Write benutzt.

mfg.

von (prx) A. K. (prx)


Lesenswert?

Max H. schrieb:
> Ein PORTD |= x; sind auch schon zwei Portzugriffe. Das ist nur die
> Kurzform für:
> PORTD = PORTD | x;

Kleiner Spass am Rande. So ist
 PIND |= 1<<PD2;
zwar per C Definition identisch mit
 PIND = PIND | 1<<PD2;
und übersetzt sich bei AVRs i.d.R. in
 SBI PIND, PD2
nur ist das nicht identisch mit
 IN R16, PIND
 OR R16, 1<<D2
 OUT PIND, R16
da die SBI Version nur PD2 toggelt, die OUT Version aber zusätzlich 
alle Pins, die als 1 gelesen werden. Streng genommen dürften C Compiler 
seit Erfindung der Schreibfunktion der PINx Ports die CBI/SBI Befehle 
nicht mehr verwenden. Faktisch ist das Ergebnis solcher Operationen auf 
PINx nun unspezifiziert und der Programmierer hat die ehrenvolle 
Aufgabe, selber drauf zu achten, ob der Compiler die "richtige" 
Befehlssequenz erzeugt.

Insoweit ist die Vorstellung, dass es sich in CBI/SBI um getrennte Lese- 
und Schreibzugriffe in einem Befehl handelt, mit Vorsicht zu geniessen. 
Erst recht bei den Xmegas und den nur "reduced core" Typen, bei denen 
diese Befehle nur noch einen Takt benötigen. Man fährt besser, wenn man 
dies als einen einzelnen Portzugriff mit spezieller Funktion betrachtet.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

A. K. schrieb:
> PIND |= 1<<PD2;

Das betrifft ja nur die verschwindend kleine Minderheit, die nicht den 
Atmega8 oder die anderen Zombies benutzt.

mfg.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

A. K. schrieb:

> Streng genommen dürften C Compiler
> seit Erfindung der Schreibfunktion der PINx Ports die CBI/SBI Befehle
> nicht mehr verwenden.

Konsequent und streng genommen einzig logische Maßnahme (hardwareseitig) 
wäre gewesen wenn alle bits in den PINX Registern immer 0 lesen würden 
sobald das zugehörige Bit im DDRX auf eins steht.

von Falk B. (falk)


Lesenswert?

@Bernd K. (prof7bit)

>Konsequent und streng genommen einzig logische Maßnahme (hardwareseitig)
>wäre gewesen wenn alle bits in den PINX Registern immer 0 lesen würden
>sobald das zugehörige Bit im DDRX auf eins steht.

Nö. Diese Register bilden einfach den Pegel des Pins ab, auch wenn es 
als Ausgang geschaltet ist. Das ist vollkommen OK und logisch.

von Bernd K. (prof7bit)


Lesenswert?

Falk Brunner schrieb:

> Nö. Diese Register bilden einfach den Pegel des Pins ab, auch wenn es
> als Ausgang geschaltet ist. Das ist vollkommen OK und logisch.

Nö. Nicht wenn sie eine komplett andere Funktion bekommen sobald der Pin 
als Ausgang geschaltet ist. Siehe hierzu bitte das Posting von A.K. und 
die darin beschriebene Problematik auf die ich mich bezog.

von Thomas E. (thomase)


Lesenswert?

Bernd K. schrieb:
> Nö. Nicht wenn sie eine komplett andere Funktion bekommen sobald der Pin
> als Ausgang geschaltet ist. Siehe hierzu bitte das Posting von A.K. und
> die darin beschriebene Problematik auf die ich mich bezog.

Nö. Siehe hierzu das entsprechende Datenblatt.

mfg.

von Falk B. (falk)


Lesenswert?

@ Bernd K. (prof7bit)

>> Nö. Diese Register bilden einfach den Pegel des Pins ab, auch wenn es
>> als Ausgang geschaltet ist. Das ist vollkommen OK und logisch.

>Nö. Nicht wenn sie eine komplett andere Funktion bekommen sobald der Pin
>als Ausgang geschaltet ist. Siehe hierzu bitte das Posting von A.K. und
>die darin beschriebene Problematik auf die ich mich bezog.

Keine Sekunde. Eine Anweisung wie

>PIND = PIND | 1<<PD2;

Ist auf dem AVR so oder so Unsinn bzw. falsch, egal ob so oder in der 
Kurzform.

PIND |= (1<<PD1);

Nur eine Anweisung ala

PIND = (1<<PD1);

ist sinnvoll, und da ist es egal, ob der Compiler einen SBI oder 
Read-Modify-Write erzeugt (Wobei, das gab es auch ein kleines 
Problemchen, weil SBI/CBI auch intern einen atomaren Read-Modify-Write 
Zugriff macht).

Das ursprüngliche Problem des OP ist sowieso ein anderes.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Falk Brunner schrieb:
> Nur eine Anweisung ala
> PIND = (1<<PD1);
> ist sinnvoll, und da ist es egal, ob der Compiler einen SBI oder
> Read-Modify-Write erzeugt

Weder SBI noch R-M-W ist da sinnvoll. Da sollte ein OUT/STS stehen.

von Thomas E. (thomase)


Lesenswert?

A. K. schrieb:
> Weder SBI noch R-M-W ist da sinnvoll. Da sollte ein OUT/STS stehen.

"14.2.2 Toggling the Pin
Writing a logic one to PINxn toggles the value of PORTxn, independent on 
the value of DDRxn. Note that the SBI instruction can be used to toggle 
one single bit in a port."

mfg.

von (prx) A. K. (prx)


Lesenswert?

Thomas Eckmann schrieb:
> "14.2.2 Toggling the Pin

Weiss ich doch, schrieb ich doch. Aber soll der Compiler wirklich die 
eingesetzten Befehle davon abhängig machen müssen, ob da
  PINA = 1; // SBI möglich
oder
  PORTA = 1; // SBI nicht möglich
steht? Also PINx Portadressen mit __attribute__((sbi)) taggen, um diese 
Nischenoptimierung durchführen zu können?

: Bearbeitet durch User
von Bastler (Gast)


Lesenswert?

Wieso sollte bei
1
PIND = (1<<PD2);
ein RMW notwendig sein?
1
cbi PIND,2
2
oder
3
ldi r16,#4
4
out PIND,r16
wird da raus kommen, nichts anderes.
Wie steht's im DB: "SCREIBEN auf PINx"

von Falk B. (falk)


Lesenswert?

@ A. K. (prx)

>> Nur eine Anweisung ala
>> PIND = (1<<PD1);
>> ist sinnvoll, und da ist es egal, ob der Compiler einen SBI oder
>> Read-Modify-Write erzeugt

>Weder SBI noch R-M-W ist da sinnvoll. Da sollte ein OUT/STS stehen.

Ja, stimmt, da war ich wohl ein wenig verwirrt. 8-0
Ich meinte, es ist egal ob dort ein sbi oder out steht.

Aber die Ursache liegt hier, da flackerte eine Erinnerung auf.

In ATmega88 Datenblatt

"Do not use Read-Modify-Write instructions (SBI and CBI) to set or clear 
the MPCMn bit. The MPCMn bit shares the same I/O location as the TXCn 
Flag and this might accidentally be cleared when using SBI or CBI 
instructions."

D.h. SBI/CBI machen atomar in Hardware ein Read-Modify-Write. Diese 
Warnung findet man bei diversen anderen Registern ebenfalls wieder!

Damit ist deine Aussage auch FALSCH!

"da die SBI Version nur PD2 toggelt, die OUT Version aber zusätzlich
alle Pins, die als 1 gelesen werden."

Beide Versionen sind falsch!

Beitrag "Re: Kleine Bitmanipulationsfrage"

Nur ein

PIND = (1<<PD1);

->

LDI r16, 1<<PD1
OUT PIND, R16

ist korrekt. Es darf KEINESFALLS ein

SBI   PIND, PD1

erzeugt werden!

von Thomas E. (thomase)


Lesenswert?

A. K. schrieb:
> Weiss ich doch, schrieb ich doch. Aber soll der Compiler wirklich die
> eingesetzten Befehle davon abhängig machen müssen, ob da
>   PINA = 1; // SBI möglich
> oder
>   PORTA = 1; // SBI nicht möglich
> steht? Also PINx Portadressen mit __attribute__((sbi)) taggen, um diese
> Nischenoptimierung durchführen zu können?

Das macht er auch nicht:
1
 PINC = 1;
2
 4d6:  81 e0         ldi  r24, 0x01  ; 1
3
 4d8:  86 b9         out  0x06, r24  ; 6
4
 PORTC = 1;
5
 4da:  88 b9         out  0x08, r24  ; 8

Sondern mit '|=' benutzt er den 'sbi':
1
 PINC |= 1;
2
 4d6:  30 9a         sbi  0x06, 0  ; 6
3
 PORTC |= 1;
4
 4d8:  40 9a         sbi  0x08, 0  ; 8

Der Programmierer muss allerdings wissen, dass man sich mit
1
PINC |= 3;
ins Knie schiesst. Denn der Compiler ist nicht sein Kindermädchen.

mfg.

von (prx) A. K. (prx)


Lesenswert?

Falk Brunner schrieb:
> D.h. SBI/CBI machen atomar in Hardware ein Read-Modify-Write. Diese
> Warnung findet man bei diversen anderen Registern ebenfalls wieder!

Ist nicht der Punkt. Bei den PINx Registern fällt man mit dieser 
Vorstellung auf die Nase, weil die eben nicht so arbeiten, wie R-M-W 
vorgibt. Siehe dort. Für diesen Unfug kann ich nichts, das hat Atmel so 
verbockt, wohl an Assembler-Fans denkend.

> Damit ist deine Aussage auch FALSCH!

Meine Aussage bezog sich ausschliesslich auf die PINx Register, nicht 
auf die CBI/SBI Befehle im Allgemeinen.

: Bearbeitet durch User
von Bastler (Gast)


Lesenswert?

Komisch daß im DB ausdrücklich SBI zum "Single Bit toggle" genannt wird. 
Wenn die bei Atmel merken, daß das keinesfalls geht, Eden sie traurig 
sein.

von (prx) A. K. (prx)


Lesenswert?

Daraus ergibt sich insgesamt, dass sich die CBI/SBI Befehle 
normalerweise wie eine atomare R-M-W Befehlsfolge verhalten, ausser es 
handelt sich um PINx Portregister.

von (prx) A. K. (prx)


Lesenswert?

Thomas Eckmann schrieb:
> Der Programmierer muss allerdings wissen, dass man sich mit
> PINC |= 3;
> ins Knie schiesst.

Um sich besonders elegant ins Knie zu schiessen, kann man auch in 
zentraler Konfiguration
  #define XXX_PORT_IN    PINA
  #define XXX_MYPIN      PA2
schreiben, um später mit
  XXXX_PORT_IN |= 1<<XXX_MYPIN;
darauf zurückzugreifen.

Wenn man dann aufgrund Kapazitätsengpass oder Gemecker vom Layouter auf 
den Mega1280 mit
  #define XXX_PORT_IN    PINH
  #define XXX_STATUSPIN  PH1
umsteigt, dann ist die Kniescheibe futsch. Denn der geht nicht mit SBI, 
weshalb die volle R-M-W Version mit ihren Nebenwirkungen rauskommt.

Code wie
  PINx |= ...;
sollte also besser generell als unspezifiziert betrachtet werden. Dann 
entfällt zwar der kurze SBI, aber man ist auf der sicheren Seite.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ A. K. (prx)

>Daraus ergibt sich insgesamt, dass sich die CBI/SBI Befehle
>normalerweise wie eine atomare R-M-W Befehlsfolge verhalten, ausser es
>handelt sich um PINx Portregister.

Hab ich soeben an realer Hardware getestet. Stimmt. 8-0
Das nenn ich mal konsequent inkonsequent!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

N. G. schrieb:
> Ich habe gesehen, dass Registerzugriffe als volatile deklariert
> sind, also werden diese nicht vom avr-gcc optimiert, oder?
> Also wird das mehr Befehle brauchen
1
PORTD |= (1 << PD4);
2
PORTD &= ~(1 << PD5);
> als eine andere Version, bei der nur einmal auf den Port
> zugegriffen wird.
> Ich habs mal so versucht
1
PORTD |= (1 << PD4) & ~(1 << PD5);

Die Frage lässt sich leider nicht zufriedenstellend beantworten.

Version 1 besteht aus 2 Anweisungen und 4 Zugriffen, Version 2 besteht 
aus einer Anweisung und 2 Zugriffen.  GCC wird die eine Variante nie in 
die andere umwandeln oder "optimieren", weil das nicht volatile-korrekt 
wäre.  Bis dahin herrscht also Klarheit.

Was man hingegen nicht sagen kann, ist, welche Befehlssequenzen genau 
erzeugt werden, was insbesondere im Hinblick auf Atomarität wichtig 
ist.

Verkompliziert wird die Lage dadurch, daß der AVR-spezifische Teil von 
GCC ein PORTD |= als SBI ausgeben kann.  Ungeachtet der Frage, ob diese 
Transformation nun volatile-korrekt ist oder nicht, erwartet der 
Anwender hier üblicherweise ein SBI falls möglich, und das ist im Ende 
auch die Rechtfertigung für diese Transformaton.

Blöderweise kann man nicht dafür garantieren, d.h. das Ergebnist ist 
sowohl abhängig von Optimierungseinstellungen als auch vom Kontext.  Bei 
den Xmega, wo die Header i.d.R. eine Lawine von volatile Bitfields und 
Unions und tralala lostreten, geht GCC z.B. gerne davon aus, es sei 
günstiger, die Adresse in ein Register zu laden und indirekt 
zuzugreifen:
1
PORTX |= 1 << 1;
2
PORTX |= 1 << 2;
dann also nicht als
1
sbi PORTX, 1
2
sbi PORTX, 2
übersetzt sonder als
1
ldi r30, lo8(PORTX)
2
ldi r31, hi8(PORTX)
3
ld  r18, z
4
ori r18, 2
5
st  z, r18
6
ld  r18, z
7
ori r18, 4
8
st  z, r18
Abgesehen von den Blähungen sind die Operationen auf den Ports nicht 
mehr atomar, so daß eine ISR, die ebenfalls auf PORTX operiert, den 
Kürzeren zieht falls sie zwischen LD / ORI bzw. ORI / ST ausführt.

Die einzige, zufriedenstellende Lösung, die avr-gcc anbieten könnte, 
wären neue Built-in Funktionen, die atomare Operation garantieren.  Vor 
einiger Zeit hatte ich mal in Erwägung gezogen, solche zu 
implementieren, bin aber wieder davon abgekommen.... Keine Ahnung ob 
sowas verwendet werden würde oder ob es nur toter Code im avr-gcc wäre.

Konkret ein Built-in für Load-Modify-Store, der den Inhalt einer 8-Bit 
Speicherstelle folgendermaßen verändert:  Für jedes Bit in MASK, das auf 
1 ist, wird das entsprechende Bit von *ADDR auf das entsprechende Bit 
von VAL gesetzt.  Für jedes Bit in MASK, das 0 ist, bleibt der Wert von 
*ADDR unverändert.

In C ließe sich solch ein Built-in — hier ldmst genannt — in etwa wie 
folgt darstellen:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
static int8_t __inline__ __attribute__((__always_inline__))
5
xlog2 (uint8_t x)
6
{
7
    return 1 << 0 == x ? 0
8
           : 1 << 1 == x ? 1
9
           : 1 << 2 == x ? 2
10
           : 1 << 3 == x ? 3
11
           : 1 << 4 == x ? 4
12
           : 1 << 5 == x ? 5
13
           : 1 << 6 == x ? 6
14
           : 1 << 7 == x ? 7
15
           : -1;
16
}
17
18
static void __inline__ __attribute__((__always_inline__))
19
ldmst (unsigned addr, uint8_t mask, uint8_t val)
20
{
21
  if (__builtin_constant_p (mask)
22
      && 0xff == mask)
23
    *(volatile uint8_t*) addr = val;
24
  else if (__builtin_constant_p (addr)
25
           && __builtin_constant_p (mask)
26
           && (unsigned) (addr - __AVR_SFR_OFFSET__) < 0x20
27
           && xlog2 (mask) >= 0)
28
    {
29
      if (!__builtin_constant_p (val))
30
        __asm volatile ("sbrc %2,%1" "\n\t"
31
                        "sbi %i0,%1" "\n\t"
32
                        "sbrs %2,%1" "\n\t"
33
                        "cbi %i0,%1"
34
                        :: "n" (addr), "n" (xlog2 (mask)), "r" (val) : "memory");
35
      else if (1 & (val >> xlog2 (mask)))
36
        __asm volatile ("sbi %i0,%1" :: "n" (addr), "n" (xlog2 (mask)) : "memory");
37
      else
38
        __asm volatile ("cbi %i0,%1" :: "n" (addr), "n" (xlog2 (mask)) : "memory");
39
    }
40
#if defined (__AVR_ISA_RMW__)
41
  else if (__builtin_constant_p (mask)
42
           && __builtin_constant_p (val)
43
           && (0 == (mask & val)
44
               || mask == (mask & val)))
45
    {
46
      if (mask & val)
47
        __asm volatile ("las %1,%0" : "+r" (mask) : "z" (addr) : "memory");
48
      else
49
        __asm volatile ("lac %1,%0" : "+r" (mask) : "z" (addr) : "memory");
50
    }
51
#endif // RMW
52
  else
53
    {
54
      volatile uint8_t *r = (volatile uint8_t*) addr;
55
      uint8_t sreg = SREG;
56
      cli();
57
      *r = (*r & ~mask) | (mask & val);
58
      SREG = sreg;
59
    }
60
}
Und in der Anwendung dann:
1
void func (uint8_t volatile *var, uint8_t val)
2
{
3
  ldmst ((unsigned) & PORTB, 1 << 2, -1); // .2 = 1  --> sbi *,2
4
  ldmst ((unsigned) & PORTB, 1 << 7, 0);  // .7 = 0  --> cbi *,7
5
  ldmst ((unsigned) & PORTB, 3 << 6, 0);  // .6 = .7 = 0
6
  ldmst ((unsigned) & PORTB, 1 << 5, val << 5);   //  .5 = val.0
7
  ldmst ((unsigned) & PORTB, 1 << 5, ~(val << 5));   //  .5 = ~val.0
8
  ldmst ((unsigned) & *var, 3, -1);       //  .0 = .1 = 1
9
  ldmst ((unsigned) & *var, 0x55, 0xf);   //  .0 = .2 = 1; .4 = .6 = 0
10
}
Im Compiler hat man natürlich bessere Möglichkeiten das zu optimieren, 
z.B. kann man sich in den Fällen 4 und 5 den Shift sparen wenn man Bit 0 
von VAL verwendet.

Früher gab es auch mal die Makros sbi() und cbi(); wahrscheinlich 
geistern die immer noch irgendwo rum. Verwendet werden die aber wohl 
nicht mehr...

> es scheint aber so nicht zu funktionieren...
> [...] Wie müsste der Befehl mit nur einem Portzugriff aussehen?

Das gibt es keinen, weil ein Bit gesetzt und eins gelöscht wird.

von N.G. (Gast)


Lesenswert?

>> es scheint aber so nicht zu funktionieren...
>> [...] Wie müsste der Befehl mit nur einem Portzugriff aussehen?
>
>Das gibt es keinen, weil ein Bit gesetzt und eins gelöscht wird.

Danke, das war zwar nicht die Antwort, die ich mir erhofft hatte... Aber 
danke
Auch danke an alle anderen, die Erläuterungen habe ich mit Interesse 
verfolgt

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

N.G. schrieb:
>>> es scheint aber so nicht zu funktionieren...
>>> [...] Wie müsste der Befehl mit nur einem Portzugriff aussehen?
>>
>>Das gibt es keinen, weil ein Bit gesetzt und eins gelöscht wird.
>
> Danke, das war zwar nicht die Antwort, die ich mir erhofft hatte...

Falls es wirklich eine Rolle spielten sollte nur genau einen 
Portzugriff zu veranstalten, dann kann man Buchführung betreiben und 
merken, welcher Wert gerade im Register steht — vorausgesetzt es ist ein 
reines Konfigurations- oder Ausgaberegister das nicht von der Hardware 
verändert wird.

Aber die Anwort hattest du wohl auch nicht erhofft, weil das weder 
kürzer noch schneller ist als direkt auf dem Port zu operieren.

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:
>> [...] Wie müsste der Befehl mit nur einem Portzugriff aussehen?
>
> Das gibt es keinen, weil ein Bit gesetzt und eins gelöscht wird.

Weshalb es bei manchen µCs I/O-Ports gibt, die mehrere Pins gleichzeitig 
auf beliebige Werte setzen können, ohne die übrigen Pins zu ändern. Ein 
Weg dazu ist ein Maskenregister, mit dem die zu setzenden Pins 
ausgewählt werden. Ein anderer Weg nutzt deshalb Ports halber Wortbreite 
um beim Schreiben in voller Wortbreite gleichermassen setzen und löschen 
zu können.

von Falk B. (falk)


Lesenswert?

@ A. K. (prx)

>Weshalb es bei manchen µCs I/O-Ports gibt, die mehrere Pins gleichzeitig
>auf beliebige Werte setzen können, ohne die übrigen Pins zu ändern.

Irgendwann ist es auch mal wieder gut. Der AVR ist schon recht flott im 
Bit Banging, da kann man alle möglichen Dinge mit machen. Wenn es 
wirklich alles gleichzeitig und hochflexibel sein muss, nimmt man halt 
einen CPLD/FPGA.
Andere Prozessoren haben da deutlich mehr Probleme.

von Peter D. (peda)


Lesenswert?

Die Code-/Laufzeiteinsparung beim Togglen mit PINx ist so lächerlich 
gering, daß ich das zugunsten der Lesbarkeit noch nie benutzt habe und 
auch nie benutzen werde.

von (prx) A. K. (prx)


Lesenswert?

Peter Dannegger schrieb:
> Die Code-/Laufzeiteinsparung beim Togglen mit PINx ist so lächerlich
> gering, daß ich das zugunsten der Lesbarkeit noch nie benutzt habe und
> auch nie benutzen werde.

Meist nicht wichtig, kann es dort interessant werden, wo mehrere Pins 
betroffen sind und die atomare Eigenschaft dieser Wackelei wichtig ist.

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.