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
- ATtiny13 – i.e. MBAVR-1 development board
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);
}
}

