New EEPROM module names

Posted on
Page
of 3
Prev
/ 3
Next
  • read() works - with somehow a hick-up:

    • powering board on
    • connect
    • upload with run with included reading of 256 bytes returned 256 0xFF
    • executing same read from the console: delivers real data
    • subsequent uploads with runs delivers real data.
      This is the console output:

      1v72 Copyright 2014 G.Williams
      >echo(0);
      new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255])
      =undefined
      >console.log(fram.read(0,256));
      new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 32, 46, 46, 46, 105, 116, 32, 119, 111, 114, 107, 115, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 82, 65, 77, 64, 49, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
      =undefined
      >
      =undefined
      >reset();
      =undefined
      _____                 _
      |   __|___ ___ ___ _ _|_|___ ___
      |   __|_ -| . |  _| | | |   | . |
      |_____|___|  _|_| |___|_|_|_|___|
            |_| http://espruino.com
      1v72 Copyright 2014 G.Williams
      >echo(0);
      new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 32, 46, 46, 46, 105, 116, 32, 119, 111, 114, 107, 115, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 82, 65, 77, 64, 49, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
      =undefined
      >
      

    data read as string:

    >console.log(E.toString(fram.read(0,256)­));
    ! ...it works!FRAM@128
    =undefined
    > 
    

    That' stuff I wrote to the memory in post three (3) months ago...
    This also proves that it is pretty resilient: I had the FRAM for a long time wired and did many other things... and countless power cycles, and more, and the stuff is still there.

    Have to find out if I can recreate the initial case,...

    Yes, can be recreated: the first time after a power cycle reads just 0xFF...
    ...all the times. So it has to do with power up. May be I go too quickly after the FRAM...

    It is not a timing issue... it has to do with the first power cycle...

    Definitly, it has to do with power cycle: reading just one byte upfront clears the issue and all subsequent reads read what they are supposed to.

     1v72 Copyright 2014 G.Williams
    >echo(0);
    =undefined
    >console.log(fram.read(0,1));
    new Uint8Array([255])
    =undefined
    new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 32, 46, 46, 46, 105, 116, 32, 119, 111, 114, 107, 115, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 82, 65, 77, 64, 49, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
    =undefined
    > 
    

    Btw, my 256KBits / 32KBytes FRAM was $4 only... not that bad.

  • About the write(): shows the same behavior: first write() after power cycle fails... I other words, any first operation fails. A dummy read of one single byte gets the code over the bump.

    fram.read(0,1);
    fram.write(0,"Thanks, Mr. DrAzzy!");
    console.log(E.toString(fram.read(0,19)))­;
    

    delivers:

     1v72 Copyright 2014 G.Williams
    >echo(0);
    Thanks, Mr. DrAzzy!
    =undefined
    > 
    

    What is the 3rd parm num do for or in the write()?

  • hmmmm....

    I wonder if it's that the CS pin is tristated until the first SPI call, and might have drifted low, leaving the chip confused until the first read asserts the CS line. I've added cspin.set() in connect to make sure the CS pin is high to begin with.

  • @Gordon, I wonder why the read still has to create (temporary) twice buffer space / memory. new Uint8Array(... is the first to just keep the clock going for the spi.send, the second one is the var ov=... for receiving the bytes delivered by the sent read command. I elaborated on that in other threads, where I suggested to have to have same parm options for spi.send() as spi.write() has: optional object to provide just a (single byte) string and a repetition count. This would eliminate the creation of one buffer - the buffer to just keep the SCK line clocking. What is the reason that this parameter option of spi.write() is not available for spi.send()?

  • @DrAzzy, let's compare the pieces from [1]=your and [2]=my code.

    setup [1]:

    exports.connect = function(spi, pgsz, cap, cspin) {
    	if (cap > 4096 || !cap || pgsz > cap || !cspin) {
    		throw "Unsupported or invalid options";
    	}
    	cspin.set(); //pull the CS line high. 
        return new AT25(spi, pgsz, cap, cspin);
    

    setup [2]:

    var framspiModule = { connect: function(spi,cs,hd,wp) {
      pinMode(cs,"output"); cs.set();
      if (hd) { pinMode(hd,"output"); hd.set(); }
      if (wp) { pinMode(wp,"output"); wp.set(); }
      var fram = {
        ...
      }
      return fram;
    }
    

    The relevant difference is the CS setup: code[2] uses pinMode() to make sure that the pin is not automatically but dedicated configured before setting it high with *set(). I 'm not sure if EEPROM's need this pin for feedback for ready/not ready sate detection by the processor. I wouldn't have expected either to have to use the dedicated configuration, because the set() happens surely early enough before the first read() hits and it is set low with reset(). My defensive/conservative programming made me add it, and it obviously had spared me trouble.

    runtime instance state/pattern[1]:

    function AT25(spi, pgsz, cap, cspin) {
      this.spi = spi;
      this.cspin=cspin;
      this.pgsz=pgsz;
      this.cap=cap<<7;
      this.ca=0;
    }
    AT25.prototype.read = function(...){};
    AT25.prototype.write = function(...){};
    

    runtime instance state/pattern[2]:

       var fram = {
        read: function(...){...},
        write: function(){...}
      };
    

    [1] allows multiple instances that keep (dynamic) state, where as [2] is just a singleton with the functions that hold (statically) on to the connect parms by closure. Most important, [1] keeps memory size information to prevent lock up in read-opnly mode, and - as a convenience - previously read address + 1 for read next n bytes (for details see read() implementation). [2] could be enhanced to support this as well by adding a variable in the closure scope. A better approach though is to choose the multi-instances pattern rather than the singleton. [2] could also be enhanced with size information (and check functions) , but it was intentionally kept a 'unintelligent', simple, low level device access API, because from the very beginning, it was never meant to be directly used by the application. A memory manager was intended to know about size and would provide safe access, and at the same time a much higher level API for the application. For resource constraint setups, the user should have options to go simpler and closer to the hardware, therefore [2] needs to be enhanced for justified standalone use.

  • [1] read():

    AT25.prototype.read= function(add,bytes) {
    	if (add===undefined) {
    		add=this.ca;
    	}
    	var t=new Uint8Array(bytes+(this.cap>65536?4:3));
    	var i=0;
    	t[i++]=3;
    	if(this.cap>65536){t[i++]=add>>16;}
    	t[i++]=add>>8; 
    	t[i]=add;
    	var ov=this.spi.send(t,this.cspin);
    	this.ca=add+bytes;
    	return new Uint8Array(ov.buffer,(this.cap>65536?4:3­),bytes);
    }
    

    [2] read(a,n) w/ adress and number of bytes:

    , read: function(a,n){
        cs.reset(); spi.send([0x03,a>>8,a]);
        return spi.send(new Uint8Array(n),cs);
     }
    

    [1] enables an easy read next by allowing to call ~.read(undefined,bytes);~ to get the next bytes following a previous read(s) that provided an initial address. Since AT25 is also geared towards large capacity EEPROM memory, it supports size dependent 2 and 3 bytes addressing. After reading the specified number of bytes, the next address to read from is kept for a simple read next bytes. @DrAzzy, what is the reason for creating Uint8Array for returning the value(s)? Is spi.send() not returning already an Uint8Array in ov variable? - And if it returns a string, it is about - with 1v72's flat strings and arrays - as efficient as Uint8Array in both cases, where enough memory is still available for a contiguous block to allocate and for the regular, chained storage block allocation. If the user does not like the result as a string, 'conversion-overlay' is easy (as shown), and could even be off different format.

    [2] having no state and being singleton, there is no support for read next. Since [2] is geared towards FRAM/MRAM - which are not as popular - and more pricy - and usually of smaller capacity, only two byte addressing is supported. Extension to size dependent number of address bytes is desirable, since recently larger chips showed up on the market and market presence is growing.

    Most difference between [1] and [2] are in write sequence. Even though both suffer from having to crate a trow away buffer to keep the sck pin clocking, [1] includes the command w/ address AND 'clock bytes' in that buffer with an uses a single spi.send(), where as [2] sends command w/ address and data using separate *spi.send()*s.

    *It is suggested to add to spi.send() the same parameter object option as spi.write() has, where a single byte and a count keep the SCK line clocking without sacrificing memory for throw away. The key part of a read would then look like this:

    return spi.send({ data: 0x00, cnt: n }; // 0x00 or other suitable: 0xAA
    

    The advantage of sending all at once is the use of integrated CS handling. [2] can use it only for the data and uses a separate reset() before sending command w/ address.

  • [1] write(add,data,num):

    AT25.prototype.write= function(add,data,num) {
    	var l=data.length,g;
    	if(typeof data!="string"){data=E.toString(data);}
    	var idx=0;
    	while (idx < l) {
    		this.spi.send(6,this.cspin); //WREN
    		var i=this.pgsz?(this.pgsz-(add%this.pgsz)):­l;
    		var t=(this.cap>65536)?E.toString(2,add>>16,­add>>8,add):E.toString(2,add>>8,add);
    		t=t+data.substr(idx,i);
    		this.spi.send(t,this.cspin);
    		var et=getTime()+0.012;
    		while (getTime() < et && this.pgsz) {g="";}
    		idx+=i; add+=i;
    	}
    	return l;
    

    [2] write(a,d) w/ address, data:

    , write: function(a,d){
        spi.send(0x06,cs); cs.reset();
        spi.send([0x02,a>>8,a]);
        spi.send(d); cs.set();
        return d.length;
      }
    

    [1] is and has to be elaborate to adhere to the EEPROM's page size restrictions / buffering and page write timing. It uses the pgsz page size information as provided in the connect for catering as optimal as possible to FRAM/MRAM, which has none of the EEPROM limitations, not even even in regard of the virtual limit of rewrites. Addresses are also handled capacity dependent.

    [2] is geared towards FRAM/MRM and can therefore be leaner.

    Major difference - again - is the command w/ address and data send sequence: in one shot or two (per page for EEPROM and per write for FRAM/MRAM. Some juggling around could eventually increase performance a bit - I expect. 'Insiders' would be able to tell if something like this is more frugal in resource consumption (even though having an additional spi.send() invocation):

    See 3 code variations as attachment of this post..

  • code[2] uses pinMode()

    pinMode shouldn't be required as the state is set automatically. Obviously it helps if you'd explicitly set the state to something else before, but I don't think it should be in a module.

    For instance, you may actually want to configure your line as open drain with a pull-up - but if the module explicitly sets the state then you wouldn't be able to do that.

    spi.send(...)

    It doesn't behave like spi.write because the code that iterates was meant only for output, and not for getting input as well. There may be a way around that though.

    Personally I wonder whether there shouldn't be an spi.read method, which would then allow SPI to be 'piped' to other things.

  • CS / line as open drain with (external) pull-up

    How about adding something to connect() that gives this option, like the string parameter for the pinMode()?

    So far the issue was only on power cycle...

    On the other hand, CS is essential, especially in a bus concept - where it is (conceptually) the only private line, a floating CS line calls for unpredictable effects. Therefore, pull-up - internal or external - is the minimum to be applied in any setup.

    Also, a lot of devices observe the power and cs line cycle to get setup in a predictable state.

  • Just tested with brand new 1v72... #FRAM / #MRAM with AT25 module is not working anymore, even when doing an extra read before the real read, I get all the times 0xFF... Definitely, at least a pull-up is required. Adding a pinMode(pin,"output"); get's it back to work. I assume the better performance in 1v72 - and the 18Mhz SCK (connected FRAM/MRAM can handle 40MHz) - provides not enough stability on the CS with having it floating...

  • @allObjects - look at the code in:

    http://www.espruino.com/modules/AT25.js

    Right there on the 4th line of connect(), I set the CS pin high; CS pin DOES NOT FLOAT with the current version of the module. If this isn't fixing it I would guess that the problem wasn't related to CS pin.

    Do you have WP and HOLD held high as well?

    Unless adding the cspin.set() broke the module completely, then I don't know what to say - that module code was tested and worked 100% fine with an AT25 last night.

    I thought the FRAM was supposed to be compatible, but I guess it's not.

    The reason I made the new buffer was that we needed to return in Uint8Array. My understanding was that the processing penalty for the new Uint8Array(ov.buffer....) was a low cost operation, and the alternative would have been to send everything as a string, and then run the substring through E.toUint8Array().

    I did not know that you could break up an SPI transfer like that. Is that okay to do?

  • Breaking up an SPI transfer - as far as I know - is possible - because the clock defines what is going on (and of course some other pins too). This is a main reason why clocked communication is so much more faster and more reliable than timed communication. For Espruino, the only penalty can be performance by going back and forth form JavaScript to firmware SPI.send implementation (as I read in Espruino doc).

    WP and HOLD held high

    WP and HOLD are hardwired to high.

    CS NOT floating

    I know that CS is NOT floating. Your implementation makes totally sense... but I assume that because of FRAM/MRAMs can handle much faster transfers, the timing can be a challenge... We know that in the past, the CS got raised to fast and communication did not complete - and this has been fixed. Furthermore, I do not know what Espruino - and the chip - 'really' do when changing state on the CS output pin with automatic pinMode() when applying set(), reset().

  • I did not know that you could break up an SPI transfer like that. Is that okay to do?

    Yes, it should be fine. After all it's clocked so it doesn't (usually) matter if it pauses for a bit.

    Having said that, using CS like @allObjects does there is a bit of a hack. If you're going to do multiple SPI sends then I'd manually lower and raise it, rather than manually lowering and then supplying cs to the final SPI send.

    Uint8Array(ov.buffer....) is extremely low cost, so I guess it's just personal taste which is better really.

  • It's possible that the first .set causes the line to drop low for a microsecond. I didn't think so but it's possible.

    If you just perform a cs.set() in your own code, on onInit, does that fix the problem?

  • I personally like the integrated CS pin option - after I understood what it is for and how it works... that's why I used it for the last send... to get rid of an extra statement. What I miss(ed) is(was) to have the same control for the first spi.send... that's why I had to do it - hacky ;-) -manually. Therefore: what about an additional parm in spi.send() that would allow the CS to go low and be kept low... after all, it is a 'hard'-wired sequence of statements that begin a communication, have some 'inner'-segments, and close a communication. After all a connect, do some stuff, disconnect pattern.

    I do not want to sound ungreatful... it's just the crave for to getting to the bottom of things... and surface back up with increased understanding and confidence... and accept the things that cannot be changed (reasonably). May be it is the ethnic related 'gesunde Unzufriedenheit' and the style of 'Das Bessere is der Feind des Guten' - literally: Better is the enemy of Good - ...only the best is good enough, just short of unhealthy perfection. In sports, it's called practice... - or what answer do you get from any athlete that already has done it yesterday, the day before, three days ago,... and want's to do it today? ...may be for the seventh day the athlete will take a break... ;-)

  • Assuming sorting out the functional issue with FRAM doesn't force this (I've got an SPI FRAM chip here from Fujitsu - not Cypress), I don't plan to rewrite that to directly control CS yet.

    I'll see if it works with my FRAM chip. If it doesn't, I'll put a cypress chip on my digikey shopping list.

  • Cannot reproduce with MB85RS64V up to 20mhz (did not test outside mfg specs)

    http://www.fujitsu.com/downloads/MICRO/f­sa/pdf/products/memory/fram/MB85RS64V-DS­501-00015-4v0-E.pdf

    
    SPI1.setup({sck:B3,miso:B4,mosi:B5,baud:­20000000});
    rom=require("AT25").connect(SPI1,0,64,B6­);
    echo(1);
    var z = rom.read(0,8000);  //read the whole damned thing
    
    

    VCC tied to WP and HOLD, CS going to B6, and everything else connected in the obvious way.

    What exact code are you using to reproduce the problem? How is everything wired? Do you have HOLD or WP connected to Espruino pins? If so, are these set correctly, or are they being allowed to float? I'll bet if hold was floating, that could cause bad things.

    I am loving the effect of flat strings on memory use. 8kbytes goes into 504 jsvars - 0.8% overhead!

    HOWEVER - memory use brings me to a problem with SPI, - specifically with that doubled buffer needed to keep the clock running. For that one line, memory usage is DOUBLE THE SIZE OF THE THING YOU'RE READING. I'm not sure I see how to get around that without changes to SPI functions. We can argue about what the best way to do it, but when it comes down to it, you need to call SPI.send() with something the length of the data I want back (plus the 3 bytes at the front, ofc), so the memory used at that step will always be twice that of the data, whenever using SPI. For writing, there's SPI.write() that ignores the returned data - but there's nothing like that for reading.

  • The only other difference I can think of is that there is something timing-related, and you're using your own BigRam builds (that are compiled without RELEASE=1 and so may be a bit slower?).

    Well, I made a bug yesterday for SPI send. If it returned Uint8Arrays you could conceivably do SPI1.send(new Array(50)) which would just allocate a sparse array.

    I think there's room for an SPI.read function - if only to make it compatible with the pipe method. I'm not sure how you'd stop it, but it could be very cool to be able to pipe data from some SPI device straight into an HTTP connection or file.

  • very cool to be able to pipe data from some SPI device straight into an HTTP connection or file

    two birds with one stone - 7 Fliegen auf einen Streich - ... kind of 'DMA' and streaming in one shot!

  • @DrAzzy thanks for picking this MEMORY thing up... I had touched on that a while ago and more than once in the last few days. I did not think about the sparse array thing, but it helps for sure.

    When thinking about this DMA hub a few posts ago I was thinking about optionally passing a default transfer max buffer size in the connect and an transfer invocation and implement it the same way you did it for the AT25 module... Even though FRAM does not require paging (waiting), I would have used that mechanism to limit the temporary (excessive) memory use for the read().

    Using a page size with FRAM has a performance penalty, it is better than run out of memory. So I thought about an additional parameter for the wait time... In case a EEPROM chips have different wait times, this parameter could come in handy!

  • do ~~~SPI1.send(new Array(numberOfBytesToSend)); // sparse array to save memory ~~~

    Did not work for me... what do I miss?

  • @DrAzzy, took a look at the AT25.js module code at espruino.com/modules/AT25.js... and wondered a bit about the source (inline) documentation... ;). Published doc at http://www.espruino.com/AT25 at http://www.espruino.com/AT25 show an API parameter asStr - named num in the code.

    What I'm looking for is a) what exactly AT25 returns on read() - and - b) what is expected to be returned - and - c) what are there compatibility requirements for what is returned.

  • asStr was removed - it was for before E.toString() was added. I'll go get rid of it in those places, thanks.

    It now just returns a Uint8Array, no matter what.

    The post-overhaul AT24/AT25 drivers are completely incompatible with the old version. It had to be done - the old version was terribad.

  • @DrAzzy, did some experimenting with the code... and came up with some hybrid. I was even implementing a 'chunked' read in order to not temporary double the memory needs. Attached are variations of the AT25 module code with mono write, split write (manual and automatic CS handling), and chunked read - mono write. Even though they are called FRAM..., they include all the code for EEPROMs.

    The chunked-read version has still the data conversion implemented at the end for convenience to return a string. Furthermore, the chunked read includes two versions of chunking:

    1. a read that is a mono read used called from within a chunked read
    2. a combined read, that calls itself when asked to read chunked

    With version 1 the the application has to call either read-single or read-chunked.
    Within version 2, the application calls always read, but passes an additional chunk size value parameter greater 0 to ask for chunking.

    Working through the AT25 code in very detail, I made some changes in sequencing: Please take a look at sequence of invalid option detection in connect() and sequence of string conversion and length determination.

    I wonder if for a split page write string conversion is required. spi.send() understands to send string and Uint8Array. Most other data types create anyway unpredictable results (length).

    Also notice the approach to factor out (of the loop) the command with address and data building for mono write AND command w/ address building for split write.


    3 Attachments

  • Inspired by @DrAzzy's AT25 module implementations, I implemented a dedicated module for FRAM/MRAM. Here the code with usage example, tests, and test output. Documentation is in code (Attachment includes all in one file ready to be pasted into IDE editor, uploaded, and run. - Chip used: 256 Kbit / 32KB - 32K*8 - Cypress FRAM FM25V02-G about 4$). For more about FRAM/MRAM see 256-Kbit (32 K × 8) Serial (SPI) F-RAM - Ferroelecric RAM - SPI challenges.

    var FRAM = (function(){
    
    /* Copyright (C) 2014 allObjects aka Markus Muetschard. See the file LICENSE for copying permission. */
    
    /*
    
    FRAM/MRAM SPI Module - Fero-electric / Magneto-resistive nonvolatile RAM
    ========================================­================================
    Supports up to 1 MByte capacity FRAM/MRAM such as
      - Cypress.com 256Kbit (32 K x 8) SPI FRAM - FM25V02-G
      - Fujitsu.com  64Kbit ( 8 K x 8) SPI FRAM - MB85RS64V
    *** usage:
    var FRAM = require("FRAM");
      returns FRAM 'class' (function(), 'default' constructor) for oo-style use.
      Note: You can name the class what ever you want it to be.
    var fram = new FRAM(spi,cap,cs,md);
      creates a connected FRAM instance (same as connect(), see next)
    var fram = new (require("FRAM"))(spi,cap,cs,md);
      is a combination of require and new and can be used when there is
      no need for the application to have access to the class object
      Note: new directly on (require("..."))(...); requires require() to be in ()s.
    var fram = require("FRAM").connect(spi,cap,cs,md);
      is there for connect()-style usage.
    Parameters to pass on new ... or connect() are: 
      - spi - SPI instance (hard or soft)
      - cap - capacity in Kbits
      - cs  - pin that drives FRAM/MRAM chip select
      - md  - optional - for pinMode(cs,md); // pass "output" when no external pull-up
      if undefined is returned on new or connect, error happened (not implemented yet)
    fram.read(a,n,f);
      reads n bytes starting at address a; f is optional return format:
      - f - absent or === 0: Uint8Array
      - f - === 1: String
      if a === undefined, last read/written address+1 is used; initialized on new to 0
      if undefined is returned, error happened (not implemented yet)
    fram.write(a,d);
      writes String | Array d at address a and returns number of written bytes
      if a === undefined, last read/written addr+1 is used; initialized on new w/ 0
      if -1 is returned, error happened (not implemented yet)
      
    *** example:
    SPI2.setup({sck:B13, miso:B14, mosi:B15, baud: 18000000}); // setup hw SPI2
    var fram = new (require("FRAM"))(SPI2,256,A2,"output");­ // FRAM w/ CS on A2
    console.log("Capacity: " + fram.cap*128/8 + " KBytes"); // 32KBytes w/ 256Kbits
    console.log("Bytes written @ 0: "+fram.write(0,"String at addr 0.")); // 17
    console.log("17 bytes read @ 0: "+fram.read(0,17,1)); // 'String at addr 0.'
    console.log("17 bytes read @ 0: "+fram.read(0,17)); // ...[83, 116, 105,...46]...
    console.log("Bytes written @ 0: "+fram.write(0,[65,66,67,68,69,70])); // 6 (0..5)
    console.log("Bytes written @ n: "+fram.write(undefined,": @")); // 3 (@ next addr)
    console.log("17 bytes read @ 0: "+fram.read(0,17,1)); // 'ABCDEF: @ addr 0.'
    */
      
    var ca2 = function(c,a) { this.cs.reset(); this.spi.send([c,a>>8,a]); };
    var ca3 = function(c,a) { this.cs.reset(); this.spi.send([c,a>>16,a>>8,a]); };
    
    var FRAM = function(spi,cap,cs,md) {
      cs.set(); if (md) { pinMode(cs,md); }
      this.spi = spi;
      this.cap = cap>>7;
      this.cs = cs;
      this.ca = (cap>8388608) ? ca3 : ca2;
      this.a=0;
    };
    FRAM.connect = function(spi,cap,cs,md) { 
      return new FRAM(spi,cap,cs,md);
    };
    FRAM.prototype.read = function(a,n,f){
      a = (a===undefined) ? this.a : a; this.ca(3,a);
      var r = this.spi.send(new Uint8Array(n),this.cs); this.a += n;
      return (f===1) ? E.toString(r) : r;
    };
    FRAM.prototype.write = function(a,d){
      a = (a===undefined) ? this.a : a;
      this.spi.send(0x06,this.cs); this.ca(2,a);
      this.spi.send(d); this.cs.set(); this.a += d.length;
      return d.length;
    };
    
    return FRAM; // exports = FRAM;
    
    })();
    

    Usage example and test code (256 Kbit / 32KB - 32K*8 - Cypress FRAM F25V02-G):

    SPI2.setup({sck:B13, miso:B14, mosi:B15, baud: 18000000});
    // var FRAM = require("FRAM"); // get module
    var fram = new FRAM(SPI2,256,A2,"output");
    // var fram = FRAM.connect(SPI2,256,A2,"output"); // alternative 1 w/ get module
    // var fram = new (require("FRAM")).connect(SPI2,256,A2,"o­utput"); // alternative 2
    // var fram = require("FRAM").connect(SPI2,256,A2,"out­put"); // classical
    
    console.log("~");
    console.log("fram.cap(acity)" +
                " = " + fram.cap*128 + " Kbit" +
                " = " + (fram.cap*128)*(1024/8) + " Bytes" +
                " = " + (fram.cap*128)*(1024/8)/1024 + " KBytes");
    
    function writes() {console.log("~");
    console.log("*** writes ***");
    console.log("@000:10: 'FRAM@000 A':       " + fram.write(  0,"FRAM@000 A"));
    console.log("@008:11: 'FRAM@016 AB':      " + fram.write( 16,"FRAM@016 AB"));
    console.log("@032:12: 'FRAM@032 ACD':     " + fram.write( 32,"FRAM@032 ABC"));
    console.log("@128:13: 'FRAM@128 ABCD':    " + fram.write(128,"FRAM@128 ABCD"));
    console.log("@256:14: 'FRAM@256 ABCDE':   " + fram.write(256,"FRAM@256 ABCDE"));
    console.log("@512:15: 'FRAM@512 ABCDEF':  " + fram.write(512,"FRAM@512 ABCDEF"));
    }
    function reads() {console.log("~");
    console.log("*** reads ***");
    console.log("@000:10:",fram.read(  0, 10));
    console.log("@016:11:",fram.read( 16, 11));
    console.log("@032:12:",fram.read( 32, 12));
    console.log("@128:13:",fram.read(128, 13));
    console.log("@256:14:",fram.read(256, 14));
    console.log("@512:15:",fram.read(512, 15));
    console.log("@000:10:",fram.read(  0, 10,1));
    console.log("@016:11:",fram.read( 16, 11,1));
    console.log("@032:12:",fram.read( 32, 12,1));
    console.log("@128:13:",fram.read(128, 13,1));
    console.log("@256:14:",fram.read(256, 14,1));
    console.log("@512:15:",fram.read(512, 15,1));
    }
    function hurray() {console.log("~");
    console.log("*** reads, overwrite, and reads ***");
    console.log("read  @000:44: " + fram.read( 0,44));
    console.log("read  @000:44: " + fram.read( 0,44,1));
    console.log("               0....'....1....'....2....'....3....'....­4....'");
    console.log("write @010:20: 'Hurray! ...it works!':  " + 
                fram.write( 10,"Hurray! ...it works!"));
    console.log("read  @010:20: " + fram.read(10,20));
    console.log("read  @010:20: " + fram.read(10,20,1));
    console.log("read  @000:44: " + fram.read( 0,44));
    console.log("read  @000:44: " + fram.read( 0,44,1));
    console.log("               0....'....1....'....2....'....3....'....­4....'");
    }
    function clear() {console.log("~");
      console.log("*** clear (fill all with '~' ***");
      var x = 0, b = 256, r = fram.cap * 16 * 1024 ; // bytes;
      var f = new Uint8Array(b); f.fill(126,0,b); f = E.toString(f);
      while(r > 0) { 
        x += fram.write(x,(r > b) ? f : f.substr(0,r));
        r -= b;
      }
    }
    

    Test output:

     1v72 Copyright 2015 G.Williams
    >echo(0);
    ~
    fram.cap(acity) = 256 Kbit = 32768 Bytes = 32 KBytes
    ~
    *** clear (fill all with '~' ***
    ~
    *** reads ***
    @000:10: new Uint8Array([126, 126, 126, 126, 126, 126, 126, 126, 126, 126])
    @016:11: new Uint8Array([126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126])
    @032:12: new Uint8Array([126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126])
    @128:13: new Uint8Array([126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126])
    @256:14: new Uint8Array([126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126])
    @512:15: new Uint8Array([126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126])
    @000:10: ~~~~~~~~~~
    @016:11: ~~~~~~~~~~~
    @032:12: ~~~~~~~~~~~~
    @128:13: ~~~~~~~~~~~~~
    @256:14: ~~~~~~~~~~~~~~
    @512:15: ~~~~~~~~~~~~~~~
    ~
    *** reads, overwrite, and reads ***
    read  @000:44: 126,126,126,126,126,126,126,126,126,126,­126,126,126,126,126,126,126,126,126,126,­126,126,126,126,126,126,126,126,126,126,­126,126,126,126,126,126,126,126,126,126,­126,126,126,126
    read  @000:44: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~­~~~~
                   0....'....1....'....2....'....3....'....­4....'
    write @010:20: 'Hurray! ...it works!':  20
    read  @010:20: 72,117,114,114,97,121,33,32,46,46,46,105­,116,32,119,111,114,107,115,33
    read  @010:20: Hurray! ...it works!
    read  @000:44: 126,126,126,126,126,126,126,126,126,126,­72,117,114,114,97,121,33,32,46,46,46,105­,116,32,119,111,114,107,115,33,126,126,1­26,126,126,126,126,126,126,126,126,126,1­26,126
    read  @000:44: ~~~~~~~~~~Hurray! ...it works!~~~~~~~~~~~~~~
                   0....'....1....'....2....'....3....'....­4....'
    ~
    *** clear (fill all with '~' ***
    ~
    *** writes ***
    @000:10: 'FRAM@000 A':       10
    @008:11: 'FRAM@016 AB':      11
    @032:12: 'FRAM@032 ACD':     12
    @128:13: 'FRAM@128 ABCD':    13
    @256:14: 'FRAM@256 ABCDE':   14
    @512:15: 'FRAM@512 ABCDEF':  15
    ~
    *** reads ***
    @000:10: new Uint8Array([70, 82, 65, 77, 64, 48, 48, 48, 32, 65])
    @016:11: new Uint8Array([70, 82, 65, 77, 64, 48, 49, 54, 32, 65, 66])
    @032:12: new Uint8Array([70, 82, 65, 77, 64, 48, 51, 50, 32, 65, 66, 67])
    @128:13: new Uint8Array([70, 82, 65, 77, 64, 49, 50, 56, 32, 65, 66, 67, 68])
    @256:14: new Uint8Array([70, 82, 65, 77, 64, 50, 53, 54, 32, 65, 66, 67, 68, 69])
    @512:15: new Uint8Array([70, 82, 65, 77, 64, 53, 49, 50, 32, 65, 66, 67, 68, 69, 70])
    @000:10: FRAM@000 A
    @016:11: FRAM@016 AB
    @032:12: FRAM@032 ABC
    @128:13: FRAM@128 ABCD
    @256:14: FRAM@256 ABCDE
    @512:15: FRAM@512 ABCDEF
    ~
    *** reads, overwrite, and reads ***
    read  @000:44: 70,82,65,77,64,48,48,48,32,65,126,126,12­6,126,126,126,70,82,65,77,64,48,49,54,32­,65,66,126,126,126,126,126,70,82,65,77,6­4,48,51,50,32,65,66,67
    read  @000:44: FRAM@000 A~~~~~~FRAM@016 AB~~~~~FRAM@032 ABC
                   0....'....1....'....2....'....3....'....­4....'
    write @010:20: 'Hurray! ...it works!':  20
    read  @010:20: 72,117,114,114,97,121,33,32,46,46,46,105­,116,32,119,111,114,107,115,33
    read  @010:20: Hurray! ...it works!
    read  @000:44: 70,82,65,77,64,48,48,48,32,65,72,117,114­,114,97,121,33,32,46,46,46,105,116,32,11­9,111,114,107,115,33,126,126,70,82,65,77­,64,48,51,50,32,65,66,67
    read  @000:44: FRAM@000 AHurray! ...it works!~~FRAM@032 ABC
                   0....'....1....'....2....'....3....'....­4....'
    =undefined
    >
    

    1 Attachment

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

New EEPROM module names

Posted by Avatar for DrAzzy @DrAzzy

Actions