-
-
-
-
-
Looks like I2C.readFrom already returns an Uint8Array, so I think you are doing a double allocation.
Not sure, but I think your memory usage might be smaller with just:var data = read(register, length);
Or not, or might not even be measurable, if that allocation is just in a small function, and the GC frees up memory...
-
Assuming that's a TI TMP117 (providing a link to the chip and / or the library you try to port sometimes helps, or saves a couple of seconds), the Arduino code simply reads two bytes from register
0
.At line 17 that delay
// Delay to allow sufficient conversion time delay(10);
I don't think its necessary for two reasons:
- the datasheet doesn't say it's necessary :) (If I read the datasheet correctly, in continuous mode - and that's the default - you can just read the temperature values. Maybe you would have to wait before the first, but see the second point:
- Espruino is slow, so usually you can just ignore < 1ms delays. :) But always test it...
I think @maze1980 is pretty close, this probably works:
var addr = 0x48; //chip addr read = function(reg, len) { i2c.writeTo(addr, reg); return i2c.readFrom(addr, len); }; write = function(reg, data) { i2c.writeTo(addr, [reg, data]); }; // read two bytes from register `0` var b = read(0, 2)); // and calculate the temperature: var temperature = ((b[0] << 8) | b[1]) * 0.0078125; console.log('temperature:', temperature );
- the datasheet doesn't say it's necessary :) (If I read the datasheet correctly, in continuous mode - and that's the default - you can just read the temperature values. Maybe you would have to wait before the first, but see the second point:
-
Math.pow
-> Looks like you have found something:>Math.pow(2,19) == 524288 =false
AFAIK all math operations are floating point operations in javascript & Espruino.
So while(something << 19) / 32000000
is perfectly valid 64 bit integer operation in C, and probably reasonably performant since bit-shifting is supported since forever. That just doesn't exist in javascript.
What's the source of those operations? -
The point is -IMO - there is something wrong with floating point calculation. The bit-mask mismatch is a result of the floating point error.
The result of calculation
915E6 * Math.pow(2,19)
in Espruino is not 479723520000000, it's 479723519999999.9375.To demonstrate it, ran this in
- Espruino 'Linux' build on my laptop
- DS-D6 (nRF52832, just sitting in a box, BLE console is really convenient :) )
- Browser console
- node v8.11.2
- F# interactive (.Net, to test on completely different platform)
Results are identical in non-Espruino environments:
> 915E6 * Math.pow(2,19) // The result in Espruino: 479723519999999.9375 // The result in browser / node / F#: 479723520000000
Oh, btw just bit-shifting indeed wraps around in browser & node:
> 915E6<<10 657129472 > 915E6<<11 1314258944 > 915E6<<12 -1666449408 > 915E6<<13 962068480 > 915E6<<14 1924136960 > 915E6<<15 -446693376 > 915E6<<16 -893386752 > 915E6<<17 -1786773504 > 915E6<<18 721420288 > 915E6<<19 1442840576
- Espruino 'Linux' build on my laptop
-
Nope no magic corruption:) Only different decimal precision
Look at code at line 57-L60:
/*57*/ var newDiv = 0xE4C000; /*58*/ var msband = newDiv & 0xFFFF0000; /*59*/ var midand = newDiv & 0x0000FF00; /*60*/ var lsband = newDiv & 0x000000FF;
Going back from line 60-59-58:
Assign 3 variables using the value of a variable callednewDiv
and some binary operations. What's the value of newDiv at that moment in time? It's exactly0xE4C000
, because you just assigned that value at L57.
Anything happened before is irrelevant.To demonstrate it (start with
correct.js
):Add
var bla = newDiv
to L45
Addprint('bla == 14991360:', bla == 14991360)
to L66It will print
bla == 14991360: false
so, thebla
variable still holds that almost-14991360-but-not-exactly value.
Just typebla-14991360
and you get-0
. Or type(bla-14991360)*1e9
, and you get the same-1.86264514923
.
No corruption here, as far as I can tell, only different fraction handling. -
Yepp, it's rounding and bitwise operations, simplest repro is
🥁🥁🥁
🥁🥁🥁:
0.99999999999999995 & 1
Results:
// Firefox and Chromium: > 0.99999999999999994&1 0 > 0.99999999999999995&1 1 > 0.99999999999999996&1 1 // Espruino: >0.99999999999999994&1 =0 >0.99999999999999995&1 =0 // It's ok just a bit higher: >0.99999999999999996&1 =1
Edit: with @Robin's numbers:
// In browser: > var val = 915E6; > var newVal = val * Math.pow(2, 19); > var newDiv = newVal / 32000000 > {val, newVal, newDiv} {val: 915000000, newVal: 479723520000000, newDiv: 14991360} > (newDiv-14991360)*1e9 0 // Exactly 0 in browser
// Espruino: ... >newDiv-14991360 =-0 >(newDiv-14991360)*1e9 =-1.86264514923 // not exactly 0!
-
Ok, so summarised the
correct.js
andincorrect.js
output the same in browser. Tested in node, they do output the same:> node .\correct.js L145 msband=E40000 L146 midand=C000 L147 lsband=0 > node .\incorrect.js L145 msband=E40000 L146 midand=C000 L147 lsband=0
, but different in Espruino, right?
My guess is rounding is somewhat messed up, the interesting part:
>var val = 915E6; =915000000 >var newVal = val * Math.pow(2, 19); =479723519999999.9375 >var newDiv = newVal / 32000000 =14991360 // but doesn't equal to the literal value: >newDiv==(14991360) =false // it's smaller: >newDiv<(14991360) =true >newDiv>(14991360) =false
So it's not exactly 14991360, but a bit smaller. In your
correct
version you set it to the exact literal value, that's why it behaves differently.// Espruino: >newDiv & 0xff00 =48896 // with literal value >14991360 & 0xff00 =49152
If you round it, you get what you expect:
>Math.round(newDiv) == 14991360 =true >Math.round(newDiv) & 0xff00 =49152 // in hex: >(newDiv & 0xff00).toString(16) ="bf00" >(Math.round(newDiv) & 0xff00).toString(16) ="c000"
That doesn't mean I have an explanation, probably a different behaviour with bitwise operations on fractions in Espruino.
Maybe a bug? Because after explicit rounding it works the same as in node / browser. -
-
-
Some background info: basically, I want to log a row of data (about 100-200 bytes) every minute. Saw the
E.openFile
method, but since I don't write continuously, just usingappend
felt safer & simpler.
Would be powered by a power bank, because I need 5 volts for the PMS7003, but wanted to test the coin cell backup.
First I modified the Pixl as described in "CR2032 battery backup" section and did some testing with the coin cell writing a row every 3 seconds. Was working fine for a couple of hours, but eventually the SD card didn't like the low voltage :)
Then wanted to do some power measurements, but that took a "bit" longer than expected... Without a scope, just run reads or writes continuously for 10 seconds, and wrote the current value. That 30mA is the "average" consumption of the Pixl.Js + SD card.But probably would need a scope or some more sophisticated method to really capture what's going on.
-
Ooops, missed the SPI part, sorry.
If you search for SPI in the docs, you get all the modules that use SPI, and you can look at the code.For example from the LIS2DH12 that has SPI interface as well (at the bottom of the file):
exports.connectSPI = function(spi,cs,options) { if ("function"==typeof options) throw new Error("Use require(LIS2DH12).connectSPI(..., {callback:function() { ... }} instead"); return new LIS2DH12(function(reg,len) { // read return spi.send([reg|0xC0,new Uint8Array(len)], cs).slice(1); }, function(reg,data) { // write return spi.write(reg, data, cs); },options); };
The interesting part:
// reg - the register address // len - how many bytes to read function read(reg,len) { return spi.send([reg|0xC0,new Uint8Array(len)], cs).slice(1); } // reg - the register address // data - the data you want to send function write(reg,data) { return spi.write(reg, data, cs); }
-
-
Morning? /me cooking dinner :)
Oh, looks like there is a misunderstanding in the write part, added this to the original post:
Tests done:
- append a 46 character long line to an existing file (to simulate adding a new line to a log file. This is my original use case)
- read a 4 character file
- read a 334 character long file
So on the write tests the file is continuously growing.
Did the read tests out of curiosity / for completeness's sake. Right now I don't intend to read the data with Espruino.The power consumption is more than likely to be lower than manufacturer's values, because there is the overhead of JS execution (reading and writing small chunks of data each time), and also it's a Pixl.JS, and that has to maintain Bluetooth connection. So I'm pretty sure not even close to real 100% duty cycle.
Now thinking about that: probably I'm wrong about the maximum current draw, and the real max current is higher.(kind-of sort-of have a scope, but haven't really used it. They forked Sigrok / Pulseview, and the software support was pretty meh for a long time. I think the logic analyzer part is supported by Sigrok, but the scope part is still not supported in Sigrok. In hindsight, probably should have skipped it...)
- append a 46 character long line to an existing file (to simulate adding a new line to a log file. This is my original use case)
-
I did some timing & power consumption measurements with a couple of SD cards.
My setup is not perfect, don't have a scope set up, so just did reads and writes in a loop for 10 seconds, and measured the power consumption.Hardware:
- USB port :)
- Ruideng UM25C to measure the current consumption. 100uA resolution. Don't know about it's absolute accuracy, but the values are pretty consistent. Update speed could be a bit faster...
- Pixl.JS 2v04
- SD card adapter, wire length is about 10cm
SD Cards:
- really old TwinMos 128Mb card
- Sandisk Ultra 32Gb (got it like 5-6 years ago)
- Sandisk EDGE 16Gb (got it last year with a Raspberry Pi bundle)
Tests done:
- append a 46 character long line to an existing file (to simulate adding a new line to a log file. This is my original use case)
- read a 4 character file
- read a 334 character long file
A helper function (runs the
funk
function continuously forseconds
seconds, and returns how many times it had executed):function doFor(seconds, funk) { if (isNaN(seconds)) {throw new Error("seconds NaN!")} if (!(typeof funk === 'function')) {throw new Error("funk ! function!")} // warmup funk(); var endT = (new Date()).getTime() + 1000 * seconds; var ts = 0; while ((new Date()).getTime() < endT) {funk(); ts++;} return ts; }
Test values and files for perf measurements:
// two test files, one is 4 characters long, the other is 334 characters long Lorem Ipsum :) fs.writeFile("4ch.txt", "alma") fs.writeFile("334ch.txt", `In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document without relying on meaningful content (also called greeking).Replacing the actual content with placeholder text allows designers to design the form of the content before the content itself has been produced.`) // just a row of data sor = "Thu Jan 1 1970 00:06:43 GMT+0000,100,22.5,233\n" // reading the files: doFor(10, function(){fs.readFile("4ch.txt")}) doFor(10, function(){fs.readFile("334ch.txt")}) // writing data: doFor(10, function(){fs.appendFile("teszt.txt", sor)})
Baseline power consumption:
- Pixl idle, no BLE connection, LCD on: 100uA
- Pixl idle, BLE connected: 0.9-1mA
- Pixl idle, BLE disconnected after writing 128Mb (SD mounted, LCD off): 2-300uA
- Pixl idle, BLE disconnected after writing 32Gb Sandisk (same if SD still mounted or unmounted): 5-600uA
- Pixl idle, BLE disconnected after writing 32Gb Sandisk (SD unmounted, LCD off): 3-400uA
- Pixl connected & running in a loop
doFor(10, function(){})
: 8.4mA
Some surprises:
- all cards work just fine at 8MHz SPI clock with this setup. (altho' I didn't check every single byte, data seems to be OK on all cards...)
- reading 4 bytes of data takes almost as much time as reading 334 bytes. Ok, probably isn't surprising if someone knows that data is stored in sectors...
- the old 128Mb card beats the 16Gb Sandisk in both speed and power consumption. Beats the newer card even more, if we adjust the power consumption for read/write speed.
The 32Gb Sandisk Ultra is faster, and consumes more power.
But if we assume that a single read or write takes the propotionally less time, it's overall energy consumption is lower, if we go to 1MHz reads and 2MHz writes and above. Write energy consumption:- 18mA, 14.8 write/sec with the old card -> 1.22 mili-amper-second for one write
- 31.2mA, 27.4 write/sec with the 32Gb card -> 1.14 mili-amper-second for one write
So looks like the fastest card at the highest speed is the winner?
But 30mA current is a bit high if you run on a coin cell. Or might not matter, because a capacitor could smooth out a single write-spike? Dunno, I guess that's the point where a proper setup with an oscilloscope would be handy.Raw data in the attachment
- USB port :)
-
Nice & thanks for getting back!
There isESP32.enableWifi(false)
to disable Wifi. But still didn't got a proper ADC value :(
If you are willing to dig deeper into the datasheet, I think you can use peek 8/16/32 poke 8/16/32 to directly read and write memory addresses / registers. So theoretically you can initialize the other ADC without recompiling the firmware.
If you have time, you can contribute to improve Espruino's ESP32 support (it's 100% community driven).(edit: after some digging into the Espressif's SDK & ADC2 issues, the ESP32 feels like a dual core trainwreck...)
-
I guess it's multiple things:
The page Robin linked says you can't use ADC2 when Wifi is active, and Wifi is active on Espruino & ESP32 by default.
Also, I don't think you should set the pins tooutput
.This code works for me (ok, just pulled the pins to 3v3 with a resistor, but results were around 0.999, when pulled to 3v3, so seems to be ok).
var pins = [D36,D37,D38,D39,D32,D33,D34,D35] function readSensors(pins) { pins.forEach(function(pin) { console.log(pin, ' -> ', analogRead(pin)); }); } readSensors(pins)
Prints something like this (D34 is pulled to 3v3, the rest is just floating):
D36 -> 0.576171875 D37 -> 0 D38 -> 0 D39 -> 0 D32 -> 0.10400390625 D33 -> 0.15966796875 D34 -> 0.99975585937 D35 -> 0.52758789062
Just multiply the results with 3.3 to get the voltage in volts, if you don't have any voltage divider.
-
I'm not an expert in ESP32's memory, but AFAIK there is a separate amount of memory for the underlying Espressif RTOS. Used for networking & stuff. And those
Cannot allocate memory (line: 34, free heap: 60 bytes)
messages seem to be complaining about that heap.If you don't use BLE, maybe you can try to disable BLE by calling
ESP32.enableBLE(false)
. That gives more JS vars, maybe some heap too. I must admit, I'm just guessing here... -
-
-
Ah, ok. I meant the 2*AA suggestion while you are developing, so you don't waste a lot of coin cells. Blue LEDs forward voltage is right around 3V or so,
Gordon's circuit maybe the easiest way forward, as there is no diode waste running from the battery. And no different voltage levels when powered from USB or battery.
Most likely yes. Of course depends on how accurate and secure this must be: you can cover it with something, so it disappears. Clone BLE tag. Or might still have enough signal strength just on the other side of the door.
For the gateway, take a look at EspruinoHub