Author Topic: [AVR] Display updating at wrong rate not sure why  (Read 2159 times)

0 Members and 1 Guest are viewing this topic.

Offline blewisjr

  • Frequent Contributor
  • **
  • Posts: 301
[AVR] Display updating at wrong rate not sure why
« on: May 18, 2013, 05:32:59 pm »
Hello everyone.

I am working on a project where I am updating a 4 digit 7 segment display.  In this project I need to use the timer which is updating the display for another purpose as well.  For some reason my display is updating at the wrong rate giving me false results and I am not sure why as the calculations show I am updating at the proper rate.  So I think I messed something up somewhere.  I am trying to trigger the ISR once every 5 ms.  For some reason it seems like it is calling a lot faster then this.  I ran a quick test by placing a counter in the ISR then triggering a port toggle and measuring the toggle with my scope.  I did a count to 200 because that should be a 1 second interval.  Instead I am getting a 500ms interval which is 2x as fast as what I want.

Here is the code I am using. Including the port toggle debug code.  All calculations I used are in the comments.

Code: [Select]
#define ONE   0b00000110
#define TWO   0b01011011
#define ZERO  0b00111111

#define DIG_ONE (1<<0)
#define DIG_TWO (1<<1)
#define DIG_THREE (1<<2)
#define DIG_FOUR (1<<3)

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

volatile uint8_t cnt = 0;

/*
 * Timer1 Compare Match A Interrupt Service Routine.
 * Description:
 *     Called once every 5ms to update the 4 digit 7 segment display.
 */
ISR (TIMER1_COMPA_vect)
{
    // For debug purpose
    cnt++;
   
    // Cycle through digits and update them
    if (PINC & DIG_ONE)
    {
        // Digit 1 is updated switch to Digit 2 and update
        PORTC &= ~DIG_ONE;
        PORTD = TWO;
        PORTC |= DIG_TWO;
    }
    else if (PINC & DIG_TWO)
    {
        // Digit 2 is updated switch to Digit 3 and update
        PORTC &= ~DIG_TWO;
        PORTD = ZERO;
        PORTC |= DIG_THREE;
    }
    else if (PINC & DIG_THREE)
    {
        // Digit 3 is updated switch to Digit 4 and update
        PORTC &= ~DIG_THREE;
        PORTD = ZERO;
        PORTC |= DIG_FOUR;
    }
    else
    {
        // We need to update Digit 1 make sure all other digits are off and update
        PORTC &= ~(DIG_TWO | DIG_THREE | DIG_FOUR);
        PORTD = ONE;
        PORTC |= DIG_ONE;
    }
   
    // For debug test
    if (cnt == 200)
    {
        PORTB ^= (1<<PORTB0);
        cnt = 0;
    }
}

int main(void)
{
    // Configuration code
    TCCR1A |= (1<<COM1A1);              // clear OC1A register on compare match
    TIMSK1 |= (1<<OCIE1A);              // enable Timer1 Compare Match A Interrupt
    sei();                              // enable global interrupts
    OCR1A = 2499;                       // match compare at Timer value of 2499
                                        // this will give us a refresh time of 5ms per display
                                        // 1000/5 = 200 which means we need to update at a rate of 200 HZ
                                        // 1 MHZ / (2 * 1 * 200) - 1 = 2499
    TCCR1B |= ((1<<WGM12) | (1<<CS10)); // start timer in CTC mode with no prescale
    DDRD = 0b01111111;                  // set PortD 0 - 6 as output to control 7 segments of display
    DDRC = 0b00001111;                  // set PortC 0 - 3 as output to control the digit selection transistors
   
    // For debug purpose
    DDRB |= (1<<DDB0);
   
    while (1);
    return 0;
}
« Last Edit: May 18, 2013, 05:35:07 pm by blewisjr »
 

Offline elgonzo

  • Supporter
  • ****
  • Posts: 690
  • Country: 00
Re: [AVR] Display updating at wrong rate not sure why
« Reply #1 on: May 18, 2013, 06:11:51 pm »
Assuming, your timer clock source is indeed 1MHz, then the code is running fine, and you just have a superfluous division by 2 in your calculation of:

Quote
1 MHZ / (2 * 1 * 200) - 1 = 2499

 

Offline blewisjr

  • Frequent Contributor
  • **
  • Posts: 301
Re: [AVR] Display updating at wrong rate not sure why
« Reply #2 on: May 18, 2013, 06:25:09 pm »
Yes the internal clock is running at 1 MHZ.  This is weird because I derived the equation to get the timer from the one in the data sheet.

f_OCnA = f_clkIO / (2 * N * (1 + OCRnA))

which became

OCRnA = f_clkIO / (2 * N * f_OCnA) - 1

So you are saying the 2 should not be there?

EDIT:
Perfect actually removing the 2 from the equation fixed the problem and gave me the right number.  So the new question is where did I go wrong when deriving the equation lol.
« Last Edit: May 18, 2013, 06:30:05 pm by blewisjr »
 

Offline elgonzo

  • Supporter
  • ****
  • Posts: 690
  • Country: 00
Re: [AVR] Display updating at wrong rate not sure why
« Reply #3 on: May 18, 2013, 06:37:58 pm »
The formula you quoted is for waveform generation in CTC mode by toggling the output logical level. That means, to get one full period of a waveform, it has to toggle twice. That means, to produce a 1MHz waveform it has to toggle at 2MHz speed.

In your case you do not want to generate waveform, so you should not trigger at twice the speed of the desired interrupt frequency :)
 

Offline blewisjr

  • Frequent Contributor
  • **
  • Posts: 301
Re: [AVR] Display updating at wrong rate not sure why
« Reply #4 on: May 18, 2013, 06:52:03 pm »
Doh so basically I derived the wrong formula lol.  I see I am running in CTC but being that I want to get a specific time frame I should have not used the formula from the datasheet.  Wish they gave a normal timer formula in there and I would not have made that mistake.  I should have instead derived from the standard T = 1/f  formula with modification for the cpu clock speed.  aka.

OCRnA = f_clk_io / N * f_OCnA

The frequency I want is f = 1/T  in my case 1000/5 = 200 HZ

Lol such a newbie mistake.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf