-
-
... string data store ... went over my head on the first read
No wonder, you were at that time deep down in the details of the HW of EEPROMS. Coming back up into application (close) layers, it will be a breeze for you (and you may tell me where my doc needs to be fixed/enhanced, since I'm not of English mother tongue nor eloquent writer... JS is closer to me than English).
over my head
I'm fairing about the same way when looking on things coming out of your fine 'micro brewery' - on first reads. After taking the time diving into it, I get the exquisite taste. Thanks for your contributions!
the writes will of course be slow
Speed in accessing FRAM/MRAM depends on the needs of the application. To get/set config data and user data, the current speed is good enough, because the amount of data is not that critical - and there is most of the time little visibility to the user - if there is even one - to notice and complain about sluggishness. Speed is required only in graphics because of the amount of data and because visibility. My code to communicate with the FRAM was quite similar to your EEPROM code, even with the size limit because of (simplified) 2 bytes addressing with (singed) int. I can easily see speeding up the memory read/write process by using "compiled"; option, or moving the critical code into assembler all together... especially the part that shows patterns for what DMA was implemented: get a particular amount data at a particular address from one SPI (or other wise connected) device to another one (and back), like in my graphical app where screen buffer has to be saved for an overlay/pop-up - and then restored. For fast handling of those transfers, some chips have the hold pin, which keeps state, while the partial data just read is written to the other device... I was thinking along these lines to have some software DMA module implemented:
// devA & devB setup & connected, such as LCD display, (serial) RAM/EEPROM, etc. // both implementing same kind of read/write interface var dmaAB = require("DMA").connect(devA,devB,memBufSize); // w/ req/conn pattern var DMA = require("DMA"); var dmaAB = new DMA(....); // w/ oo/class req/conn dmaAB.xfer(0,addr1,bytes,addr2); // xfers bytes in memBufSize chunks from A to B dmaAB.xfer(1,addr2,bytes,addr1); // xfers bytes in memBufSize chunks from B to A
I can picture to use DMA on an intermediating Espruino in the data line between just any 'devices': sensors and internet... etc. I can also picture an option where the dma is setup to be trigger by a sourcing device to transfer the data to the sinking one... (...with the classical 'null' device...
Piggy-backing existing (module) code with extending or overwriting is always an option, and if this is not good enough or too cumbersome, I could see different implementations for a particular layer in the existing software stack... assuming it is layered/a stack and not a monolith... ;-). On a micro - on the other hand - a few terse, dedicated modules go further than larger, elaborate multi-purpose components. Therefore, a good and easy way to compose all kinds of needed specific functions and just those form very smaller ones is key, and require("module") is the key enabler for that.
Try using my AT25 module to interface with your FRAM
My FRAM is soldered onto my Espruino board. Will re-jumper-cable it and and do some testing, and also look at my x-code for the string memory. The string memory x-code needs transformation towards the available memory read/write interface with its data converters before I go and move it onto Espruino. I'd like to have also a test-bed/test for the sting memory store. And last but not least, implement an optional key function: store and read back by key rather than physical address (related object id)... even if it is just to get those physical addresses of the objects on init after a (re)boot.
-
For a TO-92 packaged 11ACxxx/11LCxxx EEPROM a breakout is not even required: it can go directly into the breadboard. On the other hand, more and more manufacturers drop packages for through hole soldering, and having SMT areas on a shield - next larger pads and some through holes - provide great options for proto typing.
-
Used your code modified and built some stuff around to easily control it with a global command function r(). I chose r for now because I commanding it from the console.
Function r accepts the stepping interval in milliseconds as argument.
Special values are 0 and no argument (undefined), which stop the motor or reverse current direction, respectively. For latter, there exists also a global stop() command function.
Changing direction does not need a stop command, the code manages that by itself. Positive values step clock-wise, negative ones counter clock-wise (looking at the spindle side).- r(1); // the fastest - about 15 rpm - you can go
- r(); // reverses direction (after above r(1) it is like issuing r(-1);
- r(0); // stops the motor
- stop(); // stops the motor as well
Note that a stop always stops at an even 'position' and switches all driving pins off.
Code:
// stPs stepper pins // st step 0..8 // stT step Time in milliseconds [ms] // stI step Interval (from setInterval() and for clearInterval() // sts steps 0001,0011,0010,... pin signals // stBW sts - steps Backwards // stFW sts - steps Forward // dmy ...because of (cond) ? exprT : exprF needs something to assign to var run = false; var st = 0; var stT = 0; var stI = null; var sts = null; var stSt = 0b0000; var stFW = [0b1000,0b1100,0b0100,0b0110,0b0010,0b0011,0b0001,0b1001]; var stBW = [0b0001,0b0011,0b0010,0b0110,0b0100,0b1100,0b1000,0b1001]; var stPs = [C6,C7,C8,C9]; // setI setInterval(i,stsC) i in [ms] with (optionl) step Change (if not null), // and direction info (string) var setI = function(t,stsN,d) { console.log("t = ",t, d); if (stI) clearInterval(stI); if (stsN) sts = stsN; run = true; stI = setInterval(stp,t); }; // stp step var stp = function() { digitalWrite(stPs, sts[st = ++st % 8]); }; // _sFW step ForWard var _sFW = function(t) { console.log("FW w/ " + t); if (stT > 0) { setI((stT = t),null," ~F"); } else { if (stT) { stop(); } st--; setI((stT = t),stFW," FW"); } }; // _sBW step BackWards var _sBW = function(t) { console.log("BW w/ " + t); if (stT < 0) { setI(-(stT = t),null," ~B"); } else { if (stT) { stop(); } st++; setI(-(stT = t),stBW," BW"); } }; // stop var stop = function() { console.log("stop"); if (stI) { stI = clearInterval(stI); } console.log(stI); run = false; digitalWrite(stPs, stSt); }; // run function - t is stepping interval in [ms] var r = function(t) { if (typeof t === "undefined" ) { if (stT) { console.log((stT > 0) ? "F>B" : "B>F"); r(-stT); } else { console.log("What ?"); } } else { dmy = (t) ? (t>0) ? _sFW(t) : _sBW(t) : stop(); } };
To get to to higher speeds, a different approach then setInterval() has to be taken. In order not to hog the Espruino just for the stepper, an interrupt driven stepping in assembler needs to be implemented to get to shorter pulses.
Attached clip shows 2 seconds fastest forward
r(1);
, then for same time and same speed reverser();
, then 5 seconds slower forwardr(6);
, and finally stopstop();
The 2 seconds ticking you hear in the background comes from a digital clock standing close by... ;-)
Console:
>r(1); setTimeout(function(){r(); setTimeout(function(){ r(6); setTimeout(function(){ stop(); },5000); },2000); },2000); FW w/ 1 t = 1 FW =2 F>B BW w/ -1 stop t = 1 BW FW w/ 6 stop t = 6 FW stop >
- r(1); // the fastest - about 15 rpm - you can go
-
Dud? right - sadly literally... some are just mechanical duds.
I got myself a few of these dirt cheap things... and some they hum smoothly, some they 'rattle' - you hear a hum overlaid with another synchronous noise of much lower frequency... at higher speeds (attached sound examples are at 1[ms] stepping interval. The volume of the rattling/touching noise is from placing the an empty open tuna can upside down on top the phone and the motor on top). Hold the motor with its back onto something resonating or your ear, and you will hear it whether your motors are smooth humming runners or guard rail smashing drunken drivers (out of the 5 I got, 2 hum, 2 hit a bit, one is stuck until you give it a twist in the right direction.)
The rotating magnet is not always centered and therefore touch the poles. Even a very little it touching just slows them down in getting them moving, and due to the construction, the 2nd step after the initial step just pulls the rotor back in the original position... because it did not reach the 2nd step fully when the poles change again.
Pulling the rotor out you will notice marks where it touches... bending the poles a tiny tiny little bit can solve the issue... but increases the gap and reduces of course the max torque.
Run them on 5 V first to separate the good from the bad one. Running them on 12 V works - in some way the duds even better when started slower and then sped up, but they get pretty quickly hotter than I like them... on the other hand, they have quite nice torque. For a running motor heat dissipation is probably not work... but in applications with duty cycles, heat dissipation may be manageable.
Attached is a shot showing the marks on the rotor - exactly at the position you will notice in the touch.mp4 clip, where you actually can her and 'see' where it touches... (stepping interval - stT = 15[ms]). Attached are too additional - just audio - 'clips' with healthy and unhealthy sound.
-
@fobus, your 'initial correct' code - post #8 - works off the bat with about 12..13 rpm (counter clock-wise looking at the spindle)... just as expected... make it two (2)[ms] stepping speed.
I use pins C6, C7, C8, and C9 - driver board inputs IN1, IN2, IN3, and IN4 - driver output boards A, B, C, and D - motor wires blue, pink, yellow, orange, and red (red on 4.66V driver chip outputs, the others on driver chip outputs.
I started with stepping speed/interval 1000ms - first so slow without motor to observe the LEDs, especially the overlapping ON / half stepping - and and then with motor. I kept shortening the interval down to 2[ms]. 1[ms] did not work. Since I have no forces applied (yet), I can run it powered by 5V from laptop USB / Board Bat (4.66 Volts at the driver power pin). Will do some more exploring later with separate driver powering and attempt to increase speed... under no and load... and observe the pins at the driver chip with the scope.
-
For an alternative and dedicated variation, take a look at Tasker - Task synchronizer - kind of a 'purposed' Promise.
*EDIT* (at the time of version 1v94 (2017-08-29))
Version 1v86 (2016-07-05) introduced Promise and Promise has matured thru version 1v91 (2017-01-12). Promise makes life of synchronizing/sequencing of asynchronous tasks/callback of callbacks of callbacks of... much much easier... Promise is practically the only way out of callback-hell.
-
Excellent pub and .md!
EEPROM vs FRAM/MRAM
... are Ferro-electric RAM - FRAM / FeRAM - and Magneto-resistive RAM - MRAM - are other kinds of non-volatile memory, with MRAM being more robust than FRAM.
Fujitsu claims...
For comparison of FRAM and (even better) MRAM see attachment (replica of Comparing Technologies: MRAM vs. FRAM, in case the link moves...
@DrAzzy, did you (ever) take advantage of the partial or full write protection features?
-
Tasker example with 5 taks 0..4, where task 1 and 3 fail (emulated) twice and once and succeed in 3rd and 2nd try, respectively.
// Setup of 5 task: t0..t4 var t0 = function(done) { // task0 console.log("t0 started"); setTimeout(function(){ done(true); },5000); }; var t1 = function(done,trie) { console.log("t1 started"); setTimeout(function(){ var ok = trie >= 3; // emulating failure on 1st & 2nd try console.log("t1 " + trie + " ok: " + ok); done(ok,3); // allow 3 tries },2000); }; var t2 = function(done) { console.log("t2 started"); setTimeout(function(){ done(true); },15000); }; var t3 = function(done,trie) { console.log("t3 started"); var ok = trie >= 2; console.log("t1 " + trie + " ok: " + ok); setTimeout(function(){ done(ok,2); },2500); }; var t4 = function(done) { console.log("t4 started"); setTimeout(function(){ done(true); },12500); }; // define ok function - application var ok = function(oks,sts,tries,tasks) { console.log("All " + oks + " tasks successfully executed."); }; // define err function var err = function(oks,sts,tries,tasks) { console.log("Only " + oks + " tasks of " + sts.length + " successfully executed."); }; // Execute the tasks new Tasker([t0,t1,t2,t3,t4],ok,err,true);
The console output reads as follows:
1v71 Copyright 2014 G.Williams >echo(0); Task 0 kickoff 1 Task 1 kickoff 1 Task 2 kickoff 1 Task 3 kickoff 1 Task 4 kickoff 1 =undefined t0 started t1 started t2 started t3 started t1 1 ok: false t4 started t1 1 ok: false Task 1 try 1 ok: false Task 1 kickoff 2 t1 started Task 3 try 1 ok: false Task 3 kickoff 2 t3 started t1 2 ok: true t1 2 ok: false Task 1 try 2 ok: false Task 1 kickoff 3 t1 started Task 0 try 1 ok: true Task 3 try 2 ok: true t1 3 ok: true Task 1 try 3 ok: true Task 4 try 1 ok: true Task 2 try 1 ok: true All 5 tasks successfully executed. >
-
With almost almost all setup type of functions asking for a callback when done, such as connect(), Tasker is a helpful tool to fire off what ever (asynchronous) tasks that have to complete successfully before moving on or - on completion with error(s) - take other actions.
It is related to contributions made by @Alex in conversation about Javascript Promises?
and [EDIT] @JumJum in conversation about Async handling.Taskser's main built-in features are:
- supports ok and err or callbacks
- supports retries
- keeps statistics about successes / failures and (re)tries
- furnishes retries
- provides task with single tasker callback
- provides task with try count
- provides statistics, to ok and err callbacks
- provides means for easy, complete start over
- allows application defined names for task callback and try count
- tasks are invoked with setTimeout() to avoid calling stack fill-up on retries of 'synchronous' / chained tasks.
- supports the next() concept with nesting / chaining
Initially, I had even a fatter version supporting (optional) extended logging, names for Tasker instances, names for the tasks, additional statistics about start time, end time, execution/elapsed time, and task results with passing them to the ok and err callbacks.
The fat version included also a part callback function invoked on successful or failed completion of each individual task to take additional action.
Dropping tries information, logging, and passing these things to the callbacks makes this implementation even lighter.
I'm using it as a module for simplifying synchronization of my setup tasks. Use is though not limited to just that. Anywhere in the app where a set of things have to happen before process flow can continue, a new Tasker can be instantiated. Taskers are fully reentrant and can be nested/cascaded/chained...
Setup of tasks can be inline in the Tasker constructor as anonymous functions or upfront as globally or locally scoped variables.
Skeletal task definition looks like this:
*Note: trie is for reserved word try ;-)*var taskX = function(done,trie) { // do things... // on success (in success callback): done(true); // on error (in failure callback): done(false); // for no retries done(false,3) // with 2 retries - totally 3 tries };
For the ok and err setup see next post with example of 5 tasks.
Invocation of the Tasker looks like this:
Tasker.new([task0Fnct,task1Fnct,task2Fnct,...],okFnct,errFnct,lg);
*Tasker code (with some doc):
// Tasker - kind of a 'Purposed' Promise // allows retries, resumes when all task are completed with // either ok or error function depending on the tasks results // Helpful for sequence agnostic setup of multiple interdependent // 'things' that require resume callbacks, for example: // Setup of multiple communication devices, display, GPS, etc. // When all successfully setup and ready, the application code // as placed in/passed as the ok() function will resume. // Task is a function that gets passed a done function and a try cnt. // On successfull completion, task calls done with true (in callback). // On failure, it calls done with false and optional number of tries. // ok and err functions get number of successfully passed tasks (oks) // and arrays of statutes (sts, true/false), actual tries, and tasks. // Tasker is invoked with array of tasks, ok and err function (and // optional boolean for logging: // Tasker.new([t0Fnct,t1Fnct,t2Fnct,...],okFnct,errFnct,lg); // Tasker can be made fatter/leaner by adding statistics about // start, end, and execution times / removing log, oks, and tries var Tasker = (function(){ var T = function(tasks,ok,err,lg) { this.tasks = tasks; this.ok = (ok) ? ok : function(){}; this.err = (err) ? err : function(){}; this.cnt = 0; this.sts = []; this.tries = []; this.lg = lg; tasks.forEach(function(t,id){ this._do(this,t,id,1); },this); }; T.prototype._do = function(_this,t,id,n) { if (this.lg) console.log("Task "+id+" kickoff "+n); var done = function(ok,tries){ _this.done(ok,id,n,tries); }; this.tries[id] = n; setTimeout(function(){ t(done,n); },1); }, T.prototype.done = function(ok,id,n,tries) { if (this.lg) console.log("Task "+id+" try "+n+" ok: "+ok); this.cnt++; if (!(this.sts[id] = ok) && tries && (tries > n)) { this.cnt--; this._do(this,this.tasks[id],id,n + 1); } if (this.cnt === this.tasks.length) { var oks = this.sts.filter(function(o){ return o; }).length; var sts = this.sts, _tries = this.tries, _tasks = this.tasks; this.sts = null; this.tries = null; this.tasks = null; this[(oks == this.cnt) ? "ok" : "err"](oks,sts,tries,tasks); } }; return T; })();
*EDIT* (at the time of version 1v94 (2017-08-29))
Feel free to continue reading in this conversation about Tasker... it will make you just more appreciate what happened here:
Version 1v86 (2016-07-05) introduced Promise and Promise has matured thru version 1v91 (2017-01-12). Promise makes life of synchronizing/sequencing of asynchronous tasks/callback of callbacks of callbacks of... much much easier... Promise is practically the only way out of callback-hell.
- supports ok and err or callbacks
-
-
Like the aToS and sToA... both great role models for my iToS and sToI extensions... in order to touch on a subject that was discussed earlier.
Having UInt8Array as the base class and the other things as helpers is just the right thing to do! Thanks.
Noticed that some xToY and yToX conversion things are hanging out there in duplicates. Could it be worth to have like a module out there that has basic helper functions useful just all over the place? (If require supports nested requires the modules that need this module could just include a require and with that dependency on dependency can easily be managed. I did not test that nested requires works...
-
For keeping consistency it has to be a throw-away, because quite many connects actually do something and would create an object in a state one is most likely not interested in. If otherwise, the modification can just be sticked to the instance - as per the beauty of JavaScript.
Therefore, I came up with the idea of passing no parms which makes it comparable with the default constructor in Java and it can be assured that nothing unwanted happens. Going that route is the easiest for keeping the require().connect() pattern vs. returning class.
-
The hardware only has 16 IRQ lines, for pins x0..x15
explains a lot... and: No matter what power to the software, hardware shines trough!
@Gordon, are these 16 IRQ lines a) dedicated 16 interrupts? - or b) do they come out of a pool of interrupts?
-
I have a drawer full of EEPROMs (dozens of them) and not one of them was made by Atmel.
How many photo-copiers (now digital) do we have and we still speak (in America) of ...go make a Xerox of it? ...Kleenex... and many many more.
This goes for many things for which the brand name was and is still used rather than a term of the general taxonomy.
So using the brand name is not that strange... last but not least it is still a minting term.
-
-
if you don't export the whole class, then you can't add things to the prototype?
...Well, you can, it's just ever so slightly more difficult
What are the possible (bad) side effects when having first to connect to get to the prototype via a - throw-away - instance?
In a language where classes are 1st class objects, I just would add connect() as a class (~static) method, which creates the object, issues the connect, and returns the object. In JavaScript this would be adding the connect as a 'strange' method to the constructor (or class) function. Would that be safe/robust enough in regard to side effects?
If we want to stick with creating a throw-away through connect() to access the prototype, passing no parms to the connect could be the way out of the dilemma. A connect with no passed parms could return the instance right after the new - without following through to the end.
-
i==3
With binding the number of arguments to a function is creating a dependency that may come back biting. For sure it is an efficient way to manage the power. If the device has a NOP after the command, this could be used as an escape by artificially extending the command. What ever other four-byte command could then just add the NOP to escape. An alternative to that could be an additional parameter when writing a four byte command, but with the frequency the command is called, it creates overhead. Since until now - and this is a while - it is the only four byte command and thus could be considered rare, I though would stick with the i == 3.
-
When thinking about monitoring, I was initially going for Arduino or a like hardware. Compared to with Espruino, it is even more suitable to run the electronics from a battery. I like the built-in interrupt drivenness of Espruino, which helps with power conservation.
From your implementation I understand that it is not enough to directly measure voltages over a sense resistor. The few millivolts differences would deliver a too course grain ramp of values. This fact is taken care of the current sense amps. And as an added benefit, the amps provide at the same time the galvanic separation.
-
Looks great... and takes care of the page stuff transparently.
I know the usual way is to export only the connect(). The connect hides the new. With 1v72 you could return the
OWmem
(function) as class (see How to create a module that is a 'Class' - aka a function usable with new - or: How to make require() return a function and not an object).Exposing the class itself allows to add/modify the prototype by additional,
OWmem
extending requires and adding method. A similar approach is already used when extending theGraphics
class dynamically with specific fonts. For example,require("Font8x16").add(Graphics);
, adds the.setFont8x16()
method to the Graphics class.There are other helpful effects coming along: returning the class allows to name it what ever the user wants it to have... to overcome the typical name space issue in JavaScript (taken care of in requre.js/AMD module technique for the browser).
Loading a bare metal OWmem and extending it with what ever space allows and benefits the application the most. I could even see your 'room for improvement' methods using this technique: in bare metal empty defined but already called, and allowed to be overridden on demand. Other methods could be any data conversion types / helper methods to be added
in addition what you already have to make OWmem generically usable.Dynamic extensions should work with minification. I do though not know about how it works with save().
-
Weird that same port same pin does not bother firmware, but same pin of different ports does. Multiple watches on the same pin - with different setups - could have some advantages. One watch could be the counting the changes, two others the rises and falls, and three more the first changes. To make that possible, all would have to be in the firmware. If the hardware has to be setup, then different setups are contradictory, and the last setup would win.
-
First of all, thank you for the explanation. 2nd, I have to say that I'm in software an hardware is 'just' a hobby. Nevertheless...
This Linear LT1999-10 is quite an interesting device. I like the input construction: it floats. I was thinking about monitoring what pannels do, but with basic means the galvanic separation is a problem. There are galvanic separated power supplies that would be able to power a floating espruino / pico or a like to be at the measuring source (connected with ground to one end of the sense resistor. The data transfer would then have to be wireless - wifi or other radio, infrared - or via optocouplers. With the LT1999-10 I assume that I would not have to jump through such hoops. In addition, the sense resistor has not be between load and ground, which keeps ground (better) grounded... My expected loads are only up to about 10..12 A in a 12 V context.
Did you ever think to use the ADCs from Espruino - in other words - put (one) Espruino right at the source connected to LT1999-10 output? You would then not incur the latency to get all the values into the calculations process. From the amount of thrown out values, I assume you make many measurements to still have a statistical valid number of samples. What is the expected - or required - frequency of delivering medians to the charge/flow controller?
I used Espruino ADCs for getting the values from a touch screen and map them to display coordinates... and they do quite nicely.
We know that software is never bug free... but it is of great relieve - I'm sure for @fobus - that hardware isn't perfect either... ;-) and the scope where to find the cause for an issues has to include that.
@fobus' key element is the setup for this extremely terse version of interval callback (paraphrased from stp):