I want to achieve the generation of a custom binary signal over a digital pin at the highest possible frequency on Arduino Uno.
Using Timer's output pins (e.g. OC0A), one can get a pin to toggle at a maximum frequency of 16MHz (which corresponds to a sqaure wave of frequency 8MHz), as described here: Maximum frequency of digital signal in Arduino Uno?
However as far as I understand, Timer's output pins are only useful if one needs to generate a repetitive waveform such as a PWM or square wave, so it cannot serve my purpose which requires the generation of a custom binary signal.
Using the following code, I was expecting digital pin 9 to toggle at a frequency close to 16MHz too, since I use no prescaler and set the Compare Match Register value to 0:
void setup()
{
DDRB = 1 << 1; // Set D9 as OUTPUT
cli();
TCNT0 = 0; TCCR0A = 0; TCCR0B = 0;
TCCR0A |= (1 << WGM01); // CTC mode
TCCR0B |= (1 << CS00); // no prescaling
OCR0A = 0; // Highest timer overflow frequency possible
TIMSK0 |= (1 << OCIE0A);
sei();
}
ISR(TIMER0_COMPA_vect)
{
PORTB ^= 1 << 1; // Toggle D9; this allows to measure the toggle frequency, however this could be replaced by some code to generate a custom binary signal
}
void loop(){}
However in fact it appears to toggle at a frequency of only approximately 410kHz (which corresponds to a square wave of frequency 205kHz), as the below image shows:
I used Timer0 but I get the same frequency with Timer1 and Timer2.
- How can one explain that using this code I get this toggle frequency on the digital pin ?
- How can I generate a custom binary signal over a digital pin at the highest possible frequency ?
PINB = 1 << 1;
rather thanPORTB ^= 1 << 1
to save a couple of cycles. The construction may look weird, but they've designed the AVR GPIO hardware so that you can toggle pin be writing 1 bits to their bit positions in the PINx registers; writing 0-bits have no effect. If you take the writing in a tight loop outside of an interrupt suggestion, this may have some impact.