Fast PWM 1MHz Arduino UNO

Hey,

I’m new to programming PWM and I’m not sure if i do/understand it correctly.
I want a 1MHz square wave signal with 50% duty cycle. I thought the best way to do this is via a fast PWM. I think pin B1 should toggle at 1MHz by this implementation.
Am I doing this correctly? Am I missing something? and what goes in my main loop?

void setup() {
  // put your setup code here, to run once:
  
  DDRB |= (1<<DDB1);                        // Set Pin B1 as Output (OC1A)
    
  TCCR1A = (1<<COM1A0)|(1<<WGM11);          // Wave Form Generation is Fast PWM with ICR1 TOP and toggle on compare match
  TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS10); // no prescaler
  ICR1 = 15;                                // 1MHz Freq -> (fclk/1MHz)-1 fclk=16MHz TOP=15
}

void loop() {
  // put your main code here, to run repeatedly:

}

You forgot OC1A at 8

OCR1A = 8 to give you 50% duty cycle

The best way is to use a timer in CTC mode, not PWM.
CTC mode → Duty cycle = 50% only.

PWM : Duty Cycle ->256 steps
Clock = 16 MHz
So max PWM frequency = 16 MHz / 256 = 62.5 kHz.

But I toggle the pin on every compare match so shouldn’t it be automatically 50% duty cycle?

Are you sure? The datasheet includes this formula:

PWM_Freq_Formel

When i use 15 as my TOP value I get 1MHz. And my TOP value is also ICR1 right?

CTC mode allows to go up to system_clock / 2 = 8 MHz
This mode is the mode intended by Atmel to generate frequencies with a duty cycle of 50%.
When you use 15 as the top value how precise do you have the frequency? 1/15 = 7%?
When a mode is specially designed to perform a function and gives best result, why not use it?

You can use CTC mode, but you would have to toggle the pin in software on the overflow and compare interrupts. PWM is used so there’s no CPU cycle involved in toggling the pins.

The reason you need to specify OCR1A is the CPU needs to know when to toggle the pins. Toggle on compare does not mean it will toggle automatically at 50%

No. In “Clear Timer on Compare Match” (CTC) mode (WGM=4) you can have the OC1A and/or OC1B pins toggle on compare match. Just set the COM1A0 or COM1B0 bits. No interrupt or software needed.

TCCR1A = 0;
TCCR1B = 0;

TCCR1A |= 1 << COM1A0;  // Toggle OC1A on compare match
// TCCR1A |= 1 << COM1B0;  // Toggle OC1B on compare
TCCR1B |= 1 << WGM12; // Set WGM=4: CTC, TOP in OCR1A
OCR1A = 7;  // TOP = 7, Frequency = 1 MHz (2 MHz but toggling)
// OCR1B = 3;  Same, but leading by 90 degrees
TCCR1B |= 1 << CS10;  // Start clock at 16 MHz

You could also set OC1B to toggle. The code can easily be adapted to Timer2.

Thanks, the CTC mode is probably the better option!

Hi,
What do you need the 1MHz signal for?

Tom… :grinning: :+1: :coffee: :australia:

I just want to use it to test my frequency counter on the DUE :smiley: