Looking for digital potentiometer, highest specs.

Hi Krupski,

although I am not building a power supply, your comment does help me understand some issues I have with building a stable signal voltage from the PWM port.

In the mean time I have tried to reduce the riple in the signal more. I have changed from output pin 3 to output pin 5, in an attempt to varify the difference in frequency of the PWM signals as I mentioned in my previous post. Working with the schematic I posted on the previous page, at 3.3V output voltage I had a ripple of 7.23% (total, half each way). Connecting to pin 5 reduced that to 3.83%, so a big improvement. Adding a second 100nF cap reduced it further to 2.36%. I might be getting somewhere...

Cheers,

Hugo

HugoW:
Hi Krupski,

although I am not building a power supply, your comment does help me understand some issues I have with building a stable signal voltage from the PWM port.

In the mean time I have tried to reduce the riple in the signal more. I have changed from output pin 3 to output pin 5, in an attempt to varify the difference in frequency of the PWM signals as I mentioned in my previous post. Working with the schematic I posted on the previous page, at 3.3V output voltage I had a ripple of 7.23% (total, half each way). Connecting to pin 5 reduced that to 3.83%, so a big improvement. Adding a second 100nF cap reduced it further to 2.36%. I might be getting somewhere...

Cheers,

Hugo

Have you thought about using an R-2R resistor network to generate adjustable DC voltage?

Bournes makes nice SIP modules... a thin little 10 pin part with laser trimmed resistors in it (cost about $1 USD each).

You connect the "middle" 8 pins to an Arduino port, connect the end pin on the LSB side to ground and take your output from the other end pin.

If you want a 16 bit DAC, simply daisy-chain the R-2R parts like this:

(click pic for full size)
dac.jpg

To control it is super easy too:

// Notes:
// LSB is PORTF
// MSB is PORTK

void setDac (uint16_t value)
{
    // these 2 DDR statements need to be done only once
    // and would be better done in void setup (void)
    DDRK = 0xFF; // port-k all pins outputs
    DDRF = 0xFF; // port-f all pins outputs

    PORTK = (value >> 8); // set in top 8 bits
    PORTF = (value & 0xFF); // set in lower 8 bits
}

If you only need 8 bit granularity, then just use one port and one R-2R part, and set in a "uint8_t" value.

This method works VERY nicely and provides clean quiet DC without any filtering being needed.

Actually, you could even expand it to 24 bits or 32 bits... only limited by how many ports you have (of course, with so many bits part-to-part manufacturing variations in the R-2R ladders would be larger than your bit steps, so going past 16 bits is pointless).

I tested a quick and dirty clip-lead circuit of this with a USB DVM and captured the 16 bit numerical values from 0 to 65535 and the voltage output, then checked the results. The output was monotonic (meaning no voltage levels went the "wrong way" or overlapped - higher digital values always resulted in higher DC output, and the linearity was absurdly good (something like 99.999% - I forget the exact value).

Lastly, because no filtering is required, there is virtually no "settling time". Setting a value results in an "almost instant" change in DC output... fast enough to pump 16 bit WAV (audio) data to it and get clean sound!

Give it a try... DigiKey sells the R-2R parts, and they are only about $1 USD each. You could attach a simple op-amp unity gain buffer to the DAC output if you need to drive a lower impedance load.

Have fun!

HugoW:
Hi Krupski,

although I am not building a power supply, your comment does help me understand some issues I have with building a stable signal voltage from the PWM port.

Check this out... it's a little board I made to do an 8 bit DAC. Note how the ground pins are offset to fit into the two ground spots on the Arduino MEGA2560 board (so that it can be plugged in and work without any other parts or wiring needed).

(click pic for full size (animated GIF))

On top are two ground access pins and one DAC output pin (extra long to allow clipping on clipleads, scope probes and other junk all at once).

This little board I use mostly to test audio output code. With a MEGA2560 packed to the gills with audio data, it can play about 30 seconds at 8Khz sample rate (which sounds quite good surprisingly).

I sometimes use it to harass my cats... I record various cat sounds, then use an IR remote and the IR decode library to play whatever sound-bite I want by pressing the proper key on the remote.

I hide the board in the living room, then when the cats are getting sleepy (which is always), I play a sound and they freak out, wondering who the intruder cat is! :slight_smile:

That sounds amazing, but I do not understand it at all! The hardware I can just replicate, but the code it beyond me. After I do the code you posted in the void setup part, what would the void loop bit look like? Say I use a simple 0 - 5V (0-1023 bit) input signal over an analog in port (a pot hooked up)?

Cheers,

Hugo

HugoW:
That sounds amazing, but I do not understand it at all! The hardware I can just replicate, but the code it beyond me. After I do the code you posted in the void setup part, what would the void loop bit look like? Say I use a simple 0 - 5V (0-1023 bit) input signal over an analog in port (a pot hooked up)?

Cheers,

Hugo

What we are doing is this:

(1) Setup both of the ports we are using as outputs. The "DDR..." lines are equivalent to "pinMode ()" statements. (I'll explain WHY I didn't use pinMode a bit later).
(2) Take the 16 bit number and split it into two 8 pit "pieces".
(3) Send one piece to one port, send the other piece to the other port (which ends up outputting the voltage we want).

As you know, "pinMode" sets one particular BIT as an input or as an output. Since we are using a total of 16 pins to drive the R-2R parts, it would be a pain to do 16 "pinMode" commands. Doing it by using DDR sets all 8 bits of one port at once, so all I have to do is setup the first port and the second port, not 16 bits individually.

OK, now we have a 16 bit value that can be anything between 0 and 65535. The 65535 number is simply 2 "to the" 16'th power, which is the largest number you can make with 16 bits (all of you who are dying to say "it's 65536, not 65535" just zip it... don't want to complicate things now!)

The full range of the 16 bit value represents 0 volts to 5 volts (broken into 65536 steps!). So, for example, a value of "0" outputs 0 volts. 1/2 of 65535 (which is 32767) will output 1/2 of 5 volts, or 2.5 volts. You see? It's just a ratio... like the analog input. An analog input of 2.5 volts would give you around 1/2 of the max value which would be around 511 or 512.

Let's say we wrote a small "for" loop that did "for x = 0; x < 65536; x++;" and sent it to the DAC. On a scope, you would see a straight upward sloping line from 0 volts to 5 volts.

Now, why we split the value for the two ports. Seen as bits, "value" looks like this:

[b]15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0[/b]

...but each port is 8 bits, so we have to chop the 16 bits into 2 blocks of 8 bits, like this:

[b][color=blue][15  14  13  12  11  10   9   8][/color] [color=green][color=red][ 7   6   5   4   3   2   1   0[/color][/color][/b]]

Now, putting the bottom half (the red part) into an 8 bit port is easy... just put it in. But what about the top half? Even it's minimum value is bigger than 8 bits. So, what we do is "bit shift" it (that is, slide all the bits down, and if we slide it 8 bit places, the top half lines up the same as the bottom half. So, watch this:

[b][color=blue][15  14  13  12  11  10   9   8][/color] [color=green][color=red][ 7   6   5   4   3   2   1   0[/color][/color][/b]] ---> put low bits into low port

[color=red][b][color=blue]slide 8 bits to the right ----->[/color] [/b][/color][b][color=blue][ 7   6   5   4   3   2   1   0]

[/color][/b]

[b][color=blue]                                 [ 7   6   5   4   3   2   1   0][/color] [/b]---> put hi bits into hi port
Do you get it?

Finally, here's a small example of how you would use the code:

void setDac (uint16_t value)
{
    // the ">> 8" is what slides the bits down 8 places
    PORTK = (value >> 8); // set in top 8 bits
    // the "& 0xFF" just makes sure none of the top sneaks into the bottom
    PORTF = (value & 0xFF); // set in lower 8 bits
}

void setup (void)
{
    Serial.begin (9600); // maybe you want serial comm?
    DDRF = 0xFF; // set all port f bits as outputs
    DDRK = 0xFF; // set all port k bits as outputs
}

void loop (void)
{
    float volts; // the user will put in a voltage value
    uint16_t value; // this var will control the DAC
    // hypothetical function you wrote that asks user to enter a number
    volts = userPrompt ("Enter desired DAC voltage: ");
    value = (65535 * (volts / 5.0)); // convert volts into a "percentage" of 16 bits
    // example: user types 2.5 volts, value is 32767
    // example: user types 1.8 volts, value is 23592
    setDac (value); // send value to DAC
    // then loop around and ask for another value
}

Make sense? Notice that this example is very primitive. For example, it doesn't check if the user entered a legal value. They could type "minus 1000 volts", but they sure as heck wouldn't GET that! :slight_smile:

OK, it took me a while but I think I figured it out. I wil mess around with it a bit with only one 8-bit signal, as I have an Uno board. Since I figured out you use a Mega, I also understand where you get all the ports from! Yes, I am a beginner...

Cheers,

Hugo