Warum nur 8 MIPS bei 16 MHz Systemtakt?

OP Persönliche Seite #3292220
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
Angehängte Dateien:
Gast #3292259
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
#3292262
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.
Gast #3292276
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.
#3292305
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.
#3292312
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.
#3292319
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.
(Firma: guloshop.de) #3292320
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.
#3292335
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 ;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren