TCNT1 based Fast PWM (Mode-14) Ch-B Inverting -- NOT WORKING!

The following TCNT1 based sketch is uploaded in UNO to generate 5 Hz PWM signal (test signal to see activities on LED) on Ch-A (non inverting) and Ch-B (inverting) in Mode-14 Fast PWM. Ch-A (DPin-9) is working showing activities; but, Ch-B (DPin-10) is not working showing constant HIGH state. Would appreciate if someone checks what RONG I am doing here. (The registers' bit lay out are given below for quick reference.)

#define OC1A 9
#define OC1B 10

void setup()
{
  Serial.begin(9600);
  pinMode(OC1A, OUTPUT); //Ch-A 
  pinMode(OC1B, OUTPUT); //Ch-B

  TCCR1A = 0x00;   //reset
  TCCR1B = 0x00;   //TC1 reset and OFF
  //fOC1A = clckSys/(N*(1+ICR1)); Mode-14 FPWM; OCR1A controls duty cycle
  // 5 Hz = 16000000/(64*(1+ICR1)) ==> ICR1 = 49999

  TCCR1A |= (1 << COM1A1) | (0 << COM1A0) | (1 << WGM11); //Ch-A non-inverting, Mode-14
  TCCR1A |= (1 << COM1B1) | (1 << COM1B0); //Ch-B inverting 

  ICR1 = 49999;  //changes frequency as ICR changes
  OCR1A = 25000;   //~= 50% duty cycle 
  OCR1B = 25000;
  TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11) | (1 << CS10); //Mode-14, N = 64; 
}

void loop()
{
}


TCCR1A-1B
clockSelectionTC1

The timer seems not to count at all, my outputs are both LOW.

With all constants UL both outputs blink, but at duty cycle far away from 50%, near 8%.

Maybe is it that way

TCCR1B = (1 << WGM13).....
TCCR1B |= (1 << WGM13).....

1. Both channels are working fine in non-inverting mode with the following COM1x bits settings:

COM1A1 = 1, COM1A0 = 0
COM1B1 = 1, COM1B0 = 0

2. The channels are found not working in inverting mode with the following CM1x bits settings:

COM1A1 = 1, COM1A0 = 1
COM1B1 = 1, COM1B0 = 1

Even with all constants U/UL (unsigned/unsigned long), Ch-A works in non-inverting mode; Ch-B does not work in inverting mode. However, both channels work well in non-inverting mode.

Indeed I can confirm you findings about the inverted output having issues in fast pwm to icr1 mode, but don't understand the root cause yet.

But the data sheet says about the possibility of generating invert/non-inverted PWM signals (Fig-1).


Figure-1:

Even in Mode-10 Phase Correct PWM, the channels are not working in inverted mode (COM1x1:COM1x0 = 1:1).

#define OC1A 9
#define OC1B 10

void setup()
{
  Serial.begin(9600);
  pinMode(OC1A, OUTPUT); //Ch-A 
  pinMode(OC1B, OUTPUT);

  TCCR1A = 0x00;   //reset
  TCCR1B = 0x00;   //TC1 reset and OFF
  //fOC1A = clckSys/(2*N*ICR1); Mode-14 FPWM; OCR1A controls duty cycle
  // 5 Hz = 16000000/(2*64*ICR1) ==> ICR1 = 25000
  TCCR1A |= (1 << COM1A1) | (1 << COM1A0) | (1 << WGM11); //Ch-A non-inverting, Mode-14
  TCCR1A |= (1 << COM1B1) | (1 << COM1B0); //Ch-B inverting 

  ICR1 = 25000U;  //changes frequnecy as ICR chnages
  OCR1A = 12500U;   //~= 50% duty cycle 
  OCR1B = 12500U;
  TCNT1 = 0;
  TCCR1B |= (1 << WGM13) | (0 << WGM12) | (1 << CS11) | (1 << CS10); //Mode-14, N = 64; 
}

void loop()
{
}

Tried with your style of ORing; but, the result is the same.

How do you know?

I viewed both channels with my scope and found that the duty cycle is far away from 50%. That makes one channel almost LOW (or blink) while the other one is almost HIGH, not recognized as blinking. I could not really get a 50% cycle based on the given sketch.

Has anybody checked what the TimerOne library does with FastPWM mode?

The order of setup for the timer matters. If you set the outputs and the mode before giving specific values and starting the timer the output is as expected. That is, alternating flashes at 5 Hz on two leds attached to 9 and 10.

#define OC1A 9
#define OC1B 10

void setup()
{
  Serial.begin(9600);
  pinMode(OC1A, OUTPUT); //Ch-A
  pinMode(OC1B, OUTPUT); //Ch-B

  TCCR1A = 0x00;   //reset
  TCCR1B = 0x00;   //TC1 reset and OFF
  //fOC1A = clckSys/(N*(1+ICR1)); Mode-14 FPWM; OCR1A controls duty cycle
  // 5 Hz = 16000000/(64*(1+ICR1)) ==> ICR1 = 49999

  TCCR1A |= (1 << COM1A1) | (0 << COM1A0);  //Ch-A non-inverting, Mode-14
  TCCR1A |= (1 << COM1B1) | (1 << COM1B0); //Ch-B inverting
  TCCR1A |= (1 << WGM11);
  TCCR1B |= (1 << WGM13) | (1 << WGM12);
  ICR1 = 49999;  //changes frequency as ICR changes
  OCR1A = 25000;   //~= 50% duty cycle
  OCR1B = 25000;
  //TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11) | (1 << CS10); //Mode-14, N = 64;
  TCCR1B |= (1 << CS11) | (1 << CS10);


}

void loop()
{
}
1 Like

Thanks for pointing out! :slight_smile:

I knew that there was a pitfall but couldn't remember where it was.

In the original sketch the mode 2 was initialized that trims the immediately following compare values to 9 bits. Only after that mutilation the mode 14 was established.

1. Great! Great!!
Your sketch of post #9 is perfectly working! Frequency is reduced to 1 Hz and the LEDS are visibly alternately flashing. Moreover, both channels are working in non-invert and invert modes.

2.

The sequences of TC1 intializations:
(1) Reset TCCR1A and TCCR1B
(2) Set COM1x Bits for Ch-A
(3) Set COM1x Bits for Ch-B
(4) Set the Wave form Mode
(5) Set the values for TOP and duty cycles.
(6) Start TC1 with required prescale/division factor.

3. Let us note down the above sequence of initializations as shown by @cattledog. Humble appreciation towards the time that @cattledog has spent to resolve the case.

The LED1 and LED2 of the following diagram (Fig-1) are not flashing alternately. lED1 is flashing at 1 Hz; but, LED2 stays at constant HIGH state.
pwmApp

Figure-1:

These signals are not inverse (180°) but shifted (90°).

1.

But the following figure (Fig-1) shows that the signals Ch-A and Ch-B are of opposite polarity and synchronized. They must be synchronized meaning when Ch-A is rising , Ch-B must be falling at the same instant for them to be useful in practical applications.


Figure-1:

2. To verifyy that the signals are indeed of opposite and synchronized, let us carry out the following experiment by measuring the time interval (500 ms) between the falling edges of signals marked Ch-A and Ch-B in Fig-1. Signals at Ch-A (non-invert) and Ch-B (invert) are of opposite polarity and synchronized, which being generated using TC1 in Fast PWM Mode-14. The PWM signals are simulating the sensor signals very closely.
int0int1-1HzPWM
Figure-1:

Sketch:

volatile unsigned long timer2OverflowCount = 0;
volatile bool flag1, flag2;
volatile byte myCount = 0;

#define OC1A 9
#define OC1B 10

void setup()
{
  Serial.begin(9600);
  //-------------------------
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), ISRZ, FALLING);
  attachInterrupt(digitalPinToInterrupt(3), ISR1, FALLING);
  TIMSK2 |= (1 << TOIE2);  //TC1 overflow interrupt is enabled
  //----------------
  TCCR2A = 0x00;
  TCCR2B = 0x00;
  TCNT2 = 0x00;
  //-------generating Ch-A and Ch-B signals-------------
  pinMode(OC1A, OUTPUT); //Ch-A
  pinMode(OC1B, OUTPUT); //Ch-B

  TCCR1A = 0x00;   //reset
  TCCR1B = 0x00;   //TC1 reset and OFF
  //fOC1A = clckSys/(N*(1+ICR1)); Mode-14 FPWM; OCR1A controls duty cycle
  // 1 Hz = 16000000/(64*(1+ICR1)) ==> ICR1 = 62499, N = 256

  TCCR1A |= (1 << COM1A1) | (0 << COM1A0);  //Ch-A non-inverting, Mode-14
  TCCR1A |= (1 << COM1B1) | (1 << COM1B0); //Ch-B inverting
  TCCR1A |= (1 << WGM11);
  TCCR1B |= (1 << WGM13) | (1 << WGM12);
  ICR1 = 62499;  //changes frequency as ICR changes
  OCR1A = 31250;   //~= 50% duty cycle
  OCR1B = 31250;
  TCCR1B |= (1 << CS12); //N = 256
  //-------------------
  TCCR2B = 0x01;  //Start timeCounter /1
}

void loop()
{
  if (flag1 && flag2)
  {
    noInterrupts();
    Serial.print("Total Count = ");
    unsigned long totalCount = timer2OverflowCount * 256 + TCNT2;
    Serial.println(totalCount);
    Serial.print("Time between two falling edges = ");
    Serial.print(totalCount*0.0625*0.001, 2);
    Serial.println(" ms");
    Serial.println("================================================");
    TCNT2 = 0;
    timer2OverflowCount = 0;
    flag1 = false;
    flag2 = false;
    interrupts();
  }
}

void ISRZ()
{
  flag1 = true;
  TCCR2B = 0x01; //start N = 1
}

void ISR1()
{
  if (flag1 == true)
  {
    flag2 = true;
    TCCR2B = 0x00;  //stop timeCounter
  }
}

ISR(TIMER2_OVF_vect)
{
  timer2OverflowCount++;
}

Output:

=======================
Total Count = 7999748
Time between two falling edges = 499.98 ms
=======================

Let us change the frequency of Ch-A/B signal to 2 Hz and check that the display shows: ~-250 ms.
Output:

================================================
Total Count = 3999748
Time between two falling edges = 249.98 ms
================================================

You confuse the sensor signals (90°) and the generated PWM signals (180°). What you want to do can be done with less efforts.

As this part is off-topic I'm out here.

Where are the example codes?

There are always alternative methods; but, you have initiate the starting point from somewhere and then introduce tuning to refine the method.

This code simulates a quadrature encoder with rather high clock rate for testing (change if desired).

void setup() {

  pinMode(9, OUTPUT); //output A
  pinMode(10, OUTPUT); //output B

  TCCR1A = 0; //clear timer registers
  TCCR1B = 0;
  TCNT1 = 0;

  TCCR1B = _BV(WGM13) | _BV(WGM12); //CTC mode with ICR1 as TOP
  TCCR1A = _BV(COM1A0) | _BV(COM1B0); //Toggle OC1A/OC1B on compare match

  TCCR1B |=  _BV(CS11); // prescaler 8, 2 MHz clock rate
  ICR1 = 199;//  period 100 us, output toggle period = 200 us
  OCR1A = ICR1 - 1; //OCR1A toggle at end of period
  OCR1B = OCR1A / 2; //OCR1B toggle at middle of period
}

void loop() {
}
1 Like

Appreciate your prompt response. Sure, I will try to test the sketch and post the outcome.

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