Forum: Mikrocontroller und Digitale Elektronik [Arduino] Quarz-Genauigkeit (AVRGCC)


von Marek N. (Gast)


Lesenswert?

Hallo,

ich habe folgendes Testprogramm eingespielt, das die LED eigentlich mit 
488 Hz und paar Zerquetschten flackern lassen sollte. Leider sind meine 
Zerquetschten viel zu klein und ich messe um die 487 Hz.
Mal die Periodenzeiten gemessen und statt der 2,048 ms messe ich 2,0507 
ms.

Kann der Quarz echt über 1300 ppm daneben liegen?

Hardware-Plattform ist ein Sainsmar Arduino Uno R2 mit winzigem Quarz im 
6-poligen Gehäuse.

Das Programm arbeitet interruptgesteuert und sollte eigentlich richtig 
sein.

Beste Grüße, Marek

P.S. Gemessen mit ELV FC7008
1
/*
2
  Experimente mit Timern
3
  Timer0 im Normal Mode und Port-Toggle per Interrupt
4
  DB1BMN
5
  2013-03-25
6
*/
7
8
#include<avr/io.h>
9
#include<avr/interrupt.h>
10
11
#define LEDPORT     PORTB
12
#define LEDPORT_ddr DDRB
13
#define LEDPORT_in  PINB
14
#define LED         PB5
15
16
17
ISR (TIMER0_OVF_vect)
18
{
19
  /* Interrupt Aktion alle
20
  (16MHz/64)/256 Hz = 976,5625 Hz
21
  
22
  1/976,5625 s = 1,024 ms  
23
  */
24
25
  LEDPORT_in  |=  (1<<LED); // Toggle LED
26
}
27
28
29
int main(void)
30
{
31
32
  // Port für LED konfigurieren
33
  LEDPORT_ddr |=  (1<<LED);
34
  
35
  // Timer0 Normal Mode (Mode 0; default)
36
  // (WGM02 WGM01 WGM00) = 000
37
  TCCR0A  &=  ~(1<<WGM01)
38
          &   ~(1<<WGM00);
39
  TCCR0B  &=  ~(1<<WGM02);
40
41
  
42
  // Timer0 Prescaler 64
43
  TCCR0B |= (1<<CS01)
44
         |  (1<<CS00);
45
  // Ab hier läuft der Timer mit 16 MHz / 64 = 250 kHz (Ticks)
46
  // und erzeugt alle 256 Ticks einen Overflov
47
48
  // Timer0 Overflow Interrupt einschalten
49
  TIMSK0  |=  (1<<TOIE0);
50
51
  // alle Interrupts freigeben
52
  sei();
53
54
55
  while(1)
56
  {
57
    // NOP
58
  }
59
  return 0;
60
}

von Rainer U. (r-u)


Lesenswert?

Wie genau ist denn Dein Messgerät? (also Genauigkeit, nicht Auflösung)

Normale Quarze sollten so 30-50 ppm haben.

von 6A66 (Gast)


Lesenswert?

Marek N. schrieb:
> Hallo,
>
> ich habe folgendes Testprogramm eingespielt, das die LED eigentlich mit
> 488 Hz und paar Zerquetschten flackern lassen sollte. Leider sind meine
> Zerquetschten viel zu klein und ich messe um die 487 Hz.
> Mal die Periodenzeiten gemessen und statt der 2,048 ms messe ich 2,0507
> ms.
>
> Kann der Quarz echt über 1300 ppm daneben liegen?

Normal nicht, bei schlechter Beschaltung von Quarzen und den verkehrten 
Typen ist aber ALLES möglich! 1300ppm ist aber unwahrscheinlich.

Aber auch die besten Scopes (hier bei usn Agilent) haben eine Abweichung 
von bis zu 30ppm und mehr. Um Dein Messgerät zu kalibrieren benötigts Du 
einen genauen VCTCXO, damit weisst Du dann wie Dein Scope/Messgerät 
abweicht. Bei den meisten Messgeräten ist halt auch nur ein Quarz 
drinnen.

rgds

von Werner M. (Gast)


Lesenswert?

Marek N. schrieb:
> Kann der Quarz echt über 1300 ppm daneben liegen?

Nimm einen Radioempfänger auf der Quarzfrequenz oder einer ungeraden 
Oberwelle und hör es dir an. Die Rundfunksender halten (bis auf 
Ausnahmen) ihre Frequenz beinahe mit Atomuhrgenauigkeit.

von M. N. (Gast)


Lesenswert?

Marek N. schrieb:
> Kann der Quarz echt über 1300 ppm daneben liegen?

Offensichtlich ja, es soll ja alles billig sein.

Der FC7008 hat einen 25MHz OCXO und liefert für diesen Vergleich 
durchaus 'richtige' Ergebnisse.
Darüber hinaus kann er sogar 0 Hz messen :-)

von Peter R. (pnu)


Lesenswert?

Bei sechspoligem Gehäuse tippe ich auf Keramik-Resonator.

Auf meinem Arduino-board läuft z.B. der atmega8 (USB-RS232-Umsetzer) mit 
16 MHz Quarz und die CPU (atmega2560) mit einem 6poligen 
Keramikschwinger.

Die Frequenzablage passt auch zu einem Keramikschwinger.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Btw:

Nicht:
1
LEDPORT_in  |=  (1<<LED); // Toggle LED

sondern:
1
LEDPORT_in  =  (1<<LED); // Toggle LED

Ansonsten toggeln auch alle die Ausgänge, deren Eingänge gerade
eine 1 zurücklesen.

von Marek N. (Gast)


Lesenswert?

Hallo,

ja, es handelt sich tatsächlich um so einen kleinen Köttel: 
http://www.reichelt.de/Filter/CSTCE-16-0/3/index.html?;ACTION=3;LA=446;ARTICLE=89705;GROUPID=3175;artnr=CSTCE+16%2C0
Dieser darf ja sogar 5000 ppm daneben liegen. Gut, dann werde ich nen 
richtigen Quarz einbauen. Wundere mich eh, warum die für den USB-ATmega 
so einen verwendet haben, offenbar ist das Timing dort strenger.


Jörg Wunsch schrieb:
> sondern:
>
1
LEDPORT_in  =  (1<<LED); // Toggle LED
>
> Ansonsten toggeln auch alle die Ausgänge, deren Eingänge gerade
> eine 1 zurücklesen.

Nachvollzogen und verstanden. Vielen Dank!

Beste Grüße, Marek

von Thomas E. (thomase)


Lesenswert?

Jörg Wunsch schrieb:
> Ansonsten toggeln auch alle die Ausgänge, deren Eingänge gerade
> eine 1 zurücklesen.
HÄÄ????
Was wird denn da zurückgelesen?

Daraus: PINB |= (1 << 2);
wird das: sbi  0x16, 2
und dann toggelt PB2 und nichts anderes.

Oder wer ist hier auf dem Holzweg?

mfg.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Marek N. schrieb:
> Wundere mich eh, warum die für den USB-ATmega
> so einen verwendet haben, offenbar ist das Timing dort strenger.

Ja, das USB-Timing ist ziemlich strikt.  Für ein lowspeed-Device
genügt die Toleranz eines Keramikschwingers noch, für ein
fullspeed-Device aber nicht mehr.

Thomas Eckmann schrieb:
> HÄÄ????

Du solltest vorsichtiger in deinen Äußerungen werden …

> Was wird denn da zurückgelesen?

PINB

> Daraus: PINB |= (1 << 2);
> wird das: sbi  0x16, 2
> und dann toggelt PB2 und nichts anderes.

Nein.  Es toggelt auch alle die Pins, die beim Rücklesen von PINB eine
1 haben.

Hinweis: SBI ist eine read-modify-write-Operation …

von Falk B. (falk)


Lesenswert?

@  Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>Hinweis: SBI ist eine read-modify-write-Operation …

Mag sein, aber diese bezieht sich nur auf EIN Bit. Da bleibt die 
Quizzfrage, was der Compiler aus

PINB |= (1 << 2);

macht?

sbi PINB, 2

oder

in r16, PINB
ORI r16, 0x04
out PINB, r16

Hmmm?

von Thomas E. (thomase)


Lesenswert?

Jörg Wunsch schrieb:
> Nein.  Es toggelt auch alle die Pins, die beim Rücklesen von PINB eine
> 1 haben.
> Hinweis: SBI ist eine read-modify-write-Operation …

Also konkret:
Wenn PD7 1 ist und PD6 mit sbi (PIND|=(1<<6) toggelt, toggelt PD7 auch 
und wird 0. Danach toggelt er dann nicht mehr, weil er ja 0 ist?

Ich hoffe jetzt, daß ich das falsch verstanden habe, sonst kann ich 
meine Controller alle wegschmeissen, weil die kaputt sind.

mfg.

von Viktor N. (Gast)


Lesenswert?

Was eben nicht dasselbe sein muss.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner schrieb:

> Da bleibt die
> Quizzfrage, was der Compiler aus
>
> PINB |= (1 << 2);
>
> macht?
>
> sbi PINB, 2
>
> oder
>
> in r16, PINB
> ORI r16, 0x04
> out PINB, r16
>
> Hmmm?

Das bleibt bezüglich der Wirkung jedoch gleich.

Darauf, dass SBI ein read-modify-write ist, welches sich stets auf das
ganze Register bezieht (wie sonst sollte man es auch implementieren?),
wird an anderer Stelle in den Datenblättern teilweise hingewiesen: wo
es um das Löschen von Interruptflags geht.  Wimre beim ADC, bei dem
das Interruptflag ja in einem normalen Steuerregister steht.

Thomas Eckmann schrieb:
> Wenn PD7 1 ist und PD6 mit sbi (PIND|=(1<<6) toggelt, toggelt PD7 auch
> und wird 0. Danach toggelt er dann nicht mehr, weil er ja 0 ist?

Ja, aber selbst das Zurückschalten auf 0 dürfte ja nicht beabsichtigt
gewesen sein.

von Hawa M. (hawamand)


Lesenswert?

Mein Arduino Uno Rev.3 hat eine Gangabweichung von ca. 80ppm:
Beitrag "Gangabweichung Quarz auf Arduino Uno Board"

von Falk B. (falk)


Lesenswert?

@  Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>Darauf, dass SBI ein read-modify-write ist,

OK.

> welches sich stets auf das
>ganze Register bezieht (wie sonst sollte man es auch implementieren?),

Einspruch! Das KANN man mittels Hardware-Bitmaske machen, die sowieso 
gebraucht wird, um das einzelne Bit anzusprechen!

Wie es REAL aufgebaut ist, weiß nur Atmels Hardwareabteilung.

von Falk B. (falk)


Lesenswert?

Naja, man sollte vielleicht weniger philosiophieren und mal fix einen 
Test in ASM machen.

von Thomas E. (thomase)


Lesenswert?

Jörg Wunsch schrieb:
> Ja, aber selbst das Zurückschalten auf 0 dürfte ja nicht beabsichtigt
> gewesen sein.
Aber PD7 wird nicht 0.
Wo kriege ich denn jetzt 644p her, die diesen Bug nicht haben?


mfg.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas Eckmann schrieb:
> Aber PD7 wird nicht 0.

OK, dann ist SBI auf PINx offenbar anders implementiert als auf anderen
Registern (schön, wenn alles so konsistent ist ;-).

Trotzdem ist ein |= auf PINx gefährlich: ob es den gewünschten Zweck
erfüllt oder nicht, hängt nun davon ab, ob der Compiler es als SBI
umsetzt oder nicht, und damit beispielsweise von den Optimierungs-
einstellungen.  Die explizite Zuweisung nur des zu toggelnden Bits
ist dagegen sicher, dass sie genau das tut.

von Thomas E. (thomase)


Lesenswert?

Jörg Wunsch schrieb:
> Trotzdem ist ein |= auf PINx gefährlich: ob es den gewünschten Zweck
> erfüllt oder nicht, hängt nun davon ab, ob der Compiler es als SBI
> umsetzt oder nicht,
Ach komm. Daß der Compiler das bei -0s richtig auf sbi umsetzt und es 
ohne Optimierung nicht tut, weisst du besser als ich.
Und solange man das weiss, kann man das auch bedenkenlos einsetzten.
Wenn man allerdings Zweifel daran hat, ist die Lösung nicht, es mit "=" 
sondern sbi mit Inline-Assembler zu implementieren.
Sonst würde das nämlich bedeuten, daß man diese performantere Variante 
des Toggelns in C gar nicht nutzen kann.

mfg.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas Eckmann schrieb:
> Sonst würde das nämlich bedeuten, daß man diese performantere Variante
> des Toggelns in C gar nicht nutzen kann.

Jetzt muss ich mal fragen: häh?

Warum kann man diese denn nicht benutzen?

Ein simples

PINB = 1;

toggelt völlig problemlos PB0, egal ob mit oder ohne Optimierungen.
(Ohne Optimierung allerdings kaum wirklich performanter, als wenn
man gleich PORTB ^= 1; schreibt.)

von Falk B. (falk)


Lesenswert?

@  Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)

>Jörg Wunsch schrieb:
>> Trotzdem ist ein |= auf PINx gefährlich: ob es den gewünschten Zweck
>> erfüllt oder nicht, hängt nun davon ab, ob der Compiler es als SBI
>> umsetzt oder nicht,

Sehe ich auch so. Es ist syntaktisch ein-eindeutig.

>Ach komm. Daß der Compiler das bei -0s richtig auf sbi umsetzt und es
>ohne Optimierung nicht tut, weisst du besser als ich.

Jetzt wissen wir es alle.

>Und solange man das weiss, kann man das auch bedenkenlos einsetzten.

Nö. Das ist eine schöne Stolperfalle, hier ausnahmsweise mal umgekehrt. 
Ohne Optimierung läuft sie NICHT, nur mit Optimierung. Sowas STINKT nach 
Schuß ins Knie und unsauberen Methoden.

>Wenn man allerdings Zweifel daran hat, ist die Lösung nicht, es mit "="
>sondern sbi mit Inline-Assembler zu implementieren.

Quark.

>Sonst würde das nämlich bedeuten, daß man diese performantere Variante
>des Toggelns in C gar nicht nutzen kann.

Quark die IIte. Siehe oben!

von Thomas E. (thomase)


Lesenswert?

Jörg Wunsch schrieb:
> PINB = 1;
ergibt aber
  PINB = 1;
  3c:  81 e0         ldi  r24, 0x01  ; 1
  3e:  86 bb         out  0x16, r24  ; 22

Aber das will ich nicht haben.

Ich will das:
PINB |= 1;
  3c:  b0 9a         sbi  0x16, 0  ; 22

weil es kürzer ist.

Ein simples PORTB ^= 1; tut es übrigends auch.

Falk Brunner schrieb:
> Quark.
Ja ne is klar.
Mit Quark scheinst du dich auszukennen:
> Nö. Das ist eine schöne Stolperfalle, hier ausnahmsweise mal umgekehrt.
> Ohne Optimierung läuft sie NICHT, nur mit Optimierung. Sowas STINKT nach
> Schuß ins Knie und unsauberen Methoden.

> Ohne Optimierung läuft sie NICHT, nur mit Optimierung.
Wo ist das Problem, solange ich das weiss?

mfg.

von Falk B. (falk)


Lesenswert?

@  Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)


>> PINB = 1;
>ergibt aber
>  PINB = 1;
>  3c:  81 e0         ldi  r24, 0x01  ; 1
>  3e:  86 bb         out  0x16, r24  ; 22

Ohne Optimierung!

>Aber das will ich nicht haben.

>Ich will das:
>PINB |= 1;
>  3c:  b0 9a         sbi  0x16, 0  ; 22

MIT Optimierung!

>weil es kürzer ist.

2 Byte mehr im Flash, gleich Anzahl Takte ;-)

>> Ohne Optimierung läuft sie NICHT, nur mit Optimierung.
>Wo ist das Problem, solange ich das weiss?

Wenn du das nicht als Problem erkennst ist das dein Problem ;-)
Und das alles wegen einem einzigen | Zeichen.
Das wird ein neuer Sparklassiker, gleich nach den LED-Vorwiderständen . 
. .
Scheinbar greift das neue Sparpaket der Bundesregierung selbst hier im 
Forum schon!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas Eckmann schrieb:

> Ich will das:
> PINB |= 1;
>   3c:  b0 9a         sbi  0x16, 0  ; 22
>
> weil es kürzer ist.

Erbsenzähler. ;-)

> Ein simples PORTB ^= 1; tut es übrigends auch.

Allerdings noch länger.

Habe gerade gesehen, dass das Datenblatt die SBI-Variante in der Tat
sanktioniert:
1
Note that the SBI instruction can be used to toggle one single
2
bit in a port.

Damit ist es zumindest sicher, dass es sich immer so benimmt.

Hier das Gegenstück beim ADIF-Bit:
1
· Bit 4 ­ ADIF: ADC Interrupt Flag
2
3
[...] Beware that if doing a Read-Modify-Write on ADCSRA,
4
a pending interrupt can be disabled. This also applies if the SBI
5
and CBI instructions are used.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> Das wird ein neuer Sparklassiker, gleich nach den LED-Vorwiderständen

Ach, LED-Vorwiderstände habe ich auch schon eingespart. :-)  War mir
allerdings sicher, dass die Kanalwiderstände der Ausgangsstufen
dann problemlos deren Funktion übernehmen konnten.  Letztlich ist
es ja egal, an welcher Stelle die Energie verheizt wird.

von Thomas E. (thomase)


Lesenswert?

Jörg Wunsch schrieb:
> Allerdings noch länger.
Deswegen nimmt man ja auch PIN.

Falk Brunner schrieb:
> Wenn du das nicht als Problem erkennst ist das dein Problem ;-)
Es ist eben nicht mein "Problem".
Dann musst du auch den Takt auf einen festen Wert zementieren. Denn wenn 
man vergisst F_CPU zu definieren oder ggf. zu ändern, kann das noch viel 
schlimmere Auswirkungen haben, als festzustellen, daß sich plötzlich der 
Pullup von einem Taster in Wohlgefallen aufgelöst hat. Dann muss man 
natürlich wissen, woran es liegen kann. Aber das ist bei einer falschen 
Baudrate auch nicht anders.

Falk Brunner schrieb:
> Das wird ein neuer Sparklassiker, gleich nach den LED-Vorwiderständen .
Das ist ja nun wirklich Quark. Aber trotzdem nicht schlecht. Immerhin 
nicht vor den Vorwiderständen.

Jörg Wunsch schrieb:
> Damit ist es zumindest sicher, dass es sich immer so benimmt.
Siehste. Die Stelle wollte ich auch gerade rauskopieren.

mfg.

von Falk B. (falk)


Lesenswert?

@  Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>[...] Beware that if doing a Read-Modify-Write on ADCSRA,
>a pending interrupt can be disabled. This also applies if the SBI
>and CBI instructions are used.

MOMENT! Heißt dass, wenn ich per SBI/CBI auf ein ANDERES Bit als ADIF 
zugreife, dass ADIF gelöscht wird wenn es aktiv (=1) ist, weil die 
Maskierung der Bits in dem Befehl buggy ist? Also die Hardware die Daten 
des Registers liest, nur das eine Bit manipuliert und alles 
zurückschreibt, auch das schon gesetzte ADIF, was zu seiner Löschung 
führt? Hmm, Bug oder Feature? Ok, jetzt verstehe ich deinen Einwand.

Hmm, für normale Register ist das ja kein Problem, für Spezialregister 
mit "clear on 1" schon. Da für die einzelnen, unterschiedlichen 
Spezialregister extra Dekoder einzubauen wäre wahrscheinlich zu 
aufwändig, wenn gleich möglich.

Ist aber ein zusätzliches Argument FÜR

PINB = 1;

!!!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> MOMENT! Heißt dass, wenn ich per SBI/CBI auf ein ANDERES Bit als ADIF
> zugreife, dass ADIF gelöscht wird wenn es aktiv (=1) ist,

Ja.

> weil die
> Maskierung der Bits in dem Befehl buggy ist?

Nein.  Die ist nicht buggy.  Ein Bug wäre es, wenn das Verhalten
nicht so (oder gar anders) dokumentiert wäre.  Es ist aber so
dokumentiert, damit ist es per se kein Bug, sondern bestenfalls
unschön. ;-)

Immer dran denken: "An undocumented feature is called a bug."

von m.n. (Gast)


Lesenswert?

Marek N. schrieb:
> Hallo,
>
> ja, es handelt sich tatsächlich um so einen kleinen Köttel:
> 
http://www.reichelt.de/Filter/CSTCE-16-0/3/index.html?;ACTION=3;LA=446;ARTICLE=89705;GROUPID=3175;artnr=CSTCE+16%2C0
> Dieser darf ja sogar 5000 ppm daneben liegen.

Beim UNO R3 bin ich auch über den keram. Resonator gestolpert, wo ich 
eigentlich Quarzstabilität erwartet hatte. Für Testaufbauten greife ich 
daher das quarzstabile 16MHz Taktsignal des ATmega16U2 ab. Nach dem 
Entfernen des Resonators reicht eine kurze Drahtverbindung auf der 
Platinenunterseite des UNO R3, um beide XTAL1 Siganle zu verbinden. 
Siehe Bild: 
http://www.mino-elektronik.de/bilder/Fmeter_6LED/UNO_R3_takt_1_5_1.jpg
Das ist keine perfekte Lösung, aber auf die Schnelle ohne Aufwand 
erledigt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Falk Brunner schrieb:

> Quizzfrage, was der Compiler aus
>
> PINB |= (1 << 2);
>
> macht?
>
> sbi PINB, 2
>
> oder
>
> in r16, PINB
> ORI r16, 0x04
> out PINB, r16

beides ist möglich, und sogar indirekter Zugriff ist denkbar.

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.