16 bit PWM in atmega328

Hi all,

I hope it’s the right place to ask this question.

I have a project that requires 16 bit PWM signal, so I looked it up and found a code that does just that

void setup() {
  // Set PB1/2 as outputs.
  DDRB |= (1 << DDB1) | (1 << DDB2);

  TCCR1A =
      (1 << COM1A1) | (1 << COM1B1) |
      // Fast PWM mode.
      (1 << WGM11);
  TCCR1B =
      // Fast PWM mode.
      (1 << WGM12) | (1 << WGM13) |
      // No clock prescaling (fastest possible
      // freq).
      (1 << CS10);
  OCR1A = 0;
  // Set the counter value that corresponds to
  // full duty cycle. For 15-bit PWM use
  // 0x7fff, etc. A lower value for ICR1 will
  // allow a faster PWM frequency.
  ICR1 = 0xffff;
}

void loop() {
  // Use OCR1A and OCR1B to control the PWM
  // duty cycle. Duty cycle = OCR1A / ICR1.
  // OCR1A controls PWM on pin 9 (PORTB1).
  // OCR1B controls PWM on pin 10 (PORTB2).
    OCR1A = 0x0f01; // test signal
  OCR1B = 0xf001;   //test signal
}

the above code is taken from HERE

I tested it and pin 9 & 10 ( OCR1A & OCR1B) gave me the 16 bit PWM I am looking for. :slight_smile:

My problem now is integrating the above code in my project.

after integrating the above code in my project pin 10 (OCR1B) is no longer outputting a PWM signal, actually it is always outputting HIGH.

My project is using:

  1. Hardware SPI to control an Oled display with adafruit library
  2. I2C to control ADC ( DS1115) with adafruit library
  3. Interupts for the rotary encoder

I am guessing one of the above is the problem.
below is a portion of my code

//////////// 21.March.2015, Not a completed project. work in progress.
#include <Encoder.h> // Rotary encoder library

#include <Adafruit_ADS1015.h> //////ADC library

 Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */

#include <Adafruit_SSD1306.h>// Adafruit library for the OLED display
#include <Adafruit_GFX.h> // Adafruit library for the OLED display

#include <SPI.h> // needed for the OLED display
#include <Wire.h> // needed for the OLED display

// hardware SPI is used (Hardware Pins are  SCK = 13 and MOSI = 11) cannot be changed 
#define OLED_DC     1 // can be any digital pin
#define OLED_CS     0// can be any digital pin
#define OLED_RESET  A6// can be any digital pin, some displays don't use a RESET pin
Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS);

Encoder myEnc(2, 3); // pin 2 & 3 are inturrpt pins on the Uno, using inurrpt pins is reccomended
unsigned int oldPosition=0; // used for the encoder


void setup()   {                

    // Set PB1/2 as outputs.
  DDRB |= (1 << DDB1) | (1 << DDB2);

  TCCR1A =
      (1 << COM1A1) | (1 << COM1B1) |
      // Fast PWM mode.
      (1 << WGM11);
  TCCR1B =
      // Fast PWM mode.
      (1 << WGM12) | (1 << WGM13) |
      // No clock prescaling (fastest possible
      // freq).
      (1 << CS10);
  OCR1A = 0;
  OCR1B = 0;

  // Set the counter value that corresponds to
  // full duty cycle. For 15-bit PWM use
  // 0x7fff, etc. A lower value for ICR1 will
  // allow a faster PWM frequency.
  ICR1 = 0xffff;

  
  
 display.begin(SSD1306_SWITCHCAPVCC);
//SPI.setClockDivider(SPI_CLOCK_DIV2);


  ads.begin();




}

any idea where my problem/mistake is ? is their a solution ?
I am almost positive that something in my project is messing up Timer1 ( pin 9 &10), but if that is the case then why pin 10 is the only one not working and pin 9 is working fine !
I searched for a solution but no luck.

your help is appreciated.

Regards,

Hardware SPI also uses pin 10 as SS (slave select). Since your OLED library seems to use hardware SPI it is probable that is conflicting, as you report pin 10 as being the problem pin.

A brief read of the library code indicates you should be able to use bit-banged SPI instead, which might help.

Wow, that was the problem! The moment I changed to Software SPI instead of Hardware, pin 10 came back to life.

Many thanks :)

You can still use hardware SPI. You can use the SS pin (pin 10) as an output while using SPI. You just have to change the order of your setup so that the PWM is configured after you initialize the display.

The display.begin() method calls SPI.begin() which in turn calls digitalWrite(10, HIGH). The digitalWrite() function explicitly disables PWM on the pin.

So just reverse the order, display.begin() first, then set up your timers.