mega32u4 timer0 fast PWM, non- vs inverting for compare output is significant

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I ran an experiment to test using the fast PWM mode of timer0 for duty cycle control.  I learned something.

 

I wanted to set up the timer so that I could control period and duty cycle of timer0 to generate an output signal.

I set up the OCR0A to be the period (i.e., TOP, value 7) and OCR0B to be the duy cycle (i.e., the "match", value 0-7).

I also set up COM0B to clear on match, set on BOTTOM.  For a 16 MHz clock the period was 0.5 us and the logic high varied from 1 to 8 cycles.

But I wanted 0 to 7 cycles.   That requires using the COM0B to be inverted: set on match, clear on BOTTOM.

 

The sample program sets up an 8 cycle PWM (from 16 MHz => 0.5 usec period).

 

Here is the timing diagram:

 

Here is a scope trace:

 

 

and the code.   My intent is to have a controller set d_num and d_den every 100 us.

 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile uint8_t d_num = 2;		/* duty cycle numerator */
volatile uint8_t d_den = 7;		/* duty cycle denominator  */

void timer0_setup(void) {
  /* use Fast PWM mode => WGM0 = 0b111
   * clr OC0B on match, set OC0B on BOTTOM => COM0B = 0b10, COM0A = 0b00
   * slow /256 clock for now => CS0 = 0b100 (fast clock => CS0 = 0b001)
   * => OCR0A is period, OCR0B/OCR0A is duty cycle, output on pin TBD
   * OC0B is board pin D3 PD5 on arduino micro
   * w/ 0x09 get 620.0 ns / 4065.0 ns = 0.1525 vs 1/8 = 0.1250
   */
  TCCR0A = 0x23;	      /* COM0A=0, COM0B=0b10, WGM[1:0]=0b11 */
  TCCR0A = 0x33;	      /* COM0A=0, COM0B=0b11, WGM[1:0]=0b11 */
  TCCR0B = 0x09;	      /* WGM[2]=0b1, CS0=0b001=/1 */
  TIMSK0 = 0;		      /* no interrupts */
  OCR0A = d_den;	      /* default */
  OCR0B = d_num;	      /* default */

  DDRD |= _BV(PIN0);		   /* Pin D0 is DC-DC switch = OC0B */
}

#define CYCLE 2

int main(void) {
  uint8_t i, n;
  uint16_t k = 0;

  /* "The setup of the OC0x should be performed before setting the 
   * Data Direction Register for the port pin to output." - sec 13.4.3 */
  timer0_setup();
  
  /* blink led w/ duty cycle */
  DDRC |= _BV(PIN7);
  while (1) {
    if (k++ >= CYCLE) {
      d_num = (d_num + 1) % 8;
      OCR0B = d_num;
      k = 0;
    }
    n = (d_num % 8) + 1;
    
    PORTC |= _BV(PIN7);
    for (i = 0; i < n; i++) {
      _delay_ms(200);
      PORTC &= ~_BV(PIN7);
      _delay_ms(200);
      PORTC |= _BV(PIN7);
    }

    PORTC &= ~_BV(PIN7);
    for (i = n; i < 10; i++) {
      _delay_ms(200);
      _delay_ms(200);
    }
  }
}

 

Last Edited: Wed. Nov 6, 2019 - 02:21 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is a table illustrating the difference between using the non-inverting compare output and the inverting one.  The count at the left of the diagram is the value for OCR0B, with OCR0A=7.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I must be missing the point. In #2 the _COOB,n signals all seem to the exact inversion of the COOB,n signals - which is exactly what "inversion" implies. So where is the surprise in any of this?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The surprise (duhh point) to me was that I could not have both continuous 0v and 5v output, so the point of the inversion, as I read it, is to provide that choice.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is the whole point supposed to be

MattRW wrote:
But I wanted 0 to 7 cycles.
with the emphasis on the "0"?  Yes, AVR8 Fast PWM cannot be configured for both full-on and full-off.  So often, one might configure as you did to be able to do full-off with the PWM directly.  In many cases (LED; motor) it doesn't matter whether the apparent full-on is one count less -- can't be noticed -- but one count instead of full-off >>can<< be noticed.

 

If the above is true then the posted waveforms aren't quite right.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:

Is the whole point supposed to be

MattRW wrote:
But I wanted 0 to 7 cycles.
with the emphasis on the "0"?  Yes, AVR8 Fast PWM cannot be configured for both full-on and full-off.  So often, one might configure as you did to be able to do full-off with the PWM directly.  In many cases (LED; motor) it doesn't matter whether the apparent full-on is one count less -- can't be noticed -- but one count instead of full-off >>can<< be noticed.

 

If the above is true then the posted waveforms aren't quite right.

 

 

I don't see that.  For OCR0B=0, the duty cycle is 7/8, for OCR0B=1 it's 6/8, ..., for OCR0B=6 it's 1/8 and for OCR0B=7 it's 0/8.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MattRW wrote:
I don't see that.  For OCR0B=0, the duty cycle is 7/8, for OCR0B=1 it's 6/8, ..., for OCR0B=6 it's 1/8 and for OCR0B=7 it's 0/8.

Ah, I see now--I thought the horizontal lines were separators.

 

anyway, my supposition is correct about full-on, full-off, normal, inverted.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.