Timing issue on ATmega328

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

I'm running the 328 at 20 MHz and use the following code to drive Timer0 to generate an overflow every 1 msec., so it should produce a 500 kHz square wave (low for 1 msec., hi for 1 msec.). I calculated the initial TCNT0 value as follows:

(desired overflow frequency) / (clock period x pre-scaler) = (256 - TCNT0 initial value)

>> 256 - (.001 / (50 ns x 1024) = 236

When I use 236, however, I get a roughly 40 msec. square wave, implying an overflow period of 20 msec., not 1 msec. What am I doing wrong? I've verified the 20 MHz clock driving the CPU. Thanks.

#include 
#include 

void port_init(void)
{
 PORTB = 0x00;
 DDRB  = 0x00;
 PORTC = 0x00;
 DDRC  = 0x04;
 PORTD = 0x00;
 DDRD  = 0xFF;
}

//TIMER0 initialize - prescale:1024
// WGM: Normal
// desired value: 1mSec
// actual value:  0.973mSec (2.7%)
void timer0_init(void)
{
TCNT0  = 0x00;
TCCR0A = 0x00;
TCCR0B = 0x00;
OCR0A  = 0x00;
OCR0B  = 0x00;
TIMSK0 = 0x00;
TIFR0  = 0x00;
}


//call this routine to initialize all peripherals
void init_devices(void)
{
 //stop errant interrupts until set up
 CLI(); //disable all interrupts
 port_init();
 timer0_init();

 MCUCR  = 0x00;
 TIMSK0 = 0x00; //timer interrupt sources
 TIMSK1 = 0x00; //timer interrupt sources
 TIMSK2 = 0x00; //timer interrupt sources
 PCMSK0 = 0x00;
 PCMSK1 = 0x00;
 PCMSK2 = 0x00;
 EIMSK  = 0x00;
 EICRA  = 0x00; //extended ext ints
 PCICR  = 0x00;
// PRR0   = 0x00
 SEI(); //re-enable interrupts
}


void main(void)
{
  char x;
  init_devices();
  while (1)
  {
   TCNT0  = 236;	// Load timer0 for 1 msec delay
   TCCR0B = 5;		// Start Timer0 with 1024 pre-scaler
   while (TIFR0 == 0);
   TCCR0B = 0;  // Stop timer
   TIFR0 = 1;   // Clear overflow flag
   PORTD = !(PORTD);
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I'm running the 328 at 20 MHz and use the following code to drive Timer0 to generate an overflow every 1 msec., so it should produce a 500 kHz square wave (low for 1 msec., hi for 1 msec.).

//TIMER0 initialize - prescale:1024 
 // WGM: Normal 
 // desired value: 1mSec 
 // actual value:  0.973mSec (2.7%)

So it definitely looks as if you are trying to get 1ms.
A period of 2 msec. will give you a frequency of 50Hz.
It is difficult to debug the code when the specification is out by a factor of 1000
To get 500khz, you will need to have a 2 uS, period & a timer set for 1 uS firing once every 20 cycles.

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
while (TIFR0 == 0); 

You should never test a whole register when you're just trying to look at a single bit.

And, as an aside, is it just me or has

while (something);

become all the rage lately? As opposed to the more traditional

while (something)
  ;
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW, you say you've verified the 20MHz clock, but what does that mean? Your numbers suggest a 1MHz clock, which is exactly what you'll get in the default internal oscillator divided by 8 situation.

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

As a program pause while some condition changes, I personally prefer

 while (something);

I suppose, if I am charging the customer by the line I have just short changed myself.:)

Quote:
you say you've verified the 20MHz clock, but what does that mean? Your numbers suggest a 1MHz clock, which is exactly what you'll get in the default internal oscillator divided by 8 situation.

That would then give a frequency of 0.05 Hertz. would it not?

I think his pre-scaler should be set to 1, not 1024, but it is confusing to know because his specification is out by 1000 too ????

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

Sorry, I didn't check the notes I was copying from for consistency. I want a 1 msec. overflow rate (1 kHz) but I'm getting 20 msec. (50 Hz). I checked the clock signal on a scope as it enters the CPU.

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

OK,

Use a 16 bit timer.
1.

TCNT1H=0xb1;
    TCN1L=0xe0;
    TCCR0B = 1;   pres-scale by 1

You can use Timer 0, but set the pre-scaler to 1 not 5!

Another big improvement is to use CTC mode and then you won't even have to reloaded the TCNT. Additionaly it can toggle a port bit automagicly.

Read the tutorial on Timers & download AVRcalc https://www.avrfreaks.net/index.php?module=Freaks%20Files&func=viewFile&id=353&showinfo=1

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

Last Edited: Sat. May 21, 2011 - 03:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lautman wrote:
Sorry, I didn't check the notes I was copying from for consistency. I want a 1 msec. overflow rate (1 kHz) but I'm getting 20 msec. (50 Hz). I checked the clock signal on a scope as it enters the CPU.

You could still be using the internal oscillator. Only your fuse settings know for sure.

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

Quote:
You could still be using the internal oscillator. Only your fuse settings know for sure.

Yes, if he did not spot the difference between 1 uS & 1 ms. , he might miss the difference between fuses. I think we have all been there!

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

Quote:

As opposed to the more traditional

Not "traditional" in my world. But it is always wise to use {} after even an "empty" while() (or for, do, etc) in case somethign is to be added in later.

while(1)
 ;

may later become:

while(1) 
 PORTB = var;

but has problems when it's then extended to:

while(1) 
 PORTB = var;
 PORTD = !var;

while

while(1) {
}

later becoming

while(1) {
 PORTB = var;
 PORTD = !var;
}

has no such problems.

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

Since we're imagining problems, I can also imagine

while (something);

becoming

while (something);
{
  PORTB = var;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kk6gm wrote:

You could still be using the internal oscillator. Only your fuse settings know for sure.

Oh, snap! That was it. Thanks!

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

Hi, I'm Mauro and I'm new here.

I've a similar problem with ATMega328P.
I'm trying to use the timer0 but I've found something strange in the timing.

This is my trial code:

MAIN:	ldi r16,0b10000000   //set CLKPCE in CLKPR
        sts	CLKPR,r16
	ldi r16,0b10000000   //set CLKPS[3:0] = 0
	sts	CLKPR,r16    //set the prescaler
                             //divider = 1
		
	ldi	r16,0b01000010 //set CTC mode and
	out	TCCR0A,r16     //set toggle OCA0 on
	ldi	r16,0b00000010 //compare match
	out	TCCR0B,r16
	ldi r16,0              //set OCR0A register = 0
	out	OCR0A,r16
	sbi	DDRD,DDD6     //set PB6 as output

loop:	jmp loop

OCRA0 = 0 implies (see datasheet ATMega328P pag.102)
a freq output = clki_o / 2*N*(1+OCR0A)
(N is the prescaler divider value)

I'm using a 16MhzCrystal
I set the fuse as follow:
EXTENDED =0xFF
HIGH =0xDF
LOW =0xB7
(full swing crystal oscillator)

and i've checked the freq also by setting PB0 as CLKOUT and by oscilloscope i've see that the 16Mhz are righ.

BUT!!! on pin PD6(OCA0) I've exactly 1Mhz instead

By datasheet formula I shoud have
16000000 / 2*1*(1+0) = 8Mhz

I don't understand what is wrong!
Is it a my mistake? Or there is a problem in the system?

please help me to undertand. :-)[/code]

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

franzSBK , you probably have the DIV_8 fuse bit on.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

Hi, thanks for the reply.

I've reported the fuse bit configuration the div_8 is disabled.

also I I've thought about this.
If I set the div_8 fuse the frq output decrease, so i'm sure that is not set.
Anyway i've checked also the clock out on PB0 pin that is directly connected to the prescaler output (by fuse selection) and here there are 16Mhz.

About this I'm very frustrated.

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

Quote:
I don't understand what is wrong!
Is it a my mistake?
Yes, it is. You have configured the timer to run with a prescaler of 8.

Stefan Ernst

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

Sternst you are a Genious or probably I'm a stupid... :-)
You are right,I've though to set the CS[2:0] bits to "001" but in truth I set to "010".

Thanks for your patience!!! :-)

But unfortunately a little timing exist
In few word seting the prescaler (div by 1) now on pin PD6 I've a 7,983Mhz output.

now I don't have any job to do. I want only test the limits of the system.
I'm using the Arduino board where, I suppose, there is mounted a low quality crystal oscillator.
Now it's clearly that the ATMega is set to work at 8Mhz but at the end there is about 0.21% (~17Khz) of deviation.

I will try to change the crystal with a better one, then I'll let you know.

Thanks again!

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

Quote:

Now it's clearly that the ATMega is set to work at 8Mhz but at the end there is about 0.21% (~17Khz) of deviation.

There's something seriously wrong if it's really labelled 8.0MHz. Are you sure this isn't a CTC off-by-one issue?

I'd start by rewriting the code to use a CTC interrupt and just toggle the "output" pin in that. Or even have the timer itself toggle it's own output pin.

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

Quote:

In few word seting the prescaler (div by 1) now on pin PD6 I've a 7,983Mhz output.


5 significant digits, eh?

Are you sure that your measuring device is accurate to less than 0.1% ?!?

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

Quote:
In few word seting the prescaler (div by 1) now on pin PD6 I've a 7,983Mhz output.
???
How should that be possible? With a system clock of 8MHz you can have there at most 4 MHz.

EDIT: Ah, clocked with 16 MHz. Sorry, "ATMega is set to work at 8Mhz " confused me.

Stefan Ernst