• What - or 'Who' - do you call perfect? - I cannot expect more...

    Already w/ my version I ran the 595 w/ 5 Volts and it is quite noticeable. Doing so and scan twice makes for sure sense.

    @Gordon, what's your comment about the following piece of code? If the data buffer is built with just the column (sourcing) information per row and on scanning complemented with the 'calculated' row (draining) information, can then the Graphics class directly operate on the data buffer?

    // ledMatrix8.js - only col info in dbuf and gordon's scan
    // code exploring led matrix display w/ Espruino board
    // Espruino-WiFi / Pico / Original / Puck
    var dbuf = // display buffer, organized as rows.
    // Set LEDs @ [0,0], [1,1], [2,4] Red on (top left LED,
    // 2nd col of 2nd row and last/3rd col in last/5th row:
    //             col bits
    //  .......2   22111000
    //  color  B   GRBGRBGR
    [ 0b00000000,0b00000001 // - row 0
    , 0b00000000,0b00001000 // - row 1
    , 0b00000000,0b00000000 // - row 2
    , 0b00000000,0b00000000 // - row 3
    , 0b00000000,0b01000000 // - row 4
    var // connect definitions (Espruino -> 595 wiring): 
    //        SPI1 and other GPIOs          74HC595 (pin) 
      dspiDat=B5 // a) SDA ser data MOSI -> SER    (14)
    , dspiClk=B3 // b) SCK ser clock     -> SRCLK  (11)
    , dnss   =A0 // c) NSS to go w/ SPI  -> RCLK   (12)
    , dnoe   =A1 // d) 595 output enable -> _OE    (13)
    ;            // e) 595 _clear fix 1  -> _SRCLR (10)
    // A0 dnss is co-used for output register latch.
    //    Latch prevents blur while shifting.
    // A1 can do PWM when danger of over powering LEDs. 
    pinMode(dspiDat, "output"); dspiDat.set(); 
    pinMode(dspiClk, "output"); dspiClk.set();
    pinMode(dnss   , "output"); dnss.set();
    pinMode(dnoe   , "output"); dnoe.set();
    SPI1.setup({ mosi: dspiDat, sck: dspiClk });
    var iId       // interval ID and interval time w/
      , iTm = 10; // full scan event every 10 millisec
    function r() { // run / row drain bit (rBt) calculated
      iId = setInterval(function() {
          var rdx = 5, bdx = 0, rBt = 0xFE;
          dnoe.reset(); // enable output
          while (rdx--) {
            rBt = (rBt<<1) | 0x01;
          dnoe.set();   // disable output
        }, iTm);
    function h() { // halt
      if (iId) iId = clearInterval(iId);

    I guess it depends on how the buffer is implemented for a 3x5x3 (w*h*colorDepth) Graphic:

    • a) with Bit, Nibble, Byte, Word, DoubleWord boundaries?
    • b) row bundled with above boundary?
    • c) pixel or color bundled?

    A pure bit stream is the most efficient in memory usage but not so efficient in manipulation (would require a lot of odd calculations and bits int nibble/byte/word/doubleWord shifting and and/or/xor-ing, nible/byte/word/doubleWord depending on color depth).

    Did just some 'explorative testing'... and valid bpp - bits per pixel - is a multiple of four... in other words, pixels are nibble bound... I have to define a 3x5x4 buffer... and I assume the number of bits per color (channel) are equal. Therefore, on streaming, the first bit - MSB - of every nibble is 0 and has to be dropped - either by recompose the output - or by skipping the shift register output pin...

    A 3x5x5 buffer takes up 8 bytes, and therefore, odd rows start with odd number of nibbles... oops... some nibble manipulation for rows 1 and 3..., and all rows need a nibble leading padding. --- And this in JavaScript? It gets a bit ugly: for every 3 nibbles consumed from dbuf, a nibble has to be inserted upfront to meet the 8-bit / byte boundary of the 8-bit shift register...

    I guess a .flip() has to kick in now before every(?) full scan, and the flip has to be compiled or in Thumb-assembler... Copying from one contiguous array buffer into another one should not be that difficult... never tried it, though.


Avatar for allObjects @allObjects started