rodolaf
rodolaf

Reputation: 29

Set PWM frequency on Arduino Mega using Timer2 in "phase & frequency correct" (mode 5)

Using my Arduino Mega 2560 I am trying to generate a PWM signal where I can change both PWM frequency and Duty Cycle. For that I decided to use Timer2 OC2A output. The code is the following one:

void setup()
{
  // ======================================================
  //    Timer 2 example: Phase and Frequency correct PWM
  // ======================================================
  pinMode(10, OUTPUT);
  TCCR2A = 0;//reset the register
  TCNT2  = 0;

  TCCR2A = 0b10000001;  // COM2A1 COM2A0 COM2B1 COM2B0    -      -    WGM21  WGM20
                        //    1      0      0      0      0      0      0      1
                        // Behavior: PWM on OC2A (Arduino pin 10) ; Waveform generation mode 5 (Phase and Frequency Correct)
                        
  TCCR2B = 0b00001001;  //  FOC2A  FOC2B    -      -    WGM22   CS22   CS21   CS20
                        //    0      0      0      0      1      0      0      1
                        // Behavior: Waveform generation mode 5 (Phase and Frequency Correct) ; Prescaler -> clk/1
                        
  OCRA   = 319;         // TOP value -> defines de PWM frequency (25 kHz)
  OCR2A  = 159;         // duty cycle value (80% of ICR1)
} 

void loop() 
{

}

When I try to compile I get the following error:

PWM_Mega.ino:43:3: note: suggested alternative: 'OCR2A'
   OCRA   = 319;         // TOP value -> defines de PWM frequency (25 kHz)
   ^~~~
   OCR2A
exit status 1
'OCRA' was not declared in this scope

I understand the error is because OCRA is not defined. In the uC datasheet (see picture below), mode 5 TOP, that defines the PWM frequency, is defined using register OCRA but when I put that name into my code, it is not recognized. Does anyone know the name of that register so that I can use it in the code?

enter image description here

Thanks

Upvotes: 1

Views: 1570

Answers (2)

rodolaf
rodolaf

Reputation: 29

Many thanks, KIIV! That was exactly the point. But then I have to say that the uC datasheet is not well documented.

In order to help others having similar issues using Timer2 for PWM generation, I will post down the working code that I have tested on my Arduino Mega for three PWM Modes (1, 3 and 5). You can find also the cheat sheet I have prepared for myself. Anyone feel free to review it and comment if necessary:

ATMega 2560: Cheat sheet Timer 2 for PWM generation

// PWM generation using the Arduino Mega 2560 Rev. 3

#include "Arduino.h"


void setup()
{

//  // ==========================================================
//  //    Timer 2 example: Phase correct PWM (8 bit) ; Mode 1
//  // ==========================================================
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  TCCR2A = 0;//reset the register
  TCCR2B = 0;//reset the register
  TCNT2  = 0;

  TCCR2A = 0b10100001;  // COM2A1 COM2A0 COM2B1 COM2B0    -      -    WGM21  WGM20
                        //    1      0      1      0      0      0      0      0
                        // Behavior: PWM on OC2A and OC2B (Pins 9 and 10) ; Waveform generation mode 1 (Phase correct PWM ; TOP = 255)
                        
  TCCR2B = 0b00000010;  //  FOC2A  FOC2B    -      -    WGM22   CS22   CS21   CS20
                        //    0      0      0      0      0      0      1      0
                        // Behavior: Waveform generation mode 1 (Phase correct PWM ; TOP = 255) ; Prescaler -> clk/8

  // Note: fpwm = fclk/(N·2·255)  --> N = pre-scaler factor
  //            = 16M /(8·2·255) = 3.92 kHz
                        
  OCR2A  = 10;         // duty cycle value (4% PWM)
  OCR2B  = 100;        // duty cycle value (40% PWM)


//  // =================================================
//  //    Timer 2 example: Fast PWM (8 bit) ; Mode 3
//  // =================================================
//  pinMode(9, OUTPUT);
//  pinMode(10, OUTPUT);
//  TCCR2A = 0;//reset the register
//  TCCR2B = 0;//reset the register
//  TCNT2  = 0;
//
//  TCCR2A = 0b10100011;  // COM2A1 COM2A0 COM2B1 COM2B0    -      -    WGM21  WGM20
//                        //    1      0      1      0      0      0      1      1
//                        // Behavior: PWM on OC2A (Arduino pin 10) ; Waveform generation mode 3 (Fast PWM ; TOP = 255)
//                        
//  TCCR2B = 0b00000100;  //  FOC2A  FOC2B    -      -    WGM22   CS22   CS21   CS20
//                        //    0      0      0      0      0      1      0      0
//                        // Behavior: Waveform generation mode 3 (Normal PWM ; TOP = 255) ; Prescaler -> clk/64
//
//  // Note: fpwm = fclk/(N·256)  --> N = pre-scaler factor
//  //            = 16M /(64·256) = 976 Hz
//                        
//  OCR2A  = 10;         // duty cycle value (4% PWM)
//  OCR2B  = 100;        // duty cycle value (40% PWM)


  // ===========================================================================
  //    Timer 2 example: Phase and Frequency correct PWM (8 bit)  ; Mode 5
  // ===========================================================================
//  pinMode(9, OUTPUT);
//  TCCR2A = 0;//reset the register
//  TCCR2B = 0;//reset the register
//  TCNT2  = 0;
//
//  TCCR2A = 0b00100001;  // COM2A1 COM2A0 COM2B1 COM2B0    -      -    WGM21  WGM20
//                        //    0      0      1      0      0      0      0      1
//                        // Behavior: PWM on OC2B (Arduino pin 9) ; Waveform generation mode 5 (Phase and Frequency Correct)
//                        
//  TCCR2B = 0b00001010;  //  FOC2A  FOC2B    -      -    WGM22   CS22   CS21   CS20
//                        //    0      0      0      0      1      0      1      0
//                        // Behavior: Waveform generation mode 5 (Phase and Frequency Correct) ; Prescaler -> clk/8
//
//  // Note: fpwm = fclk/(N·(2·TOP)  --> N = pre-scaler factor
//  //            = 16M /(8·2·100) = 10 kHz
//  
//  OCR2A  = 100;         // TOP value -> defines de PWM frequency (10 kHz)
//  OCR2B  = 50;          // duty cycle value (50% Duty Cycle)
} 

void loop() 
{

}

Upvotes: 1

KIIV
KIIV

Reputation: 3739

As you want to change the Timer2 frequency you'll have to sacrifice channel A (unlike Timer1 there is no input capture register, that can be used as TOP value)

The OCRA in the image means OCR2A (OCR2A means: Output Compare Register for timer2 channel A)

Therefore you can use only channel B as PWM output

note: Timer2 is 8b only and values like 319 (0x13F) will overflow into 63 (0x3F)

Upvotes: 0

Related Questions