Arduino DAC questions

Hi folks, I am working on an arduino project where I sample some analog voltages, do some math on them and then I output an analog voltage. Currently I have a ladder DAC setup using digital outputs from pins 0,1,2,4,7,8,12,13. My ladder DAC is buffered via a unity gain op-amp on the output.

I was under the impression that the PWM digital outputs could only be used as PWM outputs and not just set high or low like the other digital outputs. But now I am not so sure, if I can use more digital outputs then I can up my bit resolution, I'd like to go to 10 bits if this is possible.

I would also like to change my code to run faster, presently it calculates an integer for its output and then does a sequence where it sets each bit high or low etc, I would like faster response so I want to use the PORTD/DDRD port access to set all the bits in one step, any problems doing this? If I go to more than 8 bits output, then I will have to switch two ports commands (PORTB and PORTD) at the same time, "splitting" the high low bits between the two, is this easy?

Thanks for all the help!


You can implement any manner of DAC outside the Arduino, but as you said, there is no DAC in the Arduino itself and PWM is not the same thing.

You can bang multiple bits at a time to the I/O registers directly. It makes your code much faster, but also much less portable to other microcontrollers. Yes, if you want to bang more than 8 bits, you will have to do it in stages, but those separate stages can now be very close together, time-wise. See the "port manipulation" page, for more details.

Thanks for the reply, so I guess if I stick with an 8 bit output I can really simplify my code by using the digital pins 0-7 as my high/low outputs and then using PORTD = (integer); to drive the pins from my integer value?

I might stick with an 8 bit output for now and re-arrange my ladder DAC to use pins 0-7 and try the direct port control.

Just remember that pins 0 and 1 are for serial communications, so you'll lose access to that functionality (other than uploading sketches by the bootloader), if you're trying to squeeze 8 bits into one IO register.

Are you worried about the moment of switching, where for a brief interval, not all of your DAC bits are updated? There are a few solutions to that, such as an intermediate latch that can let you load the bits in groups but then latch the new outputs all at once.

Or are you more worried about number of analog samples you can specify per second? We're talking successive updates taking only a couple clocks of the oscillator. It will take a LOT more time to calculate the next sample, than it will to post the sample itself.

Reading this thread I have just had a thought.

Why not combine two PWM signals together to get 16 bit resolution!

You would have to make a ladder of 9 bits long but feed one PWM signal into the most significant bit and the other PWM signal into the least significant bit. So it would take up two outputs but you would get very good resolution. You would need closely matched resistors for the ladder but you could measure and select them from a handful of 1%s.

Alternately you could filter them and put them through a weighted mixer (op-amp) so you only have one value to trim, maybe with a helical pot.

Thanks for the help guys, my project is car related and it was important for me to have a very quick DAC update voltage, on my present code I had a sequence setting each bit after one another. I then had an RC filter after the op-amp buffer to smooth the response, however I would like to drop the RC filter down so I get a faster response. Using the direct port setting I can switch the bits in one shot, there are no voltage hiccups and I can use a faster RC filter on the output.

I think at this point I'd rather leave it 8 bits and use pins 0-7 for my output, it means I just have to re-wire some of my ladder resistors, I've already finishing changing my code.

I think in the future I'll experiment with using the extra 6 digital pins as another 6 bit analog output, I might find a use for it somewhere along the line.

:( it didn't work.

My analog output used to work great, but now I've switched to pins 0-7 digital and changed my code, I get a completely whacky output.

My new code is basically:

void ioinit (void) { // initialize the digital output ports PORTD = B11111111; DDRD = B11111111; // defines pins 0 to 7 as outputs }

and then I have my output as:

PORTD = (digifraction);

digifraction is my integer number I want to output, its between 0-255.

I keep getting the same whacky output no matter how I change the code, what am I doing wrong?

I don't know why you are using brackets.

PORTD = digifraction;

should work by itself.

I found the issue, the code doesn't like it if you mix the PORT commands with regular port setups like analog inputs.

However I'm not sure how to use the PORT commands to read the analog inputs now, it doesn't have anything on the arduino extended reference page, I guess I'll have to fart around with it more.

Grumpy_Mike, that technique is totally doable. Though you probably shouldn't make a resistor ladder, since it really reduces to a single resistor. It's called the "weighted pins" technique.