Need tip for digital volume control/potmeter

Hi!
I'm in the middle of an amplifier project, and I need a digital volumecontroller. I've previously installed a dual 10k digital potmeter, MCP42010, but I've got a lot of problem that it often affect the sound, turning it really noisy. Yesterday the chip just stopped working, so i'm looking for a new volume controller. 10k way way to little, so I need atleast dual 50k. I got a PT2258 volume controller IC lying arround, but this is really hard to interface with.

Do any of you have a good choice that is simple to interface with the arduino?

What's your issue with the PT2258? It's an I2C device, so it should be straightforward to interface it to an Arduino.

I know it's great for amplifiers. the thing is that every time I change the volume, I have to tell the IC if i'm going to do a 1dB or 10dB step, and then send another bit telling what to multiply with. If im going to change the volume from -70dB to -69dB, the arduino need to transfer the hexadecimal value based on the current volume. You can't just tell the arduino to "+1/-1". Since I'm not THAT skilled, it will take ALOT of time figure out how to interface with it. If you want to take a look, I can put a link to the datasheet :slight_smile:

It appears to me that you have been given help to use that controller already in thread http://arduino.cc/forum/index.php?topic=145881.0. Is there a particular problem you still have after trying that code? Having the Arduino respond to +1/-1 is just a matter of storing what the volume was last set to.

You, that's right. I've tried before, but I didn't got it working, so I gave up, and got the MCP42010, which is not working anymore. I want the code to be something like this:

void volume_up() {
current_volume = current_volume + 1;
}

void volume_down() {
current_volume = current_volume - 1;
}

this is going to be combined with a lot of other functions, such as temprature regulated fans, lcd screen and IR remote reciever that controls everything :slight_smile:

In such a large code I want to make it as easy as possible, so if it's possible to just have "current_volume +-1", that would be great.

hansibull:
You, that's right. I've tried before, but I didn't got it working, so I gave up, and got the MCP42010, which is not working anymore. I want the code to be something like this:

void volume_up() {

current_volume = current_volume + 1;
}

void volume_down() {
current_volume = current_volume + 1;
}




this is going to be combined with a lot of other functions, such as temprature regulated fans, lcd screen and IR remote reciever that controls everything :)

In such a large code I want to make it as easy as possible, so if it's possible to just have "current_volume +-1", that would be great.

Don't give up so easy, the I2C code is in that link dc42 provided, so basically:

Not tested and maybe not complete, but:

void volume_up() {
current_volume = current_volume + 1;

  uint8_t tens = current_value / 10;
  uint8_t ones = current_value % 10;
  Wire.beginTransmission(PT_ADDR);
  Wire.write(0xD0 | tens);
  Wire.write(0xE0 | ones);
  Wire.endTransmission();
  
}

void volume_down() {
current_volume = current_volume - 1;
uint8_t tens = current_value / 10;
  uint8_t ones = current_value % 10;
  Wire.beginTransmission(PT_ADDR);
  Wire.write(0xD0 | tens);
  Wire.write(0xE0 | ones);
  Wire.endTransmission();
  
}

You might want add a test for if volume is already at min or max and not send a new command if so.

Lefty

I've tried your code, but I couldn't communicate with it for some reason, so I'm trying "bare bone"
besides the Wire library I'm also running a library providing a square wave generator (running at 600 hz) through a resistor.
I've set all the channels to 0dB (0b11100000 / 0xC0), but no luck.
I got curious, so I uploaded the i2c address scanner to see if I'm running at wrong address. According to the datasheet, my i2c address should be 0x80 (both address code1 and code2 pins conneced to gnd), but the i2c scanner find an i2c device at the address 0x40. I've tried both address, but none of them works.

EDIT:
this is the code I'm running:

#include <Wire.h>
#include <TVout_lite.h>
#define PT_ADDR 0x40
TVout TV;

void setup() {
    TV.tone(1000);
  Wire.begin();
 
  Wire.beginTransmission(PT_ADDR);
  Wire.write(0b10001000);
  Wire.endTransmission();
  
  
  delay(100);
  Wire.beginTransmission(PT_ADDR);
  Wire.write(0b11010000);
  Wire.write(0b11100001);
  Wire.endTransmission();
}

  


void loop() {
}

Regarding addresses 0x40 vs 0x80, it looks like the datasheet is specifying it as an 8-bit address instead of the more usual 7-bit address, See http://www.totalphase.com/support/kb/10039/ for an explanation (it's also mentioned in the Note on the Wire library page of the Arduino reference). So 0x40 is the correct address to use with the Wire library.

After sending C0 to initialize the device, you must send a command to set the volume on the desired channel, because (in the words of the datasheet) "If a register does has not been set, it is possible that no sound will be output".

PS - 0b11100000 is not the same as 0xC0.

PPS - looks like your code is now correct setting all 6 channels to -1db.

How is the circuit behaving now? I think you will need more than a resistor between the Arduino output and the device input - you will need an attenuator (i.e. voltage divider) to benig the voltage down to an allowable level, and a capacitor to remove the DC bias.

Do you mean something like this?

#include <Wire.h>
#include <TVout_lite.h>
#define PT_ADDR 0x40
TVout TV;

void setup() {
  TV.tone(1000);
  Wire.begin();
 
  Wire.beginTransmission(PT_ADDR);
  Wire.write(0xC0);
  Wire.endTransmission();
  
  
  delay(100);

}



void loop() {
    Wire.beginTransmission(PT_ADDR);
  Wire.write(0xD4);
  Wire.write(0x72);
  Wire.endTransmission();
}

it's still not respond though :frowning:

The code in your reply #6 looks OK to me now. When you say "it won't respond", what is/isn't it doing? Are you sure you are feeding a tone into it?

*CORRECTION: the code in reply#6 is NOT right, it isn't sending 0xC0 at the start, it's sending 0x88.

hansibull:
Hi!
I'm in the middle of an amplifier project, and I need a digital volumecontroller. I've previously installed a dual 10k digital potmeter, MCP42010, but I've got a lot of problem that it often affect the sound, turning it really noisy. Yesterday the chip just stopped working, so i'm looking for a new volume controller. 10k way way to little, so I need atleast dual 50k. I got a PT2258 volume controller IC lying arround, but this is really hard to interface with.

Do any of you have a good choice that is simple to interface with the arduino?

Here's a really neat little board: http://www.sureelectronics.net/goods.php?id=2009

Normally it attaches to a quadrature rotary encoder, but an Arduino can generate the same signals as the encoder and control the gain.

there is no sign of low beeping sound. I've checked all six channels. i've hooked up the test tone at pin 1, and the speaker at pin 20

EDIT: I saw the wrong address, and it's fixed. but still no diffrence :confused:

  1. Have you grounded both the AGND and DGND pins?

  2. Have you connected a capacitor between REF (pin 15) and ground?

  3. Have you capacitively coupled the input and output, as shown on the datasheet?

  4. Can you post a photo of your wiring?

Hi!
This is my current setup. I know I'm missing an input capacitor, but that just removes DC voltage, so that's not critical (I only got two 10uF caps atm.)

according to the datasheet is the setup correct, but maybe the problem is the 7/8 bit diffrence? the datasheet the i2c address is 0x80, but the arduino finds it at 0x40. maybe thats the problem?

anyway, here is my current setup:

Skjermbilde 2013-03-18 kl. 17.06.44.png

OK, that makes things clearer. I can see a few issues with that circuit:

  1. You are overdriving the input, and you are not removing the DC with a capacitor. Increase the series resistor to 100K or more, and put a capacitor in series with it (0.1uF will do).

  2. Is the device connected to the output a speaker, or an amplifier? That device is not intended to drive a speaker directly. The datasheet doesn't say whether the chip is output short-circuit-proof, so you may have damaged the output stage if you connected a speaker directly. With luck, a channel that you have never connected the speaker to will still work.

  3. You don't have pin 17 (Code 2) grounded.

  4. The datasheet suggests 10uF + 0.1uF decoupling capacitors from Vcc to ground, which you don't have. But the lack of those probably won't stop the device from working at all.

As I explained before, the 7/8 bit is just a difference in the way the I2C address is expressed. From the datasheet, it is clear that with code 1 and code 2 pins both grounded, the address will be 0x80 expressed as 8 bits, and 0x40 expressed as 7 bits. That is why the Arduino detects the device at address 0x40, and why you need to use address 0x40 with the Wire library.

btw I'm assuming that when the datasheet says "6-Channel, -10dB/step", it means that the command sets the volumes of all 6 channels simultaneously. Unfortunately, it isn't clear. You could try sending the commands to set the volume of channel 1 instead (after sending the C0 command to initialize the device).

PS - you could also try:

  1. Adding a 500ms delay before you send the C0 command (the datasheet says it needs at least 200ms).

  2. Adding a short delay (maybe 1ms) between sending the C0 command and sending the set-volume command.

WOW! I hooked up a little opamp and the IC is working like a charm! THANKS ALOT dc42!
But when I'm going to build this in to my amp, should I use high quality components, and use the exact the schematic in the datasheet?
Now I'm going to test the the code in the beginning of this post! :smiley:
again, THANKS!

I'm glad you got it working! Most components are of adequate quality these days, and following the example schematic in the datasheet is a good idea unless you really know what you are doing.

I've tested a bit, and the IC is still working great! I only got one question.
I've decided to use this code, because it's simple and understandable (the other one had this "current_value" thing, that I didn't got working.)

  void set_volume(uint8_t value) {
  uint8_t tens = value / 10;
  uint8_t ones = value % 10;
  Wire.beginTransmission(PT_ADDR);
  Wire.write(0b11010000 | tens);
  Wire.write(0b11100000 | ones);
  Wire.endTransmission();
  }

if I put the value to zero, set_volume(0); , the volume at maximum, 0dB. If I put the value to 70, set_volume(70); , the volume is at minimum, -70dB. How can I turn this around, making set_volume(0) minimum and set_volume(70) maximum?

void set_volume(uint8_t value) {
  value = 70 - value;  // added this line
  uint8_t tens = value / 10;
  uint8_t ones = value % 10;
  Wire.beginTransmission(PT_ADDR);
  Wire.write(0b11010000 | tens);
  Wire.write(0b11100000 | ones);
  Wire.endTransmission();
  }