I2c driver MCP3426
Greetings everyone;
Has anyone ever used the MCP3426, 16 bit ADC I'm looking for a spin driver for that device.
Thanks to everyone in advance
Bob
Has anyone ever used the MCP3426, 16 bit ADC I'm looking for a spin driver for that device.
Thanks to everyone in advance
Bob

Comments
If you find something that works I hope you let us know.
I had wrote Forth-code for MCP3425 in last year .
#444 in [Propforth v5.5 is available for download]thread.
Not spin.
MCP3425 is like MCP3426.
MCP3425 is 1channel A/D and don't have reference voltage.
Thanks
http://forums.parallax.com/showthread.php/160950-Need-code-for-MCP3428-Please
Here is a link to another approach. See post #14. You need the jm PASM driver from post #2.
http://forums.parallax.com/showthread.php/161040-Another-i2c-assembly-driver
_clkmode = xtal1 + pll16x 'clock mode
_xinfreq = 5_000_000 '* crystal frequency
CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq
'MCP3428 ADC Values
SCL = 17 ' Clock MCP3428 Pin 8
SDA = 18 ' Data In/Out MCP3428 Pin 7
OBJ
SN : "Simple_Numbers"
'pst : "Parallax Serial Terminal Plus"
DEBUG : "FullDuplexSerial"
adc : "jm_mcp342x"
VAR
Byte DataH, DataL, DataC
PUB Main
' pst.Start(57600)
DEBUG.start(31, 30, 0, 9600)
'MCP3428 Initialized
adc.startx(SCL, SDA, 0, 0)
' adc.set_channel(0,0)
adc.set_channel(0,16,1)
repeat
DataH := adc.raw2mv(0,16,1)
DataL := adc.raw2mv(1,16,1)
DataC := adc.raw2mv(2,16,1)
DEBUG.tx($D)
DEBUG.str(string("Data H... "))
DEBUG.Dec(DataH)
DEBUG.tx($D)
'pst.Position(1, 16)
' pst.Dec(DataL)
'pst.Position(1, 22)
'pst.Dec(DataC)
' pst.Str(String(" "
http://forums.parallax.com/showthread.php/161040-Another-i2c-assembly-driver.
That being said, I think after you do the adc.start, your loop should look like:
You should define myrawdata and millivolts both as longs.
JonnyMac or CelticLord or DuaneD, feel free to jump in here anytime. I'm a little out of my depth; I just ever used JonnyMac's PASM I2C driver.
Edit: I removed the first adc.read_raw call.
I tried both Tom's demo code from the other thread and the code below without luck.
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 OBJ Pst : "parallax serial terminal" Adc : "jm_mcp342x" Format : "StrFmt" PUB Main Pst.Start (115_200) repeat result := Pst.rxcount Pst.str(String(11, 13, "Press any key to start.")) waitcnt(clkfreq / 10 + cnt) until result Pst.RxFlush Pst.Clear Pst.home Pst.str(String(11, 13, "Starting ADC Driver")) Adc.start(adc#F, adc#F) repeat Pst.str(String(11, 13, "Set ADC Channel")) Adc.set_channel(0, Adc#SAMP_16, Adc#GAIN_1) Pst.str(String(11, 13, "Waiting for Ready")) repeat until Adc.ready == true 'wait until it is done result := Adc.read_raw Pst.str(string(11, 13, "Channel 1 raw = ")) Pst.dec(result) Pst.str(string(" = ")) ReadableBin(result, 32) waitcnt(clkfreq + cnt) PUB ReadableBin(localValue, size) | bufferPtr, localBuffer[12] '' This method display binary numbers '' in easier to read groups of four '' format. bufferPtr := Format.Ch(@localBuffer, "%") result := size // 4 if result size -= result bufferPtr := Format.Bin(bufferPtr, localValue >> size, result) if size bufferPtr := Format.Ch(bufferPtr, "_") size -= 4 repeat while size => 0 bufferPtr := Format.Bin(bufferPtr, localValue >> size, 4) if size bufferPtr := Format.Ch(bufferPtr, "_") size -= 4 byte[bufferPtr] := 0 Pst.Str(@localBuffer)Here's the output:
As can bee seen from the output, the code never gets past waiting for ready.
My first guess is I didn't wire something correctly (if any of you saw my PCB you'd likely agree). I'm hoping someone could check over the demo code I used for Jon's object to see if did something wrong.
Edit: I'm not sure if I'm using the correct parameters with the start call. I'm using float on each address bit but I'm not sure this is correct. I have a few more things to try.
Edit again: Sorry for not including the child objects to the above program. The archive attached to post #14 includes the child objects used by both this program and my latest demo program (neither programs appear to work).
I decided to try each possible combination of addresses (I suppose they're not really bits since there are three possible states).
Here's my latest (failed) demo attempt:
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 OBJ Pst : "parallax serial terminal" Adc : "jm_mcp342x" Format : "StrFmt" PUB Main | timer, timeoutInterval, address0, address1 Pst.Start (115_200) repeat result := Pst.rxcount Pst.Str(String(11, 13, "Press any key to start.")) waitcnt(clkfreq / 10 + cnt) until result Pst.RxFlush Pst.Clear Pst.Home Pst.Str(String(11, 13, "Initializing ADC Driver")) timeoutInterval := clkfreq * 2 repeat address1 from 0 to 2 repeat address0 from 0 to 2 Pst.Str(string(11, 13, "Initializing driver with address = ")) Pst.Dec(address1) Pst.Str(string(", ")) Pst.Dec(address0) Adc.Start(address1, address0) waitcnt(clkfreq + cnt) Pst.Str(String(11, 13, "Set ADC Channel")) Adc.Set_channel(0, Adc#SAMP_16, Adc#GAIN_1) timer := cnt repeat result := Adc.Ready until result or cnt - timer > timeoutInterval if result Pst.Str(string(7, 11, 13, 11, 13, " SUCCESS!", 11, 13, 7)) Pst.Str(string(11, 13, "Device found address, A1 = ")) Pst.Dec(address1) Pst.Str(string(", A0 = ")) Pst.Dec(address0) Pst.Str(string(11, 13, "Starting MainLoop Method")) waitcnt(clkfreq * 3 + cnt) Pst.Clear MainLoop else Pst.Str(string(11, 13, "Device not found using address ")) Pst.Dec(address1) Pst.Str(string(", ")) Pst.Dec(address0) Pst.Str(string(7, 11, 13, "The sensor was not detected. There is an error either in the ")) Pst.Str(string(11, 13, "way the sensor is wired or there is an error in the software. ")) Pst.Str(string(7, 11, 13, "It's also possible the ADC chip is damaged. ")) Pst.Str(string(11, 13, 11, 13, "End of Program", 7)) repeat ' keeps cog alive so terminal window doesn't clear PRI MainLoop | timer, timeoutInterval timeoutInterval := clkfreq * 2 repeat Pst.Home Pst.Str(String(11, 13, "Set ADC Channel")) Adc.Set_channel(0, Adc#SAMP_16, Adc#GAIN_1) Pst.Str(String(11, 13, "Waiting for Ready")) timer := cnt repeat result := Adc.Ready until result or cnt - timer > timeoutInterval ifnot result Pst.Str(String(7, 13, 13, 13, 13, "Timeout! Check connections.", 7)) result := Adc.Read_raw Pst.Str(string(11, 13, "Channel 1 raw = ")) Pst.Dec(result) Pst.Str(string(" = ")) ReadableBin(result, 32) '' add readout of processed bits 'waitcnt(clkfreq /20 + cnt) PUB ReadableBin(localValue, size) | bufferPtr, localBuffer[12] '' This method display binary numbers '' in easier to read groups of four '' format. bufferPtr := Format.Ch(@localBuffer, "%") result := size // 4 if result size -= result bufferPtr := Format.Bin(bufferPtr, localValue >> size, result) if size bufferPtr := Format.Ch(bufferPtr, "_") size -= 4 repeat while size => 0 bufferPtr := Format.Bin(bufferPtr, localValue >> size, 4) if size bufferPtr := Format.Ch(bufferPtr, "_") size -= 4 byte[bufferPtr] := 0 Pst.Str(@localBuffer)Here's the output from the code:
I'm attaching an archive of the program so the child objects are available. The "Format" object is used in the "ReadableBin" method (which I think makes it easier to read binary data).
I'm not sure what else to try with the software so for now, I'll check my wiring. Hopefully I made an easy to fix wiring error.
BTW, I'm running the program on a QuickStart board and I'm using the EEPROM's I2C bus.
CON 'Belonging to main _clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz _xinfreq = 5_000_000 SDA = 6, SCL = 5 'my wiring VAR long myrawdata 'raw data from adc long millivolts 'raw converted long symbol 'generally useful OBJ pst : "parallax serial terminal" adc : "jm_mcp342x" PUB main pst.Start (115_200) 'start up ser terminal pst.str(String("hello, world ")) 'runs in cog 1 pst.NewLine waitcnt(clkfreq/10+cnt) symbol := adc.startx(SCL, SDA, ADC#L, ADC#L) 'note this is startx, not start pst.str(String("Value from adc.startx: ")) 'allows one to spec i2c pins pst.hex(symbol,8) pst.NewLine waitcnt(clkfreq/10+cnt) repeat adc.set_channel(0, adc#SAMP_12, adc#GAIN_1) 'start the conversion repeat myrawdata := adc.read_raw 'do a read to get config register pst.char("*") until adc.ready == TRUE 'until data are valid pst.newline pst.str(string("Raw Data: ")) pst.hex(~~Myrawdata,8) 'sign extended myrawdata := ~~myrawdata millivolts := adc.raw2mv(myrawdata, adc#SAMP_12, adc#GAIN_1) pst.str(string(" Millivolts: ")) pst.dec(millivolts) pst.newline waitcnt(clkfreq+cnt)Duane, I think you did two things wrong (well, not wrong, just different from what works)
1. You have to use adc.startx rather than adc.start so that you override the default i2c pins (28 and 29).
2. After starting the conversion with adc.set_channel, you have to execute a read prior to each time you do adc.ready. adc.ready does NOT actually read the config register.
3. It is probably easiest to use all the adc#CONSTANTs from the driver to set bits and gain.
Edit: I take back item 1 since you are using the EEPROM i2c. EndEdit
I'm glad to know I wasn't doing it wrong.
I was only doing #2 "different from what works." Since I was using the default I2C pins I think the start method shouldn't have been a problem.
I moved my I2C lines to match yours and sure enough the code works!
Thank you very much!
Now I need to add a voltage divider to my circuit since I didn't realize this ADC is saturated at 2.048mV.
Thank you again. You've saved me from a lot of frustration.
Edit: The saturation point is 2.048V not 2.048mV.
Regards
Bob
Tom has a tendency to do that.
I'm glad you let us know you got your chip working too. I was just wondering if you had seen Tom's code.
Of course JonnyMac also deserves some praise for contributing the driver. (I learned PASM (and a bunch of other stuff) from reading Jon's Spin Zone columns.)
What a great forum.
I have a fixed divider going to one side of the (differential) input and a potentiometer between 3.3 and VSS to the other, so I can test both positive and negative.
I have a fixed divider going to one side of the differential input and a variable divider (pot) going to the other. So I can test positive and negative values.
CON 'Belonging to main _clkmode = xtal1 + pll16x 'Standard clock mode _xinfreq = 5_000_000 '* crystal frequency = 80 MHz SDA = 6, SCL = 5 'my wiring VAR word myrawdata 'raw data from adc long millivolts 'raw data converted to millivolts byte rescode 'resolution code: 0..2 for 12-, 14- 16-bit byte gaincode 'gain code: -..3 for 1, 2, 4, 8 ' long symbol OBJ pst : "parallax serial terminal" adc : "jm_mcp342x" PUB main pst.Start (115_200) 'start up ser terminal pst.str(String("hello, world ")) 'runs in cog 1 pst.NewLine waitcnt(clkfreq/10+cnt) symbol := adc.startx(SCL, SDA, ADC#L, ADC#L) 'note this is startx, not start repeat rescode from adc#SAMP_12 to adc#SAMP_16 'sample size changes slowest repeat gaincode from adc#GAIN_1 to adc#GAIN_8 ' adc.set_channel(0, rescode, gaincode) 'start the conversion repeat myrawdata := adc.read_raw 'read data and config register pst.char("*") until adc.ready == TRUE 'until conversion is complete pst.newline pst.str(string("Resolution: ")) pst.dec(lookupz(rescode:12, 14, 16)) pst.str(string(" Gain: ")) pst.dec(lookupz(gaincode:1, 2, 4, 8)) pst.str(string(" Raw Data: ")) pst.hex(Myrawdata,4) millivolts := adc.raw2mv(myrawdata, rescode, gaincode) pst.str(string(" Millivolts: ")) pst.dec(millivolts) pst.newline waitcnt(clkfreq/10+cnt) pst.newlineWhen I first ran this, I observed that the voltage returned varied with the gain variable. Higher gain, lower indicated voltage. It turned out the my voltage dividers were very high impedance (100s of Kohms). I changed the dividers to a few hundred ohms and got much more consistent results. It turns out that the impedance impedance is on the order of 1 Mohm and varies with the gain.
This will allow you to use your original higher resistor values (verify it with your test program, of course) and greatly reduce your current draw, which is probably why you chose the higher values in the first place.
I only see small differences reading voltages without a bypass cap on, say, an MCP3304, but when I read small voltages from a shunt, it can be off by a factor of 2 without the caps. Your TI ADC must be rather power hungry.
Thanks for the reminder. I saw capacitors mentioned in the datasheet but I personally hadn't added them to my circuit. I'll make sure and do this.
I'm curious to learn how Tom does with caps added to his circuit.
Ideally, the input source impedance should be
zero. This can be achievable by using an operational
amplifier with a closed-loop output impedance of tens
of ohms.
I did try a 104 ceramic cap *between* the differential inputs and it didn't really make any difference. I would worry about frequency response with large Rs and Cs (even knowing the max sample rate is 10s or 100s of Hz already).
http://cds.linear.com/docs/en/datasheet/2487ff.pdf