Positron8 - Update to: Controlling a 16x16 WS2812B RGB LED Matrix.

Started by top204, Oct 03, 2025, 04:17 PM

Previous topic - Next topic

top204

I have updated the WS2812B 16x16 matrix library code and demos, and they are available from here:

Controlling a WS2812B RGB LED Matrix

Extra procedures have been added to the library, and extra demonstration programs, all running on a PIC18F26K22 device, plugged into an Easy Driver Amicus8 board.

Below is the video I have uploaded to Youtube, with the "Game of Life" simulator running on the matrix, which is one of the new demonstration programs:


Regards
Les

charliecoutas

That's excellent Les. How do update the matrix so fast? The best I can get (with your original WS2818B driver) is a whole matrix every two seconds. Good work!

Charlie

top204

Many thanks Charlie.

For the matrix, I used a method of filling in the arrays that hold the WS2812B colours, and then sending the whole arrays to the chips in one go, instead of individually.

This makes things a lot faster, and is something I also used in the Disco 'Sound To Light' project I created using an MSGEQ7 chip:

MSGEQ7 Sound-To-Light unit Using WS2812B RGB LEDs

Below is a snippet from that code, that shows the important WS2812B procedures for indirect manipulation. So when the shadow buffer arrays are filled, the WS2812B_Update() procedure is called to transfer all the 24-bit colours to the string of WS2812B devices. It makes things a lot faster.

I am updating the WS2812B include file that gets installed with the compilers, to add this mechanism to that, and make it also compatible with PIC24 and dsPIC33 devices:

'-----------------------------------------------------------------------------------------
' WS2812B procedures
'---------------------------------------------------------------------------------------------
' Interface to a single WS2812B RGB controller chip (with gamma control)
' Input     : pRed holds the red value (0 to 255)
'           : pGreen holds the green value (0 to 255)
'           : pBlue holds the blue value (0 to 255)
' Output    : None
' Notes     : Sends the 24-bits to the S2812B MSB first (Most Significant Bit).
'           : A zero bit is a high pulse for approx 350ns
'           : A one bit is a high pulse for approx 900ns
'
Proc WS2812B_RGB(pRed As WS2812B_bRed, pGreen As WS2812B_bGreen, pBlue As WS2812B_bBlue)
    Dim bBitIndex As Byte Access                                                ' Used to access each bit in the WS2812B interface
'
' Create a Gamma correction table to make the LEDs more linear in illumonation
'
    Dim Gamma8 As Flash8 = {0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
                            0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,
                            1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,
                            2,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5,
                            5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9,  9,  9, 10,
                            10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
                            17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
                            25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
                            37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
                            51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
                            69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
                            90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110, 112, 114,
                            115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133, 135, 137, 138, 140, 142,
                            144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 167, 169, 171, 173, 175,
                            177, 180, 182, 184, 186, 189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213,
                            215, 218, 220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252, 255}

    pRed   = CRead8 Gamma8[pRed]                                                ' \
    pGreen = CRead8 Gamma8[pGreen]                                              ' | Add Gamma correction to the LEDs
    pBlue  = CRead8 Gamma8[pBlue]                                               ' /
    For bBitIndex = 23 DownTo 0                                                 ' Create a loop for the 24-bits of data to send to a WS2812B
        Rol pBlue                                                               ' WS2812B_dRGB.Byte0 \
        Rol pRed                                                                ' WS2812B_dRGB.Byte1 | Rotate the 24 colour bits
        Rol pGreen                                                              ' WS2812B_dRGB.Byte2 /
        If STATUSbits_C = 1 Then                                                ' Is the bit set?
            WS2812B_SendOne()                                                   ' Yes. So send a 1 bit to the WS2812B chip
        Else                                                                    ' Otherwise... We have a zero bit. So...
            WS2812B_SendZero()                                                  ' Send a 0 bit to the WS2812B chip
        EndIf
    Next
EndProc

'---------------------------------------------------------------------------------------------
' Fill all of a WS2812B strip with a colour
' Input     : pColour holds the 24-bit colour value
' Output    : None
' Notes     : Red is pColour.Byte0
'             Green is pColour.Byte1
'             Blue is pColour.Byte2
'
Proc WS2812B_Clear(pColour As WS2812B_lColour)
Global Dim WS2812B_wChipNumber As Word Shared                                   ' The WS2812B to access on a line of them
    WS2812B_wChipNumber = 0                                                     ' \ Create a loop for the amount of WS2812B devices to alter
    Repeat                                                                      ' /
        WS2812B_RGB(pColour.Byte0, pColour.Byte1, pColour.Byte2)
        Inc WS2812B_wChipNumber                                                 ' \
    Until WS2812B_wChipNumber >= WS2812B_Amount                                 ' / Loop for the amount of devices
    WS2812B_Finish()                                                            ' Bring the pin low long enough to reset the WS2812B devices
EndProc

'---------------------------------------------------------------------------------------------
' Fill all or some of the Red, Green and Blue arrays with a colour
' Input     : pFirst holds the first element to fill (0 to 65535)
'           : pAmount holds the number of elements to fill (0 to 65535)
'           : pColour holds the 24-Bit colour value
' Output    : None
' Notes     : None
'
Proc WS2812B_ShadFill(pFirst As Word, pAmount As Word, pColour As WS2812B_lColour)
Global Dim WS2812B_wChipNumber As Word Shared                                   ' The WS2812B to access on a line of them
    Symbol cIndexAmount = (WS2812B_Amount - 1)

    If pFirst >= WS2812B_Amount Then ExitProc                                   ' Do nothing if the first LED is past end of strip
    pAmount = pFirst + pAmount                                                  ' Calculate the last WS2812B chip
    If pAmount > cIndexAmount Then                                              ' Make sure that the loop will not go past the last pixel
        pAmount = cIndexAmount
    EndIf

    WS2812B_wChipNumber = 0                                                     ' \ Create a loop for the amount of WS2812B devices to alter
    Repeat                                                                      ' /
        If WS2812B_wChipNumber >= pFirst Then                                   ' Is it at the starting chip we want to alter?
            WS2812B_bRedArray[WS2812B_wChipNumber]   = pColour.Byte0            ' Red
            WS2812B_bGreenArray[WS2812B_wChipNumber] = pColour.Byte1            ' Green
            WS2812B_bBlueArray[WS2812B_wChipNumber]  = pColour.Byte2            ' Blue
        EndIf
        Inc WS2812B_wChipNumber                                                 ' \
    Until WS2812B_wChipNumber >= pAmount                                        ' / Loop for the amount of devices specified in pAmount
EndProc

'---------------------------------------------------------------------------------------------
' Read the red, green and blue arrays and send the contents to WS2812B devices
' Input     : None
' Output    : None
' Notes     : None
'
Proc WS2812B_Update()
Global Dim WS2812B_wChipNumber As Word Shared                                   ' The WS2812B to access on a line of them

    WS2812B_wChipNumber = 0                                                     ' \ Create a loop for the amount of WS2812B devices to alter
    Repeat                                                                      ' /
        WS2812B_RGB(WS2812B_bRedArray[WS2812B_wChipNumber], WS2812B_bGreenArray[WS2812B_wChipNumber], WS2812B_bBlueArray[WS2812B_wChipNumber])
        Inc WS2812B_wChipNumber                                                 ' \
    Until WS2812B_wChipNumber >= WS2812B_Amount                                 ' / Loop for the amount of WS2812B devices to control
    WS2812B_Finish()                                                            ' Bring the pin low long enough to reset the WS2812B devices
EndProc

Best regards
Les

JonW

Nice work, Les. Brings back memories!  In 2022, I designed and built a 16 x 2 array of 8 x 8 6 inch panels, an RF-wireless controlled array for a club scoreboard, complete with a PC application that allowed users to write live to it. I purchased some fisheye lenses from AliExpress to expand each LED, and then diffused the entire setup with a sheet that also served as a waterproof cover.  I used a font table and built a PrintAt proc to write as a massive 16 x 2, 8ft x 2ft LCD, and I also sent the whole array as a single update per panel.  I had one master that buffered the data and controlled the score and text, then addressed the other 8x8 slaves and sent the addressed colour and text data along a serial bus.  Fun at the time, but don't want to do it again, cost a bloody fortune.