• This becomes kind a series of examples how Pico comes handy for a lot of different things - see Using Pico to test new old stock (NOS) IC - MC14512 - 8 Channel Data Selector. You may guess where this is going...

    But for now, just focusing on this little interesting and quite versatile MC14599 chip from the past: a bit addressable storage of 8 bits with 1-bit wide data bus and 8 bits output port, 1 for each of the stored bits. A bit can be written and read back by 3 address lines. It behaves like Pico GPIO in "output" pin mode.

    Compared to the MC14512 - 8 Channel Data Selector - the testing software turned out to be much more complex - no easy way to just use a truth table with data driven logic - but exclusively procedural. With some shoehorning a data drive approach could be construed, but it was just easier to code while exploring the chip's workings.

    The next post shows the code and test output.


    3 Attachments

    • MC14599_pico_wiring.png
    • MC14599_datasheet.png
    • MC14599_pico.jpeg
  • The test code...

    To test a chip output, the wired Pico input is read twice, once with input_pulldown and once with input_pulldown to really detect driven High and Low as well as three-state, high impedance Z. Furthermore, when inputs, addresses or control lines do not matter, the testing goes thru all their permutations to make sure that their state and transition do really not matter. This intense testing is not visible in the output, especially for the last block that does multi-writes and multi-reads. Looking at the nested loops in the code makes though clear that it is not just a write and then a read for each of the 8 bits, but a got 1300 - thirteen hundred tests... (may be I'm paranoid... because all chips I got passed w/ flying colors).

    // MC14599_8B_ADDR_LATCH.js
    // 20230327ao
    //
    // Using pico to test NOS MC14599B 8-Bit Addressable Latches
    //
    var lon = true; // false; // true; // logging is on
    function log() { if (lon) { console.log.apply(console,arguments); } }
    // wire connections
    //  ic - pico
    var CQ0=A0, CQ1=A1, CQ2=A2, CQ3=A3, CQ4=A4, CQ5=A5, CQ6=A6, CQ7=A7
      , CW_R=B1, CE=B7, CWDS=B8, CRST=B9
      , CA0=B3, CA1=B4, CA2=B5
      , CD=B6 
      , CQ = [CQ7, CQ6, CQ5, CQ4, CQ3, CQ2, CQ1, CQ0]
      , CA = [CA2, CA1, CA0]
      ;
    function setPinModes() {
      // driving the chip controls
      pinMode(CW_R,"output");
      pinMode(CE  ,"output");
      pinMode(CWDS,"output");
      pinMode(CRST,"output");
      // driving the bit latch address lines
      pinMode(CA0,"output");
      pinMode(CA1,"output");
      pinMode(CA2,"output");
      // reading the 8B latches
      pinMode(CQ0,"input");
      pinMode(CQ1,"input");
      pinMode(CQ2,"input");
      pinMode(CQ3,"input");
      pinMode(CQ4,"input");
      pinMode(CQ5,"input");
      pinMode(CQ6,"input");
      pinMode(CQ7,"input");
      // reading / writing the chip data (preset)
      pinMode(CD,"input");
    }
    
    function hex(v) { return ((v>15) ?
      hex(v>>4) : "")+"0123456789ABCDEF".charAt(v&15); } // hex...
    function hep(v,ds) { // hex, digits (w/ blank padding up to ds)
      return ("        "+hex(v)).substr(-ds); }
    function lep(v,ds) { // hex, digits (w/ 0 padded up to ds)
      return ("00000000"+hex(v)).substr(-ds); }
    
    var tMax = 1 // test repetitions
      , tCnt = 0
      , passed, somePassed, someFailed
      ;
    var tester =
    { test: function() { // tester object (tool)
        log(++tCnt);
        this.tResetLatch();
        this.tResetData();
        this.tChipDisableLatch(true);  // onReset
        this.tChipDisableData( true);  // onReset
        this.tChipDisableLatch(false); // w all 0 then 1 - tests all to 1
        this.tChipDisableData( false); // w all 0 then 1 - tests all to 1
        this.tChipDisableLatch(false); // w all 0 then 1 - tests all to 0
        this.tChipDisableData( false); // w all 0 then 1 - tests all to 0
        this.tWrite01010();
        this.tWriteRead01010();
      }
    
    // test reset for latch
    // - expects nothing
    // - leaves -+CE, -+W_R, +WDS, -+AX(3), -+RST
    , tResetLatch: function() {
        log("\ntResetLatch","<=====");
        var td = "tResetLatch"
          , ps=[CE,CW_R,CWDS,CA2,CA1,CA0], px, v, r, t
          , p=true, passedCnt=0; failedCnt=0;
        this.dIPM(); // data input to avoid any contention
        CRST.set();
        t = 0;
        for (v = 0; v <= 1; v++) {
          this.lIPM(v);
          for (px = 0; px <= 0x3F; px++) {
            digitalWrite(ps,px);
            if ((r = digitalRead(CQ)) !== t) { // 0x00 
              log(td,"FAILED",v,hep(px,2),": 00",lep(r,2));
              p = false; failedCnt++;
            } else {
              passedCnt++;
            }
        } }
        if (p) { 
          log("-- "+td+" ok");
        } else {
          log("-- "+td+": passed =",passedCnt,", FAILED =",failedCnt);
        }
        passed &= p;
        digitalWrite(ps,0b001000);
        CRST.reset();
       }
    
    // test reset for data
    // - expects nothing
    // - leaves -+CE, -+W_R, +WDS, -+AX(3), -+RST
    , tResetData: function() {
        log("\ntResetData","<=====");
        var td = "tResetData"
          , ps=[CE,CW_R,CWDS,CA2,CA1,CA0], px, v, w, r, t
          , p=true, passedCnt=0; failedCnt=0;
        this.dIPM(); // data input to avoid any contention
        CRST.set();
        for (v = 0; v <= 1; v++) {
          this.lIPM(v); t = v * 0xFF;
          for (px = 0; px <= 0x3F; px++) {
            for (w = 0; w <= 1; w++) {
              this.dIPM(w); t = w;
              if ((r = digitalRead(CD)) !== t) { // high imp Z
                log(td,"FAILED",v,hep(px,2),":",t,r);
                p = false; failedCnt++;
              } else {
                passedCnt++;
              }
            }
        } }
        if (p) { 
          log("-- "+td+" ok");
        } else {
          log("-- "+td+": passed =",passedCnt,", FAILED =",failedCnt);
        }
        passed &= p;
        digitalWrite(ps,0b001000);
        CRST.reset();
       }
    
    // test chip -+enable (disable) for latch
    // - expects nothing when w/ rst, otherwis -+CE, -+W_R, +WDS, -+RST
    // - leaves -+CE, -+W_R, +WDS, -+AX(3), -+RST conditional use
    , tChipDisableLatch: function(withRst) {
        log("\ntChipDisableLatch",(withRst)?" WITH ":"WITHOUT","RST","<=====");
        var td = "tChipDisableLatch"+((withRst)?"AftReset":"InGeneral")
          , ps=[CW_R,CWDS,CA2,CA1,CA0], px, u, v, r, t, tt
          , p=true, passedCnt=0; failedCnt=0;
        this.dIPM(); // data input to avoid any contention
        if (withRst) CRST.set();
        CE.reset(); // -+CE disable
        if (withRst) CRST.reset();
        for (u = 0; u <= 1; u++) {
          if ( ! withRst || u === 0) {
            t = u * 0xFF; tt = ": " + lep(t,2);
            if ( ! withRst) this.allOut(u);
            for (v = 0; v <= 1; v++) {
              this.lIPM(v);
              for (px = 0; px <= 0x2F; px++) {
                digitalWrite(ps,px);
                if ((r = digitalRead(CQ)) !== t) { // high imp Z
                  log(td," FAILED",u,v,hep(px,2),tt,lep(r,2));
                  p = false; failedCnt++;
                } else {
                  passedCnt++;
       } } } } }
       if (p) { 
          log("-- "+td+" ok");
        } else {
          log("-- "+td+": passed =",passedCnt,", FAILED =",failedCnt);
        }
        passed &= p;
        digitalWrite(ps,0b001000);
       }
    
    // test chip -enable (disable) for data
    // - expects nothing
    // - leaves -+CE, -+W_R, +WDS, -+AX(3), -+RST conditional use
    , tChipDisableData: function(withRst) {
        log("\ntChipDisableData",(withRst)?" WITH ":"WITHOUT","RST","<=====");
        var td = "tChipDisableData"+((withRst)?"AftReset":"InGeneral")
          , ps=[CW_R,CWDS,CA2,CA1,CA0], px, v, w, r, t
          , p=true, passedCnt=0; failedCnt=0;
        this.dIPM(); // data input to avoid any contention
        if (withRst) CRST.set();
        CE.reset(); // -+CE disable
        if (withRst) CRST.reset();
        for (u = 0; u <= 1; u++) {
          if ( ! withRst || u === 0) {
          if ( ! withRst) this.allOut(u);
            for (v = 0; v <= 1; v++) {
              this.lIPM(v);
              for (px = 0; px <= 0x2F; px++) {
                for (w = 0; w <= 1; w++) {
                  this.dIPM(w); t = w;
                  if ((r = digitalRead(CD)) !== w) {
                    log(td," FAILED",v,hep(px,2),w,r);
                    p = false; passedCnt++;
                  } else {
                    passedCnt++;
        } } } } } }
        if (p) { 
          log("-- "+td+" ok");
        } else {
          log("-- "+td+": passed =",passedCnt,", FAILED =",failedCnt);
        }
        passed &= p;
        digitalWrite(ps,0b001000);
      }
    
    // test write individual outputs
    // - expects -+CE, -+W_R, +WDS, -+AX(3), -+RST
    // - leaves -+CE, -+W_R, +WDS, -+AX(3), -+RST not in use
    , tWrite01010() {
        log("\ntWrite01010","<=====");
        var td = "tWrite01010"
          , vs = [0,1,0,1,0]
          , ps=[CW_R,CWDS,CA2,CA1,CA0]
          , addr, t = 1, w, vx, v, r
          , p=true, passedCnt=0; failedCnt=0;
        this.allOut(0); passed &= this.validateQX(td,"setup QX=00",0);
        for (addr = 0; addr <=7; addr++) {
          for (vx = 0; vx <= 4; vx++) {
            v = vs[vx]; w = v * t;
            this.write(addr,v);
            if ( ! this.validateQX(td,"write",w)) {
              log(td,"FAILED",addr,v,":",lep(w,2),lep(digitalRead(CQ),2));
              p = false; failedCnt++;
            } else {
              passedCnt++;
            }
          }
          t = t<<1;
        }
        if (p) { 
          log("-- "+td+" ok");
        } else {
          log("-- "+td+": passed =",passedCnt,", FAILED =",failedCnt);
        }
        passed &= p;
        digitalWrite(ps,0b001000);
      }
    
    // test write individual outputs
    // - expects -+CE, -+W_R, +WDS, -+AX(3), -+RST
    // - leaves -+CE, -+W_R, +WDS, -+AX(3), -+RST not in use
    , tWriteRead01010() {
        log("\ntWriteRead01010","<=====");
        var td = "tWriteRead01010"
          , vs = [0,1,0,1,0]
          , ps=[CW_R,CWDS,CA2,CA1,CA0]
          , wddr, rddr, t = 1, w, vx, v, r
          , p=true, passedCnt=0; failedCnt=0;
        this.allOut(0); passed &= this.validateQX(td,"setup QX=00",0);
        for (wddr = 0; wddr <=7; wddr++) {
          for (vx = 0; vx <= 4; vx++) {
            v = vs[vx]; w = v * t;
            this.write(wddr,v);
            if ( ! this.validateQX(td,"write",w)) {
              log(td,"write FAILED, skip read",wddr,v,":",lep(w,2),lep(digitalRead(CQ),2));
              p = false; failedCnt += 8;
            } else {
              // log(td,"write OK, do read",wddr,v,":",lep(w,2),lep(digitalRead(CQ),2));
              for (rddr = 0; rddr <= 7; rddr++) {
                if (rddr === wddr) { // exp v
                  r = this.read(rddr,w = v);
                } else {
                  r = this.read(rddr,w = 0);
                }
                if (r !== w) {
                  log(td,"read FAILED",wddr,rddr,v,":",w,r);
                  p = false; failedCnt++;
                } else {
                  // log(td,"read OK",wddr,rddr,v,":",t,r);
                  passedCnt++;
                }
              }
            }
          }
          t = t<<1;
        }
        if (p) { 
          log("-- "+td+" ok");
        } else {
          log("-- "+td+": passed =",passedCnt,", FAILED =",failedCnt);
        }
        passed &= p;
        digitalWrite(ps,0b001000);
      }
    
    // setup latch QX for input w/ pull-up or pull-down
    , lIPM: function(falseOrTrue) { // input _pulldown / _pullup
        var pull = "input_" + ((falseOrTrue) ? "pullup" : "pulldown");
        for (var p=0; p<8; p++) { pinMode(CQ[p],pull); } }
    
     // setup data QD for input w/ pull-up or pull-down
    , dIPM: function(falseOrTrue) { // input _pulldown / _pullup
        pinMode(CD,"input_" + ((falseOrTrue) ? "pullup" : "pulldown")); }
    
     // setup data QD for input w/ high imp Z
    , dIM: function() { pinMode(CD,"input"); }
    
     // setup data QD for output
    , dOM: function() { pinMode(CD,"output"); }
    
    // set all latches to value
    , allOut(v) {
        log("allOut(",v,") <-----");
        for (var a=0; a<=7; a++) this.write(a,v);
        log("allOut:",v,lep(digitalRead(CQ),2));
      }
    
    // write at addr data bit
    // expects -+CE, -+W_R, +WDS, -+RST (not used)
    // leaves -+CE, -+W_R, +WDS, -+RST
    , write(addr,data) {
        CWDS.set();
        digitalWrite(CA,addr & 7);
        CW_R.set();
        this.dOM();
        digitalWrite(CD,data & 1);
        CE.set();
        CWDS.reset();
        CWDS.set();
        this.dIM();
        CW_R.reset();
        CE.reset();
      }
    
    // read at addr data bit (w/ opposite pull when exp !== null - false/true/0/1)
    // expects -+CE, -+W_R, +WDS, -+RST (not used)
    // leaves -+CE, -+W_R, +WDS, -+RST (uses only +CE)
    , read(addr,exp) {
        var r;r = (exp === undefined) ? undefined : ! exp;
        digitalWrite(CA,addr & 7);
        if ((r = (exp === undefined) ? undefined : ! exp) === undefined) {
          this.dIM();
        } else {
          this.dIPM(r);
        }
        CE.set();
        r = digitalRead(CD);
        CE.reset();
        this.dIM();
        return r;
      }
    
    // validate QX === t w/ pulldown and pullup
    , validateQX: function(td, det, t) {
        var p = true;
        this.lIPM(0);
        if ((r = digitalRead(CQ)) !== t) {
          log(td, det, "FAILED", lep(t,2), lep(r,2));
          p = false; }
        this.lIPM(1);
        if ((r = digitalRead(CQ)) !== t) {
          log(td, det, "FAILED", lep(t,2), lep(r,2));
          p = false; }
        return p;
      }
    
    }
    ;
    
    function onInit() {
      setPinModes();
      somePassed = false; someFailed = false;
      var tIId = setInterval(function() {
           LED1.reset(); LED2.reset();
           passed = true;
           tester.test();
           if (passed) {
             LED2.set(); somePassed = true;
           } else {
             LED1.set(); someFailed = true;
           }
           if (tCnt>=tMax) {
             clearInterval(tIId);
             if (somePassed) { LED2.set(); }
             if (someFailed) { LED1.set(); }
           }
        },750);
    }
    
    setTimeout(onInit,999); // dev only; remove before upload for save()
    

    A corresponding ouput:

    >
     ____                 _
    |  __|___ ___ ___ _ _|_|___ ___
    |  __|_ -| . |  _| | | |   | . |
    |____|___|  _|_| |___|_|_|_|___|
             |_| espruino.com
     2v17 (c) 2021 G.Williams
    >
    1
    tResetLatch <=====
    -- tResetLatch ok
    tResetData <=====
    -- tResetData ok
    tChipDisableLatch  WITH  RST <=====
    -- tChipDisableLatchAftReset ok
    tChipDisableData  WITH  RST <=====
    -- tChipDisableDataAftReset ok
    tChipDisableLatch WITHOUT RST <=====
    allOut( 0 ) <-----
    allOut: 0 00
    allOut( 1 ) <-----
    allOut: 1 FF
    -- tChipDisableLatchInGeneral ok
    tChipDisableData WITHOUT RST <=====
    allOut( 0 ) <-----
    allOut: 0 00
    allOut( 1 ) <-----
    allOut: 1 FF
    -- tChipDisableDataInGeneral ok
    tChipDisableLatch WITHOUT RST <=====
    allOut( 0 ) <-----
    allOut: 0 00
    allOut( 1 ) <-----
    allOut: 1 FF
    -- tChipDisableLatchInGeneral ok
    tChipDisableData WITHOUT RST <=====
    allOut( 0 ) <-----
    allOut: 0 00
    allOut( 1 ) <-----
    allOut: 1 FF
    -- tChipDisableDataInGeneral ok
    tWrite01010 <=====
    allOut( 0 ) <-----
    allOut: 0 00
    -- tWrite01010 ok
    tWriteRead01010 <=====
    allOut( 0 ) <-----
    allOut: 0 00
    -- tWriteRead01010 ok
    > 
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Using Pico to test new old stock (NOS) IC - MC14599 - 8 Bit Addressable Latch

Posted by Avatar for allObjects @allObjects

Actions