#include <avr/io.h>
#include <avr/interrupt.h>

#define MARGIN_RPM 1
unsigned  char digit[] = {0x88, 0xEB, 0x4C, 0x49, 0x2B, 0x19, 0x38, 0x8B, 0x08, 0x0B};

volatile  long timer=0, pulse=0;
volatile long ict_10pulse_before, ict_now;
volatile unsigned int rpm=0;
volatile unsigned int target_rpm=60;

SIGNAL(SIG_OVERFLOW1)
{
 timer++;

 if( timer - (ict_now >> 16) > 5)
  rpm = 0;

 if( target_rpm > rpm )
  OCR0 = (OCR0 == 255) ? 255 : OCR0+1;
 else if( target_rpm < rpm )
  OCR0 = (OCR0 == 0 ) ? 0 : OCR0-1;

}

SIGNAL(SIG_INPUT_CAPTURE1)
{ 
 pulse++;

 if( pulse % 10 == 0){
  ict_10pulse_before = ict_now;
  ict_now = (timer<<16) + ICR1;
 
  if( ict_now != ict_10pulse_before )
   rpm = (312500*60)/(ict_now - ict_10pulse_before);

  if( target_rpm > rpm )
   OCR0 = (OCR0 == 255) ? 255 : OCR0+1;
  else if( target_rpm < rpm )
   OCR0 = (OCR0 == 0 ) ? 0 : OCR0-1;
 }
}
///////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////
int main(void)
{
 DDRA = 0xFF;    // seven segment output
 DDRB = DDRB | 1<<PB4;  // OC0 bit PWM output
 TCCR0 = 0x67;    // Phase correct PWM, 1024prescale, rising match OC0 low
 
 DDRD &= ~(1<<PD4);   // IC1 pin input
 PORTD |=  1<<PD4;   // IC1 pin internal pull-up
 
 TIMSK |= 1<<TOIE1;  // Timer1 overflow interrupt enable
 TIMSK |= 1<<TICIE1;  // Timer1 input capture interrupt enable
 
 TCCR1B |= 1<<ICES1;  // input capture 1 : rising edge detection
 TCCR1B |= 1<<ICNC1;  // input capture 1 : noise cancel
 TCCR1B = (TCCR1B & 0xF8) | 4; // 256 prescale
 
 sei();
 
 OCR0 = 128;
 while(1){
  PORTA = digit[rpm % 10];
 }
}

