• I had a lot of fun with MAX7219 8x8 matrices and was looking to play with an RGB version. Alas, closest one I can find is from https://www.52pi.com/home/221-raspberry-­pi-3-model-b-8x8-full-color-rgb-led-matr­ix-module-for-arduino-stm32.html?search_­query=led&results=30 . It's driven by 74HC595 shift registers. The page in the link listed a wiringPi code example for RPI. Is it going to be a straightforward port? I am decent with JS but total noob with electronic interfaces (SPI). Also, I can't seem to find datasheet for the module. Just wondering if it's worth taking the plunge to try making it work on espruino.

  • Sure, it is possible. I do not know the details about the schema, but there are some typical patterns how it is done with 74HC595...

    I assume 3 of the four feed the RGB by cols (or rows) and the fourth controls the commons by rows (or cols).

    You use SPI with write to write 4-byte entities out to the 74HC595 per row (or col), where the first or last byte has only one bit on (or off) that 'selects' the common row (or col). You use the 'nss' pin to latch. You can keep the 'noe' always grounded. The latching defines the cutover.

    Recently I did something like that with 3 x 595 in series/cascaded for 12 7-segment-plus-decimal display hat have segments A...H(H=DP) of all digits in common one one 595 and the common of each digit on one and a half 595.

    Best is to have a buffer of 8 x 8x3-Byte entities (3 for the 24 bit color depth) that you write into (using Espruino Graphics lib), and an independent write in setInterval to update the display - one col (or row) at a time (24 bytes for the RGB plus additional byte with 1 bit on (or off) for the commons of the row (or col)).

  • Thanks for the info. It will be useful for my investigation. This is how the sequence goes for RPi:

    [#define](http://forum.espruino.com/sear­ch/?q=%23define) RED_DATA 0
    [#define](http://forum.espruino.com/sear­ch/?q=%23define) BLUE_DATA 1
    [#define](http://forum.espruino.com/sear­ch/?q=%23define) GREEN_DATA 2
    int main(void)
      static uint8_t data[4] = {0x0,0x0,0x0,0x0};
             static uint8_t heart[8] = {0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18};             
             int j;
             int x=2;
        for ( j=0;j<8;j++)
              data[0] = ~heart[j];
              data[2] = 0xFF;
              data[1] = 0xFF;
              data[3] = 0x01 << j ;

    My plan is to hopefully port the above. Seems like data is four bytes, with first byte being the col (or row?) data. Not sure the second and the third staying 255, and the last one seems like the col (or row) marker?

    What would the SPI.write arguments be mapping to the above?

    Thanks again!

  • Lines 20..30 do exactly what an update of the display - also called/referenced by the term flip (buffer over to display) needs to do. Including the control data for the flip with the image data is though a mixup of concerns and a bad thing. Writing to the image buffer should not be impaired by the way the buffer has physically to be moved over to the display - in this case it is not even buffer to buffer - it is ongoing like the very old technology of dual ported ram used in the past for drawing the CRT / TV screen in sync with the drawing electron ray, 60 times - or what ever - per second, interleaved (on with slower memory, slower refresh rate) or not interleaved (with faster memory, higher refresh rate).

    Separation of the concerns allows you to use the Graphics library of Espruino, a really really cool thing. Furthermore, it helps with separate timings and allows also have more than one buffer to keep currently displayed image stable while next screen update is prepared (The application knows when the (partial) update is complete and trigger a flip from build into the display buffer.

    Take a look at Graphics library, sections Drivers and Internal Use. Start out with the concept used for the Charlieplex LED Driver and transform its parallel output into serial output. Instead of having a 8 x 3 x 1 pins - a pin per col (or row) 1 per color (for each R, G, and B color - color depth 3) - you have one pin and send the data serialized through that pin... - lines 24..26 - and to select the proper row (or col), you send an extra byte with just the bit in the byte on (or off) to for that row (or col) - line - 27.

    Using the Espruino Graphcs lib you get all sorts of things for free: drawing lines, shapes outlined and filled, fonts, clear, set foreground and background color, etc., and even rotation. And when you write your own set/get/clear pixel graphics, it even even makes your work portable. The Espruino Graphics lib normalizes all for you.

    Looking at the raspi code that is used to drive the display, it makes me understand that one 595 covers one color... in other words: the pixels are grouped by color: for example, first all all R bits - for all cols - are sent out, then all G bits, then B bits, and then the row selector.

    Since the display has no buffer, you have to provide it... Initially I though you could use the Graphics buffer directly for that. But since the graphics buffer bundles the bits by pixel, it is not exactly what you are looking for. The flip implements the re-bundling. To accelerate the flip, you may run it compiled - Yes, Espruino can do that with portions of JavaScript, like inline Assembler.

    Choosing the right buffer contributes also to speed. Espruino by nature stores information in 'very' small, linked blocks scattered over the memory space, which creates overhead for something like a straight forward DMA / streaming. But over time Espruino has also added ways to ask for contiguous buffer to support such things most effective.

    For the .flip() from graphics - where the application draws - into display buffer - that feeds the display - the re-bundling has to happen in a way like this:

    *** .flip():***

    1. collecting red bits for 8 pixels and sticking it into one byte of display buffer.
    2. collecting green bits for 8 pixels and sticking it into next byte of display buffer.
    3. collecting blue bits for 8 pixels and sticking it into third byte of display buffer.
    4. adding a byte with row bit set and sticking it into fourth byte of display buffer.

    Keep doing this for all all rows. If there are more than 8 pixels in a row (more than 8 cols), do steps 1. thru 3. as many times as needed to cover a full row (all cols).
    If there are more rows than 8 rows, add as many bytes as needed to cover all rows.

    *** .updateDisplay():*** continuously within setInterval construct

    1. set nss low.
    2. ship bytes for one row one after the other
    3. set nss high (latches the data and it shows in that row)

    Keep doing this for all rows. If done for all rows, start over.

  • I could be wrong about this, but I think with those shift registers you'll need to keep updating the shift registers for it to keep displaying. If you pause or do something that uses up too much CPU time, the display might flicker.

    Had you considered the WS2812/Neopixel displays? There are loads of different ones, for instance Adafruit does all these: https://www.adafruit.com/category/186

    They're not quite as compact as the MAX7219 ones, but they're super easy to interface to - for instance http://www.espruino.com/RGB123

  • @Gordon, that's correct, the .updateDisplay() has to be on an interval..., because the display is row/time multiplexed...

  • @Gordon thanks for the note (and congrats on the baby!) - I have a 16x16 neopixel (haven't gotten around to play with it yet). I'm interested in the module in this thread because of the size and rigidity (ideas for it includes a wifi-connected icon pendant). I just got the module and hoping to squeeze some time to try it out per @allObjects' comment (thanks!).

  • Thanks! Yes, it does look nice and small - there's some hope that some of the neopixels ones will get closer soon as there are some tiny chips coming onto the market, but nothing similar I know of for now.

    It'd be worth experimenting, but I've had much better results driving this kind of thing when I create one function that scans out all rows in one go, and then schedule that maybe 100 times a second. It seems to create less obvious glitches if other code takes a while to execute. The JS execution is slow enough that there's no need for delays - just push out all rows in one bit of code.

  • @user81779, take a look at conversation about Driving LED matrix with shift registers such as 74HC595. There I build up the code for connecting a nxm LED matrix of the type you mention to Espruino.

  • @user81779, are you still pursuing this project? Test setup in conversation about Driving LED matrix with shift registers such as 74HC595 has validated that such LED modules can be connected to Espruino. Furthermore, it has shown that Espruinos Graphics libarary can be used to easily control color, write text in various fonts, set pixels, draw lines, shapes - hallow and filled - and more.

  • @allObjects I did a quick test run the other day and found that the basic sending of 4 element data array [R,B,G,row] works. I haven’t tried to leverage the Graphics lib yet but did find some anomalies:

    1. Sending just R data works fine
    2. Sending data with B and or G lit worked (got cyan pixels)
    3. Introducing R killed other B or G pixels - as if red pixels suck all the power
    4. Connecting external 5v to the module made it go disco crazy (is it because module and espruino need to share common ground?)
    5. With espruino original board and intervals to cycle through the rows in the simplest way I need 1ms to get a stable / non flickering updates

    I also realized that this module is 3 bits display - foolishly assumed I can do full color (24 bit) 😔. I suppose the LED module supports that but will need PWM per light diode to get 8bit per pixel. Which I believe is what Neopixel does, pwm controller chip per diode.

    I will tinker some more and post vids / updates.

  • is it because module and espruino need to share common ground?

    Yes - you could actually cause some damage by not sharing ground - but there's no reason you can't connect all the grounds together while still using an external power supply.

    Introducing R killed other B or G pixels - as if red pixels suck all the power

    It's quite likely - red LEDs run off a lower voltage than green and blue, so if too much power is being drawn and the voltage drops then you'd have trouble. I guess you could try scanning 3 times - once for R, G and B?

  • Forward voltage red vs the others is about or typically 2.2 to 3.5... running a red LED in parallel to a green or blue may prevent them to even lighten up... and if not, the red one will have a significantly shortened life span (max for a red is about 3.1 where minimum for green and blue are about 2.85V).

    595's seem anyway not the right thing to me since the source and sink capabilities are very limited (as per data sheet). Doing a full spectrum RGB with such a setup is quite challenging. With 3 separate RGB source / sink options you may get even intensity to create 8 decent colors. The module you refer to is a very primitive one and with given circuitry of just 595's you have pretty limited options. To make it work, you may rather have just the LED matrixes and find / built the circuitry for you demands. I'm sure you do not want to alter the carrier / breakout boards to make them better...

    Alternatives for a full spectrum, you have to go for Neopixels or DotStars. Neopixels pose signal timing challenges and DotStars (adafruit) aren't cheap. It all depends on your application...

  • (consolidating my post under this account, I have 2, user81779 is my other one I'm retiring, sorry if this is causing confusion)

    So I did further test and the module seems to be flawed as it does not support R + other color scenario. I used this code:

      data[0] = 0b11111111;
      data[2] = 0b11111111 << i ;
      data[1] = 0b00000000;
      data[3] = 0x01 << 0 ;

    for combining B+G and R+B (video attached). Red did suck the power out of other color diodes. No go with this module :( I'm better off 3d-printing a pixel mask on top of neopixel. Price wise, an 8x8 neopixel matrix clone is pretty good.

    Thanks @allObjects for your keen interest and assistance!

    2 Attachments

  • You could probably work around it by scanning R and then G, and then B. But yeah, Neopixel clones are pretty cheap. There are some crazy tiny chips coming out as well (there's one even smaller than the 3.5 x 3.5mm package), so you should see some properly small neopixel matrices soon.

  • @n00b, it ws an interesting experiment, since I had other things going on with 595s (post #8, Bubble Displays) within conversation about ShiftOut question for Hannio flipDot Display. My take-away for my Bubble Display is @Gordon's way of scanning...

    You get 8 colors out of your display, but you have to do color separate scans (which of course consumes even more processing power on top of extra processing power to support the weird color bundled wiring).

    To compensate for the missing brightness, you would have to let rows hang out longer, or vary the voltage for the various colors... (may be that was the original idea to bundle by color than by pixel to feed the 595s differently... but it did never made it, because you would need two power inputs or some smartness on the board (at least passive / resistors), but I can see nothing of it... sorry for your investment.

    Heavy time multiplexing on interpreter level is anyway not the best... and timing (and brightness) is a bit unpredictable when other things are going on.

    See you, @n00b, on other occasions.

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

Is it possible to connect this 8x8 RGB matrix to espruino boards?

Posted by Avatar for user81779 @user81779