Forum: Mikrocontroller und Digitale Elektronik Warum nur 8 MIPS bei 16 MHz Systemtakt?


von Vincent R. (vinc) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo zusammen!

Auf einem ATmega644P habe ich zu Testzwecken eine Dauerschleife laufen 
lassen, die nur PD6 umschaltet, sonst nichts.
Es ist ein 16 Mhz Quarz angeschlossen und die Fuses entsprechend 
programmiert:
LFUSE: 0x0F7 (0xFF ändert nichts)
HFUSE: 0xD9
EFUSE: 0xFF

1
#include <avr/io.h>
2
3
int main(void) {
4
5
  DDRA = 0x00;
6
  DDRB = 0xff;
7
  DDRC = 0xff;
8
  DDRD = (1 << DDD1) | (1 << DDD5) | (1 << DDD6) | (1 << DDD7);
9
10
  while(1) {
11
12
    PORTD |= (1 << PD6);
13
    PORTD &= ~(1 << PD6);
14
15
    PORTD |= (1 << PD6);
16
    PORTD &= ~(1 << PD6);
17
18
    PORTD |= (1 << PD6);
19
    PORTD &= ~(1 << PD6);
20
21
  }
22
23
  return 0;
24
}

Mit dem Oszi habe ich an PD6 gemessen (gelb) und gleichzeitig den 
Systemtakt an XTAL2 (blau).
Wie am Zeitcursor erkennbar, wird der Pin nach rund 125 ns umgeschaltet, 
was einer Freuquenz von 8 MHz entspricht.
Nun frage ich mich, warum der Controller für so eine leichte Aufgabe 
zwei Takte benötigt und nicht bloß einen.
Ist es möglich, dass er aus irgendwelchen Gründen nur mit 8 MHz taktet 
oder braucht er wirklich zwei Takte dafür?

Grüße,
Vinc

von Joachim .. (joachim_01)


Lesenswert?

Haste mal den Asm-Code angekuckt? Vielleicht schiebt der Compiler ein 
NOP() ein.

von Assembler (Gast)


Lesenswert?

Guck dir doch mal das Assembler-Listing an.

von (prx) A. K. (prx)


Lesenswert?

Die Bit Set/Reset Befehle benötigen 2 Takte.

von Joachim .. (joachim_01)


Lesenswert?

Moment mal. Du schreibst:
 PORTD &= ~(1 << PD6);
Ich vermute mal, daß das nicht einfach dem Komplementär-Befehl 
entspricht.

Bei den PICs gibts da ein:
PORTDbits.PD7 ^= 1;
Vieleicht bietet er gcc etwas ähnliches an.

von Joachim .. (joachim_01)


Lesenswert?

prx war schneller ;-)

von RTFM (Gast)


Lesenswert?

SBI und CBI brauchen auf dem ATMega 2 Takte (im Gegensatz zum ATTiny und 
XMega):
http://www.atmel.com/images/doc0856.pdf
Seite 14 und Fußnote 5 auf Seite 15

Die OUT instruction braucht dagegen auch auf dem ATMega nur 1 Takt, 
allerdings müssen vorher die Bits für den kompletten Port in einem 
Register liegen.

Folgender asm-code müsste also 4 MHz auf PD6 ausgeben (mit Verzögerungen 
für den rjmp nach jeweils 5 Perioden):
1
ldi r16, (1<<PD6)
2
ldi r17, 0
3
loop:
4
out PORTD, r16
5
out PORTD, r17
6
out PORTD, r16
7
out PORTD, r17
8
out PORTD, r16
9
out PORTD, r17
10
out PORTD, r16
11
out PORTD, r17
12
out PORTD, r16
13
out PORTD, r17
14
rjmp loop

Auf dem Mega644 müsste auch das Toggeln über schreiben ins PIN-Register 
funktionieren:
1
ldi r16, (1<<PD6)
2
loop:
3
out PIND, r16
4
out PIND, r16
5
out PIND, r16
6
out PIND, r16
7
out PIND, r16
8
out PIND, r16
9
out PIND, r16
10
out PIND, r16
11
out PIND, r16
12
out PIND, r16
13
rjmp loop

von Thomas E. (thomase)


Lesenswert?

Joachim ... schrieb:
> Moment mal. Du schreibst:
>  PORTD &= ~(1 << PD6);
> Ich vermute mal, daß das nicht einfach dem Komplementär-Befehl
> entspricht.
>
> Bei den PICs gibts da ein:
> PORTDbits.PD7 ^= 1;
> Vieleicht bietet er gcc etwas ähnliches an.
Das ist nicht PIC. Das ist C.

PORTD ^= 1; führt beim AVR und beim PIC wahrscheinlch auch, aber zu 
einem Read-Modify-Write, was wesentlich länger dauert als der eine 
sbi/cbi.

Also das:
PORTD |= (1 << PD6);
PORTD &= ~(1 << PD6);
ist effektiver.

Beim AVR gibt es aber noch PINx |= 1; Da wird wieder der sbi eingesetzt.
Damit ist Toggle-Toggle zeitlich das gleiche wie Setzen-Löschen.

mfg.

von c-hater (Gast)


Lesenswert?

RTFM schrieb:

> SBI und CBI brauchen auf dem ATMega 2 Takte (im Gegensatz zum ATTiny und
> XMega):

Das verstehst du falsch, jedenfalls was die ATtinys betrifft. Da steht: 
"reduced core tinyAVR". Das sind nur die ganz, ganz kleinen (4,5,9,10).

Ab Tiny11 aufwärts kostet SBI/CBI 2 Takte.

von (prx) A. K. (prx)


Lesenswert?

Thomas Eckmann schrieb:
> PORTD ^= 1; führt beim AVR und beim PIC wahrscheinlch auch, aber zu
> einem Read-Modify-Write, was wesentlich länger dauert als der eine
> sbi/cbi.

PICs können XOR zum Port hin. Das ist also 1 Befehl, wenn die Maske 
schon im Akku ist.

von Thomas E. (thomase)


Lesenswert?

A. K. schrieb:
> Thomas Eckmann schrieb:
>> PORTD ^= 1; führt beim AVR und beim PIC wahrscheinlch auch, aber zu
>> einem Read-Modify-Write, was wesentlich länger dauert als der eine
>> sbi/cbi.
>
> Nope. PICs können XOR zum Port hin.
Nicht schlecht.

mfg.

von Thomas E. (thomase)


Lesenswert?

A. K. schrieb:
> Thomas Eckmann schrieb:
>> PORTD ^= 1; führt beim AVR und beim PIC wahrscheinlch auch, aber zu
>> einem Read-Modify-Write, was wesentlich länger dauert als der eine
>> sbi/cbi.
>
> PICs können XOR zum Port hin. Das ist also 1 Befehl, wenn die Maske
> schon im Akku ist.
Wieso im Akku?
XORLW ist doch mit immediate.

mfg.

von (prx) A. K. (prx)


Lesenswert?

Thomas Eckmann schrieb:
> XORLW ist doch mit immediate.

Du willst nicht das Bit im Akku (W) toggeln, sondern im Port (f). Und 
dafür brauchst du XORWF, nicht XORLW: 
http://www.sprut.de/electronic/pic/assemble/befehle.html#xorwf

von Thomas E. (thomase)


Lesenswert?

A. K. schrieb:
> Thomas Eckmann schrieb:
>> XORLW ist doch mit immediate.
>
> Du willst nicht das Bit im Akku (W) toggeln, sondern im Port (f). Und
> dafür brauchst du XORWF, nicht XORLW:
> http://www.sprut.de/electronic/pic/assemble/befehle.html#xorwf
Kann ja keiner ahnen, daß W der Akku ist.

> Daumenregel: In einen PIC Befehl fester Länge passt entweder eine
> Konstante oder eine Adresse. Aber i.d.R. nicht beides.
Ja. Ist logisch.

mfg.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Thomas Eckmann schrieb:
> A. K. schrieb:
>> Nope. PICs können XOR zum Port hin.
> Nicht schlecht.

Das bringt mich auf die Frage, warum Vinc nicht einfach die 
Port-Toggle-Funktion verwendet:
1
PIND|= 1<<PD6

Hab jetzt nicht speziell im Datenblatt des ATmega644P geschaut, aber der 
sollte das eigentlich auch können.

von Thomas E. (thomase)


Lesenswert?

Markus Weber schrieb:
> Thomas Eckmann schrieb:
>> A. K. schrieb:
>>> Nope. PICs können XOR zum Port hin.
>> Nicht schlecht.
>
> Das bringt mich auf die Frage, warum Vinc nicht einfach die
> Port-Toggle-Funktion verwendet:
>
>
1
PIND|= 1<<PD6
>
> Hab jetzt nicht speziell im Datenblatt des ATmega644P geschaut, aber der
> sollte das eigentlich auch können.

Kann er auch. Aber zeitlich bringt das nichts.
Um das gleiche zu erreichen, muss
1
PIND|= 1<<PD6
ja zweimal ausgeführt werden.

mfg.

von egal² (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Kann ja keiner ahnen, daß W der Akku ist.

Ähhh... doch!

von Thomas E. (thomase)


Lesenswert?

egal² schrieb:
> Thomas Eckmann schrieb:
>> Kann ja keiner ahnen, daß W der Akku ist.
>
> Ähhh... doch!

Mir doch egal².

mfg.

von (prx) A. K. (prx)


Lesenswert?

Markus Weber schrieb:
> Das bringt mich auf die Frage, warum Vinc nicht einfach die
> Port-Toggle-Funktion verwendet:

Soweit ich das verstanden habe, ging es ihm nicht darum, ein 8MHz Signal 
zu produzieren. Sondern um eine Erklärung für die 4MHz. Und die hat er. 
Fall abgeschlossen.

von Joachim .. (joachim_01)


Lesenswert?

>>Das ist nicht PIC. Das ist C.
>PORTD ^= 1; führt beim AVR und beim PIC wahrscheinlch auch, aber zu
einem Read-Modify-Write, was wesentlich länger dauert als der eine
sbi/cbi.

Hmmmm...also ich bekomme auf einem 18F458 mit C18 das hier:

112:    LEDPin ^= 1;
28AC  7E8C     BTG LATD, 7, ACCESS

BTG ist:
BTG f, d, a Bit Toggle f 1 0111 bbba ffff ffff

Und er braucht dazu einen Takt.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Thomas Eckmann schrieb:
> Markus Weber schrieb:
>> Das bringt mich auf die Frage, warum Vinc nicht einfach die
>> Port-Toggle-Funktion verwendet:
>>
>>
1
PIND|= 1<<PD6
>>
>> Hab jetzt nicht speziell im Datenblatt des ATmega644P geschaut, aber der
>> sollte das eigentlich auch können.
>
> Kann er auch. Aber zeitlich bringt das nichts.
> Um das gleiche zu erreichen, muss
>
1
PIND|= 1<<PD6
> ja zweimal ausgeführt werden.

Sorry, Tippfehler von mir, ich meinte:
1
PIND= 1<<PD6;

Das ist dann nur ein Takt.

von (prx) A. K. (prx)


Lesenswert?

Joachim ... schrieb:
> Hmmmm...also ich bekomme auf einem 18F458 mit C18 das hier:

Oder so, gibts aber erst im PIC18.

> Und er braucht dazu einen Takt.

Sagen wir mal einen Befehlszyklus. Was 4 Takte sind.

von Thomas E. (thomase)


Lesenswert?

Markus Weber schrieb:
>
1
PIND= 1<<PD6;
>
> Das ist dann nur ein Takt.
Ja. Das ist das gleiche wie die Assemblerversion weiter oben.
Das kann der C-Compiler natürlich auch.

mfg.

von Daniel F. (df311)


Lesenswert?

1
.include "m8def.inc" ; durch passendes config-file ersetzen
2
3
ldi r16, 0x01
4
out DDRD, r16
5
6
loop: 
7
clr PORTD
8
ser PORTD
9
10
rjmp loop

eine taktmessung (einfach nur einen pin togglen) würde ich eher in ASM 
schreiben - und clr/ser brauchen laut meinem instructionset-ausdruck nur 
jeweils 1 takt. alternativ könnte man ein clr nach die initialisierung 
packen und in der schleife nur mehr com ausführen.

hier sinds 3 takte pro schleifendurchlauf, der overhead kann durch 
mehrfaches clr/ser einfach reduziert werden...

ok, ich habs auswendig geschrieben und mangels eines 644 auch nicht 
getestet, aber das prinzip sollte klar sein ;-)

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Daniel F. schrieb:
>
1
> loop:
2
> clr PORTD
3
> ser PORTD
4
>

Ich meine, clr geht nur für r0 bis r31, nicht aber für I/O-Register.

Thomas Eckmann:

Du hast natürlich Recht, ich hatte den Beitrag von RTFM nicht bis zum 
Ende gelesen.

von Vincent R. (vinc) Benutzerseite


Lesenswert?

Wow, das geht ja schnell hier :)

Wie es scheint, ist mit den zwei Takten pro Befehl in diesem Fall ja 
alles in Ordnung.
Ich wollte auch keinen Taktgenerator bauen, sondern einfach nur checken, 
ob der Controller mit dem richtigen Takt läuft.

Danke für die kompetenten Antworten!

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.