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
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.
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.
Ü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.
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.
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.
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
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.
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
intmain()
2
{
3
DDRB|=(1<<DDB1)|(1<<DDB3)|(1<<DDB4);// LEDs als Ausgang
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
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
intmain()
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
return0;
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!
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 :-)
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.
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 ;)
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.
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.