Timer troubles (signed vs unsigned?)

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm having trouble getting this timer code (adapted from the OSCCAL function in the butterfly gcc code). It doesn't really seem to go at all when I call it with 50000 (microseconds). Any ideas? Thanks!

void pause(unsigned int microsec) {
	cli(); // mt __disable_interrupt();  // disable global interrupt
	TCNT1 = 0;     // clear timer1 counter
	CLKPR = (1<<CLKPCE);        // set Clock Prescaler Change Enable
	// set prescaler = 16, Inter RC 16Mhz / 16 = 1Mhz
	CLKPR = (1<<CLKPS2);
	OCR1A = microsec;
	TCCR1B = (1<<CS11);
	while ( !(TIFR1 & (1<<OCF1A)) );
	TCCR1B = 0;
	sei();
	return;
}

Math is cool.
jevinskie.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just a guess (because you didn’t mention where it is going), but

Jevin wrote:

	// set prescaler = 16, Inter RC 16Mhz / 16 = 1Mhz}


doesn’t make sense, the Mega169, (or any of the Megas), don't have an internal 16 MHz RC oscillator.

How are you loading the program into your Mega169?
Have you changed any of the ‘Clock Source’ fuses?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

while ( !(TIFR1 & (1<<OCF1A)) );

I don't know what you mean by "won't go at all". A quick session with AVRStudio simulator or similar should show what is going on. You alluded to the butterfly; are you using a Mega169?

Anyway, it might work once, but after the first time you need to clear the OCF1A bit, or it will still be set the next time.

Perhaps you can show the code it was adapted from.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thats what I thought too, but when I was using the timer at 100 us and running it through a loop 65000 times, it turned out to be like 3.25 seconds with a prescale of 8. Its a 169V too. I've loaded it and it works, but only with small values like 100us. I haven't changed any fused, I only program it using ISP.

Math is cool.
jevinskie.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Now its

void pause(unsigned int microsec) {
	cli(); // mt __disable_interrupt();  // disable global interrupt
	TCNT1 = 0;     // clear timer1 counter
	CLKPR = (1<<CLKPCE);        // set Clock Prescaler Change Enable
	// set prescaler = 16, Inter RC 16Mhz / 16 = 1Mhz
	CLKPR = (1<<CLKPS2);
	OCR1A = microsec;
	TCCR1B = (1<<CS11);
	while ( !(TIFR1 & (1<<OCF1A)) );
	TCCR1B = 0;
	TIFR1 = 0;
	sei();
	return;
}

and still no go

It came from

void OSCCAL_calibration(void)
{
    unsigned char calibrate = FALSE;
    int temp;
    unsigned char tempL;

    CLKPR = (1<<CLKPCE);        // set Clock Prescaler Change Enable
    // set prescaler = 8, Inter RC 8Mhz / 8 = 1Mhz
    CLKPR = (1<<CLKPS1) | (1<<CLKPS0);
    
    TIMSK2 = 0;             //disable OCIE2A and TOIE2

    ASSR = (1<<AS2);        //select asynchronous operation of timer2 (32,768kHz)
    
    OCR2A = 200;            // set timer2 compare value 

    TIMSK0 = 0;             // delete any interrupt sources
        
    TCCR1B = (1<<CS10);     // start timer1 with no prescaling
    TCCR2A = (1<<CS20);     // start timer2 with no prescaling

    while((ASSR & 0x01) | (ASSR & 0x04));       //wait for TCN2UB and TCR2UB to be cleared

    Delay(1000);    // wait for external crystal to stabilise
    
    while(!calibrate)
    {
        cli(); // mt __disable_interrupt();  // disable global interrupt
        
        TIFR1 = 0xFF;   // delete TIFR1 flags
        TIFR2 = 0xFF;   // delete TIFR2 flags
        
        TCNT1H = 0;     // clear timer1 counter
        TCNT1L = 0;
        TCNT2 = 0;      // clear timer2 counter
           
        // shc/mt while ( !(TIFR2 && (1<<OCF2A)) );   // wait for timer2 compareflag    
        while ( !(TIFR2 & (1<<OCF2A)) );   // wait for timer2 compareflag

        TCCR1B = 0; // stop timer1

        sei(); // __enable_interrupt();  // enable global interrupt
    
        // shc/mt if ( (TIFR1 && (1<<TOV1)) )
        if ( (TIFR1 & (1<<TOV1)) )
        {
            temp = 0xFFFF;      // if timer1 overflows, set the temp to 0xFFFF
        }
        else
        {   // read out the timer1 counter value
            tempL = TCNT1L;
            temp = TCNT1H;
            temp = (temp << 8);
            temp += tempL;
        }
    
        if (temp > 6250)
        {
            OSCCAL--;   // the internRC oscillator runs to fast, decrease the OSCCAL
        }
        else if (temp < 6120)
        {
            OSCCAL++;   // the internRC oscillator runs to slow, increase the OSCCAL
        }
        else
            calibrate = TRUE;   // the interRC is correct
    
        TCCR1B = (1<<CS10); // start timer1
    }

Math is cool.
jevinskie.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

TIFR1 = 0;

That does not clear an interrupt flag bit or bits. Note that the original code did

Quote:
TIFR1 = 0xFF; // delete TIFR1 flags

See the datasheet for explanation.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You're right, Lee! I changed a few other things. I was prescaling the internal oscillator AND prescaling that by setting the CS11 bit (/8 prescale) instead of the CS10 bit (no prescale). Here is the code as it is now. Seems to work great!

void pause(unsigned int microsec) {
	cli(); // mt __disable_interrupt();  // disable global interrupt
	TIFR1 = 0xFF;
	TCNT1 = 0;     // clear timer1 counter
	CLKPR = (1<<CLKPCE);        // set Clock Prescaler Change Enable
	// set prescaler = 8, Inter RC 8Mhz / 8 = 1Mhz
	CLKPR = (1<<CLKPS1) | (1<<CLKPS0);
	OCR1A = microsec;
	TCCR1B = (1<<CS10);
	while ( !(TIFR1 & (1<<OCF1A)) );
	TCCR1B = 0;
	TIFR1 = 0xFF;
	sei();
	return;
}

I also changed the OSCCAL code around. I didn't seem to be getting very accurate time. The timer numbers seemed off, it was counting timer1 to 0.6185ms while timer2 (what it was calibrating against) was counting off to 0.6104ms. I changed the timer1 count to reflect that and it seems to have made it more accurate!

        if (temp > 6134)
        {
            OSCCAL--;   // the internRC oscillator runs to fast, decrease the OSCCAL
        }
        else if (temp < 6074)
        {
            OSCCAL++;   // the internRC oscillator runs to slow, increase the OSCCAL
        }
        else
            calibrate = TRUE;   // the interRC is correct

Math is cool.
jevinskie.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was wondering if this new code would be more accurate because it uses interrupts versus the "while ( !(TIFR1 & (1<<OCF1A)) );". It seems like that while instruction is basically polling the TIFR1 resister. Is the new code a better method than that?

void pause(unsigned int microsec) {
	cli(); // mt __disable_interrupt();  // disable global interrupt
	TIFR1 = 0xFF;
	TCNT1 = 0;     // clear timer1 counter
	CLKPR = (1<<CLKPCE);        // set Clock Prescaler Change Enable
	// set prescaler = 8, Inter RC 8Mhz / 8 = 1Mhz
	CLKPR = (1<<CLKPS1) | (1<<CLKPS0);
	OCR1A = microsec;
	TIMSK1 = (1<<OCIE1A);
	TCCR1B = (1<<CS10);
	sleep_enable();
	sei();
	sleep_cpu();
	return;
}

ISR(TIMER1_COMPA_vect) {
    sleep_disable();
}

Math is cool.
jevinskie.com