Forum: Mikrocontroller und Digitale Elektronik Attiny clock & Fuse Bits


von Matthias (Gast)


Lesenswert?

Hey,

ich brauch Hilfe von Profis, ich spiel zurzeit ein wenig mit 
Attiny25-20PU herum und bin total verwirrt von dem Datenblatt und dem 
Verhalten. Mir ist irgendwie nicht klar welche internen Oszillator 
Frequenz dieser besitzt. Ich hab leider kein Oszi und hab deswegen eine 
LED blinken lassen im ca. 1Hz Takt und wenn ich das einmal als grob 
Schätzung annehme müsste der interne Clock 2 MHz sein. Das macht aber 
keinen richtigen Sinn wenn ich das Datenblatt richtig verstehe.

Kann mir jemand sagen was die maximale interne Frequenz ist?
Und wie ich diese mit den Fusebits im AVR-Studio 4 einstelle?

Schon mal vielen Dank,
Matthias

von Bernie (Gast)


Lesenswert?

Warum ist dir die MAXIMALE Frequenz so wichtig?

Da sie nicht exakt reproduzierbar ist, MUSS man bei
Benutzung des internen Oszillators mit seinem
Mittelwert "rechnen". Mit dem FUSE-Bit CKDIV8 stellst du ein,
ob der µC mit den vollen (UNGEFÄHR!) 8 MHz des internen
Oszillators arbeitet, oder mit 1/8 davon (1 MHz). Bei
Auslieferung ist das FUSE-Bit auf 1/8 eingestellt.

Abgleichen kann man die Frequenz des internen Oszillators
mit dem OSCCAL-Register auf etwa 4...16 MHz.
Ohne Änderung des FUSE-Bits bekommt man 0,5...2 MHz.

von Daniel H. (Firma: keine) (commander)


Lesenswert?

Beim Attiny25 ist standardmäßig der interne Oszillator mit 8 MHz 
aktiviert, das ist auch gleichzeitig die maximale intern erzeugbare 
Frequenz. Allerdings wird der Attiny auch mit gesetzter CKDIV8-Fuse 
geliefert, d.h. der Oszillator-Takt wird durch acht geteilt, so dass der 
effektive Takt 1 MHz ist. Zusätzlich gibt es dann noch ein Register, 
über welches man andere Prescaler für den Takt einstellen kann, das muss 
aber in der Firmware geschehen.

von Bernie (Gast)


Lesenswert?

Übrigens ist dieser interne Oszillator nach meiner
Erfahrung erstaunlich genau (viel besser, als +/- 10%).

Wenn du "rückwärts gerechnet" auf 2 MHz kommst, würde
ich erst mal auf einen Programmierfehler tippen.
Wahrscheinliche Werte sind 0,9...1,1 MHz ohne Veränderung
des Fuse-Bits, oder 7,2...8,8 MHz mit Änderung.

von Karl H. (kbuchegg)


Lesenswert?

Matthias schrieb:

> LED blinken lassen im ca. 1Hz Takt

Zeig mal dein Programm und deine Berechnung.
Ich wette du hast in deiner Berechnung einen Fehler mit Faktor 2 
eingebaut, weil du nicht bedacht hast, dass eine LED die 1 Sekunde hell, 
1 Sekunde dunkel ist, mit einer Frequenz von 0.5Hz blinkt und nicht mit 
1Hz.
Sprich: wenn du in einer Timer ISR den Ausgang toggelst, dann halbierst 
du damit die Aufruffrequenz der ISR am Ausgang.

von F. F. (foldi)


Lesenswert?

Bernie schrieb:
> Übrigens ist dieser interne Oszillator nach meiner
> Erfahrung erstaunlich genau (viel besser, als +/- 10%).
>
> Wenn du "rückwärts gerechnet" auf 2 MHz kommst, würde
> ich erst mal auf einen Programmierfehler tippen.
> Wahrscheinliche Werte sind 0,9...1,1 MHz ohne Veränderung
> des Fuse-Bits, oder 7,2...8,8 MHz mit Änderung.



... oder Schwankungen in der Versorungsspannung? Weiß ja nicht wie die 
Schaltung aussieht, aber auf dem Steckbrett kann das schon mal zum 
fehlerhaften Blinken führen (hatte ich gerade erst beim Tiny13).
100nF direkt am µC und auf einmal war das merkwürdige Verhalten weg.

von Matthias (Gast)


Lesenswert?

Hi,

> Zeig mal dein Programm und deine Berechnung.

Das Programm besteht nur aus einer variablen die mit dem Systemtakt 
hochzählt, ist dieser Wert eine Million toggelt die LED. An und Aus 
dauern ca. 1 Sekunde, ist ziemlich ungenau aber es ist definitiv kein 1 
MHz takt und auch kein 8 MHz Takt.

Das Fuse Bit zum achteln der Frequenz ist aus. Außerdem kann man ja die 
CLK source umstellen von "PLL CLK" auf "int. CLK mit 8 MHz", welche 
nimmt man ich habe gerade das erste einsgestellt.

> Abgleichen kann man die Frequenz des internen Oszillators
> mit dem OSCCAL-Register auf etwa 4...16 MHz.
> Ohne Änderung des FUSE-Bits bekommt man 0,5...2 MHz.

Hab dieses Register wie im Datenblatt steht auf 0xFF für 200% Highest 
Frequency gestellt und es verdoppelt auch die Frequenz. Aber ich bin 
immer noch nicht bei 8 MHz geschweige denn bei 16 MHz.

Hab ich irgendwas vergessen oder mache ich was falsch? Wegen der 
Spannungsversorgung ich habe einen IC Sockel der einen 100 nF 
Kondensator integriert hat.

Viele Grüße, Matthias

von Daniel H. (Firma: keine) (commander)


Lesenswert?

Wie schon gesagt, zeig mal dein Programm und deinen Aufbau. Wir haben es 
hier oft genug, dass Fragen gestellt werden, weil etwas nicht klappt, 
aber der Code angeblich korrekt wäre. Am Ende ist der Code dann doch 
nicht korrekt und es liegt daran. Mit welcher Optimierung compilierst du 
dein Programm? Und wild an den Clock-Einstellungen rumzuspielen würde 
ich lassen, denn damit kann man sich ganz schnell komplett aussperren, 
und dann wird es kompliziert den AVR wieder ans Laufen zu kriegen.

von Matthias (Gast)


Lesenswert?

also ich hab jetzt einmal meinen Code eingefügt, mit der Variante des 
eigestellten OSCCAL Register auf 200%, jetzt blinkt die LED wieder in 
einem Herz Takt, also an und aus ca. 1 sek. => aktuell eine Frequenz von 
4 MHz (ca.)
1
int main ()
2
{
3
  DDRB |= (1<<DDB1)|(1<<DDB3)|(1<<DDB4);   // LEDs als Ausgang
4
5
  OSCCAL = 0xFF;
6
  CLKPR = 0x00;
7
  while(1)
8
  {
9
    y++;
10
    if (y >= 2000000)
11
    {
12
      PORTB ^= (1<<red);
13
      y = 0;
14
    }
15
  }
16
  return 0;
17
}

von Daniel H. (Firma: keine) (commander)


Lesenswert?

Das ist aber nicht das vollständige Programm, lässt sich bei mir nicht 
kompilieren, "y" und "red" sind nicht definiert.

von Spess53 (Gast)


Lesenswert?

Hi

>>also ich hab jetzt einmal meinen Code eingefügt, mit der Variante des
>eigestellten OSCCAL Register auf 200%, jetzt blinkt die LED wieder in
>einem Herz Takt, also an und aus ca. 1 sek. => aktuell eine Frequenz von
>4 MHz (ca.)

Eine Aussage kannst du nur mit dem Assemblercode machen, der der 
Compiler erstellt. Mit deinem C-Code kann man das nur ahnen.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Matthias schrieb:
> Hi,
>
>> Zeig mal dein Programm und deine Berechnung.
>
> Das Programm besteht nur aus einer variablen die mit dem Systemtakt
> hochzählt, ist dieser Wert eine Million toggelt die LED.

Sorry. Aber das ist Blödsinn!

Daraus kannst du überhaupt nichts über das Zeitverhalten ableiten. Je 
nach Optimierungseinstellung deines Compilers kommen da Hausnummern 
raus, gegen die der Wasserstand in der Donau ein Präzissionsinstrument 
ist.

Du musst das schon nach den Regeln machen!


Wenn du ungefähr eine realistische Zeitablesung machen willst, dann geht 
das so
1
// Testprogramm für CPU Takt
2
// Hier die vermeintliche Taktrate des µC eintragen
3
// Im Beispiel hier: 1Mhz
4
 
5
#define F_CPU 1000000
6
 
7
#include <avr/io.h>
8
#include <util/delay.h>
9
 
10
// Hier die tatsächlich verwendeten Parameter angeben
11
 
12
#define LED_PORT    PORTB
13
#define LED_DDR     DDRB
14
#define LED_PIN     PB1
15
 
16
int main()
17
{
18
   LED_DDR |= 1 << LED_PIN;
19
 
20
   while (1)
21
   {
22
      LED_PORT ^= 1 << LED_PIN;
23
      _delay_ms(1000);
24
   }
25
 
26
   return 0;
27
}

Wenn dein µC mit 1 Mhz läuft, dann ist die LED 1 Sekunde ein und 1 
Sekunde aus. Läuft der µC mit 8Mhz dann ist das enstprechend nur 1/8 
Sekunde, es sei denn du trägst bei F_CPU die 8000000 ein. Dann ist es 
wieder 1 Sekunde.

Das ganze beruht darauf, dass dir der Compiler nur dann die notwendigen 
Werte für _delay_ms korrekt errechnen kann, wenn der F_CPU Wert mit der 
Realität des tatsächlichen Taktes übereinstimmt. Nur dann benötigt ein 
_delay_ms(1000) auch tatsächlich 1000 Millisekunden (also 1 Sekunde).


Alles was du mit selbstgebauten Warteschleifen machst, beruht immer auf 
irgendwelchen windigen Annahmen, wie der Compiler deinen Code übersetzt 
und ist daher eine ausgesprochen schlechte Idee.


WICHTIG:
Bei obigem Code muss der Optimizer auf -Os stehen. Nur dann stimmen die 
Zeiten, die _delay_ms wartet!

von Coder (Gast)


Lesenswert?

Nimm lieber so etwas wir __delay_cycles oder wie auch immer es heissen 
mag.

von Karl H. (kbuchegg)


Lesenswert?

Matthias schrieb:
> also ich hab jetzt einmal meinen Code eingefügt, mit der Variante des
> eigestellten OSCCAL Register auf 200%, jetzt blinkt die LED wieder in
> einem Herz Takt, also an und aus ca. 1 sek. => aktuell eine Frequenz von
> 4 MHz (ca.)
>
> int main ()
> {
>   DDRB |= (1<<DDB1)|(1<<DDB3)|(1<<DDB4);   // LEDs als Ausgang
>
>   OSCCAL = 0xFF;
>   CLKPR = 0x00;
>   while(1)
>   {
>     y++;
>     if (y >= 2000000)


Aha. Und diese Operationen macht dein µC in 0-Zeit, oder wie?
Folgt man deiner Argumentation, dann benötigt (laut dir) dein µC für das 
Durcharbeiten eines Schleifendurchlaufs nur 1 Taktzyklus.
Das ist 'ein klein wenig' zu optimistisch :-)

von Daniel H. (Firma: keine) (commander)


Lesenswert?

Ich habe mir mal "y" und "red" selbst definiert und das Ganze im 
Simulator laufen lassen. Mit Optimierung -O1 lande ich nach etwa 
12.000.000 Takten in der if-Abfrage. Macht also bei 8 MHz knapp 1,5 
Sekunden.

Eine zuverlässige Zeitmessung macht man auch nicht so, wie du sie 
programmiert hast. Du hast allein schon einen großen Denkfehler. Du 
sagst, du erhöhst pro Takt den Zähler um eins. In Wirklichkeit werden 
hier schon mehrere Takte benötigt, da du, um einen Wert von 2.000.000 
feststellen zu können eine 32 Bit Variable benötigt, der AVR jedoch eine 
8 Bit-Architektur hat und daher jedes Byte einzeln berechnen muss. Zudem 
brauchst du noch einige Takte um zu prüfen, ob der richtige Wert 
erreicht wurde, so dass die schlussendlich vergangene Zeit erheblich 
abweicht.

Nutz für sowas besser einen Timer mit ISR oder die zumindest 
entsprechenden delay-Funktionen.

von Matthias (Gast)


Lesenswert?

Super vielen Dank an alle, das nächste mal werde ich gleich meinen Code 
posten das würde vieles Abkürzen.

von Daniel H. (Firma: keine) (commander)


Lesenswert?

Noch ein Nachtrag, so wie du es programmiert hast ist die Abweichung 
sogar noch größer, denn wenn du auf 2.000.000 prüft (angenommen pro 
Inkrementierung vergeht ein Takt) müsste die LED bei 8 MHz nur 1/4s an 
bzw. aus sein. Damit ist das Ganze um den Faktor 6 langsamer als 
gewünscht ;)

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


Lesenswert?

Daniel H. schrieb:
> Beim Attiny25 ist standardmäßig der interne Oszillator mit 8 MHz
> aktiviert, das ist auch gleichzeitig die maximale intern erzeugbare
> Frequenz.

Ich entschuldige mich gleich vorab, weil mein Einwurf mit dem 
Thread-Thema wenig zu tun hat, aber trotzdem, zur Ehrenrettung des 
ATtiny25:

Die maximale nutzbare reguläre Frequenz des internen Oszillators ist 16 
MHz.

Die Serie ATtiny25/45/85 besitzt einen Frequenzvervielfacher (8-fach), 
der für den Timer1 genutzt wird. Aus diesem kann die CPU getaktet werden 
(nach einem Teiler durch 4). Dadurch kann die CPU mit der doppelten 
regulären RC-Oszillator-Frequenz laufen.

OSCCAL arbeitet unabhängig davon und kann zusätzlich genutzt werden, um 
die Frequenz weiter zu erhöhen. Allerdings ist bei ca. 21 MHz Schluss, 
weil der Frequenzvervielfacher (PLL) nicht schneller als etwa 85 MHz 
schwingt. Steht jedenfalls im Datenblatt – ausgereizt habe ich das noch 
nicht.

von Daniel H. (Firma: keine) (commander)


Lesenswert?

Hast Recht, die PLL hatte ich vergessen :)

von Peter-Jan P. (pjp)


Lesenswert?

Das Problem ist hier, dass der Wert des clock prescalers nicht gesetzt 
wird. Man kann den Wert nicht einfach in das Register CLKPR schreiben, 
sondern muss erstmal das höchste Bit setzen und dann in einem weiteren 
Zugriff innerhalb von 4 Taktzyklen des gewünschten Wert einstellen.
Das Problem wird im Beitrag "AVR clock prescaler (CLKPR) und gcc-Codeoptimierung" 
genauer beleuchtet.

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.