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:
// 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?
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.
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.
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.
One more thing I found...this caused me a real headache!
If I write the code like this it works:
// 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:
// 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.
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.
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