Introduction: Inexpensive and Scalable Digital Sign Using NeoMatrix LEDs

About: I am a semiconductor engineer. I do a lot projects as a hobby, such as robotics, programming, microcontroller, 3D printing, CAD modeling, and CNC.

This is an inexpensive way to build LED digital sign that can scale to any size.

Features:

  1. Scalable:
  2. LED matrices are daisy-chained for any size and minimal wirings.
  3. Only need to fix an individual LED panel instead of the entire display.
  4. Update the digital sign and firmware over the Cloud.
  5. Using Raspberry Pi instead of ESP8266/32 for virtually unlimited way for future improvements/features.

This instruction is for advanced Arduino and Raspberry Pi users only which otherwise would take very long instructions.

Supplies

  1. LED matrices, could be any size, I use 8x32
  2. A 5V power supply with sufficient current to support the number of LED matrices. I use 60A
  3. A Raspberry Pi, I use Raspberry Pi 3B+
  4. A Buck converter or a good Raspberry Pi power supply.
  5. An Arduino Due
  6. A 9V-12V power adapter for the Arduino Due, I repurposed one from around the house.

Step 1: Daisy-Chain LED Matrices

LED matrices are daisy-chained, see the picture and notice the arrows. The picture shows an example of 3x3 daisy-chained configuration and how they wrap-around and turn up-side-down as they go into the next row. You can scale to any number of rows and columns. Having daisy-chained allows less wirings in expense of speed, assuming the display does not need high refresh rate for a large display.

Step 2: Powering LED Matrices

Use the 5V Power supply to power all of the LED Matrices. To prevent "Ground-Loop" connect all of 5V and Ground terminals from the LEDs to the power supply using wire gauge rated based on the number of LED matrices. Connect the Ground from the power supply to the Ground of the Arduino Due.

Step 3: Arduino Due Microcontroller Firmware

  1. Upload the following codes to the Arduino Due: link.
  2. Use an Arduino IDE to upload the codes.
  3. The code assumes the size of each LED matrix is 32x8 (32 columns x 8 rows):
  4. Modify the "32" and "8" correspond to the LED matrix you use:
  5. Adafruit_NeoMatrix matrix1 = Adafruit_NeoMatrix(32, 8, TILE_COLUMNS, TILE_ROWS, PIN_NORTH_SIGN, NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS + NEO_TILE_ZIGZAG + NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG, NEO_GRB + NEO_KHZ800);
  6. There are two digital I/O pins to two separate displays, in the code I use pin 46 and 52:
  7. #define PIN_NORTH_SIGN 46
  8. #define PIN_SOUTH_SIGN 52
  9. If you only use a single display you can remove codes for the 2nd display or leave the code and only use one the pin.
  10. These pins go to the input signal (center pin) of the LED (that have been daisy-chained)
  11. Also connect the Ground from Arduino Due to the Ground pin of the LED input.
  12. Modify the following lines depending on the number of rows and columns of LED matrices:
  13. #define TILE_COLUMNS 6
  14. #define TILE_ROWS 5
  15. In my case I have 6 columns and 5 rows.
  16. After uploading the firmware, the Arduino board will be powered by a 7V-12V adapter with enough current. I repurposed an adapter I found around the house.

Step 4: Raspberry Pi Setup

Some people may wonder why I used Raspberry Pi instead of an ESP32 or ESP8266. As a matter of fact, my initial design used ESP8266 running as a web server. To improve the capabilities, practically the sky is the limit to what I can do, I decided to switch to a Raspberry Pi (3B+)


Powering the 5V input power of a Raspberry Pi is not trivial. Often time you get "Under voltage warning" even though you use a power adapter that comes with it. In general you need a power supply that is slight higher than the rated voltage to be more reliable, and also enough wattage. In my case I use a 12V adapter I found around my house and use a Buck Converter to output 5.2V for stability.


Installation steps:

  1. Install a Raspberry Pi OS and connect to the local Wi-Fi.
  2. Connect a Raspberry Pi USB to the Arduino USB Programming port.
  3. Enable the Raspberry Pi VNC server
  4. There is also an option to access VNC via the Cloud by signing up to the RealVNC Connect account. As what the "Cloud" suggests, you can remotely connect to it from anywhere in the world via the internet.
  5. Install Python and pip install libraries:
  6. flask (for web server)
  7. pyserial (serial communication to Arduino)
  8. astral (optional, I include it in my code but can be removed) to allow getting the sunrise and sunset times from the internet from your location (latitude and longitude).
  9. Download my GitHub codes, and place them into the main directory.
  10. Optionally you can modify the location in the code, webserver.py file if you want to use the sunrise and sunset times:
  11. def get_Calc_Dusk_Dawn():
  12. city = astral.LocationInfo('Minneapolis', 'US', 'US/Central', 44.74683 , -93.193575)
  13. Run the Python webserver by typing:
  14. python webserver.py
  15. The webserver runs on Port 5000 instead of the standard internet HTTP port 80 or 443 (HTTPS), since it is not designed for the world to access it. You can change it to a different port in the file.
  16. To run webserver.py automatically every time you restart the Raspberry Pi, put "@reboot python webserver.py &" in the "crontab -e"
  17. Using any computer or phone on the same WiFi, open a browser and open URL address of <IP address>:5000, 192.168.0.22:5000, where 192.168.0.2 is the IP address of the Raspberry Pi. See the picture what it looks like from a browser. You can change the template page from the "template" folder of my GitHub codes. Use the browser to change the sign.
  18. The Python uses the USB to send command to the Arduino which drives the LED display.
  19. Side notes:
  20. Beside remote connection to the Raspberry Pi over the internet to change the sign, having Raspberry Pi also allows me to change the firmware of the Arduino remotely.
  21. I can also make future improvements such as additional Python programming to change the display on real-time, scheduled display change, sky is the limit.

Step 5: How to Display a Picture

To add a picture:

  1. Open web address from the previous section.
  2. Enter comma-delimited pair of <pixel number>, color number:
  3. For example 0, 234567,1,6736674, and so forth
  4. Above is an example of two pairs, the first pair for LED index=0, with color 234567. Then LED index=1 with color 6736674.
  5. The number for color is:
  6. 24-bit color
  7. <Red><Green><Blue>, each in 8-bit, so the total of 24-bit
  8. Therefore the first 8-bit for blue, bit 9-16 for Green, bit 17-24 for red.
  9. For example: 00000000 00000000 1111111 for blue, converting the binary to number is 255
  10. The 2nd picture shows how the LED index numbering works. It starts from the top right, the index enumerates down the first column from 0 to 7. Then it goes to the 2nd column from the bottom to the top of the 2nd column from 8 to 15. You can see the zig-zag pattern. You have to work the math of converting a picture, pixel by pixel, to the display:
  11. How I do it is by first converting a picture into X, Y pixels, each point with an average colors around each pixel based on the display pixel size (horizontal and vertical pixels).
  12. Use a math, in my case using Microsoft Excel Macro to convert each LED X, Y to the zig-zag LED index.
  13. I may consider publishing the Excel Macro though it only applies to the LED display I built and may be hard to explain how I transform the zig-zag into X-Y coordinate when you have many of them daisy-chained together. It is kind of flipping your brain back and forth.
  14. I also have another Instructible, using Python to convert a picture: https://www.instructables.com/Scrolling-Text-and-Picture-on-an-LED-Neo-Pixel-Neo/

Here is my Excel Macro to convert X,Y coordinates to pixel indexes and colors:

  • The following example applies to my LED configuration.
  • In this case I have 32x8 each LED panel.
  • I daisy-chained 32x8 panel into 5 rows and 6 columns

--------------------

Excel Macro:

---------------------

Sub generate_json_pixel()

  Dim ws As Worksheet

  Dim FSO As New FileSystemObject

  Dim JsonTS As TextStream

  Dim JsonText, outstr As String

  Dim jsonObj As Object

  Dim rowpixel As Dictionary

  Dim intcolor As Variant, red As Long, green As Long, blue As Integer

  Dim color As Long

  pixel_width = 192 ' 32 ' pixel total width, eventually 32x6

  Set ws = ActiveWorkbook.Sheets("Pixel Generator")

  Set rowpixel = New Dictionary

  startrow = 1

  notfirsttime = False

  TextBox_pixel.Text = ""

  For nn = 0 To 7679 ' 1279

    ntilerow = Int(nn / (8 * pixel_width))

    ncol = ((Int(nn / 8) + 0) Mod pixel_width) + 1

    If (ntilerow Mod 2) Then

      ncol = pixel_width - ncol + 1

    End If

    nrow = (nn Mod 8) + 1

    If ncol Mod 2 = 0 Then

      nrowsign = -1

      nrow = 9 - nrow

    End If

    nrow = nrow + ntilerow * 8

    intcolor = ws.Range(Cells(nrow, ncol), Cells(nrow, ncol)).Interior.color

    red = (intcolor Mod 256) / 2

    green = ((intcolor \ 256) Mod 256) / 2

    blue = (intcolor \ 65536) / 2

    color = red * 256 * 256 + green * 256 + blue

    If color > 0 And Not (red > 80 And green > 80 And blue > 80) Then

    Debug.Print ("Red=" & red & ", green=" & green & ", blue=" & blue)

      If notfirsttime Then

        outstr = outstr & ","

      End If

     notfirsttime = True

      outstr = outstr & nn & "," & color

    End If

    'ws.Cells(nrow, ncol) = nn

  Next

' output string of indexes and colors

  TextBox_pixel.Text = outstr

End Sub

At last, enjoy a cheap way to build a large LED digital display.