PWM on ATtiny85

A project log for Storing and playing back lofi audio on an MCU

Software and hardware for storing 8-kHz, 8-bit (or less) audio on an AVR MCU, and playing it back

Johan CarlssonJohan Carlsson 05/16/2022 at 23:550 Comments

I originally used an AVR ATmega328 for my PCM lofi shenanigans. It has 32 kB of flash, 2 kB of SRAM, 3 timers and runs at 16 MHz. For various reasons I got curious how an ATtiny85 would fare for the task with 8 kB of flash, 512 B of SRAM, 2 timers and running at 8 MHz.

I've only tested the PCM library on an ATmega328, but it should supposedly also work on ATmega128. How about on ATtiny85? The PCM library uses Timer 2 to generate the carrier and Timer 1 to modulate it. A quick peak in the ATtiny85 datasheet  informed me that there's only Timer 0 and Timer 1. Maybe I can do a quick port of the library by migrating the carrier-generation to Timer 0? I started doing just that, but when I was halfway done I had figured out that tn85 (that's what us cool kids call the ATtiny85) T1 (Timer 1) was not meant for modulation, but was born for PWM (generating the carrier wave used for PCM).

With my original plan, with PWM on T0, the carrier frequency would only be 31.25 kHz, half as high as on ATmega328. However, with PWM done by T1, you can get the carrier frequency up to a whopping 250 kHz! That should make low-pass filtering a cinch. For bit-crushed audio you can get an even higher frequency. So I'm developing a PCM library for ATtiny85 from scratch. The carrier generation (on T1) is done, but modulation (on T0) must still be implemented. The timers on ATtiny85 and ATmega328 are very different and not everything is documented in the datasheet, including the duty cycle you get with particular register values. I might do a log on the gotchas I've encountered at some point.

95% of the effort so far has been either digesting the datasheet (figuratively speaking) or fighting with programmers. My two USBasp dongles both broke the same weekend. I made an impromptu programmer from a Uno clone and a lash-up Gammon cable. So far it's holding up. The 5% of the time spent coding and debugging has been thoroughly enjoyable though.

Here's some demo code (C source file and Makefile) for T1 PWM. You'll need an ATtiny85 (or 45 or 25), a programmer, avr-gcc and avrdude to use it. Using just the intrinsic timer interrupts, you can dial in PWM frequencies from 0.24 Hz to 21.5 MHz, or a range of almost eight decades. However, frequencies above 250 kHz only allow bit-crushed PCM. For example, at 21.5 MHz the bit depth is only 1.585.

So far so good for PCM on ATtiny85. PWM on Timer 1 has excellent performance and was easy to implement. For lower PWM frequencies (with the timer running at 1 MHz) the implementation is only eight lines of C code. With just 8 kB of flash only bit-crushed audio seems feasible (4 bits or less per sample). It will be fun to try to do something useful with these limited resources.