Linksprite LED Matrix

February 24, 2018

The LinkSprite is an 8 x 8 LED matrix that can be used when you need something more sophisticated than a single LED to give feedback. It also opens up the world of creating letters, numbers and basic shapes.

Extremely well documented, the Linksprite is very easy to get going – although, as I post this, the documentation site is down! I’ve had this unit for a few years, having only tried a basic sketch to spell out my name using this sketch:

 unsigned char i;
 unsigned char j; 
/*Port Definitions*/
int Max7219_pinCLK = 10;
int Max7219_pinCS = 9;
int Max7219_pinDIN = 8;
 
unsigned char disp1[38][8]={
{0x3C,0x8,0x8,0x8,0x8,0x8,0x48,0x30},//J
{0x7C,0x40,0x40,0x7C,0x40,0x40,0x40,0x7C},//E
{0x3C,0x22,0x22,0x22,0x3C,0x24,0x22,0x21},//R
{0x7C,0x40,0x40,0x7C,0x40,0x40,0x40,0x7C},//E
{0x81,0xC3,0xA5,0x99,0x81,0x81,0x81,0x81},//M
{0x41,0x22,0x14,0x8,0x8,0x8,0x8,0x8},//Y
};

void Write_Max7219_byte(unsigned char DATA) 
{ 
 unsigned char i;
 digitalWrite(Max7219_pinCS,LOW); 
 for(i=8;i>=1;i--)
 { 
 digitalWrite(Max7219_pinCLK,LOW);
 digitalWrite(Max7219_pinDIN,DATA&0x80);// Extracting a bit data
 DATA = DATA<<1;
 digitalWrite(Max7219_pinCLK,HIGH);
 } 
}

void Write_Max7219(unsigned char address,unsigned char dat)
{
 digitalWrite(Max7219_pinCS,LOW);
 Write_Max7219_byte(address); //address,code of LED
 Write_Max7219_byte(dat); //data,figure on LED 
 digitalWrite(Max7219_pinCS,HIGH);
}
 
void Init_MAX7219(void)
{
 Write_Max7219(0x09, 0x00); //decoding :BCD
 Write_Max7219(0x0a, 0x03); //brightness 
 Write_Max7219(0x0b, 0x07); //scanlimit;8 LEDs
 Write_Max7219(0x0c, 0x01); //power-down mode:0,normal mode:1
 Write_Max7219(0x0f, 0x00); //test display:1;EOT,display:0
}
 
void setup()
{
 pinMode(Max7219_pinCLK,OUTPUT);
 pinMode(Max7219_pinCS,OUTPUT);
 pinMode(Max7219_pinDIN,OUTPUT);
 delay(50);
 Init_MAX7219();
}
 
void loop()
{ 
 for(j=0;j<38;j++)
 {
 for(i=1;i<9;i++)
 Write_Max7219(i,disp1[j][i-1]);
 delay(500);
 } 
}

That was 2014. With my return to the Linksprite in 2018, I found it is even easier when you reference one of several LED Matrix builders available online.

Aside from getting familiar with the MAX7219 chip which does all the heavy lifting, I found the Linksprite to be very good for studying coding in general.  I thought maybe I’d work with it for a couple hours and get bored, but it became the focus of much of my weekend experiments as I tried different things.

There are a few behaviors to consider, and some concepts you must master for the Linksprite to work. The most important is arrays, which are used to store the various codes for the images. I use the term “images” here loosely, as what you can create with 8×8 LEDs/pixels is limited. Speed and intensity parameters also come into play, and its interesting how many ways you can tackle adjusting these parameters for different effects.

Using a tilt switch, I created two sets of behaviors. One just scrolls through some arrow shapes using a long-ish method of coding.

The second uses an array and some variables to create the appearance of a moving arrow (which is nothing more than a visual trick). Both behaviors show an increase in light intensity.

I tried a number of ways to load the images and change the intensity at the same time. I tried two FOR loops running in parallel, and a FOR within a FOR. Usually I ended up with intensity changing all at once, and sometimes stopping the motion in the process. The solution here is one of many potential options, but worked the best out of what I tried.

/* JJD 2/24/18 - 2/25/18
 * Matrix HEX code from https://xantorohara.github.io/led-matrix-editor
 * 
 * Linksprite LED Matrix v1.0 (MAX7219)
 * https://www.sparkfun.com/products/retired/11861
 * http://linksprite.com/wiki/index.php5?title=LED_Matrix_Kit
 * http://store.linksprite.com/max7219-8x8-red-dot-led-matrix-kit/
 * 
 * Tested with Redboard
 * Intensity of lights change along with animation, but there are a few ways to do this.
 * Not all of them work the same way. Method here gives smoothest transitions.
 * 
 * */

#include <LedControl.h>

int CLKPIN = 10;
int CSPIN = 9;
int DINPIN = 1;
int TILT = 13;
int buttonState = 0; // Variable for reading button
int arrowDelay = 1000;
int arrowToshow = 0;

// https://xantorohara.github.io/led-matrix-editor
const uint64_t IMAGES[] =
 {
 0x081c3e7f1c1c1c1c, // DOWN 0
 0x0010307fff7f3010, // RIGHT 1
 0x1c1c1c1c7f3e1c08, // UP 2 
 0x00080cfefffe0c08, // LEFT 3
 };

//DOWN ARROW ANIMATION
const uint64_t ARROWS[] = {
 0x081c3e7f1c1c1c1c,
 0x1c3e7f1c1c1c1c00,
 0x3e7f1c1c1c1c0000,
 0x7f1c1c1c1c000000,
 0x1c1c1c1c00000000,
 0x1c1c1c0000000000,
 0x1c1c000000000000,
 0x1c00000000000000,
 0x0000000000000000,
 0x0000000000000008,
 0x000000000000081c,
 0x0000000000081c3e,
 0x00000000081c3e7f,
 0x000000081c3e7f1c,
 0x0000081c3e7f1c1c,
 0x00081c3e7f1c1c1c
};

const int IMAGES_LEN = sizeof(IMAGES)/8;

LedControl display = LedControl(DINPIN, CLKPIN, CSPIN);

void setup(){
 pinMode(TILT, INPUT);
 display.clearDisplay(0);
 display.shutdown(0,false);
 display.setIntensity(0,5);
}

void displayImage(uint64_t image)
{
 for (int i = 0; i < 8; i++) {
 byte row = (image >> i * 8) & 0xFF;
 for (int j = 0; j <8; j++) {
 display.setLed(0,i,j,bitRead(row,j));
 }
 }
}

void loop() {

// Read the state of button or tilt
 buttonState = digitalRead(TILT);

// Remember that images are numbered starting at 0,1,2,3... etc
 /* Set the brightness of the display. void setIntensity(int addr, int intensity); 
 * Params:
 * addr the address of the display to control
 * intensity the brightness of the display.
*/
 if (buttonState == HIGH) {
 display.setIntensity(0,0);
 displayImage(IMAGES[3]);
 delay(500);
 display.setIntensity(0,1);
 displayImage(IMAGES[2]);
 delay(500);
 display.setIntensity(0,2);
 displayImage(IMAGES[1]);
 delay(500);
 display.setIntensity(0,3);
 displayImage(IMAGES[0]);
 delay(500);
 display.setIntensity(0,4);
 displayImage(IMAGES[3]);
 delay(500);
 display.setIntensity(0,5);
 displayImage(IMAGES[2]);
 delay(500);
 display.setIntensity(0,6);
 displayImage(IMAGES[1]);
 delay(500);
 display.setIntensity(0,7);
 displayImage(IMAGES[0]);
 delay(500);
 display.setIntensity(0,8);
 displayImage(IMAGES[3]);
 delay(500);
 display.setIntensity(0,9);
 displayImage(IMAGES[2]);
 delay(500);
 display.setIntensity(0,10);
 displayImage(IMAGES[1]);
 delay(500);
 display.setIntensity(0,11);
 displayImage(IMAGES[0]);
 delay(500);
 display.setIntensity(0,12);
 displayImage(IMAGES[3]);
 delay(500);
 display.setIntensity(0,13);
 displayImage(IMAGES[2]);
 delay(500);
 display.setIntensity(0,14);
 displayImage(IMAGES[1]);
 delay(500);
 display.setIntensity(0,15);
 displayImage(IMAGES[0]);
 delay(500);
 
 } else {
 for (int arrowToshow = 0; arrowToshow < 15; arrowToshow++)
 // the 15 here refers to the 16 arrows (0-15) in the array above. Could also make this a variable like IMAGES_LEN
 
 {
 static int count = 0; // setting this for use as intensity, initialize only once via static
 display.setIntensity(0,count); 
 displayImage(ARROWS[arrowToshow]); // use value from FOR loop to assign the arrow image from the array
 delay(arrowDelay); 
 count ++; // increment the intensity
 if (count > 16) // limit intensity to unit threshold 0-16
 {
 count = 0;
 }
 } // close 1st FOR

} // END ELSE
} // END MAIN LOOP

This was a lot of fun and gave me some ideas for how to work this into some of my other projects. One could set a arrow to flash down/up when a temperature reaches too low/high. These LEDs are very bright and could be seen from far away if necessary.

Of course, since these came out in 2012/2014, many more sophisticated LED and NeoPixel devices are available. There’s still lots to learn from even a small 8×8 matrix – time well spent!