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

December 31, 2015

Arduino Makefile instead of IDE

For fiddling with small bits of code to try an interface the individual parts of my unit, the Arduino IDE is convenient. The overall project, though, is going to consist of multiple source and header files and will likely be unmanageable in the tiny IDE. Also, I prefer a capable source code editor, such as Sublime Text [1].

Luckily, a Makefile for Arduino [2] has already been developed and allows to compile a set of source files from the command line. It also supports programming the Due via bossac, and opening a serial monitor to listen to the Due on Serial1.

References

[1] http://www.sublimetext.com
[2] https://github.com/pauldreik/arduino-due-makefile

Mission Statement

In this post, I'm going to summarize the objectives of this project. I'm trying to develop an e-stim unit that puts the expensive commercially available boxes in their proper place. What makes me think I'm up to the challenge? I have an academic background, I'm an excellent coder, I have plenty of experience in programming close to hardware, and I have reasonable experience with microelectronics. However, only time will tell, and you may judge.

While working on this project, I will
  • share my thoughts,
  • talks about obstacles encountered and solutions found,
  • put my Eagle hardware designs up as free (as in beer) download,
  • share pictures of through-hole soldering jobs,
  • and put source code up as free (as in beer) download.
I will try to add the following features to my unit:
  • Four independent output channels.
  • Low-current pulse-width modulated (PWM) operation.
  • Minimalist user interface: Rotary encoder and push button (think of a BMW, Audi central console). En plus, a wealth of mechanical knobs adds unnecessary hardware complexity and cost where everything could be done in software in a much more convenient and reliable way.
  • A small TFT display for a user menu and status information.
  • Powered from a rechargeable battery pack. I won't discuss powering from anything that is, even indirectly, connected to the mains.
  • Great connectivity: I'm thinking about Line-in audio, USB, WiFi, or Bluetooth. I dream about how this would enable client-server operation, remote operation, a web interface, a mobile phone app, etc. I don't like how commercial boxes lock users out, and how vendors make a big secret of trivial communication protocols and charge big time for standard cables and whatnot.
  • Stim modes that can be programmed by, and shared among, users.
  • Interfacing the box with sensors for interactivity. Just picture the scenarios possible if push buttons, microphone, inclination, movement, or pressure sensors could be processed by the stim programs.
  • Cost: I will try to stay significantly below the cost of upscale commercial boxes, which range from USD 400 to USD 600. I'm not stupid and realize that vendors have to charge for development time, support, and profit. As a DIY community project, we should have a margin.
  • Your ideas and wishes are welcome!
This list will be updated from time to time, and I will link to blog posts discussing these points. The box will be based on the Arduino Due as central processor, for several reasons:
  • large number of PWM output channels
  • large number of ADC input channels
  • easily programmable in C or C++
Above all, an enthusiastic community that continues to create fantastic resources on PWM, TFT displays, Audio, Serial, USB, SPI, I2C, WiFi, Bluetooth, and all kinds of sensors is already out there. Whenever I build upon something I found out there, I will cite and give credit where credit is due.

Power Supply, 5V and 3.3V at 3A each

I won't be relying on the power supply of the Arduino Due board. It provides single Vin, 5V, and 3.3V pins only, and can support low current draws only [1].

Instead, I've come up with a dedicated power supply based on a pair of LM2596 chips. They accept input voltages between 5V and 37V, i.e. any NiMh oder LiPo rechargeable battery pack will do, and each chip supports up to 3A current. The circuit comes straight from the LM2596 data sheets [2]. On the output side, I've added pin headers for currently 6 Vin pins (left), 4 5V pins (top right), and 3 3.3V pins (bottom right). Tamiya connector wires can be seen, too.
I'm neither equipped for, nor skilled in, SMD or flow soldering, so all my hardware will be through-hole for now. I will provide Eagle files with schemes and layouts, though. Any hints on improving my soldering skills as well as on affordable printed circuit boards are welcome. Also, my supplier sent me huge pairs of inductors and capacitors, wow.

Parts List

2x LM2596-ADJ voltage regulator chip
2x 33 uH inductor
2x 1N5822 overcurrent protection Schottky diode (or similar)
2x 470 uF/40V capacitor, electrolytic
1x 100 uF/40V capacitor, electrolytic
2x 15 nF/40V capacitor
2x 1K resistor, low-tolerance metal-film
1x 3K resistor, low-tolerance metal-film (I used 2x1.6K in series)
1x 1.6K resistor, low-tolerance metal-film
1x 2x16 pin header (or whatever connectors you prefer)
2x heat sinks for LM2596-ADJ (optional)

The total cost was about 20 USD, where the LM2596 chips took the lion's share with a little over 7 USD. Schematic and board layout can be found in the project's GitHub repository.

References

[1] https://www.arduino.cc/en/Main/ArduinoBoardDue
[2] http://www.ti.com/lit/ds/symlink/lm2596.pdf

On Rotary Encoders and Debouncing Inputs to an Arduino Due

When interfacing push buttons, rotary encoders, etc. to an Arduino board, glitches in the input signal usually lead to many more inputs being recorded than the user intended to give. The typical countermeasure is called debouncing, and one finds endless posts on the interwebs, e.g. [1], about how to implement this in software or, by adding resistors and capacitors, in hardware.

I'm working with an Arduino Due, based on the ATMEL SAM3X8E processor. Today, I found in its specs [2] that this chip supports glitch filtering and debouncing on any input pin.

The following snippet uses the DIFSR register of the PIO unit to add hardware debouncing to pins D.0, D.1, and D.2 (pin numbers 25, 26, and 27) of the Due.
For other pins, use the PIOA, PIOB, or PIOC units and set the desired pin's bit to one in the binary bitmask. An overview of all Due pins, their numbers, and their assignments to PIOA ... PIOD units can be found at [3].

The debouncing filter also has a width, which comes in fractions of the slow clock (SLOWCLK) and can be set via the SCDR register of the PIO unit that hosts the pins in question. The divisor applies to all debounced pins of the unit.
Using this, I can interface a rotary encoder with push button to the Due without any additional debouncing hardware or software. The rotary encoder has three pins, named A, C, and B from the left and in this order. C gets grounded, A and B go to pins 25 (D.0) and 26 (D.1). The pushbutton pins are on the reverse side; one gets grounded, the other goes to pin 27 (D.2).

This is the setup code to be executed during startup(). It configures pins 25 to 27 as input pins, activates the internal pull-up resistors so the pins read 1 if the rotary encoder leaves them open, and get pulled to 0 if the rotary encoder closes them. Interrupt service routines are attached to each pin and get called on every change of the pin's reading from 0 to 1 or from 1 to 0. Finally, debouncing is added on the pins:

Edit: In the original post, I forgot to set PIO_IFER.

The following interrupt service routines track changes of the pin readings and update the encoder position accordingly. I started with bits of code I found at [1], and took it from there. I avoid calls to digitalRead(), which is very slow. Instead, I read the PIO unit's pin data status register PDSR directly:

Inside loop(), one may now query knob_pending, and if it's 1, look at knob_pushed and knob_pos to learn the rotary encoder's pushbutton state and relative position:

Update: A CKnob class implementing rotary encoder and push button access is now available for download from the project's github repository.

References

[1] http://playground.arduino.cc/Main/RotaryEncoders
[2] http://www.atmel.com/images/atmel-11057-32-bit-cortex-m3-microcontroller-sam3x-sam3a_datasheet.pdf
[3] http://forum.arduino.cc/index.php?topic=132130.0
Welcome, Enthusiast. This is the first post.

This blog revolves around my development of a do-it-yourself open-hardware open-source e-stim unit. I'll be writing about various issues and questions I encounter on my journey, and share my solutions, hardware designs, layouts, photos, and source code.

Although you've seen the adult content warning before entering this blog, you won't ever find pictures or texts with adult content on this blog. I've enabled the warning because of the general topic of e-stimming we're talking about here.

You're welcome to contribute by posting and asking questions. Note, however, that this blog is moderated by me and it'll take me some to find time to sift through the inbox. I'll mercilessly edit mine and your posts for spelling, grammar, layout, and correctness.

This blog does not adhere to a strict timeline. Even if a post was submitted long ago, I will edit, and will do so without always making my edits apparent to the reader.