Crosspoint Audio Router with Volume Control

2014-05-27 08:35 by Ian

I've been needing this part for a long time now. So I've finally gotten around to doing the design work and making a production-worthy module.

Raw PCBs from Osh Park:

The module uses an Analog Devices ADG2128 crosspoint analog switch and a pair of Intersil ISL23345 digital potentiometers for output level control. The entire assembly is i2c controlled and can operate with a supply voltage between 3v and 5v. Analog input must be externally constrained to fit within the supply voltage.

The idea here was to make a switch for unbalanced audio signals, but the module should have reasonable performance up to 120KHz or so, depending on the operating voltage.

In all cases, the pots are the limiting factor. They are dictating the voltage range, the maximum i2c frequency, the passable frequency range, and the choice of which pins are most-easily used as outputs. The ADG2128 is a much more capable chip than the pots in this module allow it to be. But that was the price to be paid for high-densities.


I've written a handful of libraries (hosted at github) to support this module. If there is interest in specific this-or-that, I will go into details about those. For the moment, a dump of the program's inline help should give a good idea of what it does...

ian@RASPi-512 ~/ViamSonus $ ./audioroute -h
Bus and channel selection:
    --i2c-dev     Specify the i2c device to use.
-i  --input       input pin (0-11)
-o  --output      output pin (0-7)

Options that operate on channels:
-r  --route       Route the given input to the given output.
-u  --unroute     Unroute the given input from the given output(s). If no output
                   is specified, we will unroute the given input from all outputs.
-v  --volume      Specify the value of the linear potentiometer (0-255).
                   If no output is specified, we will adjust all outputs.
-m  --mute        Mutes a specified output channel. If no output channel is
                   specified, we will mute all outputs. Note that muting an output
                   has no effect on the route.

-v  --version     Print the version and exit.
-h  --help        Print this output and exit.
-s  --status      Read and print the present condition of the PCB.
    --reset       Reset the PCB back to it's power-on state.
    --enable      Enable a PCB that was previously disabled.
    --disable     Disable the PCB. Mutes all outputs.

At the time of this writing, the code runs reasonably on my RasPi. The makefile builds a command line utility that has some built-in help. The Teensy3 code is not fleshed out, but the libraries ought to build in an Arduino environment.

Any of the base libraries can be used independently of one-another, with the exception of AudioRouter, which depends on all of the other classes. The i2c-adapter class can be factored out with minimal effort if desired. But it allows the classes to be compiled for use with either a generic linux character device (/dev/i2c) or an Arduino-esque microcontroller without modification.

Some more pictures of the finished PCBs.

The surface-mount ICs were all soldered on a hotplate with solder paste. The resistors and caps on the reverse side were done by hand.

The Bill-of-Materials for this project ran me about $60 for three of them (which all test good). They could be made in quantities of 100 for less than $20 apiece.

Testing notes:

Strange problem with readback function that causes the first two input channels to be reported incorrectly. But the hardware responds appropriately, so it is most definitely a software bug. I can swap stereo channels and adjust balance from the command line.

Isolation is good. Full line-level output is being rejected on adjacent channels with no additional circuitry. Wasn't expecting that, but I'll take it.

Column re-map works! I used a software trick to remap switch columns to potentiometer outputs. This lets the library present a consistent pin-to-channel correspondence despite the weird PCB routing.

Output short-circuit protection appears to work, but until I solve the weird readback() problem, it should be considered unreliable. I've added a global output-directed unroute() call just in case.

The potentiometers' linear tapers aren't causing the grief I was afraid they might. Audio use will just need to set a logrithmic scale for wiper positions. This will result in fewer positions of the wiper, but granularity-of-range shouldn't be a problem in such a use-case.