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); } } }