-
• #2
Sure, I think your first port of call would be to try and replace the readRegister/writeRegister commands that were in arduino:
static void writeRegister(uint8_t i2cAddress, uint8_t reg, uint16_t value) { Wire.beginTransmission(i2cAddress); i2cwrite((uint8_t)reg); i2cwrite((uint8_t)(value>>8)); i2cwrite((uint8_t)(value & 0xFF)); Wire.endTransmission(); } static uint16_t readRegister(uint8_t i2cAddress, uint8_t reg) { Wire.beginTransmission(i2cAddress); i2cwrite(ADS1015_REG_POINTER_CONVERT); Wire.endTransmission(); Wire.requestFrom(i2cAddress, (uint8_t)2); return ((i2cread() << 8) | i2cread()); }
In Espruino I reckon they should look like this:
var REG = { MASK : 3, CONVERT : 0, CONFIG : 1, LOWTHRESH : 2, HITHRESH : 3 }; function ADS1X15(i2c) { this.i2c = i2c; this.addr = 0x48; } 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]; }; // then try with I2C1.setup({ scl : ..., sda: ...} ); var ads = new ADS1X15(I2C1); console.log(ads.readRegister(REG.CONVERT));
That might actually print the conversion value... But for a fully working ADC you'll need to look at readADC_SingleEnded and copy what that's doing.
It does use a delay there, so I'd be tempted to use a callback to return the values instead, as it means Espruino can get on with other stuff in the mean time:
... getADC = function(callback) { // .. setTimeout(function() { var a = ...; callback(a); }, ); }
Maybe define a 'config' variable instead of all the #defines as well,
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) };
hope that helps!
-
• #3
Thank you for your effort, I am beginner with espruino and python, so don't understand much of your code, a bit better doing that with C, I mean it is more easy to me how to place the parts of the code and implement libraries, here for now it is a bit of cosmos to me
Is there any tutorial to show how to implement new modules, libraries, and place code properly in Web IDE?
-
• #4
There's this one?
For now, I would copy and paste this into the right-hand side of the Web IDE:
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 REG = { MASK : 3, CONVERT : 0, CONFIG : 1, LOWTHRESH : 2, HITHRESH : 3 }; function ADS1X15(i2c) { this.i2c = i2c; this.addr = 0x48; } 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]; }; 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 // TODO: config |= CONFIG.PGA_something // 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.POINTER_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.POINTER_CONVERT)); }, 8); }; // then try with I2C1.setup({ scl : ..., sda: ...} ); var ads = new ADS1X15(I2C1); ads.getADC(0, function(val) { console.log("Reading: "+val); });
Change I2C1.setup pins to whatever you're using, and then see what happens...
It might be that it works, but I haven't been able to test it.
When it is working properly, it's easy enough to convert it into a module - just remove the few 'testing' lines at the end and add
exports.connect = function(i2c) { return new ADS1X15(i2c); }
, then you're sorted. -
• #5
will check it at the evening, no errors in WEB IDE ;)
-
• #6
I've got that error when wanted to upload it into board
WARNING: Expecting a number or something iterable, got undefined WARNING: Expecting a number or something iterable, got undefined =undefined Uncaught InternalError: Timeout on I2C Write Transmit Mode 2 at line 2 col 55 this.i2c.writeTo(this.addr, reg, value>>8, value); ^ in function "writeRegister" called from line 15 col 52 this.writeRegister(REG.POINTER_CONFIG, config); ^ in function "getADC" called from line 3 col 6 }); ^
-
• #7
I2C1.setup({ scl : ..., sda: ...} );
Did you fill in which I2C pins you have it connected to there?
-
• #8
Yes I did try to choose both pins from both ports (I2C1 and I2C2) from my maple leaflabs,
I put there scl: D5, sda: D9 - for I2C1 and scl: D29, sda: D30 for I2C2 option.
Also tried to mark them that way scl: PB6, sda: PB7 and for I2c2 port, scl: PB10, sda: PB11.
but still got this errorWARNING: Expecting a number or something iterable, got undefined WARNING: Expecting a number or something iterable, got undefined =undefined WARNING: Expecting a number or something iterable, got undefined WARNING: Expecting a number or something iterable, got undefined Reading: 0
-
• #9
Have you tried pull resistors on the ic2 scl & sda to to vdd?
Are you powering the ADS1115 from 5v or 3.3v?
Not sure if your maple leaflabs i2c pins are 5v tolerant? -
• #10
It's a bug in the code I posted - as I don't have anything here to test with.
REG.POINTER_CONFIG
should beREG.CONFIG
. If you change that in the code it might work?Same with
REG.POINTER_CONVERT
toREG.CONVERT
-
• #11
code works ;)
it return one value, but only once, when I upload the code by Web IDE
do you know which function will let me to print values from one of 4 channels in which ADS1115 is equipped?
and how to use gain settings like it is in arduino library for this module? -
• #12
Have you tried calling the following code again:
ads.getADC(0, function(val) { console.log("Reading: "+val); });
The first argument is a value between 0 and 3 (for each input).
As with other things in Espruino, the code works with a callback (so Espruino can do other things while it's waiting for the ADC). For setting the gain, use the following code, but with the
ads.setGain(...)
, where...
is a value in mv (6144, 4096, 2048, 1024, 512 or 256). The value is the full swing, so 256 = +/- 0.256vvar 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 : ..., sda: ...} ); var ads = new ADS1X15(I2C1); ads.setGain(256); // +/- 0.256mV ads.getADC(0, function(val) { console.log("Reading: "+val); });
-
• #13
thank you Gordon, it is working ;) play with Espruino is much easier than C and PIC modules I see ;)
could you show me some simple construction about callback? -
• #14
I'm not sure what to suggest. This is just like
setTimeout
.Maybe you want to read 4 values every second and write them to the console, you could do:
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);
Basically you call the function and it returns almost immediately. However it calls the function you supply at some point later on.
-
• #15
I have also just put the ADS1X15 module onto the website, so you no longer need all the code I posted. You just need:
I2C1.setup({ scl : ..., sda: ...} ); var ads = require("ADS1X15").connect(I2C1); // <--- this now pulls everything from the internet ads.setGain(256); // +/- 0.256mV ads.getADC(0, function(val) { console.log("Reading: "+val); });
-
• #16
thank you for a lot of your work Gordon, now it would be much much easier for others ;)
Do you know how to set print or console.log function to show float value like from analogRead but only to show 3 places after .dot ? eg. (1.234V)
-
• #17
Try:
console.log((val*0.256/32768).toFixed(3) + "V");
You'll probably have to change
0.256
depending on the current gain of your ADC. The.toFixed(3)
turns it into a string with 3 decimal places. -
• #18
Gordon do you know how to get those ads 4 channels values print on HD44780?
your console.log construction is working in the console but didn't figure out yet
how to print those values there, it looks like it should be a different way than
analogRead values? -
• #19
I've got it ;)
-
• #20
Ok I'm having a senior moment I've clearly misunderstood how prog gain works
I've been banging away at this all afternoon and not getting anywhere.
Tried 2 different ADS1115 (16bit)I'm tying to measure 0 to 3.3v analog in
So started with gain setting is 4096 +/- 4.096V
So if I understand this correctly an input voltage of 2.048 should give 50% of range 32768 and 4.096v would give 65536I can't get an val that correlates in any way.
I've tried other gains same result.
Any ideas welcomed with thanks.Lawrence
-
• #21
Update this gives me the correct voltage in but I don't understand why?
Gain is 4096 & voltage multiplier 6.144I2C1.setup({ scl: B6, sda: B7 }); var ads = require("ADS1X15").connect(I2C1); ads.setGain(4096); setInterval(function(){ ads.getADC(3, function(val) { console.log("val:"+val+" v:"+(val*6.144/32768).toFixed(3) + "v"); }); },3000);
-
• #22
If gain is set to 4096 (accoriding to Table 3 on page 13 of TI ADS1115 datasheet:
- measurement range is from -4.096V..4.095999V
- values are (always) -32768..0..32767
(1 value unit equals to 0.000125V)
Therefore, for 2.048V you should get a value of 16384, which is at half in the positive half of the value range... 0..16384..32767
6.144/32768 = 0.0001875 - about 50% off from the above calculated 4.096 related 0.000125 value, therefore, I 'assume', the gain setting is not working correctly... it took 6.144 because:
I did look at the 'last' 'module' code and my language concious did not 'like' property names of the GAINS object that are pure numbers: lines 57..62 - even though it obviously works partially, because you do not mention the built-in error (...! in GAINS) has not caugth on). BUT: ... | 4096 is | 2 ^ 12 or | 0b0001'0000"0000'0000 or | 0x1000 - just sets bit 12 (counting from 0) outside of the PGA_MASK... not what you want. Obviously, it did not mess up, at least not totally. Since it does not throw an error it clears all (gain mattering) bit(s) - see PGA_MASK - and that ets the gain to 2/3: -6.144..0..+6.144 volts, which explains the 6.144 / 32768 term that worked for you. Make the following changes, and things should just work as expected:
Lines 56..63:
var GAINS = { G6144 : CONFIG.PGA_6_144V, // +/-6.144V range = Gain 2/3 G4096 : CONFIG.PGA_4_096V, // +/-4.096V range = Gain 1 G2048 : CONFIG.PGA_2_048V, // +/-2.048V range = Gain 2 (default) G1024 : CONFIG.PGA_1_024V, // +/-1.024V range = Gain 4 G512 : CONFIG.PGA_0_512V, // +/-0.512V range = Gain 8 G256 : CONFIG.PGA_0_256V, // +/-0.256V range = Gain 16; };
Lines 71..75:
function ADS1X15(i2c) { this.i2c = i2c; this.addr = 0x48; this.gain = 2048; }
Lines 80..84:
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]) / 32768; // returning value in volts };
Lines 85..89:
// 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 (!(("G" + gain) in GAINS)) throw new Error("Gain "+gain+" not found"); this.gain = gain; };
Lines 97 and 98:
// Set PGA/voltage range config |= GAINS["G"+this.gain];
Usage:
I2C1.setup({ scl: B6, sda: B7 }); var ads = require("ADS1X15").connect(I2C1); ads.setGain(4096); setInterval(function(){ ads.getADC(3, function(val) { console.log(v.toFixed(3) + "V"); }); },3000);
Now there are a few memory saving options that can be applied...
a) Throw GAINS away. There is already an object in place that holds the gains: CONFIG... therefore, lines 87. and 98. each become 2 lines and read:
var g = "PGA_" + ("0" + this.gain + " V").substr(-5); if (!(g.substr(0,5) + "_" + g.substr(5)) in CONFIG)) throw new Error("Gain "+gain+" not found");
var g = "PGA_" + ("0" + this.gain + " V").substr(-5); config |= CONFIG[g.substr(0,5) + "_" + g.substr(5)];
b) Simplify the gains part in CONFIG like you had it in GAINS and it forming the property names becomes inline instead of an extra composition line for string g:
Lines 18..23:
PGA_6144mV: 0x0000, // +/-6.144V range = Gain 2/3 PGA_4096mV: 0x0200, // +/-4.096V range = Gain 1 PGA_2048mV: 0x0400, // +/-2.048V range = Gain 2 (default) PGA_1024mV: 0x0600, // +/-1.024V range = Gain 4 PGA_512mV: 0x0800, // +/-0.512V range = Gain 8 PGA_256mV: 0x0A00, // +/-0.256V range = Gain 16
if (!("PGA_" + this.gain + "mV") in CONFIG)) throw new Error("Gain "+gain+" not found");
config |= CONFIG["PGA_" + this.gain + "mV"];
Btw, I wondered why the config is set all the times, is it not sufficient to set it once? Could make it sense to have 4 configs (3, or 2 in - 1 or 2 - diff mode)?
- measurement range is from -4.096V..4.095999V
-
• #23
@allObjects your real star. Thanks so much for taking the time to dig this one out. So poor assumptions on my part didn't help. I made the fixes to inline code @Gordon used initially (it was a straight port from Arduino Lib). As for modifying the module I can't even find it on Git let alone fork it!
For the optimization I will leave that to @Gordon.
One thing Lines 80..84: think it's best to return the raw value and allow user to scale to suite.Thanks again
Lawrence -
• #24
@LawrenceGrif, np, urvw. Since the division is always by 32768 and the raw value is config dependent, I did not see any value in delivering the raw value...
Ports from Arduino have their challenges: it is a very good start. In this case, I have the feeling that not all things made it through - first functionl, and second Espruino typical / spirit. The code is in an intermediary stage. For usage different from defaults, only gain made it.
For me, Espruino typical is taking advantage of JavaScript's dynamics / no compile and easy to use (litteral) object-orientation. For that I expect to pass optionally a config (modifying) object at setup time as well as at read / conversion time. The current code looks like a lot of compile language with all the symbols in the CONFIG object - which are just space-eat-aways in Espruino. Yes, it can make the code very readable and its usage 'simpler', but for quite a high price. For keeping both - frugal resource use under constraint and easy config under no constraints - and applying either only one or both depending the situation, splitting the code into two modules ADS1x15 and ADS1x5Cfg a good solution:
- ADS1x15 module is bare metal operation code wit optional acceptance of a config value in masked config register format:
{cfg:0x####, msk:0x####}
. cfg includes the bits to set msk is the (combined) mask. - ADS1x15 module provides code to easily (and safely) create the config object from scratch or applies changes on the retrievable register object.
I can see applications where changing gain between readings of the very same channel makes sense: 1st read is to find the value range, second read is for more digits for that channel's final read... assuming that the value is slow changin / time does not play that a signifcant role.
Example code for passing config or config modification information at connect time - adjusting default created registry object with 4096 (= 0x0200) gain:
// var ads = new ADS1x15(i2c,0x48,{cfg:0x0200, msk:0x0E00}); var ads = ADS1x15Mod.connect(i2c,0x48,{cfg:0x0200, msk:0x0E00}); // var ads = require("ADS1x15").connect(i2c,0x48,{cfg:0x0200, msk:0x0E00});
Example code for passing config or config modification information at conversion time - adjusting default created registry object with 2048 (= 0x0200) - back to default - gain:
ads.getADC(1,function(v){ console.log("CH1: " + v + "V"); },{cfg:0x0400, msk:0x0E00});
Example code for bare operations module (0x8583 sets defaults):
. .. ... var ADS1x15 = function(i2c,addr,cfg) { this.i2c = i2c; this.addr = addr; this.reg = 0x8583; if (cfg) { this.cfg(cfg); } }, p = ADS1x15.prototype; p.cfg = function(cfg) { this.reg = (this.reg & (0xFFFF ^ cfg.msk)) || (cfg.cfg & cfg.msk); }; p.writeReg = function(reg, val) { this.i2c.writeTo(this.addr, reg, val>>8, val); }; p.readReg = function(reg) { this.i2c.writeTo(this.addr, reg); var d = this.i2c.readFrom(this.addr, 2); return (d[0] << 8) | d[1]; }; p.getADC = function(channel, callback,cfg) { if (cfg) { this.cfg(cfg); } this.writeReg(1, this.cfg || (channel << 12))); var _this = this; setTimeout(function(){ callback(_this.readReg(0)/32768); }, 8); }; ADS1x15xMod = { connect: function(i2c,addr,cfg) { return new ADS1x1x(i2c,addr,cfg); } } // export(ADS1x15Mod); ... .. .
Btw, noticed that there is no need to do bit shifting on result for AD10XX series. The read raw value hast just a less fine granulation (resolution)... smart choice from TI: ADS1x1x are pin compatible with the ADS101x series being just less accurate...
As mentioned earlier, I'd have a gain config for each channel (gain flexibility saves hardware...). Therefore, gain may be a thing to handle differently from passing other config values.
Since sequencing is predictable by design of the app - assuming all of the design is controllable - busy checking and other more sophisticate things to make operation safe would only bloat the bare metal module.
The config helper / support module may show as a separate post...
PS: Code only partially verified... have no ADS1x1x at hand... :( ... :)
- ADS1x15 module is bare metal operation code wit optional acceptance of a config value in masked config register format:
-
• #25
@allObjects as a way of saying thanks would be happy to get an ADS1X15 to you for testing. Would that be OK with you? If so direct mail and I'll arrange.
Lawrence
Hi, I would like to use ADS1115 module with espruino, it is working by I2C, under arduino is nice library
https://github.com/adafruit/Adafruit_ADS1X15 ,
I was trying this library to work with stm32 maple leaflabs R3+ and it was working with it well.
I wonder how to use this module with espruino?
Any chance you could help me to solve it?