Using a Max7219 8×8 LED Matrix with an ATTINY85, like Trinket or DigiSpark

While waiting for part two of the handheld construction article, I thought I’d give you a little distraction about interfacing an ATTINY85 to an 8×8 LED Matrix using the Max7219 chip.

ATTINY85LEDMatrix1Been working on getting either a DigiSpark or Trinket to work with one of my 8×8 LED matrix displays. Connection is simple, but the maxmatrix library doesn’t seem to like the ATTINY85 processor. So, I went looking for something that did or, at least, getting enough knowledge to bit bang my way to displaying SOMETHING on the little display. Well, I found some code to do this, but it is not very pretty and doesn’t do enough. However, it does give a good demo of how to make these arrays do something and, even better, work with the confines of the ATTINY85 processor.
The code shows how turn on and off pixels (a specific LED in the matrix, to be more precise) and send a ‘bitmap’ to the display.
Cool stuff. Could be another game or, perhaps, a temperature display, mood indicator, etc.

You can grab the code I used (middle of the page) here…http://www.avrfreaks.net/…/max7219-8×8-dot-matrix-led-drive…

FYI-To connect it:
PB0 -> DIN
PB1 -> CS
PB2 -> CLK
+5 -> VCC
GND -> GND

Pretty easy. ATTINY85LEDMatrix21

The code I found puts a smiley face, inverts the screen, frowny face, etc. up on the display. I took out the inversion as it takes too much time.  This code, which is unattributed as the poster on the AVR forum did not credit the code, is a good start, but needs work.  I thought about modifying it to handle ASCII text, but that will be a ways off yet. I have several things to finish up before then. 

I’d love to see what you can do with this, so drop us a note in the comments or send me an email and I’d be happy to write it up and post it here.

Code:

/*
  One MAX7219 connected to an 8x8 LED matrix.
 */

#include <avr/io.h>
#include <util/delay.h>

#define CLK_HIGH()  PORTB |= (1<<PB2)
#define CLK_LOW()   PORTB &= ~(1<<PB2)
#define CS_HIGH()   PORTB |= (1<<PB1)
#define CS_LOW()    PORTB &= ~(1<<PB1)
#define DATA_HIGH() PORTB |= (1<<PB0)
#define DATA_LOW()  PORTB &= ~(1<<PB0)
#define INIT_PORT() DDRB |= (1<<PB0) | (1<<PB1) | (1<<PB2)

uint8_t smile[8] = {
        0b00000000,
        0b01100110,
        0b01100110,
        0b00011000,
        0b00011000,
        0b10000001,
        0b01000010,
        0b00111100};

uint8_t sad[8] = {
        0b00000000,
        0b01100110,
        0b01100110,
        0b00011000,
        0b00011000,
        0b00000000,
        0b00111100,
        0b01000010,
};


void spi_send(uint8_t data)
{
    uint8_t i;

    for (i = 0; i < 8; i++, data <<= 1)
    {
  CLK_LOW();
  if (data & 0x80)
      DATA_HIGH();
  else
      DATA_LOW();
  CLK_HIGH();
    }
    
}

void max7219_writec(uint8_t high_byte, uint8_t low_byte)
{
    CS_LOW();
    spi_send(high_byte);
    spi_send(low_byte);
    CS_HIGH();
}

void max7219_clear(void)
{
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
  max7219_writec(i+1, 0);
    }
}

void max7219_init(void)
{
    INIT_PORT();
    // Decode mode: none
    max7219_writec(0x09, 0);
    // Intensity: 3 (0-15)
    max7219_writec(0x0A, 1);
    // Scan limit: All "digits" (rows) on
    max7219_writec(0x0B, 7);
    // Shutdown register: Display on
    max7219_writec(0x0C, 1);
    // Display test: off
    max7219_writec(0x0F, 0);
    max7219_clear();
}


uint8_t display[8];

void update_display(void)
{
    uint8_t i;

    for (i = 0; i < 8; i++)
    {
  max7219_writec(i+1, display[i]);
    }
}

void image(uint8_t im[8])
{
    uint8_t i;

    for (i = 0; i < 8; i++)
  display[i] = im[i];
}

void set_pixel(uint8_t r, uint8_t c, uint8_t value)
{
    switch (value)
    {
    case 0: // Clear bit
  display[r] &= (uint8_t) ~(0x80 >> c);
  break;
    case 1: // Set bit
  display[r] |= (0x80 >> c);
  break;
    default: // XOR bit
  display[r] ^= (0x80 >> c);
  break;
    }
}


int main(void)
{
    uint8_t i;
    
    max7219_init();
    
    while(1)
    {
  image(sad);
  update_display();
  _delay_ms(500);
  image(smile);
  update_display();
  _delay_ms(500);

  // Invert display
//  for (i = 0 ; i < 8*8; i++)
//  {
//      set_pixel(i / 8, i % 8, 2);
//      update_display();
//      _delay_ms(10);
//  }
  _delay_ms(500);
    }
}

 

 

9 thoughts on “Using a Max7219 8×8 LED Matrix with an ATTINY85, like Trinket or DigiSpark

  1. i’m a relative newcomer to arduino, definitely to the LED matrix. Here’s my error when I run the code:
    ‘__flash’ does not name a type

      1. Sorry, I told you wrong (that will teach me to reply without re-reading the post.) You were referring to the code on the linked page. You must be using a newer version of the IDE. Remove the CONST __flash and it should work.

  2. Hi! Now I have another question…the code works GREAT except…is there an easy way to rotate the direction of the smile 90 degrees? I know I can figure it out eventually by remapping basically everything, just hoping there’s maybe an easier way.

    1. Unfortunately, not in this case. However, there is a nice library you can use that orients the display so that the pins are vertical and not horizontal as they are here.

  3. Great, thanks!

    The same code can control an 8-digit 7-segment display. The digits are encoded thus:
    uint8_t ZERO = 0b01111110;
    uint8_t ONE = 0b00110000;
    uint8_t TWO = 0b01101101;
    uint8_t THREE = 0b01111001;
    uint8_t FOUR = 0b00110011;
    uint8_t FIVE = 0b01011011;
    uint8_t SIX = 0b00011111;
    uint8_t SEVEN = 0b01110000;
    uint8_t EIGHT = 0b01111111;
    uint8_t NINE = 0b01110011;
    uint8_t DOT = 0b10000000;

Leave a comment