LDP-6416 64x16 bi-colour LED display panel

Posted on
  • http://www.embeddedadventures.com/LED_ma­trix_display_LDP-6416.html

    (datasheet here)

    This module is a real pain to drive quickly, because you need to shift out data for two bits at around 50kHz absolute minimum.

    In the most recent Espruino builds (so the 1v81 release when it's done), I've added the ability to get the register address of a single GPIO pin, which means you can use this to easily 'poke' data to the pin, which is very fast in 'compiled' code.

    So to drive the display, you can now do something like this:

    var pins = {A:B15, 
                B:B14, 
                C:B13, 
                D:B10,
                nG:B1, 
                L:A6, 
                S:A5, 
                nEN:A8,
                nR:A7};
    var pinAddr = {
      nR : pins.nR.getInfo().out_addr,
      nG : pins.nG.getInfo().out_addr,
      S : pins.S.getInfo().out_addr,
      L : pins.L.getInfo().out_addr,
      A : pins.A.getInfo().out_addr,
      B : pins.B.getInfo().out_addr,
      C : pins.C.getInfo().out_addr,
      D : pins.D.getInfo().out_addr,
      nEN : pins.nEN.getInfo().out_addr
    };
    
    // setup pin states
    pins.nEN.set();
    pins.A.reset();
    pins.B.reset();
    pins.C.reset();
    pins.D.reset();
    pins.nG.set();
    pins.nR.set();
    pins.L.set();
    pins.S.set();
    
    // GO graphics
    var g = Graphics.createArrayBuffer(64,16,2);
    
    
    function scan(pinAddr, buf) {
      "compiled";
      var nR = 0|pinAddr.nR;
      var nG = 0|pinAddr.nG;
      var S = 0|pinAddr.S;
      var L = 0|pinAddr.L;
      var pA = 0|pinAddr.A;
      var pB = 0|pinAddr.B;
      var pC = 0|pinAddr.C;
      var pD = 0|pinAddr.D;
      var nEN = 0|pinAddr.nEN;
      poke32(nEN, 0);
      for (var y=0;y<16;y++) {
        for (var i=0;i<16;i++) {
          var b = buf[y*16 + i]^255;
          for (var j=0;j<4;j++) {
            poke32(nR, b&1);
            poke32(nG, (b&2)>>1);
            poke32(S, 0);
            poke32(S, 1);
            b>>=2;
          }
        }
        poke32(nEN, 1);
        poke32(pA,y&1);
        poke32(pB,(y&2)>>1);
        poke32(pC,(y&4)>>2);
        poke32(pD,(y&8)>>3);
        poke32(L, 1);
        poke32(L, 0);
        poke32(nEN, 0);
      }
      poke32(nEN, 1);
    }
    
    //setInterval(function() {  },10);
    
    
    function animate() {
      var t = getTime();
      g.clear();
      g.setColor(1);
      g.drawString("Hello World",32+Math.sin(t)*32,0);
      g.setColor(2);
      g.drawString("World Hello",0,8);
      scan(pinAddr, g.buffer);
    }
    
    setInterval(animate,10);
    

    Sadly it can't be wrapped up in a module yet (which would obviously be ideal), but it's still a good start.

  • Questions of understanding about buffer and lines 51, 53, and 54, and conclusion for setColor():

    1. buffer: buffer is buffer of bytes (8 bits) for 4 entities of 2 bits per byte
    2. line 51: xor-s 8 LSBits to get the 1-complement (invert)?
    3. line 53: uses only LSBit (with the AND) even though 32 bits are poked?
    4. line 54: uses only secondLSBit as LSBit (with the AND and SHIFT) even though 32 bits are poked?

    Conclusion is that .setColor(colorValue) sets 2nd and 1st LSBit in buffer.

    Another question is regarding performance:
    How 'expensive' is a repeated multiplication? Using a simple, incrementing, buffer pointer for accessing the buffer, how much would be gained over the repeated multiplication?
    (Afaik, compiler cannot yet do ++bp).

    Would code below make a (time) difference?

      var bp = -1,y,i,j;
      for (y=0;y<16;y++) {
        for (i=0;i<16;i++) {
          var b = buf[bp+=1]^255;
          for (j=0;j<4;j++) {
            poke32(nR, b&1);
            b>>=1;
            poke32(nG, b&1);
            b>>=1;
            poke32(S, 0);
            poke32(S, 1);
          }
        }
    
  • buffer: buffer is buffer of bytes (8 bits) for 4 entities of 2 bits per byte
    line 51: xor-s 8 LSBits to get the 1-complement (invert)?

    Yes

    line 53: uses only LSBit (with the AND) even though 32 bits are poked?
    line 54: uses only secondLSBit as LSBit (with the AND and SHIFT) even though 32 bits are poked?

    Yes - the memory is 'bit-banded', so you just want a 1 or a 0 in there (I didn't look up exactly why, but it didn't seem to work well without it)

    How 'expensive' is a repeated multiplication?

    Not very, as far as I know - as long as the compiler knows that the values are all integers it'll be a simple 32 bit multiply, which I believe is done almost single-cycle on ARM.

    But yes, your code would be faster.

    Even faster would be to use a Uint32Array and to request 32 bits at once - the buf[ ... ] is by far the slowest bit of the whole thing

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

LDP-6416 64x16 bi-colour LED display panel

Posted by Avatar for Gordon @Gordon

Actions