[DONE] HiSpeed PWM (158kHz+) on 2 Pins with timer1

Hi!

I am a bloody beginner with arduino but managed to get a fast PWM running. I neeed the fastes PWM possible. However, with the scetch below i can make a PWM with 158kHz period and putting it out to Pin11. Also i am trying to make a second PWM with the same frequency with another thimer (2 instead of 1). However, this doesnt seem to work at all. The Pin10 just stays 0V, no PWM whatsoever... Pin10 only shows a bit more noise than the other pins: 17mVrms / 100mVpp @ around 33MHz

#define TCCR1B_CS20 0x01    // CS2:0 bits = prescaler selection = 0x01 = no prescaler --> Full 16MHz yay!
#define TCCR2B_CS20 0x01    // CS2:0 bits = prescaler selection = 0x01 = no prescaler --> Full 16MHz yay!

int period = 100;           // How many ticks shall = one period?
int duty1 = 25;              // The desired dutycycle #1. Lets make 25%
int duty2 = 53;              // The desired dutycycle #2. Lets make 53%

void setup() {
// Timer1, Pin11
  analogWrite(11,duty1); // let Arduino setup do its thing and set this pin as OUTPUT, PWMised
  TCCR1B = 0x00;          // stop Timer1 clock for register updates
  TCCR1A = 0x82;          // Clear OC1A on match, Fast PWM Mode: lower WGM1x = 14
  ICR1 = period;    // drive PWM period
  TCNT1 = duty1 - 1;   // force immediate OCR1A compare on next tick
  OCR1A = duty1;   // ON duration = drive pulse width
  TCCR1B = 0x18 | TCCR1B_CS20;    // upper WGM1x = 14, Clock Sel = prescaler, start running
  
// Timer2, Pin10
  analogWrite(10,duty2); // let Arduino setup do its thing and set this pin as OUTPUT, PWMised
  TCCR2B = 0x00;          // stop Timer2 clock for register updates
  TCCR2A = 0x82;          // Clear OC2A on match, Fast PWM Mode: lower WGM1x = 14
  ICR1 = period;    // drive PWM period
  TCNT2 = duty2 - 1;   // force immediate OCR2A compare on next tick
  OCR2A = duty2;   // ON duration = drive pulse width
  TCCR2B = 0x18 | TCCR2B_CS20;    // upper WGM1x = 14, Clock Sel = prescaler, start running
}

void loop() {
}

I am sure it is my fault, but i cannot think of what i missed... I read the forums and googled for around 3 hours... Found a lot of info on PWM, but wasnt able to find a solution...

Edit: Changed topic title to a better one which describes the solution a bit.

analogWrite() produces a PWM with the duty cycle that you specify using the timers. I’m not sure if this would make a difference, but did you try moving the function call after modifying the registers?

I tryed (and just REtryed to be sure) that already: Doesnt matter where i have the

  analogWrite(11,duty1); // let Arduino setup do its thing and set this pin as OUTPUT, PWMised
  analogWrite(10,duty2); // let Arduino setup do its thing and set this pin as OUTPUT, PWMised

At the top of the setup, at the bottom of the setup or one line just befor the disabling of the corresponding timers: The Pin10 stays @ 0V :(

the

analogWrite(11,duty1); // let Arduino setup do its thing and set this pin as OUTPUT, PWMised
analogWrite(10,duty2); // let Arduino setup do its thing and set this pin as OUTPUT, PWMised

are only there to make SURE the Pin is configured right...

Someone?

Also using a single timer (lets say timer1) would work as long as i can set 2 pins with different duty-cycles but with the same frequency...

Like: PinX = 158kHz PWM @ 50% duty; PinY = 158kHz PWM @ 37% duty

Is there somewhere a good explanation of TCCR1A and TCCR1B? Cant find anything usable really... I found something about TCCR2A and TCCR2B over at fiz-ix.com but nowhere it telly me if TCCR1X is the same layout as TCCR2X :(

Also found http://arduinodiy.wordpress.com/2012/02/28/timer-interrupts/ where they explain the registers in question but for the ATmega328 and not for the ATmega1280 i use on my Arduino Mega. :(

YAY!!! :D

I assumed that the Layout given @ http://timogruss.de/2013/06/die-timer-des-atmega128-ctc-modus-clear-timer-on-compare/ are not only for the Atmega128 but also for the 1280.

Trying to understand what i found online (and posted above) to make a working 158kHz-PWM on Pin11 with Timer1 i managed to reverse-engineer the working code. From this point it was a battle uphill, but i didnt give up... In the end i was able to make (almost. Later more on that) what i wanted: 2 Pins with separate duty-cycles on full speed (158kHz with 1%-stepping) :) (Note: If you make a stepping of 5% you only need to count to 20 inestead of 100 and this speeds up your PWM-frequency by factor 5. So the lower your resolution, the higher you can go with the frequency. 800kHz? No Problem!) I also only needed one timer (Timer1). Phew!

Here is my commented code:

int period = 99;           // How many ticks shall = one period? (Remember: Starts with 0! 0..99 = 100 Ticks)
int duty1 = 53;              // The desired dutycycle #1. Lets make 53%
int duty2 = 11;              // The desired dutycycle #2. Lets make 11%

void setup() {

  // Set the Pins to output. Pins 13-2 are PWM-capable on my Arduino mega (Atmega1280)
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);

  // Init timer1
  // STOP & clear
  TCCR1B = TCCR1A = B00000000; // Clear TCCR1A (for a known start) and  TCCR1B (to stop timer1 clock for register updates)

  // Define the pins and theyr behaviour / linking
  TCCR1A = TCCR1A | B10000000; // Clear OC1A on match, set OC1A at BOTTOM (Non-Inverting-Mode) --> Pin11
  TCCR1A = TCCR1A | B00100000; // Clear OC1B on match, set OC1B at BOTTOM (Non-Inverting-Mode) --> Pin12

  // Waveform Generation Mode: I want WGM12-WGM10 set to binary 110 --> Fast PWM, Top = ICR1 , Immediate update of OCR1A
  TCCR1A = TCCR1A | B00000010; // WGM11 = 1 & WGM10 = 0
  TCCR1B = TCCR1B | B00001000; // WGM12 = 1

  // Define TOP and the Compare
  ICR1 = period;      // ICR1 = TOP --> FastPWM with TOP = ICR1: Counts 0 to ICR1: --> drive PWM period
  TCNT1 = duty1 - 1;  // force immediate OCR1x compare on next tick

  // Set the prescaler and an unknown (to me) bit which seems important
  TCCR1B = TCCR1B | B00000001;    // last 3 bits = B001 --> prescaler = 1
  TCCR1B = TCCR1B | B00010000;  // Seems to be a read-only-bit? why set it? dont know. was this way online... 
                                // Without it, PWM-Duty HIGH is OK, but LOW is WAY too long... 30.4us instead of 4.6us.

    // Define the dury-cycles (Those can be set later on in te loop() as well!)
  OCR1A = duty1;   // ON duration = drive pulse width of OCR1A --> PIN11
  OCR1B = duty2;   // ON duration = drive pulse width of OCR1B --> PIN12
}


void loop() {
}

If someone could explain to me the bit 4 in TCCR1B and its function, i would be very happy since i want to understand the matter. ;)

Also i didnt accieved one little detail: If i set the duty to 0 it still puts the pin on 1 for 60ns. Thats normal and (now) expected: The pin gets set on the transition from counter TOP to counter BOTTOM and gets reset the tick afterwards. But it was ON for one comparation-cycle --> one clock-tick.