Advice on connection from MAX7221 to Arduino Uno with video

Hey everybody,
Please see my video below for a full explanation and any advice offered would be great!

Here is the code I am using:

/* code for max 7219 from maxim, 
reduced and optimised for using more then one 7219 in a row,
______________________________________

General notes: 


-if you are only using one max7219, then use the function maxSingle to control
 the little guy ---maxSingle(register (1-8), collum (0-255))

-if you are using more then one max7219, and they all should work the same, 
then use the function maxAll ---maxAll(register (1-8), collum (0-255))

-if you are using more than one max7219 and just want to change something
at one little guy, then use the function maxOne
---maxOne(Max you wane controll (1== the first one), register (1-8), 
collum (0-255))

/* During initiation, be sure to send every part to every max7219 and then
 upload it.
For example, if you have five max7219's, you have to send the scanLimit 5 times
before you load it-- other wise not every max7219 will get the data. the
function maxInUse  keeps track of this, just tell it how many max7219 you are
using.
*/

#include <Wire.h> 

int dataIn = 2;            // "DIN" on module
int load = 3;              // "CS" on module
int clock = 4;             // ""CLK" on module
const int ledPin =  13;    // the number of the LED pin

int maxInUse = 1;    //change this variable to set how many MAX7219's you'll use
int ledState = LOW;         // ledState used to set the LED

int e = 0;                 // just a varialble

                     // define max7219 registers
byte max7219_reg_noop        = 0x00;
byte max7219_reg_digit0      = 0x01;
byte max7219_reg_digit1      = 0x02;
byte max7219_reg_digit2      = 0x03;
byte max7219_reg_digit3      = 0x04;
byte max7219_reg_digit4      = 0x05;
byte max7219_reg_digit5      = 0x06;
byte max7219_reg_digit6      = 0x07;
byte max7219_reg_digit7      = 0x08;
byte max7219_reg_decodeMode  = 0x09;
byte max7219_reg_intensity   = 0x0a;
byte max7219_reg_scanLimit   = 0x0b;
byte max7219_reg_shutdown    = 0x0c;
byte max7219_reg_displayTest = 0x0f;



void putByte(byte data) {
  byte i = 8;
  byte mask;
  while(i > 0) {
    mask = 0x01 << (i - 1);      // get bitmask
    digitalWrite( clock, LOW);   // tick
    if (data & mask){            // choose bit
      digitalWrite(dataIn, HIGH);// send 1
    }else{
      digitalWrite(dataIn, LOW); // send 0
    }
    digitalWrite(clock, HIGH);   // tock
    --i;                         // move to lesser bit
  }
}

void maxSingle( byte reg, byte col) {    
//maxSingle is the "easy"  function to use for a     //single max7219

  digitalWrite(load, LOW);       // begin     
  putByte(reg);                  // specify register
  putByte(col);        //((data & 0x01) * 256) + data >> 1); // put data   
  digitalWrite(load,HIGH); 
}

void maxAll( byte reg, byte col) {    // initialize  all  MAX7219's in the system
  int c = 0;
  digitalWrite(load, LOW);  // begin     
  for ( c =1; c<= maxInUse; c++) {
  putByte(reg);                  // specify register
  putByte(col);             //((data & 0x01) * 256) + data >> 1); // put data
    }
  digitalWrite(load,HIGH);
}

void maxOne(byte maxNr, byte reg, byte col) {    
//maxOne is for adressing different MAX7219's, 
//while having a couple of them cascaded

  int c = 0;
  digitalWrite(load, LOW);  // begin     

  for ( c = maxInUse; c > maxNr; c--) {
    putByte(0);    // means no operation
    putByte(0);    // means no operation
  }

  putByte(reg);  // specify register
  putByte(col);//((data & 0x01) * 256) + data >> 1); // put data 

  for ( c = maxNr-1; c >= 1; c--) {
    putByte(0);    // means no operation
    putByte(0);    // means no operation
  }

  digitalWrite(load,HIGH); 
}

void putCol( byte colno, byte coldat) {
// Interprets colno as (zero ref) index in combined array
    byte t;
    t = colno >> 3;
    byte u;
    u = colno & 0x07;
    maxOne(t+1, u+1, coldat);
}


void dispon () {
 maxAll(max7219_reg_shutdown, 0x01);               // Display on
}  

void dispoff () {
 maxAll(max7219_reg_shutdown, 0x00);              // Display off
}  

byte irow = 0;          // Row index
byte icol = 0;          // Column index
byte pattern;           // bit mask
byte lcol;              // left border
byte rcol;              // right border
byte trow;              // top row marker
byte brow;              // bottom row marker

int s_vert;             // Vertical switch
int s_horz;             // Horizontal switch

// the follow variable is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 40;           // interval at which to blink (milliseconds)
long previousMillis = 0;      // will store last time LED was updated
int scantype = 0;             // switch mode

void worker () {

  if (pattern == 0) pattern = trow;            // pattern must be set
  if (s_vert != 0) {
    if (s_vert == -1) {                     // moving upward
      pattern = pattern >> 1;
      if (pattern == trow) {                   // hit the top
        s_vert = 0; s_horz = 1;
      }
    } else {
      pattern = pattern << 1;               // moving downward
      if (pattern == brow) {                // hit the bottom
        s_vert = 0; s_horz = -1;
      }
    }
    putCol(icol,pattern);              // Show the column.
    return;
  }

  if (s_horz != 0) {
    putCol(icol,0);                    // blank previous column.
    if (s_horz == -1) {                     // moving left
      icol--;
      if (icol == lcol) {                      // hit the side
        s_horz = 0; s_vert = -1;
      }
    } else {
      icol++;                               // moving right
      if (icol == rcol) {                      // hit the side
        s_horz = 0; s_vert = 1;
      }
    }
    putCol(icol,pattern);              // Show the column.
  }
 }
  

void setup () {

  pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,   OUTPUT);
  pinMode(ledPin, OUTPUT);      

  //Serial begin(9600);
  digitalWrite(13, HIGH);  

//initiation of the max 7219
  maxAll(max7219_reg_displayTest, 0x00); // no display test
  maxAll(max7219_reg_scanLimit, 0x07);      
  maxAll(max7219_reg_decodeMode, 0x00);  // using an led matrix (not digits)
  maxAll(max7219_reg_shutdown, 0x01);    // not in shutdown mode
  for (e=1; e<=8; e++) {        // empty registers, turn all LEDs off 
    maxAll(e,0);
  }
  maxAll(max7219_reg_intensity, 0x08 & 0x0f);    // the first 0x0f is the value you can set
                                                 // range: 0x00 to 0x0f
                                                 
  pattern = 0;
  scantype = 0;
  s_vert = 0;
  s_horz = 1;
  lcol = 1;              // left border
  rcol = 6;              // right border
  trow = 0x02;           // top row marker
  brow = 0x40;           // bottom row marker      
      
}  

void loop () {


  //if you use just one MAX7219 it should look like this
   /*  
   maxSingle(1,1);                       //  + - - - - - - -
   maxSingle(2,2);                       //  - + - - - - - -
   maxSingle(3,4);                       //  - - + - - - - -
   maxSingle(4,8);                       //  - - - + - - - -
   maxSingle(5,16);                      //  - - - - + - - -
   maxSingle(6,32);                      //  - - - - - + - -
   maxSingle(7,64);                      //  - - - - - - + -
   maxSingle(8,128);                     //  - - - - - - - +
  */
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    // Alternate 1

    }
    else {
      ledState = LOW;

    // Alternate 2
    // set the LED with the ledState of the variable:
    // Timed process:
    
    worker();

    }

    digitalWrite(ledPin, ledState);

    }

}

Bump again

What problem do you have at the moment the only advice I'd give you is use a second power supply for the leds.

Mark

Not directly related to your problem, but unless that LED on pin 13 has a integral current-limiting resistor suitable for 5V, you're overloading that Arduino pin. (As a diagnostic aid, the external LED doesn't seem to add any benefit to the existing onboard LED.)

I assume that your LED driver modules are driving analog output voltages which are designed to be wired up to LEDs in some way. How are they wired up, and what is the circuit intended to be between the controller board, the power supply for the LEDs, and the LEDs?

Are you powering the controller and LEDs connected to it from the Arduino's 5V line? What's the total current draw of that lot?

I agree with the previous comments.

From what you've posted, it's hard to tell what diagnostics you've performed and where your problem might be. Have you checked out the LEDs manually? Can you illuminate each LED individually using a 5V power supply and a resistor (as Peter warns about).

I'm not sure that checking the voltage levels like you did might not add to the confusion. I assume that you don't have an oscilliscope to check the Clock and Data from the Arduino.

I used an 8 segment green LED bar graph with a single 7221. I measured about 0.12 volts at the 7221 Digit output (LED cathode) and 1.0-1.4 volts at the 7221 segment output (LED anode). Effectively, measuring at these points shows the voltage across the LED. The 7221 scheme of LED driving results in an average LED voltage that is lower than you'd expect for green LEDs. More typical for green LEDs is 3V+.

I used the Arduino SPI interface. In your set up, if you change the 7221 DIN connection from pin 2 to pin 11 on the Arduino and the CLK from pin 4 to pin 13, the code below could work for you. This program only used digit 1 of the 7221 outputs. On the DIP package I have this is the "pin 2" referenced below. Note that you are using a different package and the pin assignments may be different.

//LED Bar display test

//  I hooked up the cathodes of 8 LEDs to the segment outputs of the 7221 
//  (pins 14, 16, 20, 23, 21, 15, 17 and 22) and tied all the cathodes to 
//  digit 0 (pin 2).

//  I used the SPI interface.  My Duemilanove, this uses pin 11 (MOSI) to 7221 pin 1 (DIN)
//  and Duemilanove pin 13 (Clock) to 7221 pin 4 (CLK)
//  I used Duemilanove pin 3 as the chip select connected to pin 12 of the 7221

//  Running this simplified program showed that the SPI worked, that I could command the 7221,
//  and that the LEDs were wired properly.


//  NOTE: Funny results when using a 4.7k resistor to control intensity.  Sometimes the display would shut down.
//  Switching to 10K resulted in more stable operation although it still sometimes quits after 10 cycles or so.
//  The 7221 does not get warm.  Since I could always get
//  the circuit to work properly by resetting the Arduino, I have not yet resolved this issue.


#include <SPI.h>  
const int slaveSelect = 3;         //chip select

#define MAX72_DECODE 0x09
#define MAX72_ENABLE 0x0C
#define MAX72_DISPLAYTEST 0x0F

void setup()
{  SPI.begin(); // initialize SPI
   pinMode(slaveSelect, OUTPUT);
   sendCommand(MAX72_ENABLE, 1);                        //7221 enabled
   sendCommand(MAX72_DECODE, 0x00);               //disable 7-segment decoding
}

void loop()
{   for (int i=0; i<=255;i++)                    
        {  sendCommand(1, i);
           delay(20);
        }
}

void sendCommand( int command, int value)
{   digitalWrite(slaveSelect,LOW); //chip select is active low
//2-byte data transfer to the 7221
   SPI.transfer(command);
   SPI.transfer(value);
   digitalWrite(slaveSelect,HIGH); //release chip, signal end transfer
}

Hi,
Thanks so much for your replies. I am really struggling to understand everything you say but am trying.

Ok - the board is from Harrison at Volpin props. I don't know how it is wired up and there's very little information on it. All I know is that he used a Yellowjacket with his matrix and he has sent me the code that was made for him which corrected the fact he had wired the LEDs the wrong way around (with cathode in columns instead of rows). I have NOT wired mine the wrong way round, so my cathodes are in rows and my anodes are in columns. You can see an example of his boards being wired here:

I have checked every single LED in the matrix, using the wires I have soldered on and each on lights up ok.

I have uploaded the code that arloG kindly posted but I get no response from the matrix (having changed the PIN outs on the Arduino) and the onboard LED on the Arduino Uno does not flash.

I do not know how much current it is drawing as it depends on the code that is running and how many LEDs are being lit (from what I have read).

I do have a separate battery power supply which is linked up through a voltage regulator but I am not sure what wires to connect where in order to use it. Does the ground go from the voltage regulator to the Volpin board, then to the Arduino, then back to the voltage regulator? I don't know :~

All the grounds should be connected.

It seems to me that none of us understand how this is supposed to be powered so I suggest you find that out from the vendor. The Arduino's 5V pin is only good for a couple of hundred milliamps and it looks to me as if you could easily exceed that with this lot.

Ok thanks. I think you're right, I might need to find more info from Harrison. When you say all the grounds should be connected, do you mean all together or through the arduino somehow?

MAX7221 Gnds must connect to power supply Gnd.
Arduino Gnd must connect to power supply Gnd.
Ideally, all Gnds would connect to Gnd at the power supply.

My program does not flash the on-board LED.

Obviously you've got to get the power issue sorted.

I see in your video that you've got 7221 boards that you haven't wired up yet. To investigate the software side of your project, maybe you could get a few LEDs and run some tests that won't require the external power supply. You'll need to connect the three signal wires from the 7221 to the Arduino: the clock, DIN and Chip Select. Also connect the Arduino Vcc to power the 7221 board and make sure the Arduino ground is connected to the 7221 board ground.

Connect some LEDs up. Tie all the cathode to D0 of the 7221 board. Connect one anode each to the segment pins "a", "b", etc. (you don't have to do all eight at first). To avoid drawing too much power, modify my earlier code by replacing the loop with this:

void loop()
{ int temp;
for(int j=0; j<20;j++)                          //change speed
  {  for (int i=0; i<=7;i++)                    //move light to left
        {  temp=1<<i;
           sendCommand(1, temp);
           delay(5+10*j);
        }
     for (int i=0; i<=7;i++)                    //and then to the right
        {  temp=128>>i;
           sendCommand(1, temp);         
           delay(5+10*j);
         }
  }
}

It only lights one LED at a time so power shouldn't be an issue. This version also doesn't have the unexpected shut-downs my earlier version did. If it works, you should see the LEDs be illuminated one by one. If this all works, you could then debug your software using the code you originally posted. Or write your own that better suits you purpose.

Good luck, you daft punk.

Hi,
Just to update you on this issue, I took it over to my friend who is far more intelligent than me and we spent a good few hours checking code, looking at the very limited pictures of the board and finally the chip data sheet. He was as stuck as me until we got to the chip data sheet and realised that.....the chip was in the wrong way around!

For some reason Harrison has made his v2 boards so that the chip must be mounted 'upside-down' which I obviously didn't know about. Everything is working great now and I have got this simple 'Cylon' test working.

#include "LedControl.h"
#include <binary.h>

int DIN = 12; // This is the PIN that the DATA IN is set to on the Arduino
int CLK = 11; // This is the PIN that the CLOCK is set to on the Arduino
int LOADCS = 10; // This is the PIN that the LOAD or CS is set to on the Arduino
int FlashDelay = 1; // This is the delay in MS, 1000 = 1 second
int LEDBrightness = 15; // This is the brightness that the LEDs will be, 0-15, 0 = dimmest, 15 = brightest

 //This is referencing the PINs above and loading them for the LED control.
 //If you have more than one MAX chip then change the number after LOADCS from 1 to however many chips you have
LedControl lc=LedControl(DIN,CLK,LOADCS,5);

void setup()
{
  lc.shutdown(0,false);
  lc.setIntensity(0,LEDBrightness);
  for(int index=0;index<lc.getDeviceCount();index++) {
      lc.shutdown(index,false);
  }
}

void loop()
{
  lc.setColumn(0,0,B11111111);
  lc.setColumn(0,1,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,0,B00000000);
  lc.setColumn(0,2,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,1,B00000000);
  lc.setColumn(0,3,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,2,B00000000);
  lc.setColumn(0,4,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,3,B00000000);
  lc.setColumn(0,5,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,4,B00000000);
  lc.setColumn(0,6,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,5,B00000000);
  lc.setColumn(0,7,B11111111);
  delay(FlashDelay);
 
  lc.setColumn(0,6,B00000000);
  lc.setColumn(1,0,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,7,B00000000);
  lc.setColumn(1,1,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,0,B00000000);
  lc.setColumn(1,2,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,1,B00000000);
  lc.setColumn(1,3,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,2,B00000000);
  lc.setColumn(1,4,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,3,B00000000);
  lc.setColumn(1,5,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,4,B00000000);
  lc.setColumn(1,6,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,5,B00000000);
  lc.setColumn(1,7,B11111111);
  delay(FlashDelay);
 
  lc.setColumn(1,6,B00000000);
  lc.setColumn(2,0,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,7,B00000000);
  lc.setColumn(2,1,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,0,B00000000);
  lc.setColumn(2,2,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,1,B00000000);
  lc.setColumn(2,3,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,2,B00000000);
  lc.setColumn(2,4,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,3,B00000000);
  lc.setColumn(2,5,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,4,B00000000);
  lc.setColumn(2,6,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,5,B00000000);
  lc.setColumn(2,7,B11111111);
  delay(FlashDelay);

  lc.setColumn(2,6,B00000000);
  lc.setColumn(3,0,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,7,B00000000);
  lc.setColumn(3,1,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,0,B00000000);
  lc.setColumn(3,2,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,1,B00000000);
  lc.setColumn(3,3,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,2,B00000000);
  lc.setColumn(3,4,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,3,B00000000);
  lc.setColumn(3,5,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,4,B00000000);
  lc.setColumn(3,6,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,5,B00000000);
  lc.setColumn(3,7,B11111111);
  delay(FlashDelay);

  lc.setColumn(3,6,B00000000);
  lc.setColumn(4,0,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,7,B00000000);
  lc.setColumn(4,1,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,0,B00000000);
  lc.setColumn(4,2,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,1,B00000000);
  lc.setColumn(4,3,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,2,B00000000);
  lc.setColumn(4,4,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,3,B00000000);
  lc.setColumn(4,5,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,4,B00000000);
  lc.setColumn(4,6,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,5,B00000000);
  lc.setColumn(4,7,B11111111);
  delay(FlashDelay);

  lc.setColumn(4,7,B00000000);
  lc.setColumn(4,5,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,6,B00000000);
  lc.setColumn(4,4,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,5,B00000000);
  lc.setColumn(4,3,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,4,B00000000);
  lc.setColumn(4,2,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,3,B00000000);
  lc.setColumn(4,1,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,2,B00000000);
  lc.setColumn(4,0,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,1,B00000000);
  lc.setColumn(3,7,B11111111);
  delay(FlashDelay);
  lc.setColumn(4,0,B00000000);
  lc.setColumn(3,6,B11111111);
  delay(FlashDelay);
 
  lc.setColumn(3,7,B00000000);
  lc.setColumn(3,5,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,6,B00000000);
  lc.setColumn(3,4,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,5,B00000000);
  lc.setColumn(3,3,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,4,B00000000);
  lc.setColumn(3,2,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,3,B00000000);
  lc.setColumn(3,1,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,2,B00000000);
  lc.setColumn(3,0,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,1,B00000000);
  lc.setColumn(2,7,B11111111);
  delay(FlashDelay);
  lc.setColumn(3,0,B00000000);
  lc.setColumn(2,6,B11111111);
  delay(FlashDelay);
 
  lc.setColumn(2,7,B00000000);
  lc.setColumn(2,5,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,6,B00000000);
  lc.setColumn(2,4,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,5,B00000000);
  lc.setColumn(2,3,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,4,B00000000);
  lc.setColumn(2,2,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,3,B00000000);
  lc.setColumn(2,1,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,2,B00000000);
  lc.setColumn(2,0,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,1,B00000000);
  lc.setColumn(1,7,B11111111);
  delay(FlashDelay);
  lc.setColumn(2,0,B00000000);
  lc.setColumn(1,6,B11111111);
  delay(FlashDelay);
 
  lc.setColumn(1,7,B00000000);
  lc.setColumn(1,5,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,6,B00000000);
  lc.setColumn(1,4,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,5,B00000000);
  lc.setColumn(1,3,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,4,B00000000);
  lc.setColumn(1,2,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,3,B00000000);
  lc.setColumn(1,1,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,2,B00000000);
  lc.setColumn(1,0,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,1,B00000000);
  lc.setColumn(0,7,B11111111);
  delay(FlashDelay);
  lc.setColumn(1,0,B00000000);
  lc.setColumn(0,6,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,7,B00000000);
  lc.setColumn(0,5,B00000000);
 
  lc.setColumn(0,7,B00000000);
  lc.setColumn(0,5,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,6,B00000000);
  lc.setColumn(0,4,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,5,B00000000);
  lc.setColumn(0,3,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,4,B00000000);
  lc.setColumn(0,2,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,3,B00000000);
  lc.setColumn(0,1,B11111111);
  delay(FlashDelay);
  lc.setColumn(0,2,B00000000);
  lc.setColumn(0,0,B11111111);
}

Upside down? You can be sure that you're not the only person who's struggled with this.

Congrats.