Programming a PWM in an Arduino Mega ATmega2560 micro-controller

Rego picture Rego · Sep 19, 2012 · Viewed 10.6k times · Source

I'm trying to enable a PWM on an Arduino Mega (ATmega2560), but I'm facing to some issues.

First, I'm trying to program this in Ada. I desire to use the three Timer3 channels with FastPWM, so I wrote

procedure Main is
begin

   -- Nullify Timer3 buffers
   TCCR3A := 0;
   TCCR3B := 0;
   TCCR3C := 0;

   -- Waveform Generation Mode
   --  Fast PW, 8-bit, TOP = 0x00FF, Update OCR3x at BOTTOM, TOV3 Flag Set on TOP
   --  => WGM33|WGM32|WGM31|WGM30 = 0|1|0|1
   TCCR3A := TCCR3A or TCCR3A_WGM30;
   TCCR3B := TCCR3B or TCCR3B_WGM32;

   -- Compare Output Mode:
   --  Fast PWM, non-inverting mode
   --  => COM3A1|COM3A0|COM3B1|COM3B0|COM3C1|COM3C0 = 1|0|1|0|1|0
   TCCR3A := TCCR3A or TCCR3A_COM3A1 or TCCR3A_COM3B1 or TCCR3A_COM3C1;

   -- Clock Select: clk/1024 => CS32|CS31|CS30 = 1|1|1
   TCCR3B := TCCR3B or TCCR3B_CS32 or TCCR3B_CS31 or TCCR3B_CS30;

   -- Set Timer3 pins as output :
   -- Channel A : Digital Pin 5 / Chip Pin 5 (PE3/OC3A/AIN1)
   -- Channel B : Digital Pin 2 / Chip Pin 6 (PE4/OC3B/INT4)
   -- Channel C : Digital Pin 3 / Chip Pin 7 (PE5/OC3C/INT5)
   DDRE := DDRE_DDE3 or DDRE_DDE4 or DDRE_DDE5;

   OCR3AH := 0;
   OCR3AL := 250;

   OCR3BH := 0;
   OCR3BL := 250;

   OCR3CH := 0;
   OCR3CL := 250;

end Main;

The hardware connections are OK; I tested it using simple code on the Arduino IDE. So for me it's very clear that the code is lacking something or making something wrong, and this should be caused by an issue in PWM initialization. Could someone explain me where did I make such a mistake?

Thanks in advance.

Update

If Ada can be difficult to get the whole logic, the equivalent code in C is (you can build it using AS6, the result is the same, i.e., no signal is generated):

int main(void){
    TCCR3A = 0;
    TCCR3B = 0;
    TCCR3C = 0;

    /* Waveform Generation Mode
    Fast PW, 8-bit, TOP = 0x00FF, Update OCR3x at BOTTOM, TOV3 Flag Set on TOP
    => WGM33|WGM32|WGM31|WGM30 = 0|1|0|1 */
    TCCR3A = TCCR3A|(1<<WGM30);
    TCCR3B = TCCR3B|(1<<WGM32);

    /* Compare Output Mode:
    Fast PWM, non-inverting mode
    => COM3A1|COM3A0|COM3B1|COM3B0|COM3C1|COM3C0 = 1|0|1|0|1|0*/
    TCCR3A = TCCR3A|(1<<COM3A1)|(1<<COM3B1)|(1<<COM3C1);

    /* Clock Select: clk/1024 => CS32|CS31|CS30 = 1|1|1 */
    TCCR3B = TCCR3B|(1<<CS32)|(1<<CS31)|(1<<CS30);

    /* Set Timer3 pins as output :
    Channel A : Digital Pin 5 / Chip Pin 5 (PE3/OC3A/AIN1)
    Channel B : Digital Pin 2 / Chip Pin 6 (PE4/OC3B/INT4)
    Channel C : Digital Pin 3 / Chip Pin 7 (PE5/OC3C/INT5)*/
    DDRE = DDRE|(1<<DDE3)|(1<<DDE4)|(1<<DDE5);

    /* Set PWM Duty Cycles */
    OCR3AH = 0;
    OCR3AL = 250;

    OCR3BH = 0;
    OCR3BL = 250;

    OCR3CH = 0;
    OCR3CL = 250;
}

Answer

Brian Drummond picture Brian Drummond · Nov 19, 2012

Looking at www.atmel.com/Images/doc2549.pdf page 136, I see a note:

"The Power Reduction Timer/Counter3 bit, PRTIM3, in “PRR1 – Power Reduction Register 1” on page 57 must be written to zero to enable Timer/Counter3 module."

May be relevant?

I don't know what the defaults are for the power management regs, and I haven't used the 2560.

The rest looks OK to me, though I have used the timer libraries avr-timer0.adb etc on the 328p instead of rolling my own.