ATtiny13 – hardware PWM

This article shows how to make an ATtiny13 to generate hardware PWM (Pulse Width Modulation) signal. The example code uses timer in Fast PWM mode (WGM02:0 = 3, see manual section 11.7.3). In this mode, by setting the COM0A1:0 bits to one, the compare unit allows generation of PWM waveforms on the AC0A pin (PB0) with duty resolution 0..255. The presented example can operate on few frequencies: 4.687kHz, 585Hz, 73Hz, 18Hz, 4Hz (@1.2MHz). If you need higher PWM frequencies then set fuse bits to run ATtiny13 with 9.6MHz clock source. The example code is on Github, click here.

Parts Required

Circuit Diagram

Software

This code is written in C and can be compiled using the avr-gcc. All information about how to compile this AVR project is here.

/**
 * Copyright (c) 2019, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com>
 * ATtiny13/031
 * Example of hardware Fast PWM.
 * Features:
 * - PWM duty resolution: 0..255
 * - PWM frequencies (@1.2MHz): 4.687kHz, 585Hz, 73Hz, 18Hz, 4Hz 
 */

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

#define N_1    (_BV(CS00))
#define N_8    (_BV(CS01))
#define N_64   (_BV(CS01)|_BV(CS00))
#define N_256  (_BV(CS02))
#define N_1024 (_BV(CS02)|_BV(CS00))

static void
pwm_init(void)
{
    DDRB |= _BV(PB0); // set PWM pin as OUTPUT
    TCCR0A |= _BV(WGM01)|_BV(WGM00); // set timer mode to FAST PWM
    TCCR0A |= _BV(COM0A1); // connect PWM signal to pin (AC0A => PB0)
}

/* When timer is set to Fast PWM Mode, the freqency can be
calculated using equation: F = F_CPU / (N * 256) 
Posible frequencies (@1.2MHz):
 -> F(N_1) = 4.687kHz
 -> F(N_8) = 585Hz
 -> F(N_64) = 73Hz
 -> F(N_256) = 18Hz
 -> F(N_1024) = 4Hz */
static void
pwm_set_frequency(uint32_t N)
{

    TCCR0B = (TCCR0B & ~((1<<CS02)|(1<<CS01)|(1<<CS00))) | N; // set prescaler
}

static void
pwm_set_duty(uint8_t duty)
{

    OCR0A = duty; // set the OCRnx
}

static void
pwm_stop(void)
{

    TCCR0B &= ~((1<<CS02)|(1<<CS01)|(1<<CS00)); // stop the timer
}

int
main(void)
{
    uint8_t duty = 0;

    /* setup */
    pwm_init();
    pwm_set_frequency(N_1);

    /* loop */
    while (1) {
        pwm_set_duty(duty++);
        _delay_ms(100);
    }
}

 

Leave a Comment