2012-06-05

Klipsch Promedia 5.1 Replacement Volume Control Pod (with Arduino and Remote Control)

Klipsch ProMedia Ultra 5.1 Computer Speaker System

I've got this speaker system. It's called the "ProMedia Ultra 5.1 Computer Speaker System" and it was made by Klipsch, most known for their horn-loaded big concert loudspeakers and home theater speakers. This, however, is a computer speaker system (though it still has mini-horns, as you can see). As it was designed for the subwoofer to sit under a computer desk and the volume control to sit on the desk by your monitor, they went for a wired volume control box. However, I use these speakers for my home theater system (they are certainly loud enough for the job), and the control box doesn't have a desk to sit on.
That little silver control box is connected to the subwoofer (which doubles as the system's power amplifier) by a 10-foot cable with a 9-pin DIN connector, and it barely reaches the couch, and somebody trips over the cord, and it breaks off one of the tiny pins on the DIN connector and then your control pod is useless and things are absolutely terrible.

I set out to fix this, by replacing the control box with an Arduino, and enabling myself to control the whole system with a universal remote I had lying around.

YouTube video of the new box in action

What's going on here?

Some back-story. Apparently, Klipsch (being primarily just a speaker company) has gained a bit of a reputation for building computer speaker systems that break. They make amazing speakers, but it would seem that electronics are not their strong suit. As a result of this, or simply having a lot of time, some wonderful people traced all of the circuits and components of the entire electrical system of a few different models of ProMedia systems, including the 5.1 and 5.1 Ultra. The 5.1 schematics can be found here, and the separate page covering control pods here. If you plan to read this from a technical point of view, it would be handy to keep both of those open in other tabs.

Anyway, the aforementioned incident with the tripping and the breaking of the Mini-DIN connector resulted in a call to the Klipsch parts department, where I learned that they didn't sell the control pod anymore, but they do still have large quantities of the cable itself in stock. That's all I needed, so I ordered one and a week later had a fully-functional system again. After that, I thought, "the cable has to go."

In the process of designing the remote-control interface, the first thought I had was was simply to drop the Arduino on top of the original control pod, and manipulate the volume-knob inputs into the microcontroller, but I quickly realized that while I could do that, it would at best only let me control the volume. Without access to the code of the original chip and a way to re-program it, or the ability to replace it with a pin-compatible something else, I realized I had to scrap the original box entirely. This didn't look like too much of a problem, as there are only six digital connections to account for: +5V, GND, two serial lines, and two lines labeled PWR_MODE and HP_MODE. Then there are analog ground, right, and left, for the headphone/line in connection.

Digital Interface

I suspected the two-wire serial was I2C, and following it to the amplifier end on the schematics led me to a chip labeled PT2258. This is a "6-Channel Electronic Volume Controller IC" (datasheet [PDF]) made by Princeton Technology Corp. Confirming that this was controlled over I2C, the only signals left to account for were the PWR and HP_MODE wires. Using a logic analyzer, I snooped the signals from these wires, as well as the I2C commands. I already had the I2C commands from the datasheet, but I figured I might as well check to make sure nothing non-standard was happening. Also, this provided a reference for what to do with the MODE wires in relation to I2C commands being sent.
Logic Analyzer screenshot, showing switch from Power mode to Headphone mode
Fig. 1: Switching from powered speaker mode to headphone mode
Notice that channels 2 and 3 are not labeled PWR_MODE and HP_MODE, but rather PWR_UC and HP_UC (UC for microcontroller). This is because I was not taking the measurement at the actual control pod output, but rather at the microcontroller output, which is connected to a PNP transistor. I replicated this circuit layout in my implementation, and I thought it would be less confusing to myself later if the code was doing exactly what the logic diagram told me. The functionality is that if you write a LOW to the PWR transistor, the speaker amp turns on, and if you write a LOW to the HP transistor, the mini-jack on the control pod switches from line-in to headphone-out mode. These are never both activated at the same time. I haven't experimented with it, but a brief examination of the schematics indicates you'd just end up with headphones and speakers running at the same time. Referencing the PT2258 datasheet, we see in Fig. 1 a Mute command (0xF9) being sent to the volume controller (address 0x88), followed by turning off of the speaker amp, a small delay, and enabling of the headphone mode. Approximately 3.2 seconds later, a full set of volumes are sent (the stored headphone mode volume level), along with an Unmute command. The long delay allows for the speaker amplifiers to bleed out before enabling sound through the preamp stage again.

I2C Communication

Logic Analyzer screenshot, showing I2C volume control packets, followed by an unmute byte
Fig. 2: Sending the first volume set in headphone mode
The way the volume is set on the PT2258 is by sending "a multiple of 10dB followed by a 1dB code to the attenuator in sequence." You could do this for only one channel, but since the goal is to change the volume of the whole system, an attenuation value is sent for all 6 channels every time the volume is changed. Take a look at the bytes being sent here. The first two are 0x84 and 0x91. The control code for a channel 1, -10db value is 0x8n, where n is the attenuation multiplier. So a byte of 0x84 tells the system to set channel 1 to -10db * 4, or -40db. The next code, 0x9n, is the channel 1, -1db multiplier. So the 0x91 means channel 1, -1db * 1, or -1db. Together, this makes -41db, which when taken out of the maximum volume of 80 gives us a volume level of 39. You might recognize this as the default volume level for headphone mode when you initially plug in the system (which I had just done). A pairing of 0x86 and 0x97 would have been [ (-10 * 6) + (-1 * 7) ] = -67, for a volume of 80-67= 13. Taking another look at the picture, you will recognize the pattern: 0x84 0x91, 0x44 0x51, 0x04 0x11, 0x24 0x31, 0x64 0x71. That's Front Right, Front Left, Rear Right, Rear Left, and Center all set at -41db. Also important to note is that a -10db value and a -1db value must be sent together for any particular channel. Sending either on its own or with other unpaired codes is "not permitted," but I don't know exactly what (if anything) would go wrong.
Next, you might notice that the final volume pair, 0xA7 0xB9, is a value of maximum attenuation (80-79 = volume level 1). This is for the subwoofer channel. The way the ProMedia 5.1 system handles the subwoofer signal is by taking the LFE input and mixing it into the Front Right and Front Left speakers. This ensures that any LFE sound too high-frequency for the subwoofer gets played through the front speakers. Then, each of the 5 remaining channels (including the two front channels now with LFE mixed in) are tapped just before the PT2258 and mixed back together through another preamp stage, and then fed into channel 6 of the PT2258. This ensures that any sound sent to the regular speakers that could benefit from a low-frequency boost makes it to the subwoofer. As channel 6, then, is simply all the other channels added together, it doesn't have a line out to the headphone amp, and so it is simply set to max attenuation for all headphone mode volumes. In Fig. 2, an unmute signal (0xF8) is seen at the end because it is the first volume setting sent after switching from speaker mode to headphone mode. Any further volume changes do not have or need an unmute command.

 Remote Control

 Replicating the digital interface is simple enough with the Arduino built-in "Wire" library for I2C and a couple of digital output pins to toggle the MODE lines, so the next task was figuring out how to control things with a standard IR remote. Turns out that's about as easy as things get. The first step is to download the IRRemote Library by Ken Shirriff. (You may have to modify one line in a header file as explained on his page in "Note for Arduino 1.0.") Then you get an IR Receiver module, such as this one from Radio Shack, and give it a digital pin, a GND, and power (in this case, a resistor to 5V). Finally, you grab about 7 lines of code from the example file IRrecvDemo and run a switch/case off "results.value" and you're done. Using the IRrecvDemo file to see what codes came out of a standard Sony TV remote, I made this:
Sony universal TV remote with hex codes shown for each button
Fig. 3: Sony Remote Codes
Remote codes will be different depending on what sort of remote you want to use, but it shouldn't be too hard to figure out which codes you will need if you just use the IRrecvDemo and make a note of the buttons and their corresponding codes.


Display

Now that we've taken care of user input and connection to the speakers, the last important bit is the volume display. I acquired a four character seven-seg display, and instead of a dedicated controller I just wired it directly to the Arduino. I had exactly enough pins left to wire it up, after leaving digital pins 0 and 1 for serial to the computer, and two analog pins I'd wired up to input switches (which don't do anything anymore, after I remembered that I had an entire TV remote full of buttons to use). For the display update/refresh timing, I used the Timer1 library available on the Arduino Playground wiki. This worked out perfectly, because the IR receiver code utilizes Timer 2. Following that all I had to do was wire up the 3 headphone wires to a new 3.5mm jack and throw everything in a box. It ended up being a fairly ugly box, but that's not really the point of this project so it's OK.


Resources

Schematic
Fig. 4: Schematic
The 220-ohm resistor on the IR Receiver might not actually be necessary; I've seen it implemented with and without. It works fine with it, though. Another interesting note is that I was typing the schematic up in the font Futura and the last thing I added was the picture from the back of the RadioShack box. Turns out they used essentially the same font, though all the text you see I actually re-typed because the picture quality wasn't that great (as you can see on the image of the module).

I don't have any CAD schematics or a circuit board layout because I basically just put this together as I went.  Future plans include putting together a PCB with the right connector so you don't have to tear apart the control pod end of the 9-pin cable. Also a nice box, two 3.5mm jacks, etc.

You may notice in the pictures that the "Vs" pin on the IR Receiver appears to be connected to the "AREF" signal. I actually clipped that leg off the proto shield and wired that pin to the resistor to 5V, because it was an otherwise perfect spot with the GND and Pin 13 right there.

Datasheets (Google Drive)

Arduino Code (Google Drive)
Arduino Code (Pastebin)
A note about the Arduino code:
"As of Arduino 1.0, the [Wire] library inherits from the Stream functions, making it consistent with other read/write libraries. Because of this, send() and receive() have been replaced with read() and write()." - Arduino - Wire
I wrote this in Arduino 1.0, so make sure you're upgraded.

Pictures



Created with Admarket's flickrSLiDR.

6 comments:

  1. Nice work!

    If you are interested you can also take a look at my design that was published a month ago.. They are very much alike :)

    http://neoxy-yx.blogspot.com/2012/04/51-amplifier-system-redesign.html

    Did you have any problem with communicating with the PT2258? I had some unknown issues and had to send volume command twice to accept it.

    Keep on the good work!

    ReplyDelete
  2. Wow, nice project, looks quite a bit more involved than mine. The only problem I had with the PT2258 was that Arduino wants the 7-bit I2C address, and the PT2258 datasheet gives you the address as 8-bit (because you never need to read from it) so I kept getting NACK on my address send. Somehow I had completely overlooked that and couldn't figure out why my Arduino was sending 0x10 instead of 0x88. I showed it to somebody else who instantly spotted my problem (and I felt pretty dumb). Once I dealt with that though everything worked great.
    I did see that the datasheet recommends sending a Clear Register command [0xC0] on startup, which I didn't do because from what I saw the Klipsch box didn't do it, but that might be worth trying.

    ReplyDelete
  3. Yes, 7-bit addressing confused me to. But then I red the library info (address/2) solved my problem. I will definetly try the 0xc0 command when I will have some spare time and see if this solves my problem with double data sending.

    Currently I'm working on a new temperature/humidity regulator project with web server and multiple expansion ports based od Mega 2560.

    I will follow your blog in hope to see more of your future projects, if you are planning them :)

    ReplyDelete
  4. Awesome work! I've owned the 5.1 Ultras for years, repaired the amp once, and always wished the control pod had an IR remote. I'm definitely going to be trying this, but I don't have any experience with Arduino.

    ReplyDelete
  5. would you be willing to make a replacement unit if I fronted the costs?

    ReplyDelete