ATtiny85 Counter/Timer0 Input for Frequency Capture

Hey Everyone,

I've been reading quite a bit and searching around a lot and found a lot of things regarding this specific task, but I never found anything conclusive or working regarding this application. I think I have an OK start, but need a little kick in the right direction to make sure I'm going about this the right way.

So here's the Background/Theory:
ATtiny85 8-bit Counter/Timer0 can be set count up with an external signal(the signal to be measured)
Timer1
There's an overflow interrupt on the counter which fires an "ISR" and will reset the counter(I think)
Counter/Timer0 is on Pin 7 (as far as I understand)

Standard Method 1:For Higher Frequencies
So, feed the signal to be measured into Counter/Timer0(Pin7) and over some fixed (user defined) interval of time count the amount of (overflow interrupts*256bits)+ the current counter value to get ticks/time period. From there, calculate frequency. Sounds simple to me...

Standard Method 2:For Lower Frequencies
Fire an Interrupt when Pin7 goes high. Get the current Millis/Micros. When the interrupt Fires again, get the time, detach the interrupt and calculate Time2-Time1=Period and calculate the frequency. Maybe take a few samples and average them. Also, sounds simple.

Theory Implementation(and setting up the ATtiny's registers):
(and this is where it gets fuzzy to me as setting the related registers and whatnot is not exactly my expertise but I've been reading quite a bit and started to jot some things down based on some other code I saw. I started with some existing code FreqCount and FreqMeasure to adapt the code for a ATtiny85. Of course, it's not a straight forward as there's no input capture unit (ICP) to adapt FreqMeasure which would probably make things a little more straight forward and needing certain counter/timer capabilities for both timer0 and timer1 make FreqCount adaptation a little trickier too.

I'm trying to think outside the box a little, but my ideas may just be ludicrous, so any ideas would be helpful. I'd like to start from scratch somewhat to make a simple frequency measuring method.

Here's a couple ideas I had that I hope would work in pseudo code(we can get into register specifics later)
Alternative 1

Wire signal into Counter/Timer0(Pin7)
Setup Timer/Counter0 Registers for rising edge input
Setup Overflow ICR (Overflow Interrupt)
ISR Overflow{InterruptCount++}

InterruptCount =0
Set Timer/Counter0=0 //clear timer
StartMicros=CurrentMicros
AttachTimer0/enable
While Loop StartMicros+LoopTime>CurrentMicros
{
//Do something(counter is counting)
}
Ticks = Counter0 value+(Interrupt count*255)
Disable Counter
Calculate Frequency = (Ticks/looptime)*1,000,000 = hertz

Alternative 2-Period Measure

Wire signal into Counter/Timer0(Pin7)
Setup T/C0 Registers for rising edge input
Setup Compare Register = 2
Setup Compare Register Interrupt(I need to better understand this)
Clear Flags

ISR Compare(when two tick are reached)
{
Set Period = CurrentMicros-StartMicros;
}

Set TC0=0 //clear timer
StartMicros=CurrentMicros
period=0;
AttachCounter/Timer0
Loop While  Period = 0
{

}
Disable Counter
Calculate Frequency =(1/period)*1,000,000=Hz

Just some ideas and wondering if they're physically possible. I'm open to trying some other things out as well. I'll make a followup post with some of the register settings and trying to test those actual ideas.

Thanks!

Update:

I opted for "Standard Method 2" because I need T0/Pin7 for I2C so I'm going to use interrupts to count the pulses. Also, since PCINT/PCMSK registers trigger only pin change, not edge level interrupts, I have to filter only for high. Simple enough.

Anyway, I've implements a simple solution and My results are not as accurate as I'd like. 5% error if my measurements are correct. I expected much better at lower frequencies, but maybe this is due to the code/routine.

Here's what my ISR looks like:

//PCINT Interrupt
ISR(PCINT_VECTOR)
{
  if (ReadPinState()>0)
  {
    InterruptCount++;
    switch(InterruptCount)
    {
      case 1: t1=micros();
              break;
      case 2: period=micros()-t1;
              InterruptCount=0;
              break;
      default:
              InterruptCount=0;
              break; 
    }

  }
}

I'm wondering if there is a better method to get better timing/accuracy. More samples? Different timer methods?

Nick Gammon gives an excellent write on various techniques, including the t85:

My results are not as accurate as I'd like. 5% error if my measurements are correct.

The internal oscillator is not very accurate, it can be off by 10%.
You can tune it to be within 1%

Update:
I just tried my sketch below using a tuned ATtiny85.

With a input frequence at 54.366 HZ my output was 54592.
Thats an error of 0,4%

#include <TinyDebugKnockBang.h>

volatile unsigned long Count;
long previousMillis = 0; 
long interval = 1000;

ISR(PCINT0_vect) {
  Count++; 
}

void setup()
{ 
  OSCCAL = 0x69;
  Debug.begin(250000);
  Debug.println("Freq......");
  GIMSK = _BV(PCIE);    // Enable pin change interrupt Table 9.3.2
  PCMSK = _BV(PCINT4);  // Enable the interrupt for only pin 4,Table 9.3.4
}

void loop ()   {
unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;   
    Debug.println("Count  ");
    Debug.println(Count/2);
    Count=0;
  }
} //loop

@Erni, awesome!

I'm trying to find out how to tune my Attiny. I can't find a complete guide and having some issues. I'm trying to use my Deumilanova for facilitate the serial communication to tune it. Any ideas?

I just made another thread here: Tuning Internal Oscillator of ATTiny85 - Hardware Setup for Two Way Serial? - Microcontrollers - Arduino Forum

I got it calibrated with the Poor Man's Tuner. Though I know each chip's results will be different mine is :
OSCCAL = 0x45;
Calibration steps are linked in my previous post/thread above.

Anyway, I added that line into my code and it's MUCH more accurate...Something I can live with. I'd like better, but this will do for now.

The problem I'm having now is some delays in getting the correct value that I'm getting with my I2C communication with another device. I'm sending the measured period to the master device...

I'm trying to use a DigiSpark with USB & AT85 to measure frequencies up to 400kHz. I'm going to try using the pulseIn() function. Will let everyone know how it turns out and will compare results with my Oscope.

Is there a reason that you're using a tiny85 instead of the 84 (or 841)? Those have enough pins that you can put a crystal on them, and have a good (16-bit with option for external clock) timer (841 has 2) that you can use without breaking millis/etc by using timer0....