[AVR] Display updating at wrong rate not sure why - Page 1
Forum section: electronics / general

author: blewisjr
author_rank: Frequent Contributor
timestamp: May 18, 2013, 05:32:59 pm
content: 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:#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 purposecnt++;// Cycle through digits and update themif (PINC & DIG_ONE){// Digit 1 is updated switch to Digit 2 and updatePORTC &= ~DIG_ONE;PORTD = TWO;PORTC |= DIG_TWO;}else if (PINC & DIG_TWO){// Digit 2 is updated switch to Digit 3 and updatePORTC &= ~DIG_TWO;PORTD = ZERO;PORTC |= DIG_THREE;}else if (PINC & DIG_THREE){// Digit 3 is updated switch to Digit 4 and updatePORTC &= ~DIG_THREE;PORTD = ZERO;PORTC |= DIG_FOUR;}else{// We need to update Digit 1 make sure all other digits are off and updatePORTC &= ~(DIG_TWO | DIG_THREE | DIG_FOUR);PORTD = ONE;PORTC |= DIG_ONE;}// For debug testif (cnt == 200){PORTB ^= (1<<PORTB0);cnt = 0;}}int main(void){// Configuration codeTCCR1A |= (1<<COM1A1); // clear OC1A register on compare matchTIMSK1 |= (1<<OCIE1A); // enable Timer1 Compare Match A Interruptsei(); // enable global interruptsOCR1A = 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 = 2499TCCR1B |= ((1<<WGM12) | (1<<CS10)); // start timer in CTC mode with no prescaleDDRD = 0b01111111; // set PortD 0 - 6 as output to control 7 segments of displayDDRC = 0b00001111; // set PortC 0 - 3 as output to control the digit selection transistors// For debug purposeDDRB |= (1<<DDB0);while (1);return 0;}

author: elgonzo
author_rank: Unknown
timestamp: May 18, 2013, 06:11:51 pm
content: 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

author: blewisjr
author_rank: Frequent Contributor
timestamp: May 18, 2013, 06:25:09 pm
content: 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 becameOCRnA = f_clkIO / (2 * N * f_OCnA) - 1So 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.

author: elgonzo
author_rank: Unknown
timestamp: May 18, 2013, 06:37:58 pm
content: 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

author: blewisjr
author_rank: Frequent Contributor
timestamp: May 18, 2013, 06:52:03 pm
content: 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_OCnAThe frequency I want is f = 1/T in my case 1000/5 = 200 HZLol such a newbie mistake.