Pages: [1]   Go Down
Author Topic: Programming the hardware timers - advanced level  (Read 1708 times)
0 Members and 1 Guest are viewing this topic.
Valencia, Spain
Offline Offline
Faraday Member
**
Karma: 152
Posts: 5757
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

HI,

I'm trying to output a square wave on an Arduino pin using a hardware timer. I'm using eight bit timer (timer 0) but I can't seem to get it to work like in the datasheet. I want the highest clock rate possible from the chip.

Here's my timer setup code:

Code:
    // Timer 0 -> Output on OC0A
    TCCR0A = _BV(WGM01)   // CTC mode
            |_BV(COM0A0); // Toggle OC0A output on every match
    OCR0A = 4;            // Reset when it reaches this value
    TCCR0B = _BV(CS00);   // Start timer, no prescale

I think that should toggle the ouput pin OC0A every 4 clock cycles, giving a nice square wave.

What I actually get is something like a PWM wave with a very short low pulse, like this (the purple line):



If I increase the value in OCR0A it makes the low part of the pulse wider, but a value of 3 or less makes it disappear (at least on my 'scope...)

Questions:
a) If I'm toggling a pin high/low based on a regular event (anything at all!), how can I get anything but a nice square wave (50% duty cycle)?
b) The datasheet says I can put zero in OCR0A when I want maximum frequency output. Why does the minimum useful value seem to be 4?
Logged

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Valencia, Spain
Offline Offline
Faraday Member
**
Karma: 152
Posts: 5757
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Update: It is working properly, but the wave coming out of the Arduino is really nasty/ringy and the digital input on my 'scope wasn't seeing it properly.

I tried looking at it in analogue and on a different 'scope and the signals are there, they're just horrible.

Logged

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19351
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Using your code in a working sketch, thus:

Code:
void setup ()
{
  pinMode (6,OUTPUT);
  // Timer 0 -> Output on OC0A
  TCCR0A = _BV(WGM01)   // CTC mode
          |_BV(COM0A0); // Toggle OC0A output on every match
  OCR0A = 4;            // Reset when it reaches this value
  TCCR0B = _BV(CS00);   // Start timer, no prescale
}
void loop () { }

I get 1.6 MHz frequency (which you expect). The ringing isn't too bad for that frequency on my scope:



The above capture was with the probe set to x10.





The above is with a x1 probe.


Quote
... signals are there, they're just horrible ...

Can you post what you have?
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19351
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
b) The datasheet says I can put zero in OCR0A when I want maximum frequency output. Why does the minimum useful value seem to be 4?

You can use zero which gives a frequency of 8 MHz (because it takes two toggles per cycle):



I've used a similar bit of code to generate clock pulses for programming other processors so it can't be too dirty. The ringing I suspect is partly an artifact of the measuring. This is only a 60 MHz scope.
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Valencia, Spain
Offline Offline
Faraday Member
**
Karma: 152
Posts: 5757
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've used a similar bit of code to generate clock pulses for programming other processors so it can't be too dirty. The ringing I suspect is partly an artifact of the measuring. This is only a 60 MHz scope.

Here's captures with 2, 1 and 0 in OCR0A.







I'm using a DSO quad to look at it so the bandwidth is a lot less than 60MHz. I also hooked up an old green screen 'scope and the results were similar (though maybe 50% a less ringy).

I'm working with a bare chip in a breadboard so suppose the ringing could be due to the breadboard as well as the 'scopes. FWIW I looked at the output from an Arduino Uno and it was a little bit better.

Whatever, the important thing right now is that I'm not going crazy and the timer works as specified. I can get on with the rest of software.
« Last Edit: September 23, 2012, 05:26:56 am by Nick Gammon » Logged

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Valencia, Spain
Offline Offline
Faraday Member
**
Karma: 152
Posts: 5757
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

One more thing I found...this caused me a real headache!

If I write the code like this it works:

Code:
    // Timer 0 -> Output on OC0A
    TCCR0A = _BV(WGM01)   // CTC mode
            |_BV(COM0A0); // Toggle OC0A output on every match
    OCR0A = 4;            // Reset when it reaches this value
    TCCR0B = _BV(CS00);   // Start timer, no prescale

If I write the code like this, it doesn't:

Code:
    // Timer 0 -> Output on OC0A
    OCR0A = 4;            // Reset when it reaches this value
    TCCR0A = _BV(WGM01)   // CTC mode
            |_BV(COM0A0); // Toggle OC0A output on every match
    TCCR0B = _BV(CS00);   // Start timer, no prescale

I switched the two lines around when I was cleaning up the code a bit. It took me a whole day to figure out what had happened.
Logged

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19351
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I've noticed that before, that the place you change OCR0A can affect results. I can't see any real explanation in the datasheet, except for page 108 where it says under CTC mode "Update of OCRx at ... Immediate".

But in your non-working sequence it isn't yet in CTC mode (you update OCR0A and then change to CTC mode) so somehow it loses that update.
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19351
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

In some modes (which may be the mode in place at the start) the update of OCR0A is buffered. Now how that affects things I'm not sure, except maybe this:

  • It starts in a buffered mode (eg. one of the PWM modes) because of init()
  • You change OCR0A but it goes into the buffer, ready for when the count ticks over (TOP or BOTTOM)
  • You change modes to CTC mode almost immediately
  • Since it is now in a non-buffered mode the (planned) copy from the buffer to the real register is lost
  • The old value of OCR0A is now retained
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19351
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have a mention of this problem on my page about timers:

http://www.gammon.com.au/forum/?id=11504

Near the bottom where I try out all the modes is this line:

Quote
Also note that you need to set the counter after starting the timer (as shown above) or you get rather strange results like this ...
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Valencia, Spain
Offline Offline
Faraday Member
**
Karma: 152
Posts: 5757
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

But in your non-working sequence it isn't yet in CTC mode (you update OCR0A and then change to CTC mode) so somehow it loses that update.

My theory is that it's because the register is double-buffered in PWM mode but not in CTC mode.

The value is lost if you write it while the timer is in PWM mode then switch to CTC mode before it gets copied to the real register.
Logged

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Pages: [1]   Go Up
Jump to: