PWM pin 9 using registers [solved]

I thought it was time that I got my head round using registers to control PWM as I may want to use it for something that I have in mind. Because of existing hardware I need to control the PWM duty cycle on pin 9 of a Nano. Reading around I find that PWM on pins 9 and 10 are controlled by timer1

Looking further I found this example

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  DDRB |= (1 << DDB1) | (1 << DDB2);
  // PB1 and PB2 is now an output
  
  ICR1 = 0xFFFF;
  // set TOP to 16bit
  
  OCR1A = 0x3FFF; //is this pin 9 ?
  // set PWM for 25% duty cycle @ 16bit
  OCR1B = 0xBFFF; //is this pin 10 ?
  // set PWM for 75% duty cycle @ 16bit
  
  TCCR1A |= (1 << COM1A1) | (1 << COM1B1);
  // set none-inverting mode
  
  TCCR1A |= (1 << WGM11);
  TCCR1B |= (1 << WGM12) | (1 << WGM13);
  // set Fast PWM mode using ICR1 as TOP
  
  TCCR1B |= (1 << CS10);
  // START the timer with no prescaler
  
  // we have a working Fast PWM
}

void loop()
{
}

to which I have added questions about which pin is being controlled. The other comments are part of the original example

If the above code is correct then I would expect PWM output on pins 9 and 10 but that does not appear to be occurring. Changing the values of OCR1A or OCR1B does not change the output on pins 9 and 10. 9 appears permanently LOW whilst 10 appears to be permanently HIGH

Where have I gone wrong ?

There are timer presets from the ide which need to be cleared before doing your setup.

It is a good habit to always start your custom timer register code with

TCCR1A = 0;
TCCR1B =0;

I think in your case, the bit in WGM10 is still set from the default pwm mode of the ide and your mode is winding up as Fast pwm to OCR1A.

Then, with OCR1A as TOP value, the output setting makes it always on, and the compare match on OCR1B is never seen as its value is higher than OCR1A.

There is no need to use ICR1 for TOP if you are not using it for variable frequencies. There are several PWM modes with a fixed TOP value. Using ICR1 does give a wider selection of tradeoffs between resolution (bits) and frequency.

Here is an example I wrote of 16-bit PWM on Timer1:

/*
  Demonstration of 16-bit PWM on Timer1
  Written by John Wasser
  
  PWM16Begin(): Set up Timer1 for PWM.
  PWM16EnableA(): Start the PWM output on Pin 9
  PWM16EnableB(): Start the PWM output on Pin 10
  PWM16A(unsigned int value): Set the PWM value for Pin 9.
  PWM16B(unsigned int value): Set the PWM value for Pin 10.
*/


// Set 'TOP' for PWM resolution.  Assumes 16 MHz clock.
// const unsigned int TOP = 0xFFFF; // 16-bit resolution.   244 Hz PWM
// const unsigned int TOP = 0x7FFF; // 15-bit resolution.   488 Hz PWM
// const unsigned int TOP = 0x3FFF; // 14-bit resolution.   976 Hz PWM
// const unsigned int TOP = 0x1FFF; // 13-bit resolution.  1953 Hz PWM
// const unsigned int TOP = 0x0FFF; // 12-bit resolution.  3906 Hz PWM
const unsigned int TOP = 0x07FF; // 11-bit resolution.  7812 Hz PWM
// const unsigned int TOP = 0x03FF; // 10-bit resolution. 15624 Hz PWM




void PWM16Begin()
{
  // Stop Timer/Counter1
  TCCR1A = 0;  // Timer/Counter1 Control Register A
  TCCR1B = 0;  // Timer/Counter1 Control Register B
  TIMSK1 = 0;   // Timer/Counter1 Interrupt Mask Register
  TIFR1 = 0;   // Timer/Counter1 Interrupt Flag Register
  ICR1 = TOP;
  OCR1A = 0;  // Default to 0% PWM
  OCR1B = 0;  // Default to 0% PWM


  // Set clock prescale to 1 for maximum PWM frequency
  TCCR1B |= (1 << CS10);


  // Set to Timer/Counter1 to Waveform Generation Mode 14: Fast PWM with TOP set by ICR1
  TCCR1A |= (1 << WGM11);
  TCCR1B |= (1 << WGM13) | (1 << WGM12) ;
}


void PWM16EnableA()
{
  // Enable Fast PWM on Pin 9: Set OC1A at BOTTOM and clear OC1A on OCR1A compare
  TCCR1A |= (1 << COM1A1);
  pinMode(9, OUTPUT);
}


void PWM16EnableB()
{
  // Enable Fast PWM on Pin 10: Set OC1B at BOTTOM and clear OC1B on OCR1B compare
  TCCR1A |= (1 << COM1B1);
  pinMode(10, OUTPUT);
}


inline void PWM16A(unsigned int PWMValue)
{
  OCR1A = constrain(PWMValue, 0, TOP);
}


inline void PWM16B(unsigned int PWMValue)
{
  OCR1B = constrain(PWMValue, 0, TOP);
}




void setup()
{
  Serial.begin(9600);
  PWM16Begin();


  // On the Arduino UNO T1A is Pin 9 and T1B is Pin 10


  //  PWM16A(0);  // Set initial PWM value for Pin 9
  //  PWM16EnableA();  // Turn PWM on for Pin 9


  PWM16B(0);  // Set initial PWM value for Pin 10
  PWM16EnableB();  // Turn PWM on for Pin 10
}


void loop()
{
  int analogValue = analogRead(A0);
  unsigned int PWMValue = map(analogValue, 0, 1023, 0, TOP);
  PWM16B(PWMValue);  // Update the PWM at the end of the current cycle
}

Thanks John, I have that example working. Now to experiment with it and understand what it is doing should I need to use it in a project