If you haven’t read Part 1, check it out here. This post will have a bit more of a look at how the matrix is wired up and how the code works. There are a few little quirks and gotchas to watch out for. A disclaimer for this, I had never used addressable LEDs before this project, and I have limited Arduino experience, so there are probably better ways to do this. That being said, this all works and I think the results are pretty sweet. It is worth downloading the code from part 1 before you read this post.
The main LED Matrix caused me the most headaches figuring out all the hardware. However once this was done it’s actually one of the simpler parts of the system. The main challenge is just the sheer number of LEDs and the demands this puts on the Arduino. The Arduino has to store an array of every LEDs colour in its RAM and each LED needs 3 bytes. This adds up to (900×3) 2700 bytes or about 2.6kB. Unfortunately an Arduino Nano only has 2kB of RAM, so I had to go for the Arduino Mega (8kB RAM). The wiring for the matrix is by far the simplest of all the controllers.
The Arudino Mega is powered by the USB cable from your old laptop (or chosen controller). The LEDs are powered from one of the PC power supplies. Keep in mind here that 900 ws2812 LEDs at full noise (white at maximum brightness) will draw over 50 Amps. This is much more than most PC power supplies can handle on their 5V rail (eg a Corsair CX430 can only provide 20Amps). For this reason, and because it’s not really needed I have limited the brightness of the LEDs in the code. Obviously this can be changed but do so at your own risk. The data line from the LEDs connects to Pin 2 of the Arduino Mega. Also remember to connect a ground from the power supply to the Arduino Mega. This will help keep the data signal consistent. As each row was 50 LEDs and the strips come in lengths of 150, you will need to cut them into three sections. Each time you cut a section you just need to solder a short length of cable from each of the three pins (5V, Data, GND) to the corresponding ones. The same applies when joining one strip to another. See image below for a rough schematic. The code assumes that the top left LED is the first in the chain. The numbers then increase as you move to the right. For the second line the numbers increase as you move to the left and then repeat.
The Arduino code for the Matrix consists of four files:
- Matrix Controller (most constants are defined here and any images used)
- a_Globals_Setup (global variables are defined here, as is the initial setup function)
- b_Main_Control (loop function and the bulk of the processing is done here)
- c_Text_Functions (some functions that help display text are defined here, I got a lot of this code from a site online and I feel really bad that I can’t remember who it was)
In addition to these files, you will also need to get the FastLED library from here. This library provides the basic functionality for turning the LED lights on and off and changing their colour. Follow the instructions here to get it setup in the Arduino IDE. Below we will have a look at what is in each file.
As mentioned this file defines all the constants used in the program. These include codes for the serial communications, the size of the LED matrix, and any images that you want to display. Lets have a look at a few interesting sections:
#include <avr/pgmspace.h> #include <FastLED.h> #define LED_PIN 2 #define ROWS 18 #define COLUMNS 50 #define NUM_LEDS ROWS*COLUMNS #define CHAR_WIDTH 5 #define BAUD 9600 #define COLOUR_MESSAGE 1 #define TEXT_MESSAGE 2 #define TEAM1_MESSAGE 3 #define TEAM2_MESSAGE 4 #define START_MESSAGE 5 #define SCORE_MESSAGE 6 #define GAME_TEXT_MESSAGE 7 #define GAME_MATRIX_MESSAGE 8 #define GAME_SCORE_MESSAGE 9 const byte END_MARKER = 255;
The first two lines add in the required libraries. FastLED as mentioned above, and the built in pgmspace library. The pgmspace library allows the large image arrays to be stored the flash memory of the device. As flash memory is much larger than RAM (256kB instead of 8kB on the mega), this means you can stored a lot more images.
LED_PIN is the physical pin number that the data line connects to. The next three lines define the size of the array, you can modify this if you have a different number of LEDs. CHAR_WIDTH is width of any text that is displayed. Don’t change this unless you want to redo the text array. The BAUD variable defines the serial comms speed. Make sure this matches up with your PC program. The remaining lines are codes for different types of serial messages. This code is the first character in a serial message and will define what is done with the remaining information. The final line is an end of message marker for the serial communications.
The remainder of this file has an array that defines all the letters of the alphabet (upper case only), and a bunch of images. These can be made using the Image to RGB Array tool. At the moment there is a bunch of flags and the Maker Hacker logo, but you can change them to whatever you like. There are also some smaller flags defined for the scoreboard.
This file defines the global variables used within the program. The first few lines are the serial comms message and a flag to detect new messages. The remainder defines information that makes up the current state of the LED array. Things like the text colour, text string, team information etc. The setup function is pretty basic. It sets up the array for the FastLED library, opens the serial port, then displays the Maker Hacker logo for four seconds. It also limits the brightness of the LEDs to 50% for the reasons mentioned above.
This is business part of the code. The loop function exists here, which runs constantly checking for new serial messages, and if the game has started run the game animation. The first line of loop function sends a message to the PC saying it is ready to receive data. It then waits for a 50ms to receive data, if it doesn’t get any, it moves one. This is due to the fact that when the FastLED library updates the LED colours it disables interrupts. This means that the Arduino can’t receive serial messages.
Below is a summary of the rest of the functions and what they do:
- showScoreboard (no arguments, displays the current score board)
- showImage (Displays an image on the matrix. Image must match the matrix size. Takes an image as an argument, these are defined in the Matrix Controller file.)
- showImageAt (Displays an image at a location. Arguments are: image, size width and height, coordinate for the top left corner (x,y), the final argument is a bool that decides if any other image should be cleared before displaying the new image)
- showText (Displays text in the middle left of the matrix. Arguments are the text string and its length)
- showTextAt (Displays text at a position, arguments are text, text length, top left co-ordinates and bool to clear previous info or not)
- processData (checks a serial message and makes changes based on the info it contains)
- showGameIntro (Shows the flags from each team at the start of the game)
- showGameEnd (Shows the “Game Over” text)
- recvWithEndMarker (receive a serial message)
- coordToLEDNum (Converts an x,y co-ordinate to the LED number. LED number 0 is the top left LED and then works backwards and forwards down the table. This saves a lot of cable but makes the calculation more complicated).
As mentioned a lot of this code was written by someone else and can’t recall who. These functions are used to display individual characters in a text string. Below is a summary of the functions and what they do:
- showLetter (displays a letter at a location, x, y coordinates)
- convertToLocation (converts the byte (first column of the letter) into x,y coordinates)
- findLetterIndex (converts the ASCII value of a letter into the array index required to collect the right character from the text array)
Hopefully this has cleared up the workings of the Matrix part of the table. Looking back over the code as I wrote this, there is definitely room for improvement. However I think the code is solid and reasonably easy to follow. Stay tuned for the next part and feel free to leave a comment or reach out to me via the socials and I will be happy to help.