# Comparing Crystals using Int0 and Int1

When you get yourself a new Arduino how can you check its crystal freqency?
Well, if you got the PDIP version and you are very skilled you might grab the quartz signal at pin 9 or 10 of the chip:

and you will see a signal like this on an analogue scope:

These are the results of a sample of Arduinos I got:

```15.887.581
15.889.320
15.892.500
15.945.056
15.984.439
15.993.904
16.000.709
16.000.780
16.001.452
16.005.733
16.005.838
```
And I must admit my frequency counter is not new so all the values could be off by some 100 Hz.

With the SMD version it will be hard to get access to CPU pins 7 or 8 (32 TQFP or 32 MLF) or pins 5 or 6 (28 MLF). So you better divide the clock frequency by two in order to pick the signal at one of the header pins. These few lines of code do the job:

 ```const byte outpin  = 11; void setup() {  // generate 8 MHz signal at outpin:  TCCR2A = B01000010;  TCCR2B = B00000001; // Prescaler: 1  pinMode(outpin, OUTPUT); } void loop() {} ```

and you get the 8.000.000 Hz signal at pin-11 of your Arduino.

 Recently I wanted to compare the clock frequencies of two Arduinos, and I thought to let them send their pin-11-outputs to the interrupt inputs of a third Arduino (Interrupt pins 2 and 3). It could be done easily like this: The upper and the lower ones are those to be compared. Their pin-11-outputs go to the interrupt input pins of the middle one.
The output of the lower one goes to pin-2 invoking isr0 which increments the value of count.
The output of the upper one goes to pin-3 invoking isr1 which decrements the value of count.

If their frequencies are the same the value of count will remain to zero. Otherwise count shows the difference of the frequencies. This little program will compare the pulse frequencies of two souces:

 ```long count = 0; long dt = 10000; long t = millis() + dt; /* without this semaphor you will get * erroneous results occasionally */ boolean f = false; void setup() {  attachInterrupt(0, isr0, RISING);  attachInterrupt(1, isr1, RISING);  f = true; } void loop() {  if (millis() < t) return;  f = false;  t = t + dt;  Serial.println(count);  count = 0;  f = true; } void isr0() { if (f) count++; } void isr0() { if (f) count--; } ```

At the end of the day, you might get results like this:

You can clearly see that one Arduino produces 11 or 12 pulse more than the other in each ten second interval giving a difference of about 1.15 pulses per second. As the prescaler was set to 256 you have to multiply this value by 512 to get the difference of the crystal frequencies.
Unfortunately, it only works up to input frequencies of some 50 kHz. At higher frequencies the ISR won't be finished before the next pulse arrives. Why is it so? The reason is: the compiler would not know what you are doing inside the ISR, and so it generates PUSHs and POPs for nearly everything causing an overhead of about 5 μs. So you have to change the prescaler to 256. That will take a long time to get some results.

If you decide to code the ISR yourself and force the compiler to hold the count variable in certain registers no PUSHs and POPs are necessary. Doing this the program accepts frequencies up to 125 kHz.
So, instead of calling `attachInterrupt` you have to use a specific parameter for the ISR

```ISR(INT0_vect, ISR_NAKED)
```
Using `NAKED` no PUSHs, POPs or RETURNS will be generated.
The declaration
```register byte b1 asm("r4");
```
gives you fast access to that byte, eliminates the need for PUSH/POP and it won't be overwritten by other commands.

This version locates two variables in fixed MCU registers which is not supported by IDE versions later than 1.6.6.

The complete source is here:

 ```/* see also:   http://www.phanderson.com/arduino/ext_int.html   Interrupt-Pins ATmega328: Pin-2 and Pin-3   works up to 125kHz */ const byte tcnt2 = 131; register byte sreg asm("r2");   // temporary storage for SREG register byte eins asm("r17");  // constant as there is no ADDI instruction register byte b0 asm("r16");    // SUBI, requires register number above 15 register byte b1 asm("r4"); register byte b2 asm("r5"); register byte b3 asm("r6"); volatile long count; boolean tunix = true; void setup() {  Serial.begin(9600);  Serial.println(__FILE__);  // setup Timer2:  TCCR2B = 0;        // Disable Timer2 while we set it up  TCNT2  = tcnt2;    // Reset Timer Count to tcnt2 out of 255  TIFR2  = 0;        // Timer2 INT Flag Reg: Clear Timer Overflow Flag  TIMSK2 = 1;        // Timer2 INT Reg: Timer2 Overflow Interrupt Enable  TCCR2A = 0;        // Timer2 Control Reg A: Wave Gen Mode normal  TCCR2B = 5;        // Timer2 Control Reg B: Timer Prescaler set to 128  // setup Int0, Int1:  EICRA = B00001010; // configure both for falling  EIMSK = B00000011; // mask for INT1 and INT0 } void loop() {  if (tunix) return;  Serial.println(count);  b0 = 0;  b1 = 0;  b2 = 0;  b3 = 0;  EIMSK = B00000011; // reenable INT1 and INT0  tunix = true; } //Timer2 Overflow Interrupt Vector, called every 1ms ISR(TIMER2_OVF_vect) {  static int msCnt;  if (++msCnt > 999) {    EIMSK = 0; // disable INT1 and INT0    ((byte*)(&count))[0] = b0;    ((byte*)(&count))[1] = b1;    ((byte*)(&count))[2] = b2;    ((byte*)(&count))[3] = b3;    tunix = false;    msCnt = 0;           // Resets the interrupt counter  }  TCNT2 = tcnt2;     // Reset Timer to tcnt2 out of 255  TIFR2 = 0;         // Timer2 INT Flag Reg: Clear Timer Overflow Flag }; ISR(INT0_vect, ISR_NAKED) { // count++;  asm("in   %4,__SREG__" "\n\t"   // save flags      "ldi  %5,1"  "\n\t"      "add  %0,%5" "\n\t"      "adc  %1,r1" "\n\t"      "adc  %2,r1" "\n\t"      "adc  %3,r1" "\n\t"      "out __SREG__,%4" "\n\t"  // restore flags      "reti"      :      "=r" (b0),      "=r" (b1),      "=r" (b2),      "=r" (b3),      "=r" (sreg),      "=r" (eins)      : : ); } ISR(INT1_vect, ISR_NAKED) {  asm("in   %4,__SREG__" "\n\t"   // save flags      "subi %0,1"  "\n\t"      "sbc  %1,r1" "\n\t"      "sbc  %2,r1" "\n\t"      "sbc  %3,r1" "\n\t"      "out __SREG__,%4" "\n\t"  // restore flags      "reti"      :      "=r" (b0),      "=r" (b1),      "=r" (b2),      "=r" (b3),      "=r" (sreg)      //"=r" (save)      : : ); } ```

With this program you get the difference faster and with higher precision:

As can be seen the crystals are quite stable, and there is a constant difference of 5 Hz. Due to the prescaler the crystals differ by 640 Hz that is 40 ppm.

contact: nji(at)gmx.de