-
• #52
Ok differential testing
[0,1] chn: A0 & chn: A1 works
[2,3] Doesn'tAdadfruit doc points to Differential only on A0&A1 and A2&A3
-- valid duo of channels as an array: [0,1], [0,3], [1,3], or [2,3] for differential read
If that's correct then some of the above config isn't correct.
https://learn.adafruit.com/adafruit-4-channel-adc-breakouts/signal-connectionsA few things the ADS1X15 inputs float quite high.
When doing differential the first channel is compared to 2nd e.g to get a positive reading A0 has to be > A1. -
• #53
Try:
var ads = require("https://gist.githubusercontent.com/gfwilliams/da8f09f91c8d0011cbae/raw/51dcef9df30bafa7282fb0bea17cda1d637e488f/ADS1X15.js").connect(...)
Looks like there was a bit of a bug in the code.
-
• #54
Uncaught SyntaxError: Got ':' expected EOF
at line 93 col 9
"1,3" : CONFIG.MUX_DIFF_1_3 }, // Differential P = AIN1, N... -
• #55
Soft-Tested with the attached file.
ADStxt15Ext.js is the module (modified name for temporary coexistence in my sandbox modules folder.
ADS1x15Ext_tst.js is a testing approach with TDS - Test Data Specs and the MTEST - Module TESTer.
A validation (in
vals:[]
) can be specified in two formats:[ "id_of_the_validation" , function() { /*returning true or false */ return true;} ]
or
[ "interpretable.left.side definedOperator interpretable.right.side" ]
The following two are exactly the same:
, [ "defaultI2Addr", function(test) { return test.inst.addr === test.tds.defaultI2cAddr; } ] , [ "inst.addr === tds.defaultI2CAddr" ]
The
test
is the ModuleTESTer singleton, is always passed and provides access to themod
(ule), theinst
(ance - afer the.connect()
) andtds
(TestDataSpecs). More at a later time.// // ./__tsts/ADS1x15Ext_tst.js // var MOD = require("ADS1x15Ext"); var TDS = // ...TestDataSpec { vInfo: { v:1, d:20150915, a:"allObjects" } , moduleName:"ADS1x15Ext" , defaultI2CAddr: 0x48 // .addr after connect w/ new , defaultAPGGain: 2048 // .gain after connect w/ new , updatedAddr: 0xA5 // .addr after setAddr() , updatedGain: 6144 // .gain after setGAin() , invalidGain: 9999 // for setGAin() , invalidGainXptnMsg: "Gain 9999 not found" , gain4096: 4096 // .gain , adcRaw0: 0 // raw 0 , adcRaw32767: 32767 // raw max , adcRaw32768N: -32768 // raw min , adcRaw1: 1 // raw 1 , adcRaw1N: -1 // raw -1 , ch0: 0 // channel 0 (1st) , ch1: 1 // channel 1 (2nd) , ch2: 2 // channel 2 (3rd) , ch3: 3 // channel 3 (4th) , readCnt: 2 // read count in bytes on read register 1..3 , vars: { i2c: null // used in test , savedGain: -1 // used to save gain , adcRaw: -1 // raw value read from ADC } , tsts: // tests [ { id:"getModule():" , f: function(test) { test.mod = require(test.tds.moduleName); } , vals: [ [ "mod !== undefined" ] , [ "mod !== null" ] , [ "typeof:mod.connect === function" ] ] } , { id:"connect():" , f: function(test) { test.inst = test.mod.connect(test.tds.vars.i2c); } , vals: [ [ "inst !== undefined" ] , [ "inst !== null" ] , [ "inst.i2c === tds.vars.i2c" ] , [ "inst.addr === tds.defaultI2CAddr" ] , [ "inst.gain === tds.defaultAPGGain" ] , [ "typeof:inst.setAddr === function" ] , [ "typeof:inst.setGain === function" ] ] } , { id:"setAddr():" , f: function(test) { test.inst.setAddr(test.tds.updatedAddr); } , vals: [ [ "inst.addr === tds.updatedAddr" ] ] } , { id:"setGain():" , f: function(test) { test.inst.setGain(test.tds.updatedGain); } , vals: [ [ "inst.gain === tds.updatedGain" ] ] } , { id:"setGain() w invald gain:" , f: function(test) { test.tds.vars.savedGain = test.inst.gain; test.inst.setGain(test.tds.invalidGain); } , vals: // exception happpens, gain stays untouched [ [ "tstXptn.msg === tds.invalidGainXptnMsg" ] , [ "tstXptn.type === Error" ] , [ "inst.gain === tds.vars.savedGain" ] ] } , { id:"getADC() ch0 adcRaw0 0 via defaultI2CAddr:" , f: function(test) { test.inst.i2c.regs[0] = test.tds.adcRaw0; test.inst.setAddr(test.tds.defaultI2CAddr); test.inst.setGain(test.tds.gain4096); test.inst.getADC(test.tds.ch0,function(raw){ test.tds.vars.adcRaw = raw; }); return 2 * 8; // timeout to let timeouted callback happen } , vals: // ...not yet complete [ [ "tds.vars.adcRaw === tds.adcRaw0" ] , [ "inst.i2c.wAddr === tds.defaultI2CAddr" ] , [ "inst.i2c.rAddr === tds.defaultI2CAddr" ] , [ "inst.i2c.rCnt === tds.readCnt" ] ] } ] }; TDS.vars.i2c = // ...I2C mock / partial emulation just check used invocations { wAddr: -1 // write and... , rAddr: -1 // ...read addr separate for complet getADC validation , rCnt: -1 // read count , reg: -1 // reg ptr , regs: [-1,-1,-1,-1] // 4 16 bit regs , writeTo: function(wAddr,reg,msb,lsb) { this.wAddr = wAddr; this.reg = reg; if (typeof msb === "undefined") { return; } // ----> break if (this.reg === 0) { new Error("Conversion register 0 cannot be written to"); } this.regs[this.reg] = (msb << 8) | lsb; } , readFrom: function(addr,cnt) { this.rAddr = addr; this.rCnt = cnt; return new Uint8Array([this.regs[this.reg]>>8,this.regs[this.reg] & 0xFF]); } }; var MTEST = // Module TEST { vInfo: { v:1, d:20150915, a:"allObjects" } , tds: null // test data spec , dbg: false // debug , mod: null // module , inst: null // instance (afer new or new in connect) , tstsOk: 0 // number of tests that succeeded , tstsNOk: 0 // number of tests that failed , validsOk: 0 // number of validations that succeeded , validsNOk: 0 // number of validations that failed , tme: undefined // ongoing timeout , tstXptn: "" // exception last thrown by tst function/method , tstIdx: -1, tstId: "nyd" , valIdx: -1, valId: "nyd" , test: function(tds) { this.tds = tds; this.mod = null; this.inst = null; this.tstsOk = 0; this.tstsNOk = 0; this.validsOk = 0; this.validsNOk = 0; this.tme = undefined; this.tstXptn = ""; this.tstIdx = 0; tstId = "nyd"; this.valIdx = 0; valId = "nyd"; this.logHdr("-"); console.log("-"); this.logTest(); this._test(); } , _test: function() { var _this = this; var tst = this.tds.tsts[this.tstIdx]; if (this.tme) { this.tme = undefined; } else { this.tstId = tst.id; this.tstX = ""; try { this.tme = tst.f(this); } catch(tstXptn) { this.tstXptn = tstXptn; } } if (this.tme) { setTimeout(function(){ _this._test(); },this.tme); } else { this.logTst(); if (this.dbg && (this.tstXptn)) { console.log(this.tstXptn); } var tOk = true, vOK; tst.vals.forEach(function(val,vdx){ this.valIdx = vdx; if (val.length === 1) { this.log(vOk = this.interpret(this.valId = val[0])); } else { this.valId = val[0]; this.log(vOk = val[1](this)); } if (vOk) { this.validsOk++; } else { this.validsNOk++; } tOk &= vOk; },this); if (tOk) { this.tstsOk++; } else { this.tstsNOk++; } this.tstIdx++; if (this.tstIdx < this.tds.tsts.length) { setTimeout(function(){ _this._test(); },1); } else { this.logHdr("~"); this.logRslts("~"); } } } , interpret: function(s) { var sEs = s.split(" "); return this[sEs[1]](this.resolve(sEs[0]),this.resolve(sEs[2])); } , resolve: function(s) { var r = null; if (this.dbg) { console.log("resolve(): " + s); } try { r = this[s]; if (typeof r === "undefined") { if (s.indexOf("typeof:") === 0) { r = typeof this.resolve(s.substr(7)); } else { var ps = s.split("."), pc = ps.length, x = -1; r = this; while (++x < pc) { r = r[ps[x]]; } } } } catch(xptn) { throw new Error( [ "Error:", this.tds.moduleName, this.tstId, this.valId , "Unable to resolve:", s, "(", xptn, ")" ].join(" ") ); } if (this.dbg) { console.log("resolve()d: " + r); } return r; } , logHdr: function(pf) { var tdsVInfo = this.tds.vInfo; console.log("-"); console.log( [ pf + " Module TEST:", this.tds.moduleName , "vrsn:" + tdsVInfo.v, "date:" + tdsVInfo.d, "auth:" + tdsVInfo.a ].join(" ")); } , logTest: function() { console.log( "- " + this.tds.moduleName); } , logTst: function() { console.log( "- " + this.tstId); } , log: function(ok) { console.log( [ ((ok) ? "- ok " : "- FAILED ") , this.valId ].join(" ")); } , logRslts: function(pf) { console.log(pf + ((this.tstsNOk === 0) ? " ok " : " FAILED ")); this.logTV(pf,"tests",this.tstsOk,this.tstsNOk); this.logTV(pf,"validations",this.validsOk,this.validsNOk); console.log(pf); } , logTV: function(pf,tv,ok,nok) { var v = ok + nok; console.log( [ pf, " ", Math.round(ok / v * 100), "% of " , v, " ", tv, " passed", " (", ok, " : ", nok, ")" ].join("")); } }; MTEST["null" ] = null; MTEST["undefined"] = undefined; MTEST["function" ] = "function"; MTEST.number = "number"; MTEST.boolean = "boolean"; MTEST.Error = "Error"; MTEST["==="] = function(a,b) { var r = (a === b); if (this.dbg) { console.log([a," === ",b].join(" ")); } return r; }; MTEST["!=="] = function(a,b) { var r = (a !== b); if (this.dbg) { console.log([a," !== ",b].join(" ")); } return r; }; var debug = function(){ test(1); }; var test = function(dbg){ MTEST.dbg = dbg; MTEST.test(TDS); }; test();
Output in console:
- - Module TEST: ADS1x15Ext vrsn:1 date:20150915 auth:allObjects - - ADS1x15Ext - getModule(): - ok mod !== undefined - ok mod !== null - ok typeof:mod.connect === function =undefined - connect(): - ok inst !== undefined - ok inst !== null - ok inst.i2c === tds.vars.i2c - ok inst.addr === tds.defaultI2CAddr - ok inst.gain === tds.defaultAPGGain - ok typeof:inst.setAddr === function - ok typeof:inst.setGain === function - setAddr(): - ok inst.addr === tds.updatedAddr - setGain(): - ok inst.gain === tds.updatedGain - setGain() w invald gain: - ok tstXptn.msg === tds.invalidGainXptnMsg - ok tstXptn.type === Error - ok inst.gain === tds.vars.savedGain - getADC() ch0 adcRaw0 0 via defaultI2CAddr: - ok tds.vars.adcRaw === tds.adcRaw0 - ok inst.i2c.wAddr === tds.defaultI2CAddr - ok inst.i2c.rAddr === tds.defaultI2CAddr - ok inst.i2c.rCnt === tds.readCnt - ~ Module TEST: ADS1x15Ext vrsn:1 date:20150915 auth:allObjects ~ ok ~ 100% of 6 tests passed (6 : 0) ~ 100% of 19 validations passed (19 : 0) ~ >
2 Attachments
-
• #56
Oops. Try with:
https://gist.githubusercontent.com/gfwilliams/da8f09f91c8d0011cbae/raw/72d4e9e462ccff66703d47797b350694357fa56d/ADS1X15.js
@allObjects, the
if (!isNaN(channelSpec))
test doesn't work properly in Espruino. Looks like there's a bug there that meansisNaN([1,2])
is false.edit: just fixed it, but it'll only get into the 1v81 release
-
• #58
My problem - trying to copy paste code without testing :)
-
• #60
I see. We can test for array and flip the if-then w it if-else. Will take a look at it late today.
NOTE: module has no dependency from module testing code.
-
• #61
According to datasheet not all differential combinations are supported by the Mux, that's why there is this error message (reason: no point to support ). It follows same pattern as gain. The supported MUX combinations are exactly what @LawrenceGrif experiences: 0,1 - 0,3 - 1,3 - 2,3 as defined per data sheet.
-
• #62
isNaN([1,2])... I thought I had 'tested' that... but may be on the wrong plaform... as said. Going for typeof (=== "number") would probably be a better choice, even better than checking for array.
-
• #63
Yep, that's what I'd done?
I updated the website an hour or so ago, so a straight:
var ads = require("ADS1X15").connect(I2C1);
should work now.
-
• #64
Quick test seems ok will do full test over weekend.
Thanks to you both.Lawrence
-
• #65
hi, wanted to use this module again,
used this code on the green EspruinoI2C1.setup({ scl : B6, sda: B7} ); var ads = require("ADS1X15").connect(I2C1); // <--- this now pulls everything from the internet ads.setGain(4096); // +/- 0.256mV ads.getADC(0, function(val) { console.log("Reading: "+val); }); function everySecond() { ads.getADC(0, function(val0) { ads.getADC(1, function(val1) { ads.getADC(2, function(val2) { ads.getADC(3, function(val3) { console.log(val0,val1,val2,val3); }); }); }); }); } setInterval(everySecond, 1000);
and got this error
in function called from system Uncaught Error: Invalid differential channelSpec 0 at line 1 col 157 ...ifferential channelSpec "+a);c|=e}c|=d[this.gain];this.write... ^ in function "getADC" called from line 10 col 7 }); ^
before it was working well
is something wrong with the code? or module from "require function"? -
• #66
ADS1X15.prototype.getADC = function(channelSpec, callback) { var config = CONFIG.CQUE_NONE | // Disable the comparator (default val) CONFIG.CLAT_NONLAT | // Non-latching (default val) CONFIG.CPOL_ACTVLOW | // Alert/Rdy active low (default val) CONFIG.CMODE_TRAD | // Traditional comparator (default val) CONFIG.DR_1600SPS | // 1600 samples per second (default) CONFIG.MODE_SINGLE; // Single-shot mode (default) // single ended (channelSpec is a number) or differential (channelSpec is array w/ valid channel duo) if ("number" == typeof channelSpec) { // Set single-ended input channel config |= [CONFIG.MUX_SINGLE_0,CONFIG.MUX_SINGLE_1,CONFIG.MUX_SINGLE_2,CONFIG.MUX_SINGLE_3][channelSpec]; } else { // Set differential input channels from channelSpec var dif = DIFFS[channelSpec]; if (typeof dif === "undefined") throw new Error("Invalid differential channelSpec " + channelSpec); config |= dif; }
Looking at the module code, I can't see how it's getting to that error with 0 as the channelSpec.... since
"number"==typeof 0
should be true... -
• #67
That's actually a bug in 1v81 (
a=0;typeof a
being wrong) - if you use one of the 'nightly' builds of Espruino it'll work fine.I'm not sure why the module worked before - unless the bug only got introduced in 1v81 (but it seemed like it had been there for a while).
-
• #68
not sure, but before I updated WebIDE code works fine, could that be a problem? any chance do return to earlier version of WebIDE?
-
• #69
You can use an older version of firmware using 'advanced flasher' but I'd advise you just use a more recent firmware that'll have this (and other things!) fixed.
-
• #70
I still use 1v81 , now used this code
var CONFIG = { OS_MASK : (0x8000), OS_SINGLE : (0x8000), // Write: Set to start a single-conversion OS_BUSY : (0x0000), // Read: Bit = 0 when conversion is in progress OS_NOTBUSY : (0x8000), // Read: Bit = 1 when device is not performing a conversion MUX_MASK : (0x7000), MUX_DIFF_0_1 : (0x0000), // Differential P = AIN0, N = AIN1 (default) MUX_DIFF_0_3 : (0x1000), // Differential P = AIN0, N = AIN3 MUX_DIFF_1_3 : (0x2000), // Differential P = AIN1, N = AIN3 MUX_DIFF_2_3 : (0x3000), // Differential P = AIN2, N = AIN3 MUX_SINGLE_0 : (0x4000), // Single-ended AIN0 MUX_SINGLE_1 : (0x5000), // Single-ended AIN1 MUX_SINGLE_2 : (0x6000), // Single-ended AIN2 MUX_SINGLE_3 : (0x7000), // Single-ended AIN3 PGA_MASK : (0x0E00), PGA_6_144V : (0x0000), // +/-6.144V range = Gain 2/3 PGA_4_096V : (0x0200), // +/-4.096V range = Gain 1 PGA_2_048V : (0x0400), // +/-2.048V range = Gain 2 (default) PGA_1_024V : (0x0600), // +/-1.024V range = Gain 4 PGA_0_512V : (0x0800), // +/-0.512V range = Gain 8 PGA_0_256V : (0x0A00), // +/-0.256V range = Gain 16 MODE_MASK : (0x0100), MODE_CONTIN : (0x0000), // Continuous conversion mode MODE_SINGLE : (0x0100), // Power-down single-shot mode (default) DR_MASK : (0x00E0), DR_128SPS : (0x0000), // 128 samples per second DR_250SPS : (0x0020), // 250 samples per second DR_490SPS : (0x0040), // 490 samples per second DR_920SPS : (0x0060), // 920 samples per second DR_1600SPS : (0x0080), // 1600 samples per second (default) DR_2400SPS : (0x00A0), // 2400 samples per second DR_3300SPS : (0x00C0), // 3300 samples per second CMODE_MASK : (0x0010), CMODE_TRAD : (0x0000), // Traditional comparator with hysteresis (default) CMODE_WINDOW : (0x0010), // Window comparator CPOL_MASK : (0x0008), CPOL_ACTVLOW : (0x0000), // ALERT/RDY pin is low when active (default) CPOL_ACTVHI : (0x0008), // ALERT/RDY pin is high when active CLAT_MASK : (0x0004), // Determines if ALERT/RDY pin latches once asserted CLAT_NONLAT : (0x0000), // Non-latching comparator (default) CLAT_LATCH : (0x0004), // Latching comparator CQUE_MASK : (0x0003), CQUE_1CONV : (0x0000), // Assert ALERT/RDY after one conversions CQUE_2CONV : (0x0001), // Assert ALERT/RDY after two conversions CQUE_4CONV : (0x0002), // Assert ALERT/RDY after four conversions CQUE_NONE : (0x0003), // Disable the comparator and put ALERT/RDY in high state (default) }; var GAINS = { 6144 : CONFIG.PGA_6_144V, // +/-6.144V range = Gain 2/3 4096 : CONFIG.PGA_4_096V, // +/-4.096V range = Gain 1 2048 : CONFIG.PGA_2_048V, // +/-2.048V range = Gain 2 (default) 1024 : CONFIG.PGA_1_024V, // +/-1.024V range = Gain 4 512 : CONFIG.PGA_0_512V, // +/-0.512V range = Gain 8 256 : CONFIG.PGA_0_256V, // +/-0.256V range = Gain 16; }; var REG = { MASK : 3, CONVERT : 0, CONFIG : 1, LOWTHRESH : 2, HITHRESH : 3 }; function ADS1X15(i2c) { this.i2c = i2c; this.addr = 0x48; this.gain = 0; } ADS1X15.prototype.writeRegister = function(reg, value) { this.i2c.writeTo(this.addr, reg, value>>8, value); }; ADS1X15.prototype.readRegister = function(reg) { this.i2c.writeTo(this.addr, reg); var d = this.i2c.readFrom(this.addr, 2); return (d[0] << 8) | d[1]; }; /// set the gain, with a value in mv (6144, 4096, 2048, 1024, 512 or 256). The value is the full swing, so 256 = +/- 0.256v ADS1X15.prototype.setGain = function(gain) { if (!(gain in GAINS)) throw new Error("Gain "+gain+" not found"); this.gain = gain; }; ADS1X15.prototype.getADC = function(channel, callback) { var config = CONFIG.CQUE_NONE | // Disable the comparator (default val) CONFIG.CLAT_NONLAT | // Non-latching (default val) CONFIG.CPOL_ACTVLOW | // Alert/Rdy active low (default val) CONFIG.CMODE_TRAD | // Traditional comparator (default val) CONFIG.DR_1600SPS | // 1600 samples per second (default) CONFIG.MODE_SINGLE; // Single-shot mode (default) // Set PGA/voltage range config |= this.gain; // Set single-ended input channel config |= [CONFIG.MUX_SINGLE_0,CONFIG.MUX_SINGLE_1,CONFIG.MUX_SINGLE_2,CONFIG.MUX_SINGLE_3][channel]; // Set 'start single-conversion' bit config |= CONFIG.OS_SINGLE; // Write config register to the ADC this.writeRegister(REG.CONFIG, config); // Wait for the conversion to complete var ads = this; setTimeout(function() { // Read the conversion results // Shift 12-bit results right 4 bits for the ADS1015 callback(ads.readRegister(REG.CONVERT)); }, 8); }; // then try with I2C1.setup({ scl : B6, sda: B7} ); var ads = new ADS1X15(I2C1); ads.setGain(512); // +/- 0.256mV function everySecond() { ads.getADC(0, function(val0) { ads.getADC(1, function(val1) { ads.getADC(2, function(val2) { ads.getADC(3, function(val3) { console.log(val0,val1,val2,val3); }); }); }); }); } setInterval(everySecond, 1000);
and ADS shows me only one channel value, I've connected 3 voltage sources into it,
|_____|___| _|_| |___|_|_|_|___| |_| http://espruino.com 1v81 Copyright 2015 G.Williams >echo(0); =undefined 4531 75 79 78 4533 74 79 78 4580 75 79 77 4527 75 78 78 4622 75 79 78
I checked 3 other ADS, they are working on arduino, but here I get only one value,
could anyone help to fix it? pleasealso I am not sure about gain settings,
seems they have some error too, as eg. 256 gain shows lower value than 2048? -
• #71
any updates about new version of espruino software? or ads1115 error fix?
-
• #72
Anything from the git builds from the last few weeks should have this fixed, so you can just use the instructions under
Cutting Edge
on http://www.espruino.com/DownloadI'll do a 1v82 release today though. I think it's stable enough now.
What do you mean by the ads1115 error fix? The
typeof 0
issue, or is there something else? -
• #73
I didn't get readings of all sensors I connected, just first one, but I connected 3 of them,
it might be typeof 0 issue you wrote, but I don't know how to deal with this? -
• #74
Have you tried with the new 1v82 release? That should have
typeof 0
fixed, so the original code should work fine on channel 0 now. -
• #75
thank you Gordon, it is working now, espruino is reading all channels and gain is working as well,
I can now move on and try to finish my project ;)do you know the way how to create new var value which will get readings from this ADS function?
ads.getADC(0, function(val0) {});
I have to do plenty of mathematical operations with my variable on few channels, it would be much simpler to use eg. var inputOne instead of this function above,
actually I can't print val0 outside the function, and I need to use readings from ADS in few steps, make a math and then print it,
I appreciate help in this case
-- Did you add .connect(...) like I said?
I did but not in the correct place, sorry your going to treat my like eejit & assume nothing!
Ok working will test the differential inputs tomorrow.
And will order some strain gauges to test with.
Thanks @Gordon & @allObjects