Mcp4725 I2c Dac

kewakl

Senior Member
I have this circuit [EDIT: Diagram is NOT complete. { Does not show 5K pulldown on analog channel 1}{Does not show reset 10K pullup}{Does not show piezo connections}] EDITED DIAGRAM
ADDED:the almost red items - moved some items for clarity
The piezo third lead to leg 21 (out 0) - not used in program.
The piezo was taken from a toy. It had three leads. Do not know what the third lead is.
The reset switch is just a stiff wire. I touch it to the 0V for a reset.



and this code
Code:
 Symbol LCD_CMD_Ext		=	124        
 Symbol LCD_Reset		=	8
 Symbol LCD_CMD 		=	254
 Symbol LCD_CLR 		=	1
 Symbol Line1			=	128
 Symbol Line2			=	192

#no_data
#no_table

setfreq m8
hi2csetup i2cmaster, %11000000, i2cslow, i2cbyte
hi2cout %00000000,(%00000110)
pause 50
serout 7,t9600_8,(LCD_CMD_Ext,LCD_CLR)
PAUSE 20
serout 7,t9600_8,(LCD_CMD,line1,"Signal In       ")
serout 7,t9600_8,(LCD_CMD,line2,"Signal Out      ")
pause 50
main:
readadc 0,b0
'
'MCP4725  I2C DAC
'Address %11000000  ($C0)
'Mode: Write DAC (C2,C1,C0) -> 0,1,0 (Do not update EEPROM)
'
'12-bit
'ADDRESS
'1st Byte %11000000
'2nd Byte %01000000
'3rd Byte D11-D4
'4th Byte D3-D0,x,x,x,x
'
'1st byte is sent by hi2cout - slave address
'2nd byte is the first position in the parentheses
'3rd byte is b4
'4th byte is b5
'

b4=b0	'copy potentiometer analog value to lo-byte of command value
b5=0	'clear hi-byte of command value
w3=w3*8	'shift left 4 places    [EDIT: W3 is the wrong word - the shifting seems to be unnecessary anyway????11-11-09]

hi2cout (%01000000,b4,b5)	'command I2C DAC to generate analog value

readadc 1,b2
'justify the positions of b0 abd b2 on the LCD
if B0<10 then
  serout 7,t9600_8,(LCD_CMD,140,"  ",#b0)
endif
if B0>9 and B0<100 then
  serout 7,t9600_8,(LCD_CMD,140," ",#b0)
endif
if B0>99 then
  serout 7,t9600_8,(LCD_CMD,140,#b0)
endif

if B2<10 then
  serout 7,t9600_8,(LCD_CMD,204,"  ",#b2)
endif
if B2>9 and B2<100 then
  serout 7,t9600_8,(LCD_CMD,204," ",#b2)
endif
if B2>99 then
  serout 7,t9600_8,(LCD_CMD,204,#b2)
endif
pause 150
toggle 6
goto main
The MCP4725 breakout has I2C pullups in place (10K)
The 5K pulldown on output 7 kills noise on the LCD RXD line when the PICAXE is not running.
P.E. 5.2.7


Now the issue - if it is an issue.
The circuit and code work - (I will optimze/tidy later - I am learning this DAC)
but the I2C DAC output value is always 1 count less than the commanded value
from the pot.
Ex. If the analog value (analog input 0) from the pot is 124, the return analog value (analog input 1) from the I2C DAC will be 123.

I know that this will not influence a scaled value by much, but is there anything that I can do to make the values match?
(Note1: The (wht/ora) wire from Output 6 goes to a piezo used for listening for a resetting picaxe
Note2: The green wire at the bottom is a reset line - I do not yet have a good small pb)
)

SparkFun pages, containing links to pictures, datasheets and schematics
MCP BOARD
LCD DISPLAY

Unfortunately, SparkFun usually has programming examples for ATMEL/C code
 
Last edited:

boriz

Senior Member
Excellent question format. If only they were all like this.

The first thing that occurs to me is the old 1-based or 0-based number system confusion. Perhaps the ADC is using 1-based (input or output), so your 0-based Picaxe ADC reading will need to have 1 added before sending it to the DAC. (Even if this is not the cause, it could still be the solution if you don’t mind the kludge)

What’s the outputs for an input of zero, and an input of one?

Could it be something to do with different source impedances for the different ADCs?

Could noise be a factor? Can you ‘scope the inputs to look for ripple?

Could there be something different about the Picaxe ADCs?. Do you get the same results if you swap the ADC channels?

Is it some sort of scaling error? Like do you get a larger error at the top end (>250 input) than at the bottom end (<5 input)? Or is it a consistent 1 less over the entire range?

Just some thoughts off the top of my head.
 

hippy

Technical Support
Staff member
The first thing I'd do is disconnect the DAC output from the PICAXE and put a calibrated scope on it to see what it shows when set to a specific level by the PICAXE. You need to determine if it's the DAC output or PICAXE ADC input where the error is coming from.
 

ylp88

Senior Member
You only need around 20mV of error... Perhaps you should also check that the grounds and supplies are at the same potential for both the PICAXE and the DAC.

On that note, 0.5 ohms of resistance on each of your supply lines between the DAC and the PICAXE with a 20mA current supplying the chip will produce the necessary difference.

ylp88
 

kewakl

Senior Member
I'll respond to the points as I can....
Scope - I do not have nor have access to a scope of any quality/accuracy/resolution.
Scaling Error - Do not think so. Except for a '0' signal, the ADC generated value is always 1 less than commanded value.
ADC channel differences - Wish I'd have thought of that.
0-base vs 1-base - will have to read the data sheet more thoroughly. Need to talk to Juan Valdez first.
Noise a factor - Easily it could be. Refer to my Scope remark. The datasheet recommend using a 10uF Tantalum parallel to the 0.1uF Ceramic.
The breakout has the 0.1uF, so I'll try the 10uF later.

Oh, the 5K on the ADC line in the picture - the 124-123 issue was present before the resistor was placed.
The resistor simply provides a 0V ref when the ADC is disconnected.(datasheet - Fig 2-15 pg 7 - should not be an issue)

@boriz, (Kludge add 1) you know, I tried that. But in thinking it over... I failed to *SHIFT* the added 1 into the correct position.
I added 1 *AFTER* shifting the data. (See 4th byte description in code)
@hippy, is there a proper way to do this shift. The way I used does work, but your code is usually more eloquent.

@ylp88 - maybe 2 shielded runs for +v/0v straight to the vbatt connector to minimize single-point contact resistance. maybe 2 shielded runs for analog out.

Voltage is NOT 5Vdc as per drawing. 4.5Vdc from 3*AA cells.
 

hippy

Technical Support
Staff member
@boriz, (Kludge add 1) you know, I tried that. But in thinking it over... I failed to *SHIFT* the added 1 into the correct position.
I added 1 *AFTER* shifting the data. (See 4th byte description in code)
@hippy, is there a proper way to do this shift. The way I used does work, but your code is usually more eloquent.
It should just be simple case of adding 1 before sending the data out ( or adding 1 to the ADC1 read ), however that could introduce problems with the extremes of zero and full-scale DAC output.

The crucial key is what the DAC is putting out with respect to what it's told to put out. You need to determine that's correct or not before looking at any other issues. If you don't have a scope then a multi-meter may do, although that too should be calibrated.

It's no good relying on what's read in to determine what the DAC puts out if there is an issue with the circuit or ADC input, and simply bodging the reading or what's output won't necessarily get what you actually want to achieve, which I presume is a specific DAC output for a specific value it's told to be.
 

hippy

Technical Support
Staff member
Of course it could always be a good old fashioned programming bug / design error ...

readadc 0,b0
b4=b0 'copy potentiometer analog value to lo-byte of command value
b5=0 'clear hi-byte of command value
w3=w3*8 'shift left 4 places

That can be simplified to -

ReadAdc 0, b0
w3 = b0 * 8

So when b0 = %1111 1111 ( $FF, 255, full ), you output as 16-bits in w3 ...

%---- -111 1111 1000

That's not setting the DAC output to %---- -111 1111 1111 which would be full output. Hence the earlier suggestion to look at DAC output; when the DAC is told to put out a particular output it would be clear that it wasn't doing that.

You probably need -

ReadAdc 0, b0
w3 = b0 * 8
If bit0 = 1 Then : w3 = w3 | $0007 : End If

Added : Though isn't it a 12-bit DAC ? "* 8" is shift left 3 bits, not 4

So that would be -

ReadAdc 0, b0
w3 = b0 * 16
If bit0 = 1 Then : w3 = w3 | $000F : End If

Or better still -

ReadAdc10 0, w0
w3 = w0 * 4
If bit0 = 1 Then : w3 = w3 | $0003 : End If
 
Last edited:

kewakl

Senior Member
Of course it could always be a good old fashioned programming bug / design error ...
<SNIP>
Added : Though isn't it a 12-bit DAC ? "* 8" is shift left 3 bits, not 4

So that would be -

ReadAdc 0, b0
w3 = b0 * 16
If bit0 = 1 Then : w3 = w3 | $000F : End If

Or better still -

ReadAdc10 0, w0
w3 = w0 * 4
If bit0 = 1 Then : w3 = w3 | $0003 : End If
hippy, I'll have to rebuild the circuit and check that.
"* 8" is shift left 3 bits, not 4
*good old fashioned programming bug*:eek:

I am having a THICK moment - usually I can follow your code,
but what is this doing ?
Code:
If bit0 = 1 Then : w3 = w3 | $0003 : End If
After the shift, this wouldn't do anything.
Bits 3 to 0 are Don't Care for the DAC input.


If you don't have a scope then a multi-meter may do, although that too should be calibrated.
Have a respectable, if not great, Fluke 79III meter.
I can do a Comparative measurement (not a calibration) on a calibrated bench meter/power supply. This way I would know how far out my meter is.
 

kewakl

Senior Member
small update.
I have determined that the datasheet is confusing. ha ha

Really, I messed up when I picked W3 for the word to shift. B4 and B5 belong to W2. Cannot count.
This means that the shifting specified in the datasheet is IRRELEVENT for this mode.
MODE %01000000 (Write DAC Register - Load configuration bits and data code to the DAC Register) Do not write to EEPROM
specifies this write command format
Code:
1st Byte  2nd Byte   3rd Byte  4th Byte 
%11000000 %01000000  D11-D4    D3-D0,x,x,x,x
     ----     xx--x
 ---- |    ---   |
  |   |     |    +power-down mode
  |   |     |
  |   |     +write command type
  |   +address code
  +device code
So, if the shift is required, then I would assume that shifting would move the databits from D0-D7 to D4-D11.
However, I picked the wrong word, thus did not shift the databits. And I was only off 1 count.
 

kewakl

Senior Member
@boriz
I used different ADCs.still 124/123.
I would change-up to 28x2, but then the added work of ADCSETUP. not til I understand this DAC better.

I am at a total loss about this table from page 17.

Somehow, I am thinking that I WILL ALWAYS see -1 LSB.

Hope I'm wrong.:confused::confused::confused:
 

boriz

Senior Member
So... (And this is all theory. I’ve never used a DAC)

Your DAC is 12 bits, so 1 LSb = 4.5v/4095 = about 1.09mV ?

Your Picaxe READADC is 8 bits, so 1 LSb = 4.5v/255 = about 17.64mV ?

So with everything working properly, the DAC output needs to be set to at least 17.64mV for the ADC to read 1. The nearest DAC output would be 16*4.5/4095 = 17.58mV, which just a little too short, so you need to use 17*4.5/4095 = 18.68mV. You send 17 to the DAC to read 1 on the ADC ?

But you can’t just use multiples of 17 ‘coz the rounding errors would get you with bigger voltages, and 17*255 = 4335, too large a number to be stored in 12 bits. The actual conversion factor would need to be 4095/255 = 16.05882353 ! (Not a comfortable number for a Picaxe :)

But, with an error of only 88.9 parts per million, you can use the integer fraction 225/14, which is equivalent to 16.0714. Not too far out.

Then the Picaxe can scale thus: Output to DAC = Required 8bit ADC number * 225/14

EG: Required 8bit ADC is 124, so you send 124*225/14 = 1992.857 (round to 1993) and the DAC should produce 1993*4.5/4095 = 2.19v output. That should measure on the 8bit 4.5v ADC scale as 124 :)

Remember that because of the way Picaxe does maths, the first part of 124*225/14 will evaluate first and give 27900 and is only then divided by 14, so make sure you use a word variable. Anything up to 255 is fine and will not cause overflow.

Hope I’m making sense.
 

kewakl

Senior Member
So... (And this is all theory. I’ve never used a DAC)

Your DAC is 12 bits, so 1 LSb = 4.5v/4095 = about 1.09mV ?

Your Picaxe READADC is 8 bits, so 1 LSb = 4.5v/255 = about 17.64mV ?

So with everything working properly, the DAC output needs to be set to at least 17.64mV for the ADC to read 1. The nearest DAC output would be 16*4.5/4095 = 17.58mV, which just a little too short, so you need to use 17*4.5/4095 = 18.68mV. You send 17 to the DAC to read 1 on the ADC ?

But you can’t just use multiples of 17 ‘coz the rounding errors would get you with bigger voltages, and 17*255 = 4335, too large a number to be stored in 12 bits. The actual conversion factor would need to be 4095/255 = 16.05882353 ! (Not a comfortable number for a Picaxe

But, with an error of only 88.9 parts per million, you can use the integer fraction 225/14, which is equivalent to 16.0714. Not too far out.

Then the Picaxe can scale thus: Output to DAC = Required 8bit ADC number * 225/14

EG: Required 8bit ADC is 124, so you send 124*225/14 = 1992.857 (round to 1993) and the DAC should produce 1993*4.5/4095 = 2.19v output. That should measure on the 8bit 4.5v ADC scale as 124

Remember that because of the way Picaxe does maths, the first part of 124*225/14 will evaluate first and give 27900 and is only then divided by 14, so make sure you use a word variable. Anything up to 255 is fine and will not cause overflow.

Hope I’m making sense.
Good info, now to understand it.
More coffee, please!


I've never used a DAC either. This is my first go at one. My results SEEMED to be very close, so I thought I'd ask if I really had an issue.
I basically wanted to build an analog signal follower so I could verify that everything was working more-or-less correctly.
I have NOT attempted any scaling - simply taking the readadc value and sending that to the DAC. Probably not the right to do.
I need to hit the datasheet again.
 

hippy

Technical Support
Staff member
From the datasheet it appears this DAC will never put out full Vsupply, output will be -

Vout = N * Vsupply / 4096 ( where N = 0 to 4095 )

You can get a one-to-one proportional mapping of Vfader ( 0% to 100% ) to Vout ( 0% to 100% ) but the two 100% voltages will not be the same. To get the DAC to exactly match the Vfader voltage you need to buffer that with gain of 4096/4095, ie -

Vfinal = Vout * 4096/4095
 

westaust55

Moderator
Did not see that this had been picked up

(aka old fashion programming error)

b4=b0 'copy potentiometer analog value to lo-byte of command value
b5=0 'clear hi-byte of command value
w3=w3*8 'shift left 4 places


BUT . . .

w3 uses b7:b6

so believe your code should use w2 which uses b4:b5

EDIT: ah okay see you have picked that up :eek: seems easier to pick these things up in retrospect
I did a search for "w2" and found it in post 9 - should have done that first


Secondly,

as you are only using READADC which is an 8-bit command
why don't you use:
w2 = b4 * 256 ie shift 8 bits to the left - which would maximise the range from the DAC.
Then when the 10K pot is at the top end of its travel, (ie = supply voltage) then the DAC would also produce its maximum value
or . . . am I missing something ? :confused:
 
Last edited:

hippy

Technical Support
Staff member
What's so very odd, given all the 'wrongs', that the code appeared to be working ( albeit consistently reporting 'one below' ). It doesn't look like anything should have worked at all. I'm starting to wonder if the hardware is even correct or working as it was preceived to be; the DAC input to PICAXE could be floating and what that ADC channel is returning is the residual voltage sampled from the pot left on the internal ADC sample and hold capacitor.

The best course is perhaps to rip the project apart and start again from first principles.
 

kewakl

Senior Member
What's so very odd, given all the 'wrongs', that the code appeared to be working ( albeit consistently reporting 'one below' ). It doesn't look like anything should have worked at all. I'm starting to wonder if the hardware is even correct or working as it was preceived to be; the DAC input to PICAXE could be floating and what that ADC channel is returning is the residual voltage sampled from the pot left on the internal ADC sample and hold capacitor.

The best course is perhaps to rip the project apart and start again from first principles.
@hippy
Notice the 5k resistor on leg3, pulling the analog input low.

Rip apart. have done and rebuilt as closely as per posted picture.
works same as originally reported.
hippy said--From the datasheet it appears this DAC will never put out full Vsupply, output will be -
do you think that this is related to the table posted in post 10?

@westy
No, you're not missing anything. I really wanted to grasp the basics first.

I really appreciate all the responses (glad I did not say that this is for automotive:eek: -- it really ISN'T) just a learning exercise.


Next project 3 axis accelerometer. (FOR AUTOMOTIVE!!)
3*AA powered logger. The boy is almost ready for driver's permit!
Gotta know what he's making the car do! New thread-later!
 

MartinM57

Moderator
Standalone battery powered automotive g-force datalogger - won't even raise a collective eyebrow. But even the slightest hint that you've even thought about plugging it into the car will raise untold angst and collective hand-wringing.... :D
 

hippy

Technical Support
Staff member
@hippy
Notice the 5k resistor on leg3, pulling the analog input low.
Except it doesn't, not on the diagram anyway. It connects Out 7 to the Serial LCD to 0V. I wasn't sure what the line into the 28X1 was but that connects direct to 0V, not via the 5K.

Also, it won't have any effect on the ADC S&H capacitor unless analogue input 3 were selected and read.

do you think that this is related to the table posted in post 10?
Yes, that defines the functionality.
 

kewakl

Senior Member
Except it doesn't, not on the diagram anyway. It connects Out 7 to the Serial LCD to 0V. I wasn't sure what the line into the 28X1 was but that connects direct to 0V, not via the 5K.
look at the photo. Below the PICAXE. Leg 3. Next to the 10K pullup on the RESET line
The diagram was done from memory in MSPaint. So, it is NOT exact, just the important items and connections.

Yes, that line is going to leg19, 0V.
 

kewakl

Senior Member
Standalone battery powered automotive g-force datalogger - won't even raise a collective eyebrow. But even the slightest hint that you've even thought about plugging it into the car will raise untold angst and collective hand-wringing.... :D
But I do need some way for the engine running to enable the logger.
do not want to replace batteries after every trip. Haven't planned *anything* yet, so I'll not post more about it until I'm ready to start the project.
(hand-wringing and angst -- yes I've read many posts. I understand the reasoning behind most)
 

hippy

Technical Support
Staff member
look at the photo. Below the PICAXE. Leg 3. Next to the 10K pullup on the RESET line
The diagram was done from memory in MSPaint. So, it is NOT exact, just the important items and connections.

Yes, that line is going to leg19, 0V.
No offence intended, but life's sometimes too short to spend time analysing a layout in depth, tracing wires, counting pin numbers on chips, checking colours of resistors.

When a circuit is drawn from memory it's best to say so as otherwise there's no reason to believe it's not correct, not what was intended. The breadboard is simply an embodiment of what the circuit does, so only of secondary importance.
 

kewakl

Senior Member
No offence intended, but life's sometimes too short to spend time analysing a layout in depth, tracing wires, counting pin numbers on chips, checking colours of resistors.
None taken I am surprised that anyone spent so much time trying to help!

When a circuit is drawn from memory it's best to say so as otherwise there's no reason to believe it's not correct, not what was intended. The breadboard is simply an embodiment of what the circuit does, so only of secondary importance.
Excellent point.
 

kewakl

Senior Member
Shift Right | Left

Math operators >> and <<. (since this is an x1)

:eek:


Manuals are a wonderful tool. Reading glasses are wonderful tools.(not the eBay variety)
 

kewakl

Senior Member
No offence intended, but life's sometimes too short to spend time analysing a layout in depth, tracing wires, counting pin numbers on chips, checking colours of resistors.

When a circuit is drawn from memory it's best to say so as otherwise there's no reason to believe it's not correct, not what was intended. The breadboard is simply an embodiment of what the circuit does, so only of secondary importance.
I have edited the diagram in the original post. The almost red items were added.
Some components were moved for clarity and so I could place/label newly added components. Sorry for not declaring that the circuit was not exact.
I have learned.:)
 
Top