Forum: Mikrocontroller und Digitale Elektronik ATmega8 läuft um den Faktor 10 zu langsam


von µC Neuling (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe ein Problem mit meinem ATmega8. Dieser sollte eigentlich mit 
einem externen Quarz auf 8Mhz laufen (die Fuses sind auf Bild2 zu 
sehen).

Wenn ich allerdings die Frequenz messe ist dieser um den Faktor 10 zu 
langsam d.h. er läuft nur mit 800 khz (siehe Bild 1).
Dieses Ergebnis habe ich bekommen indem ich einfach einen IO Pin toggeln 
lasse:

while(1)
    {
       PORTC ^= (1<<0);
    }

Hat da jemand eine Idee an was das liegen könnte ?

MfG.

von Max D. (max_d)


Lesenswert?

Das togglen erfolgt nicht in einem taktzyklus (und selbst dann hättest 
du nur 4 mhz), schreib lieber ein proggi das einen timer als ausgabe 
verwendet (und einen festen Teiler hat)...

von R. M. (rmax)


Lesenswert?

Deine Schleife braucht vermutlich 5 Takte pro Duchrlauf.

von Peter II (Gast)


Lesenswert?

Max D. schrieb:
> Das togglen erfolgt nicht in einem taktzyklus

doch macht es.

von Peter II (Gast)


Lesenswert?

Peter II schrieb:
> Max D. schrieb:
>> Das togglen erfolgt nicht in einem taktzyklus
>
> doch macht es.

nachtrag:

Wenn man es wirklich toggelt, aber ich sehe gerade das er es ja von hand 
macht. Dann ist es wirklicht nicht der Fall.

von Max D. (max_d)


Lesenswert?

Peter II schrieb:
> Max D. schrieb:
>> Das togglen erfolgt nicht in einem taktzyklus
>
> doch macht es.

naja, der loop verzögert dann, dann hast du nichtmehr einen zyklus (ich 
wollts einfach halten)

von Matthias L. (Gast)


Lesenswert?

>doch macht es.

>PORTC ^= (1<<0);

Nein. XOR ist immer:

IN  Rxx, PORTC
EOR Rxx, 0x01
OUT PORTC, Rxx
JMP zurück


Aber das sollte man im ASM-Listing erkennen. Da kann man zählen. Diese 
vier Befehle sollten acht Takte brauchen..

von µC Neuling (Gast)


Lesenswert?

Okey das habe ich mir fast gedacht.
Allerdings war mir nicht klar das das so gravierend ist da ja immerhin 
nur 1/10 der original Taktfrequenz übrig bleiben.

von Karl H. (kbuchegg)


Lesenswert?

µC Neuling schrieb:
> Okey das habe ich mir fast gedacht.
> Allerdings war mir nicht klar das das so gravierend ist da ja immerhin
> nur 1/10 der original Taktfrequenz übrig bleiben.

So
1
while(1)
2
    {
3
       PORTC |= (1<<0);
4
       PORTC &= ~(1<<0);
5
    }

sollte es schneller gehen. Das müsste dich fast bis auf 2.6Mhz bringen. 
Allerdings ist die 'Schwingung' dann leicht asymetrisch.

Bis auf 4Mhz kommt man dann nur noch mit dem Einsatz eines Timers, den 
den Pin in Hardware toggelt.

von µC Neuling (Gast)


Lesenswert?

Alles klar, vielen dank für die Hilfe :-)

von c-hater (Gast)


Lesenswert?

µC Neuling schrieb:

> ich habe ein Problem mit meinem ATmega8.

Nein, hast du nicht. Du hast vielmehr ein Problem mit dem Verständnis 
deiner Programmiersprache. Was allerdings insofern entschuldbar ist, als 
daß es sich um eine Scheißsprache handelt. Allerdings hast du sie selber 
ausgewählt und zwar ganz offensichtlich falsch für den beabsichtigten 
Zweck, der ja wohl die Messung einer Taktfrequenz ist.

Dafür sind Hochsprachen grundsätzlich ungeeignet, auch 
Pseudohochsprachen bzw. aufgedonnerte Makroassembler wie C. Weil man 
einfach nicht vorhersagen kann, was der gewählte Compiler in der 
gewählten Version mit den gewählten Optimierungsoptionen letztlich für 
einen Code produziert.

In einer richtigen Sprache (natürlich Assembler) siehst du hingegen 
jederzeit, was genau du tust.

Dieser syntaktisch wunderschön aufgedonnerte Bullshit:

> while(1)
>     {
>        PORTC ^= (1<<0);
>     }

wird vom Compiler (ohne Optimierung) nämlich (bestenfalls) etwa so 
ausgedrückt:

loop:
  in reg1,PORTC   ;1
  ldi reg2,1<<0   ;1
  eor reg1,reg2   ;1
  out PORTC,reg1  ;1
  rjmp loop       ;2

d.h.: Du müßtest also zwar keine 8 MHz messen, aber immerhin 8/6, also 
ca. 1,33 Mhz. Keine Ahnung, wie es dein C-Compiler schafft, die Sache 
noch suboptimaler umzusetzen, aber von 1,33MHz bis 800kHz ist es nicht 
mehr allzu weit, ich würde es also auf jeden Fall erstmal dem Compiler 
anlasten.

Übrigens: In Assembler schafft man ohne Änderung des Grundkonzeptes 
wenigstens 8/5=1,6MHz, einfach indem man die Initialisierung von reg2 
aus der Schleife holt. Die meisten Compiler schaffen das inzwischen 
allerdings auch in irgendeiner Optimierung.

Mit einem etwas besseren Ansatz, den einem weder Assembler noch Compiler 
abnehmen können, (zwei Hilfregister, beide vor dem Eintritt in die 
Schleife initialisiert) schon 8/4=2MHz und bei Ausnutzung eines Features 
der neueren AVRs (Hardwaretogglen) 8/3=2,67MHz. Und natürlich: Wenn man 
einen Timer zu Hilfe nimmt, kommt man auf 8/2=4MHz. Und das Ende der 
Geschichte ist die Benutzung von CLKO, was die Sache dann endgültig auf 
8/1=8MHz bringt. Mehr geht absolut nicht. ;o)

> Dieser sollte eigentlich mit
> einem externen Quarz auf 8Mhz laufen

Das tut er aller Wahrscheinlichkeit nach auch.

von R. M. (rmax)


Lesenswert?

@kbuchegg: Wie kommst Du denn auf die 2,6MHz?

Deine Schleife compiliert hier zu SBI, CBI, RJMP, mit 1, 1 und 2 Takten, 
es müßten also 2MHz mit einem Puls-Pausen-Verhältnis von 1:3 
herauskommen.

@c-hater: Du übersiehst, daß bei der XOR-Variante eine Periode des 
Ausgangssignals zwei Schleifendurchläufe braucht.

von Dietrich L. (dietrichl)


Lesenswert?

c-hater schrieb:
> Du müßtest also zwar keine 8 MHz messen, aber immerhin 8/6, also
> ca. 1,33 Mhz

Das ist nicht die Frequenz, sondern die halbe Periode. Für eine ganze 
Periode muss die Schleife 2x durchlaufen werden, das wäre dann 665kHz.
Bei 800kHz wurde also noch etwas optimiert.

Gruß Dietrich

von R. M. (rmax)


Lesenswert?

Hier noch eine Variante, die 1MHz symmetrisch schafft:
1
    uint8_t a = PORTC;
2
    for (;;) {
3
        a ^= 1;
4
        PORTC = a;
5
    }
Die eigentliche Schleife besteht dann nur noch aus EOR (1), OUT (1) und 
RJMP (2).

von Karl H. (kbuchegg)


Lesenswert?

R. Max schrieb:
> @kbuchegg: Wie kommst Du denn auf die 2,6MHz?
>
> Deine Schleife compiliert hier zu SBI, CBI, RJMP, mit 1, 1 und 2 Takten,
> es müßten also 2MHz mit einem Puls-Pausen-Verhältnis von 1:3
> herauskommen.

Ah, richtig. rjmp braucht länger. Ich hatte alles mit 1 Takt angesetzt.
Danke für die Korrektur.

von Karl H. (kbuchegg)


Lesenswert?

> Die meisten Compiler schaffen das inzwischen
> allerdings auch in irgendeiner Optimierung.

Deine Polemik ist nicht zum aushalten.
Wenn du von C wenig Ahnung hast und es nicht magst, dann ist das ok. 
Aber hör bitte auf, den Unsinn auch noch zu verbreiten.

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


Lesenswert?

µC Neuling schrieb:
> while(1)
>     {
>        PORTC ^= (1<<0);
>     }

Bist du auf den alten ATmega8 angewiesen? Wenn du den Nachfolger seines 
Nachfolgers nimmst, also den ATmega88A und damit einen einigermaßen 
aktuellen Mikrocontroller, dann kannst du das Togglen so erreichen:
1
while(1)
2
    {
3
       PINC= (1<<0);
4
    }

Das läuft ungefähr dreimal so schnell, weil es vom Compiler in ganze 
zwei Assembler-Befehle übersetzt wird, die insgesamt 3 Takte brauchen:
1
out PINC,(1<<0)
2
rjmp PC-1

von Yalu X. (yalu) (Moderator)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Wenn du von C wenig Ahnung hast und es nicht magst, dann ist das ok.
> Aber hör bitte auf, den Unsinn auch noch zu verbreiten.

Naja, da er ja offensichtlich von Assembler genauso wenig Ahnung hat
(seine Berechnung der resultierenden Frequenz legen dies zumindest
nahe), relativieren sich seine Aussagen entsprechend ;-)

von c-hater (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Wenn du von C wenig Ahnung hast und es nicht magst, dann ist das ok.

Ich habe durchaus Ahnung von C, aber gerade deshalb mag ich die Sprache 
nicht. Nur Leute, die es gerade so schaffen in C zu programmieren und 
auch nix anderes können, die mögen C.

> Aber hör bitte auf, den Unsinn auch noch zu verbreiten.

Das ist kein Unsinn.

von c-hater (Gast)


Lesenswert?

Dietrich L. schrieb:

> Das ist nicht die Frequenz, sondern die halbe Periode. Für eine ganze
> Periode muss die Schleife 2x durchlaufen werden, das wäre dann 665kHz.

Ähem, ja natürlich. Peinlich, peinlich...

von Walter S. (avatar)


Lesenswert?

c-hater schrieb:
> Nur Leute, die es gerade so schaffen in C zu programmieren und
> auch nix anderes können, die mögen C.

ich habe schon in Assembler programmiert als deine Eltern sich 
wahrscheinlich noch nicht gekannt haben. Anfangs noch von Hand 
assembliert Hex-Zahlen eingetippt, später mit Assembler und dann endlich 
C (zwischendurch noch Algol, Fortran, Pascal, Lisp, PL1, ...) und ich 
kann Dir sagen alles ist besser als Assembler (den ich nur verwende wenn 
ich irgendwelche Zyklen zählen muss)
Ich möchte dich Mal sehen wenn Du einen Compiler oder ein auch nur 
leicht komplexes Programm in Assembler schreibst.

von Walter S. (avatar)


Lesenswert?

c-hater schrieb:
>> Das ist nicht die Frequenz, sondern die halbe Periode. Für eine ganze
>> Periode muss die Schleife 2x durchlaufen werden, das wäre dann 665kHz.
>
> Ähem, ja natürlich. Peinlich, peinlich...

nicht so schlimm, in Assembler kann das schon Mal passieren ;-)

von µC Neuling (Gast)


Lesenswert?

Markus Weber schrieb:
> Bist du auf den alten ATmega8 angewiesen? Wenn du den Nachfolger seines
> Nachfolgers nimmst, also den ATmega88A und damit einen einigermaßen
> aktuellen Mikrocontroller, dann kannst du das Togglen so erreichen

Angewiesen bin ich nicht wirklich auf den ATmega8, ich bin im Moment nur 
ein bisschen am Ausprobieren  und hatte mit dazu ein günstiges 
Starterkit gekauft wo eben dieser ATmega8 dabei war.

Mir geht es auch gar nicht darum einen IO Pin mit 8Mhz toggeln zu lassen 
sondern mich hatte nur gewundert wie die Differenz zwischen 
Prozessortakt und der Frequenz des IO Pins zustande kommt.
Aber das hat sich ja geklärt ;-)



MfG.

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.