Forum: Compiler & IDEs atmega168: Minimale Impulsbreite am Portausgang?


von John G. (johngo)


Lesenswert?

Hallo,

wie kurz kann denn der kürzestmögliche Impuls am Ausgang eines Ports 
sein, den ich per Software erzeugen kann?

Mein gemessener Impuls dauert 2 CPU-Takte. Aber, wenn ich das richtig 
verstanden habe, sollte ja eine Impulsdauer von 1 Takt möglich sein, 
weil die SBI und CBI Befehle laut Datenblatt nur 1 cycle brauchen.


Ich mach das so in C:

PORTD |= (1<<PORTD3);
PORTD &= ~(1<<PORTD3);

Im Disassembler schauts dann so aus:
+00000166:   9A5B        SBI     0x0B,3           Set bit in I/O 
register
+00000167:   985B        CBI     0x0B,3           Clear bit in I/O 
register

Am Logikanalysator schauts dann so aus:

Clck: 010101010101010101010101010
Port: 000000000111100000000000000

Also, der Port ist 2 Takte lang auf 1, und nicht nur einen.
Weiß jemand, woran das liegt könnte?

Danke,
Johngo

von Johannes M. (johnny-m)


Lesenswert?

Ich weiß jetzt nicht, in welch komischem Datenblatt Du nachgesehen hast, 
aber in der Befehlssatzdokumentation steht recht eindeutig, dass cbi und 
sbi zwei Taktzyklen benötigen!

EDIT:
In meinem Datenblatt vom ATMega48/88/168 steht ebenfalls zwei 
Taktzyklen...

von John G. (johngo)


Lesenswert?

Ja, genau, alles klar!
Da hab ich wohl in die Spalte vom xmega geschaut!

Danke!
Johngo

von Εrnst B. (ernst)


Lesenswert?

Gehts über einen Schreibzugriff auf PINx evtl schneller?

Im Atmega48-Datenblatt unter "12.2.2":

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

also
1
PIND=(1<<PIND3);
2
PIND=(1<<PIND3);

Mal ausprobieren, ob das schneller ist...

von Benedikt K. (benedikt)


Lesenswert?

Ja, geht schneller. cbi/sbi müssen halt Lesen, verodern und 
zurückschreiben.

von Johannes M. (johnny-m)


Lesenswert?

Benedikt K. wrote:
> Ja, geht schneller.
Wie das? Der Compiler macht sicher aus den beiden Zeilen von Ernst auch 
ein sbi (wie ja schon im Original). Und sbi braucht nunmal je 2 Takte, 
da ändert es auch nichts, wenn man auf PIND statt PORTD zugreift.

Es gibt afaik keine einzige Möglichkeit, per Software an einen Pin etwas 
in weniger als zwei Taktzyklen auszugeben.

von Stefan E. (sternst)


Lesenswert?

Johannes M. wrote:
> Wie das? Der Compiler macht sicher aus den beiden Zeilen von Ernst auch
> ein sbi (wie ja schon im Original). Und sbi braucht nunmal je 2 Takte,
> da ändert es auch nichts, wenn man auf PIND statt PORTD zugreift.

Warum sollte er? Da steht doch kein "|=", sondern "=", und daraus macht 
der Compiler ein OUT, was 1 Takt braucht.

von Johannes M. (johnny-m)


Lesenswert?

Stefan Ernst wrote:
> Warum sollte er? Da steht doch kein "|=", sondern "=", und daraus macht
> der Compiler ein OUT, was 1 Takt braucht.
Für ein out muss aber erst mal ein Wert in einem Rechenregister 
stehen, und der kommt mit ldi da rein, was der zweite Takt ist... (OK, 
im Prinzip hast Du natürlich Recht: Das ldi muss nur einmal ganz am 
Anfang gemacht werden. Demnach haut es natürlich doch hin...)

von Stefan E. (sternst)


Lesenswert?

Johannes M. wrote:
> Für ein out muss aber erst mal ein Wert in einem Rechenregister

Das muss man aber nur einmal machen, nicht jedesmal.

von Stefan E. (sternst)


Lesenswert?

Der Compiler macht aus dem Sourcecode von Ernst:
LDI     R24,0x08
OUT     0x10,R24
OUT     0x10,R24

Und damit hat man einen Puls mit einer Breite von einem Takt.

von Johannes M. (johnny-m)


Lesenswert?

Stefan Ernst wrote:
> Johannes M. wrote:
>> Für ein out muss aber erst mal ein Wert in einem Rechenregister
>
> Das muss man aber nur einmal machen, nicht jedesmal.
Richtig, siehe oben...

von Stefan E. (sternst)


Lesenswert?

Sorry. Habe ich das überlesen, oder hast du nochmal editiert?

von Johannes M. (johnny-m)


Lesenswert?

Stefan Ernst wrote:
> Sorry. Habe ich das überlesen, oder hast du nochmal editiert?
Sagen wir es so: Ich habe mein Privileg als registrierter User schamlos 
ausgenutzt...

von John G. (johngo)


Lesenswert?

Und das funktioniert auch beim Zugriff aufs normale PORTD 
Schreibregister: nur 1 Takt.

portD = PORTD;
hibit = portD | (1 << PORTD3);
lobit = portD & ~(1 << PORTD3);

PORTD = hibit;
PORTD = lobit;

von Johannes M. (johnny-m)


Lesenswert?

John Go wrote:
> Und das funktioniert auch beim Zugriff aufs normale PORTD
> Schreibregister: nur 1 Takt.
>
> portD = PORTD;
> hibit = portD | (1 << PORTD3);
> lobit = portD & ~(1 << PORTD3);
>
> PORTD = hibit;
> PORTD = lobit;
Jo, damit veränderst Du aber jedes Mal auch alle anderen Bits im 
Portregister, wenn PORTD sich in der Zwischenzeit ändert, und musst 
außerdem darauf spekulieren, dass der µC noch genügend Register frei 
hat, um die beiden Konstanten in Rechenregistern zu lassen. Der 
ATMega168 hat extra für solche Sachen die Pin-Toggle-Funktion durch 
Schreibzugriff auf PINx, also warum nutzt Du sie nicht?

von John G. (johngo)


Lesenswert?

Genau, jetzt hab ich erst die Pin-Toggle Funktion verstanden.

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.