Hallo,

Ik vermoed dat ik een probleem heb met mijn ATMEGA168 Input compare register.

Het volgende:
Ik heb een gps ontvangen die geeft een 1pps signaal +-1uS aan de ICP pin van mijn AVR. De oscilator is een isotemp 10Mhz xtal. die een nauwkeurigheid heeft van ca 20 PPB.

Nu tel ik het aantal 10Mhz klokpulsen(=timer1) tussen 2 opgaande 1 pps flanken. Nu verwacht ik daar een constante waarde krijg met een fout van ca +-1. Maar ik de fout verspringt hoofdzakkelijk tussen de -232 en +280. Dat vind ik raar. Als het aan de hardware zou liggen had ik verwacht dat deze langzaam zou verlopen.

Dus ik vermoed dat ik een probleem heb met mijn ICP interrupt.
Maar wat kan het probleem zijn? De enige interupten die enabled zijn is de timer overflow en de icp. Ik ben een beetje uit of opties wat een mogelijk probleem zou kunnen zijn voor mijn gemeten fout.
Dus heb je een sugestie.

alvast bedankt, Megavolt

Ik heb een gps ontvangen die geeft een 1pps signaal +-1uS aan de ICP pin van mijn AVR

Je houdt er rekening mee, dat de ICP-pin op elke niveau-verandering reageert - dus ook op de neergaande flank?

Op 31 december 2009 14:22:59 schreef pros:
[...]
Je houdt er rekening mee, dat de ICP-pin op elke niveau-verandering reageert - dus ook op de neergaande flank?

Volgens mij kan je een register instellen of hij op opgaande of neergaande flank moet triggeren.

Je hebt gelijk. Zover was ik nog niet geraakt in de manual... :-)

Tweede poging:

Maar ik de fout verspringt hoofdzakkelijk tussen de -232 en +280

Is het je al opgevallen dat 232 + 280 = 512? Toeval? Of iets met het declareren/behandelen van variabelen dat mis loopt?

512 dat is wel toevallig. Maar er komen ook wel andere waardes invoor. Hieronder de interrupt routine.

De controller doet de volgende dingen:
- lcd update (niet via interrupt,1x per sec)
- serial inlezen (interrupt based, 9600bd, 1 string per sec)
- manual pwm (interrupt based,50% 136 hz)

- Als ik de overige interupt functies uitzet. blijft het probleem. Want de meeste tijd is de controller niks aan het doen in een while loopje.


// Overflow interupt
void timer_overflow (void)
{
	PORTB |= (1 << PB1);	// Set 1 at OC1A, for manual PWM (136 hz)
	icp_counter++;		// overflow counter
}

// ICP interupt
void timer_inputcompare (void)
{uint16_t timer_icp;
 cli (); // stop interrupt
 timer_icp_update++;		// interrupt triggered
  if (GPS_found == 0) GPS_found=1; // GPS signal found.

 timer_icp=timer1_ReadICP(); // read ICP value;
 icp_counter--;
 // skip measurement when counter is restarted.
 if (timer_icp > timer_icp_last)
 {   XTAL_pulse=(uint32_t)(icp_counter << 16);
     XTAL_pulse+=timer_icp - timer_icp_last;

 } 
	icp_counter=0;
	GPS_pulse++;				// count the 1 PPS pulses
	timer_icp_last=timer_icp;
	sei(); // start interrupts
}

Ik had nog nooit met die ICP gestoeid; tijd om er eens aan te beginnen:


#define F_CPU 20000000UL

#include "Main.h"

ISR(TIMER1_CAPT_vect)
{
    TCNT1 = 0;					// Timer herstarten
    intflag = 1;
}


int main(void)
{
    unsigned int cnt = 0;
    
    CLKPR = (1 << CLKPCE);
    CLKPR = 0;					// Set max. system-clk
    lcd_init();
    TCCR1A = 0;					// Gewoon tellen, niets meer
    TIMSK1 = (1 << ICIE1);			// ICP-interrupt enable
    TCNT1 = 0;
    ICR1 = 0;
    TCCR1B = (1 << CS10) | (1 << CS12);	// Prescaler = 1024
    intflag = 0;
    sei();

    lcd_clrscr();
    lcd_puts_P(" Ready for work.");

    while (1) {
	if (intflag == 1) {
	    cnt++;
	    intflag = 0;
	    sprintf(tekst, " %05u  %05u", ICR1, cnt);
	    lcd_gotoyx(1, 0);
	    lcd_puts(tekst);
	}
    }
}

Broncode is voor avr-gcc, voor alle duidelijkheid.
Bij een klok van 1Hz op de ICP-pin wisselt het resusltaat tussen 19532 en 19533. Dat komt aardig overeen met de theoretische waarde.

Dank je voor de code.

Ik heb je code getest zonder 1024 prescaling. En dan werkt het. Dan is de fout idd +-1. Dus het ligt aan mijn code. De vraag is alleen wat is er dan fout. Maar in iedergeval dank voor je hulp!!

p.s de sprinf functie kende ik nog niet. Die is handig!