3 out of 4 timer pins don't do anything

I’m sorry to ask about this after all the past posts I’ve made about timers but I’m honestly oblivious to the gremmlins that operate inside them. I do what the spec sheet says, I do what the manual says and I get totally weird results. If there’s an error in my code, staring at it for hours has not helped me find it.

All I want is to get a complimentary output on timers 1 and 2 (pins 3, 11, 9 and 10). I get a wave on pin 3 so if pin 3 works, why the heck doesn’t pin 11 work when I’ve very nearly copy pasted the setup for that? Also neither pins 9 or 10 work so I don’t even have a starting point there.

void setup() {

  DDRB |= (1 << PB3);
  DDRD |= (1 << PD3);

  cli();

  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = 0;
  
  OCR2A = 127;
  OCR2B = 127;

  TCCR2A |= (1 << WGM20);
  TCCR2A |= (1 << WGM21);
  TCCR2B |= (1 << WGM22);

  TCCR2A |= (1 << COM2B1);
  TCCR2A |= (1 << COM2A1);
  TCCR2A |= (1 << COM2A0);
  
  TCCR2B |= (1 << CS20);

  TIMSK2 |= (1 << OCIE2A);
  TIMSK2 |= (1 << OCIE2B);
  

  DDRB |= (1 << PB1);       // Pin 9 output
  DDRB |= (1 << PB2);       // Pin 10 output
  TCCR1A = 0;               // Clear register
  TCCR1B = 0;               // Clear register
  TCCR1A = (1 << COM1A1);   // Non-inverting on A pin 
  TCCR1A = (1 << COM1B0);   // Inverting on B pin
  TCCR1A = (1 << COM1B1);   // Inverting on B pin
  TCCR1B = (1 << WGM13);    // Mode 8 for phase/freq correct using ICR top
  TCCR1B = (1 << CS10);     // No prescaler
  ICR1 = 400;               // Define top. 400 = 40kHz but full wave is 1/2 that or 20kHz
  OCR1A = 200;              // Define OCR = duty.  This will vary
  TIMSK1 |= (1 << OCIE1A);
  TIMSK1 |= (1 << OCIE1B);

  sei();
}

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

}


ISR (TIMER2_COMPA_vect) {

  digitalWrite(3, !digitalRead(3));
  
}
ISR (TIMER2_COMPB_vect) {

  digitalWrite(11, !digitalRead(11));
  
}
ISR (TIMER1_COMPA_vect) {

  digitalWrite(9, !digitalRead(9));
  
}
ISR (TIMER1_COMPB_vect) {

  digitalWrite(10, !digitalRead(10));
  
}

You are using WGM 7. That means that OCR2A is used to set the TOP of the count and can’t be used for PWM. You can use OCR2A for PWM if you use WGM 3 (TOP is a constant 255).

Also, for Timer1 you forgot to set OCR1B:

  ICR1 = 400;               // Define top. 400 = 40kHz but full wave is 1/2 that or 20kHz
  OCR1A = 200;              // Define OCR = duty.  This will vary

John has pointed out the issue with fast PWM with OCR2A.

I think you also have fundamental problem with trying to use both hardware compare output modes on the A and B pins and compare interrupts with digital output on the same pins. When the hardware outputs are enabled the pins are disconnected from normal digital input/output.

From the data sheet

Bits 7:6 – COM2An: Compare Output Mode for Channel A [n = 1:0]
These bits control the Output Compare pin (OC2A) behavior. If one or both of the COM2A[1:0] bits are
set, the OC2A output overrides the normal port functionality of the I/O pin it is connected to.

I think you will get the current state of the output pin when you use digitalRead(), even if the output is being driven by the timer.

Ok I made both corrections (removing the pinmode setup and adding OCR1B).
However all this did was transform pin 3 into a sawtooth (how that happened is beyond me). Still nothing at all on pins 11, 9 and 10. I should also point out that I have tested this sketch on 2 nanos to ensure the drivers are not simply blown or something.

Ok… I figured I’d try mode 3 just for fun and I put the port setup back in. Seems you do need those lines of code for it to work properly. Now I’m getting output on 3 and 11 but 3 is 30kHz and 11 is 62.5 kHz. Whaaa???

And Timer 1 still gives nothing.

Edit:

On a hunch I blew away the B channel interrupt and ISR and put the pin toggle onto the interrupt for channel A. This way there’s only 1 interrupt that occurs when OCR2A does a compare match and that match toggles both pins. Now I get 17.5 kHz on both 3 and 11. Dunno where these weird frequency numbers are coming from but things are at least moving in the right direction. However 3 and 11 are slightly out of phase from 180 degrees and are more like 100 degrees out of phase. Got the edge from 1 coinciding with 2/3 across the peak of the other. Something weird is going on here since I can delete certain important lines of code and it doesn’t even affect anything.

What output on what pins are you trying to achieve?

Trying to get complimentary outputs (1 inverted 1 non-inverted) on pins 3, 11, 9 and 10 all at the same time.

At the present time I have 3 and 11 working at 62.5 kHz. I have pin 9 working as well but pin 10 just will not work - it’s flatlined and I see nothing wrong with the code as it’s identical to numerous web examples:

void setup() {

  DDRB |= (1 << PB3);
  DDRD |= (1 << PD3);

  DDRB |= (1 << PB1);       // Pin 9 output
  DDRB |= (1 << PB2);       // Pin 10 output

  cli();

  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = 0;
  
  OCR2A = 127;
  OCR2B = 127;

  TCCR2A |= (1 << WGM20);
  TCCR2A |= (1 << WGM21);    
//  TCCR2B |= (1 << WGM22);    // I got fed up and switched modes and it worked

  TCCR2A |= (1 << COM2B1);
  TCCR2A |= (1 << COM2A1);
  TCCR2A |= (1 << COM2A0);
  
  TCCR2B |= (1 << CS20);

//  TIMSK2 |= (1 << OCIE2A);
//  TIMSK2 |= (1 << OCIE2B);
  


  TCCR1A = 0;               // Clear register
  TCCR1B = 0;               // Clear register
  TCNT1 = 0;

  ICR1 = 400;               // Define top. 400 = 40kHz but full wave is 1/2 that or 20kHz
  OCR1A = 200;              // Define OCR = duty.  This will vary
  OCR1B = 200;

  TCCR1A = (1 << COM1B1);   // Non-inverting on B pin 
  TCCR1A = (1 << COM1A0);   // Inverting on A pin
  TCCR1A = (1 << COM1A1);   // Inverting on A pin
  TCCR1B = (1 << WGM13);    // Mode 8 for phase/freq correct using ICR top
  TCCR1B = (1 << CS10);     // No prescaler

//  TIMSK1 |= (1 << OCIE1A);
//  TIMSK1 |= (1 << OCIE1B);

  sei();
}

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

}

I agree that there is nothing wrong with the code (except your Timer1 TOP is off by 1). I think you have a hardware problem.

What is the resistance between Pin 10 and Ground when the Arduino is powered off? If it is Open Line (infinite resistance) there may be a broken trace or connection. If it is a very low resistance it may be shorted to Ground.

I added some comments to keep track of what the c ode was doing:

// Trying to get complimentary outputs (1 inverted 1 non-inverted) on pins 3, 11, 9 and 10 all at the same time.

// Output Compare Pins
const byte OC1A = 9;  // PB1
const byte OC1B = 10; // PB2
const byte OC2A = 11; // PB3
const byte OC2B = 3;  // PD3

void setup()
{
  pinMode(OC1A, OUTPUT);
  pinMode(OC1B, OUTPUT);
  pinMode(OC2A, OUTPUT);
  pinMode(OC2B, OUTPUT);

  cli();

  //////////////////////
  // Timer2
  //////////////////////
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = 0;

  // WGM3: Fast PWM. TOP=255 (62.5 kHz)
  TCCR2A |= (1 << WGM20);
  TCCR2A |= (1 << WGM21);
  //  TCCR2B |= (1 << WGM22);

  // Square wave
  OCR2A = 127;
  OCR2B = 127;

  // Inverted PWM on OC2A
  TCCR2A |= (1 << COM2A1);
  TCCR2A |= (1 << COM2A0);
  // Normal PWM on OC2B
  TCCR2A |= (1 << COM2B1);

  // Set Clock Select to 1: No Prescale
  TCCR2B |= (1 << CS20);

  //  TIMSK2 |= (1 << OCIE2A); // Enable Output Compare Interrupt on OCR2A
  //  TIMSK2 |= (1 << OCIE2B); // Enable Output Compare Interrupt on OCR2B


  //////////////////////
  // Timer1
  //////////////////////
  TCCR1A = 0;               // Clear register
  TCCR1B = 0;               // Clear register
  TCNT1 = 0;

  // WGM8: PWM, Phase and Frequency Correct, TYOP in ICR1
  TCCR1B |= (1 << WGM13);    // Mode 8 for phase/freq correct using ICR top

  ICR1 = 399;               // Define TOP=399 (20 kHz)

  // Square Waves on both channels
  OCR1A = 199;              // Define OCR =
  OCR1B = 199;

  // Inverted PWM on OC1A
  TCCR1A |= (1 << COM1A0);   // Inverting on A pin
  TCCR1A |= (1 << COM1A1);   // Inverting on A pin
  // Normal PWM on OC1B
  TCCR1A |= (1 << COM1B1);   // Non-inverting on B pin

  // Set Clock Select to 1: No Prescale
  TCCR1B |= (1 << CS10);

  //  TIMSK1 |= (1 << OCIE1A); // Enable Output Compare Interrupt on OCR1A
  //  TIMSK1 |= (1 << OCIE1B); // Enable Output Compare Interrupt on OCR1B

  sei();
}

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

Hope you don’t mind but instead of measuring resistance I just tried 2 other nanos I had at hand and did a component swap. They both behave the same. By the way I should also note that I’m getting a square wave of 122 Hz on 9 which is odd since that’s way too slow for CS10. Changing the prescaler even slower makes the wave slower still. Pin 10 still has nothing even after every combination of COM1.

Something must be wrong about the code… maybe the order of things? I know Nick wrote comprehensive tutorials for timers but his coding style is very unlike the code above so it’s hard for me to just line up the pieces.

OOPS! I didn’t notice it before and I included the same mistake in my code. The ‘=’ should be ‘|=’ to set bits without clearing bits. That explains why everything is wrong.
“TCCR1A = (1 << COM1A1);” turns on PWM on OC1A but it turns off the inversion and turns off PWM on OC1B.
"TCCR1B = (1 << CS10); " turns on Clock Select 1 (no prescale) but it sets the WGM back to 0. That sets TOP to 0xFFFF (244+Hz) and OC1A toggles every compare match so 122+Hz.

Do you mean I have to re-order the lines of code so that WGM comes after CS10?

If that fixes the frequency problem, do you have any insights as to why my pin10 refuses to work? Thanks for your continued help.

No. I said "The ‘=’ should be ‘|=’ to set bits without clearing bits. "

As I explained, “TCCR1A = (1 << COM1A1);” turns on PWM on OC1A but it turns off the inversion and turns off PWM on OC1B. OC1B is Pin 10.

No. You need to use |= (the compound bitwise or) instead of = (equal) as you set multiple bits in a register. When you use = any previous setting is blown away.

I always like to set the CS bits last, as that actually starts the timer.

Oops. I see John beat me to the reply.

1 Like

Holy crap, how did I miss that!

See the problem with getting absorbed in a coding problem is that the most elementary of syntax errors become suddenly invisible to you as you look for complex issues that aren’t there.

Now it frickin works.

Thanks guys. This is another one for the archives so I don’t have to ask again 2 yrs from now.

1 Like

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.