January 02, 2016

Digital-Analog Conversion, or Voltage Control by PWM

For volume (amplitude) control of the unit's output channels, I will need a way of converting a digital volume value (say, a percentage) to an analog voltage level.

Essentially, a digital-analog converter (ADC) is required. I will, however, not use the ADC channels of the Due: it's only got two of them, and using them would be overkill, too. The common way to digitally control a voltage is by pulse-width modulation and a low-pass filter. Basically, a high-frequency PWM waveform gets smoothened by the capacitor in the low-pass filter. Then, the duty cycle of the PWM waveform is varied to control the voltage. The output voltage equals the integral of the PWM voltage (3.3V for the Due) over one PWM period. Hence, varying the duty cycle between 0% and 100% will yield an output voltage varying linearly between 0V and 3.3V. The website [1] nicely explains the concept in easy words.

A small rippling may remain in the output voltage depending on the design of the low-pass filter. For this, the capacitor is first chosen according to the current load that the voltage line needs to drive. Then, the resistor value determines the low-pass filter's properties, such as cutoff frequency, ripple voltage, and settling time. The applet [2] allows to compute output voltage, ripple voltage, and settling time for a duty cycle step change if given a PWM frequency and the resistor and capacitor values of the low-pass filter.

References

[1] http://provideyourown.com/2011/analogwrite-convert-pwm-to-voltage/
[2] http://sim.okawa-denshi.jp/en/PWMtool.php

Audio-In from Line-Out, Arduino Due DAC

Audio tracks can be a great source of widely varying and entertaining beat patterns for e-stim. All powerful boxes can generate e-stim pulses from a line-in port. I want to support this, too, and think about computing volume (VU) and frequency analysis (FFT) information as a source of time-varying information for e-stim programs.

The common way to interface a line-in port with an Arduino is the LM386 low-end audio amplifier chip. After all, we're not interested in high fidelity over a wide range of frequencies, but just in volume and beat pattern information. Sketches and circuits for LM386 are a dime a dozen on the interwebs, and most are based on the 20-gain minimum-parts circuit from the chip's datasheet [1]. Some examples and circuits can be found on [2,3,4].

To the left is my realization of that circuit, including a line-in connector with an audio cable coming from my notebook plugged in. Because the LM386 runs on 5V and the Due's ADC runs on 3.3V, I've added a simple 5V to 3.3V voltage divider using a 2.7k and a 5.6k resistor in series. You'll quickly fry the ADC channel if you don't. A number of alternative voltage conversion strategies can be found here [5]. The 10uF capacitor for a gain of 200 can still be seen soldered in, but is disconnected.
Two things didn't go too well in the first place. For one, it's paramount that the 5V supply is a good one. I had to realize that, when powering my Due from my notebook's USB, my power supply does not do too well because the LM2596 chip requires an input voltage of at least 8.5V. Powering from a 9V block fixed this. Second, the yellow cable runs to channel 0 of the Due's ADC, which is PIO A.2 pin number 85 [6]. It's stupidly labelled "A7" on the Due board, which helped a lot to eat into my spare time.

I'm running the ADC in free-running mode, meaning that it continuously converts incoming voltage in the 0V to 3.3V range to 12-bit integers in the range 0 to 4095. I've set up the Due DAC's direct memory access (DMA) to transfer the readings into a double-buffer in memory: An interrupt is triggered whenever a buffer is full, which happens every 2000/128 ~ 15 ms. The interrupt service routine (ISR) then switches buffers. Information on the Due's ADC and DMA controllers can be found in the SAM3X8E data sheet [7].

Now there's always a buffer being filled by DMA, while a full buffer holding ~15 ms worth of amplitude data could be processed inside loop(). I could be computing VU or FFT values from the amplitude information stored therein. But that's for another post.

Parts List

1x LM386 audio amplifier
1x 220uF capacitor, electrolytic
2x 10uF capacitor, electrolytic (3 for 200-gain)
1x 47nF capacitor
1x 10k resistor
1x 5.6k resistor (or similar)
1x 2.7k resistor (or similar at half the value)
1x 10 Ohms resistor
1x 3 pin header
1x mono audio socket

The total cost is about USD 5. Eagle files with scheme and board layout can be found in the project's GitHub repository.

References

[1] http://www.ti.com/lit/ds/symlink/lm386.pdf
[2] http://www.instructables.com/id/LM386-Audio-Amplifier/
[3] http://www.arduino-hacks.com/arduino-vu-meter-lm386electret-microphone-condenser/
[4] https://www.arduino.cc/en/Tutorial/SimpleAudioPlayer
[5] http://jamesreubenknowles.com/level-shifting-stragety-experments-1741
[6] http://forum.arduino.cc/index.php?topic=132130.0
[7] http://www.atmel.com/images/atmel-11057-32-bit-cortex-m3-microcontroller-sam3x-sam3a_datasheet.pdf