Klaas
Posts: 1
Joined: Mon Feb 04, 2013 10:28 pm

[SPI] LED Matrix using Maxim MAX7221

Wed Apr 24, 2013 9:58 pm

I have been reading this board searching for information on how to control a LED Matrix. A lot of information was available and useful to get a LED Matrix working using a Maxim MAX7221. Via this post I want to share with you the "How to" on controlling the LED Matrix.

Build LED Matrix hardware

1. Only a couple of components are needed, see schematic:
SchematicMatrix8x8.png
Schematic
SchematicMatrix8x8.png (11.01 KiB) Viewed 5182 times
Make sure you also read the Data Sheet for the Maxim MAX7221

I build it on a test board first (on this picture I cascaded two matrix's).
TestSetup.jpg
Test Setup
TestSetup.jpg (55.91 KiB) Viewed 5182 times
The nice this about this schematic is that you can easily cascade multiple matrix's.

Setup the Raspberry Pi

1. Install the latest wheezy raspbian (2013-02-09).
2. Enable the SPI device

Code: Select all

sudo nano /etc/modules
>Add line: spi_bcm2708
3. Reboot

Code: Select all

sudo reboot
4. Check if SPI devices are available

Code: Select all

ls /dev/spi*
>Result should be: /dev/spidev0.0  /dev/spidev0.1
*** Always make sure your hardware is powered down before doing (re)connecting! ***

Create sample program, compile and run.

Below a sample program which generates some nice effects.

Code: Select all

/*********************************************
 * SPI to MAX7221 (using spidev driver)
 *********************************************/

#include <math.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

void timestamp(const char *s)
{
	time_t curtime;
	struct tm *loctime;
	char timestr [20];

	curtime = time(NULL);
	loctime = localtime(&curtime);
	strftime(timestr,20,"%H:%M.%S",loctime);
	
    printf("%s - %s",timestr,s);
}


static void pabort(const char *s)
{
	perror(s);
	abort();
}

static const char *device = "/dev/spidev0.0";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 200000;
static uint16_t delay;

static void matrixwrite(int fd, unsigned char max_address, unsigned char max_data)
{
	uint8_t tx[] = { max_address, max_data, };
	write(fd, tx, 2);
}

static void initspi(int fd)
{
	int ret = 0;

	/** spi mode **/
	ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
	if (ret == -1)
		pabort("can't set spi mode");

	ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
	if (ret == -1)
		pabort("can't get spi mode");

	/** bits per word **/
	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't set bits per word");

	ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't get bits per word");

	/** max speed hz **/
	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't set max speed hz");

	ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't get max speed hz");

}


void matrix_single(int fd, int delay, int repeat)
{
	uint8_t col; // Column
	uint8_t row; // Row
	uint8_t z;

	timestamp("2. single leds.\n");
	for (z = 1; z <= repeat; z++) {
		for (col = 1; col <= 8; col++) {
			for (row = 0; row <= 7; row++) {
				z = pow(2,row);
				matrixwrite(fd, col, z);
				usleep(delay);
			}
			matrixwrite(fd, col, 0);
		}
	}
}

void matrix_colwipe(int fd, int delay, int repeat)
{
	uint8_t col; // Column
	uint8_t row; // Row
	uint8_t z;

	timestamp("3. Column wipe.\n");
	for (z = 1; z <= repeat; z++) {
		for (col = 1; col <= 8; col++) {
			matrixwrite(fd, col, 0xFF);
			usleep(delay);
		}
		for (col = 1; col <= 8; col++) {
			matrixwrite(fd, col, 0x00);
			usleep(delay);
		}
	}
	for (z = 1; z <= repeat; z++) {
		for (col = 8; col >= 1; col--) {
			matrixwrite(fd, col, 0xFF);
			usleep(delay);
		}
		for (col = 1; col <= 8; col++) {
			matrixwrite(fd, col, 0x00);
			usleep(delay);
		}
	}
}


void matrix_linewipe(int fd, int delay, int repeat)
{
	uint8_t col; // Column
	uint8_t row; // Row
	uint8_t z;

	timestamp("4. Line wipe.\n");
	for (z = 1; z <= repeat; z++) {
		for (row = 0; row <= 7; row++) {
			z = pow(2,row);
			for (col = 1; col <= 8; col++) {
				matrixwrite(fd, col, z);
				usleep(delay);
			}
			for (col = 8; col >= 1; col--) {
				matrixwrite(fd, col, 0);
				usleep(delay);
			}
		}
	}
}

void matrix_linewipeupdown(int fd, int delay, int repeat)
{
	uint8_t col; // Column
	uint8_t row; // Row
	uint8_t z;

	timestamp("5. Line up/down.\n");
	for (z = 1; z <= repeat; z++) {
		for (col = 1; col <= 8; col++) {
			matrixwrite(fd, col, 0xFF);
			usleep(delay);
			matrixwrite(fd, col, 0);
		}
		for (col = 8; col >= 1; col--) {
			matrixwrite(fd, col, 0xFF);
			usleep(delay);
			matrixwrite(fd, col, 0);
		}
	}
}


void matrix_flash(int fd, int delay1, int delay2, int repeat)
{
	uint8_t col; // Column
	uint8_t row; // Row
	uint8_t z;

	timestamp("6. Flash.\n");
	
	for (z = 1; z <= repeat; z++) {
		for (col = 1; col <= 8; col++) {
			matrixwrite(fd, col, 0xFF);
		}
		usleep(delay1);		
		for (col = 1; col <= 8; col++) {
			matrixwrite(fd, col, 0x00);
		}
		usleep(delay2);		
	}
	
}


int main(int argc, char *argv[])
{
	int fd;

	fd = open(device, O_RDWR);

	if (fd < 0)
		pabort("can't open device");

	initspi(fd);

	printf("---------------------------------------\n");
	printf("spi mode: %d\n", mode);
	printf("bits per word: %d\n", bits);
	printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
	printf("---------------------------------------\n");
	
	uint8_t col; // Column

	//All leds off.
	for (col = 1; col <= 8; col++) { matrixwrite(fd, col, 0); }
	
	timestamp("1. Self test.\n");
	matrixwrite(fd, 0x0F, 0x01);
	usleep(500000);
	matrixwrite(fd, 0x0F, 0x00);
	usleep(500000);

	// Initialize Matrix
	matrixwrite(fd, 0x0C, 0x01); // Normal operation
	matrixwrite(fd, 0x0B, 0x07); // Scan Limit (all digits)
	matrixwrite(fd, 0x0A, 0x07); // Intensity
	matrixwrite(fd, 0x09, 0x00); // Decode mode (off)

	matrix_single(fd, 10000, 2);
	usleep(1000000);
	matrix_colwipe(fd, 20000, 5);
	usleep(1000000);
	matrix_linewipe(fd, 20000, 5);
	usleep(1000000);
	matrix_linewipeupdown(fd, 40000, 5);
	usleep(1000000);
	matrix_flash(fd, 30000, 70000, 20);

	timestamp("Completed.\n");

	//All leds off.
	for (col = 1; col <= 8; col++) { matrixwrite(fd, col, 0); }
	
	close(fd);

	return;
}
1. Connect LED Matrix to Raspberry Pi and start the Raspberry.

2. Copy the code above to your Raspberry Pi to a file called "matrix_test.c".

3. Compile the source:

Code: Select all

gcc -omatrixtest matrix_test.c -lm
Compiler warning can be ignored.

4. Start the program:

Code: Select all

sudo ./matrixtest
Result displayed (and your matrix should start blinking too... 8-) ):

Code: Select all

---------------------------------------
spi mode: 0
bits per word: 8
max speed: 200000 Hz (200 KHz)
---------------------------------------
23:43.01 - 1. Self test.
23:43.02 - 2. single leds.
23:43.04 - 3. Column wipe.
23:43.08 - 4. Line wipe.
23:43.12 - 5. Line up/down.
23:43.16 - 6. Flash.
23:43.18 - Completed.
Happy building... :D

metroroland
Posts: 2
Joined: Wed Jun 26, 2013 5:49 am

Re: [SPI] LED Matrix using Maxim MAX7221

Wed Jun 26, 2013 5:53 am

Hi,

I am using your solution. Yet what if I want to cascade multiple Max7221s? Do I need to change the' bits per word' parameter such that I can successful to write to different drivers?

User avatar
Richard-TX
Posts: 1549
Joined: Tue May 28, 2013 3:24 pm
Location: North Texas

Re: [SPI] LED Matrix using Maxim MAX7221

Sat Jun 29, 2013 1:14 pm

The Max7221 allows for cascading on the SPI bus so the limit on the number of devices on a RPI is fairly high. It appears to be unlimited. (How many no-op commands can you send?)

Look at page 10 and the diagram at the bottom of page 13 of the document at http://datasheets.maximintegrated.com/e ... AX7221.pdf

Nothing special is needed to address the different chips.

If four MAX7219s are cascaded, then to write to the fourth chip, sent the desired 16-bit word, followed by
three no-op codes. When LOAD/CS goes high, data is latched in all devices. The
first three chips receive no-op commands, and the fourth receives the intended data.

Think of it like a shift register and it will become clearer.
Richard
Doing Unix since 1985.
The 9-25-2013 image of Wheezy can be found at:
http://downloads.raspberrypi.org/raspbian/images/raspbian-2013-09-27/2013-09-25-wheezy-raspbian.zip

metroroland
Posts: 2
Joined: Wed Jun 26, 2013 5:49 am

Re: [SPI] LED Matrix using Maxim MAX7221

Tue Jul 02, 2013 5:51 am

Hi Richard-TX,

I am curious when some other solution on the web require custom setting of load/CS to high/low to latch data, this one doesn't require. I suspect there is some different in writing the tx[] to fd, or can spidev handle this automatically, when I write uint8_t tx[] = { 0,0,max_address, max_data, }; to it?

Regards,

Roland

RobertPHeller
Posts: 18
Joined: Thu Jun 18, 2015 1:27 pm
Location: Wendell, MA, USA
Contact: Website

Re: [SPI] LED Matrix using Maxim MAX7221

Wed Oct 26, 2016 8:41 pm

I am having trouble getting this to work on a Raspberry Pi B+ Model 2 (with the 40-pin header). Is this because this is a 3.3V device and not a 5V device, which the MAX7221 is meant for? My MAX7221 board works just fine with an Arduino driving it.
Robert Heller -- 978-544-6933
Deepwoods Software -- Custom Software Services
http://www.deepsoft.com/ -- Linux Administration Services
heller@deepsoft.com -- Webhosting Services

Return to “Interfacing (DSI, CSI, I2C, etc.)”