Do I need to run an ISR to get fast PWM working?

Hello,

I am trying to generate the pwm waveform shown in the attached image using an arduino nano (atmega328). I’m using the 16 bit timer (timer 1) and I’m having trouble getting any pwm output on the pins. I’ve been testing with a bench top digital power supply inputting 9 V (20 mA) into Vin. The light on the micro is on but I’m not getting any output on the pwm pins (connected to an oscilloscope). I suspect there is something wrong with how I have set up my code.

I thought if I selected Fast PWM then it generates an output at the pin on compare automatically and I didn’t need to use an ISR. I can set one up if needed and I know it can be done that way but I didn’t think it was necessary. Am I wrong and do I need to set up an ISR or is there a different reason my PWM is not working?

And if I do need an ISR to get the PWM working then what’s the point of having an inverted fast pwm option when you can set the output pin either low or high in the ISR?

void setup() 
{
  // Defining PB1 and PB2 as outputs by setting PORTB1 and PORTB2
  // Setting DDB1 and DDB2
  DDRB = DDRB | 00000110;
  
  //stop interrupts
  cli();
  
  // Initilize OCR1A = 300 (pulse_width = 150us), OCR1B, and ICR1
  ICR1 = 0xFFFF;
  OCR1B = 299;
  OCR1A = ICR1 - OCR1B;
  
  // Enable Timer/counter1 by clearing PRTIM1
  PRR = PRR & 11110111;
  
  // Selecting the Prescaler to be 8, frequency is 30.5 Hz
  // Clearing clock select bits CS12 and CS10 
  TCCR1B = TCCR1B & 11111010;
  // Setting clock select bit CS11
  TCCR1B = TCCR1B | 00000010;
  
  // We want non-inverting mode for OC1A, and inverting mode for OC1B
  // Clearing COM1A0
  TCCR1A = TCCR1A & 10111111;
  // Setting COM1A1, COM1B1, and COM1B0
  TCCR1A = TCCR1A | 10110000;
  
  // We want Fast PWM with ICR1 as TOP
  // Clearing WGM10
  TCCR1A = TCCR1A & 11111110;
  // Setting WGM11
  TCCR1A = TCCR1A | 00000010;
  // Setting WGM13 and WGM12
  TCCR1B = TCCR1B | 00011000;
  
  // Enable PWM
  // Setting OCIE1A and OCEI1B
  TIMSK1 = TIMSK1 | 00000110;
  
  //allow interrupts 
  sei(); 

}

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

}

You don't need interrupts and you don't want this line:

  TIMSK1 = TIMSK1 | 00000110;

That will enable an interrupt handler that you don't have.

Can you please redo your sketch with proper names? My eyes are glazing over looking at all those bits. For example, instead of:

  DDRB = DDRB | 00000110;

Use:

  DDRB |= bit (DDB1) | bit (DDB2);

The days of writing code in binary have well and truly gone.


  // Enable Timer/counter1 by clearing PRTIM1
  PRR = PRR & 11110111;

PRR is the power reduction register. That's not an appropriate way of starting the timer. It will be on, anyway.

This is closer to what you want:

void setup()
  {
  // Defining PB1 and PB2 as outputs by setting PORTB1 and PORTB2
  // Setting DDB1 and DDB2
  DDRB |= bit (DDB1) | bit (DDB2);
 
  // stop timer 1
  TCCR1A = 0;
  TCCR1B = 0;
  
  TCCR1A = bit (COM1B0) | bit (COM1B1)  // Set OC1B on Compare Match, clear
                                        // OC1B at BOTTOM (inverting mode)
         | bit (COM1A1)                 // Clear OC1A on Compare Match, set
                                        // OC1A at BOTTOM (non-inverting mode)
         | bit (WGM11);                 // Fast PWM, top at ICR1
  TCCR1B = bit (WGM12)  | bit (WGM13)   //       ditto
         | bit (CS11);                  // Start timer, prescaler of 8

  // Initialize OCR1A = 300 (pulse_width = 150us), OCR1B, and ICR1
  ICR1 = 0xFFFF;
  OCR1B = 299;
  OCR1A = ICR1 - OCR1B;

  }  // end of setup

void loop()
  {
  }

Output of it:

Thank you :slight_smile:

Seems to be outputting nice pwm now and I just realised I had which pin I wanted to invert opposite ways but that's easy to fix. I think possibly for the binary I maybe needed to write B00000110 rather than 00000110 and that might have been another issue but I'll use the proper names rather than binary since it seems nicer way to write it anyway. Sorry for the belated reply and thanks for the help :).