Arduino Mega2560 PWM Bug

Good evening everyone,

I would appreciate if someone can help me with a weird bug.

The goal of my code is to generate 6 PWM signals. I have managed to get 5 working.

Context : Driving 6 switching devices within an intelligent power module (3 x half-bridges)

For some or other reason Pin 5 (Timer 3) does not want to write any output, please see attached code and screenshot of simulation via Proteus.

The setup for pins 6,7,8 (Timer 4) is the same and all three channels work. Pin 5 does have alternate functions, but even writing DDRE = 0b10000000 to choose the 0C3A output option there is no change.

I am using the PWM.h library.

There is probably something trivial wrong, but I cannot seem to find the solution.

If anyone can help I would appreciate it immenesly.



MEGA_Final.ino (5.23 KB)

Original poster’s code…

/*  Interrupt credit : https://www.instructables.com/id/Arduino-Timer-Interrupts/
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 */



#include <PWM.h>

//timer 3 (controls pin 5, 3, 2)
//timer 4 (controls pin 8, 7, 6)

const int Pin5 = 5;   // TIMER3 Define name for Phase W sine output signal, constant as pin hardware is fixed (TIMER_1)
const int Pin3 = 3;   // TIMER3 Define name for Phase W sine output signal, constant as pin hardware is fixed (TIMER_1)
const int Pin2 = 2;   // TIMER3 Define name for Phase W sine output signal, constant as pin hardware is fixed (TIMER_1)

const int Pin8 = 8;   // TIMER4 Define name for Phase W sine output signal, constant as pin hardware is fixed (TIMER_1)
const int Pin7 = 7;   // TIMER4 Define name for Phase W sine output signal, constant as pin hardware is fixed (TIMER_1)
const int Pin6 = 6;   // TIMER4 Define name for Phase W sine output signal, constant as pin hardware is fixed (TIMER_1)


volatile int duty = 0;

int f_sw = 8000;                                  // Set switching frequency
int f_sine_adj = 125;                             // 125 = 50Hz, adjust to 150 for ??.??Hz
float mod_index = 0.800;                          // Set modulation index
int mod_index_scaler = round(127.000*mod_index);  // Scaling modulation index percentage, 0-100% -> 0-127

int sine_tableU[106];  // Array to store sine values of Phase U
int sine_tableV[106];  // Array to store sine values of Phase V
int sine_tableW[106];  // Array to store sine values of Phase W

int sine_tableU1[106];  // Array to store sine values of Phase U
int sine_tableV1[106];  // Array to store sine values of Phase V
int sine_tableW1[106];  // Array to store sine values of Phase W

float period_interval = (2*PI)/105; // Calculate period interval

void setup()
{  
  for (int i = 0; i < 106; i++)   // Calculate and store sine values for three phases
    {
      sine_tableU[i] = 127 + round(mod_index_scaler*sin(period_interval*i));            // Phase U : sin(t)
      sine_tableV[i] = 127 + round(mod_index_scaler*sin(period_interval*i+(2*PI/3)));   // Phase V : sin(t+120deg)
      sine_tableW[i] = 127 + round(mod_index_scaler*sin(period_interval*i-(2*PI/3)));   // Phase W : sin(t-120deg)

      sine_tableU1[i] = 127 - round(mod_index_scaler*sin(period_interval*i));            // Phase U : sin(t)
      sine_tableV1[i] = 127 - round(mod_index_scaler*sin(period_interval*i+(2*PI/3)));   // Phase V : sin(t+120deg)
      sine_tableW1[i] = 127 - round(mod_index_scaler*sin(period_interval*i-(2*PI/3)));   // Phase W : sin(t-120deg)
    }
  //***********************************************************************************************

  InitTimersSafe();
  //Set up Timer 2 for 8kHz interrupt
  cli();              // Disable Interrupts
  
  TCCR2A = 0;         // Clear TCCR2A register
  TCCR2B = 0;         // Clear TCCR2B register
  TCNT2  = 0;         // Reset counter value
  
  OCR2A = f_sine_adj;       // Set TOP count value, 16Mega/((freq_req*8)-1) (must be <256), 8kHz
  TCCR2A |= (1 << WGM21);   // Set CTC Mode Operation
  TCCR2B |= (1 << CS21);    // Set clock prescaler, divide by 8
  TIMSK2 |= (1 << OCIE2A);  // Enable timer compare interrupt

  GTCCR = (1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); // Halt all timers
  TCNT0 = 0;                                 // Reset Timer0 count
  TCNT1 = 0x00;                              // Reset Timer1 count (16 bit timer)
  TCNT2 = 0x00;                                 // Reset Timer2 count ( 8-bit timer)
  TCNT3 = 0x00;                                 // Reset Timer2 count ( 8-bit timer)
  TCNT4 = 0x00;                                 // Reset Timer2 count ( 8-bit timer)
  GTCCR = 0;                                 // Release all timers - Sync timers
  
  sei();    //Enable interrupts
  
  //***********************************************************************************************

  
  SetPinFrequency(Pin3,8000);   // Set pin frequency  TIMER_3
  SetPinFrequency(Pin2,8000);   // Set pin frequency  TIMER 3
  SetPinFrequency(Pin5,8000);   // Set pin frequency  TIMER_3

  SetPinFrequency(Pin8,8000);   // Set pin frequency  TIMER_4
  SetPinFrequency(Pin7,8000);   // Set pin frequency  TIMER_4
  SetPinFrequency(Pin6,8000);   // Set pin frequency  TIMER_4
}

void loop(void)
{
  // Enter user code to loop continuously 
}

/********************************************************************************************/
ISR(TIMER2_COMPA_vect)    // Interrupt service routine for Timer_2
{
  if(duty==106)           // Check if at end of array
      duty = 0;           // Restart at first element of array
  else
      {
        

        pwmWrite(Pin8,sine_tableU1[duty]);   // Update duty cycle of Phase U, write to pin
        pwmWrite(Pin7,sine_tableV1[duty]);   // Update duty cycle of Phase V, write to pin
        pwmWrite(Pin6,sine_tableW1[duty]);   // Update duty cycle of Phase W, write to pin

        pwmWrite(Pin5,sine_tableU[duty]);    // Update duty cycle of Phase U, write to pin
        pwmWrite(Pin3,sine_tableV[duty]);    // Update duty cycle of Phase V, write to pin
        pwmWrite(Pin2,sine_tableW[duty]);    // Update duty cycle of Phase W, write to pin
        
        duty++;                              // Index to next element in array
      }
}
/********************************************************************************************/

I think I found the problem. This table in the ATimerDefs.h file of the PWM library doesn't match the defines in Arduino.h:

//4 bytes each, 18 elements, 72 Bytes total
const TimerData timer_to_pwm_data[] = {
{0, 0, 0, 0}, //NOT_ON_TIMER
{0, 0, 0, 0}, //TIMER0A disabled when initialized
{OCR0A_MEM, OCR0B_MEM, TCCR0A_MEM, COM0B1, false}, //TIMER0B

{ICR1_MEM, OCR1A_MEM, TCCR1A_MEM, COM1A1, true}, //TIMER1A
{ICR1_MEM, OCR1B_MEM, TCCR1A_MEM, COM1B1, true}, //TIMER1B no C channel on timer 1?

{0, 0, 0, 0, 0}, //TIMER2 
{0, 0, 0, 0, 0}, //TIMER2A disabled when initialized
{OCR2A_MEM, OCR2B_MEM, TCCR2A_MEM, COM2B1, false}, //TIMER2B

{ICR3_MEM, OCR3A_MEM, TCCR3A_MEM, COM3A1, true}, //TIMER3A
{ICR3_MEM, OCR3B_MEM, TCCR3A_MEM, COM3B1, true}, //TIMER3B
{ICR3_MEM, OCR3C_MEM, TCCR3A_MEM, COM3C1, true}, //TIMER3C

{ICR4_MEM, OCR4A_MEM, TCCR4A_MEM, COM4A1, true}, //TIMER4A
{ICR4_MEM, OCR4B_MEM, TCCR4A_MEM, COM4B1, true}, //TIMER4B
{ICR4_MEM, OCR4C_MEM, TCCR4A_MEM, COM4C1, true}, //TIMER4C
{0, 0, 0, 0, 0}, //TIMER4D 

{ICR5_MEM, OCR5A_MEM, TCCR5A_MEM, COM5A1, true}, //TIMER5A
{ICR5_MEM, OCR5B_MEM, TCCR5A_MEM, COM5B1, true}, //TIMER5B
{ICR5_MEM, OCR5C_MEM, TCCR5A_MEM, COM5C1, true}, //TIMER5C
};

There are 19 defines in Arduino.h, including Timer1C which the PWM library skips. This will cause your Timer3A pin (Pin 5) to land on the Timer2B (Pin 9) entry in the PWM library. Look at Pin 9 to see if your signal is there.

#define NOT_ON_TIMER 0
#define TIMER0A 1
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
#define TIMER1C 5
#define TIMER2  6
#define TIMER2A 7
#define TIMER2B 8
#define TIMER3A 9
#define TIMER3B 10
#define TIMER3C 11
#define TIMER4A 12
#define TIMER4B 13
#define TIMER4C 14
#define TIMER4D 15
#define TIMER5A 16
#define TIMER5B 17
#define TIMER5C 18
1 Like