Friday, 1 June 2018

It speaks!

Porting TTS to the ESP8266 processor has been on my to-do list for a while now, prompted by a comment on an issue I'd created to remind me. To do this, I realised that I'd have to reacquaint myself with PWM on the ATmega328p.

At its most basic, a PWM waveform is a square-wave with a varying duty-cycle. Both the frequency of the square-wave and the duty-cycle are determined on an AVR by the its built-in timers. PWM on Arduino pin 9 (hardware pin 15, OC1A), for example, is driven by Timer-1, a 16-bit timer.

Several PWM modes are available; TTS chooses the "phase and frequency corrected" option.

The diagram shows how this works to change the duty-cycle of the output pin:
  • the timer counts from BOTTOM to TOP and back down again
  • when it crosses the OCR1 threshold going up, it sets the OC1A output high,
  • when it crosses this threshold on the way down again, it sets the OC1A output low. 
Therefore by dynamically changing OCR1, we can change the "volume" on the output pin.

The final piece of the puzzle is how the frequency of the square wave is determined. Since the timer ticks on every clock cycle, it will take 2*TOP cycles to cycle from BOTTOM to TOP and back. The AVR has a clock frequency of 16MHz and PWM_TOP in the TTS library is defined as 1200/2. This gives a frequency of about 13kHz.

By default PWM on Arduino/ESP8266 has a range of 1023 and frequency of 1kHz. However it provides APIs to change these values. By setting them appropriately, the ESP8266 speaks!

Wemos Mini D1 with TTS amplifier and super-cheap speaker
The picture shows a Wemos Mini D1 connected to a modified version of the simple LM386 amplifier described at the TTS GitHub. (The modifications arose from a Hackaday article on the LM386 and are summarised in the GitHub's README.)

This amplifier sounds surprisingly good, considering its total cost was about €1. Hooking it up to a signal generator and oscilloscope produced the following pretty pictures.

At low volume, the output is a pretty faithful inversion of the input signal (a 1kHz sine wave):

Undistorted Signal
At high volume, the output is clipped by the supply rails (but still sounds pretty good to my untrained ear):
Clipped Signal
These pictures were produced using an Xprotolab Plain, an amazing combination of Oscilloscope, Signal Generator and Protocol Analyzer implemented on an AVR XMEGA. Buy one!
Xprotolab Plain