74HC595 ghosting/shadowing problem

Hello everyone,

I've made a board with an atmega328 running the arduino bootloader to drive an 11x15 LED matrix.

I'm using two 74HC595s to step through each row of the matrix and as far as I can tell the hardware is all correct, but there is one very small problem that's causing major issues - when I switch to the next row the LED just below in the previous row will stay lit at about 50% power.

I'll post a link to a video of a slow scan through each row with all columns "on" after this post (first posts don't allow links) so you can see the problem.

After a bit of googling i've read that "blanking" the shift registers will fix it, but.. how? Sending '0' 15 times to shiftout doesn't do it (and I hope it's just that i'm doing something stupid).

Here's basically the code i'm using (i'm at work right now so don't have access to the actual file):

Set all column pins to LOW

for j=0-14{
r = 1<<j
latchPin LOW
shiftOut(data,clock,MSBFIRST,r)
latchPin HIGH
}

Could someone kindly explain to me the proper way to do this? I'm still new to the world of making electronics, but it seems like such a simple thing: power one and only one row one after the other. I can't seem to get it right.

Thank you very much for your time,
Travis

Here's the link to the video: - YouTube

It's supposed to be lighting each row for 50ms, but as you can see there are two rows lit. It's not just the camera being slow, but one of the rows is actually dimmer which isn't seen in the video very well.

The shift registers are 16 bits total, yes? How you account for the 16th bit?
Are you completely turning off the row before turning on the next row?

Oops, yes the two shift registers have 8 bits of output x 2 = 16bits. Accounting in hardware I simply leave the last 'bit' pin alone, in software I said 15 times but meant 16 (0-15 hah).

I may not be completely turning it off. I think that's what they meant by clearing the display. How would one be sure that that previous row was completely off?

Ah, unless you meant the 0-14 loop. I tried 0-15 to make sure both bytes were being sent data as well. I think that may be where my code is right now to be honest, but it didn't seem to make a difference either way.

It's a bit hard to see, better if you had some test-pattern (a line) on one row (same row all the time) so one could se the ghosting on the previous row.

But what would be much better is a little schematics to go with your code and explanation.

Do you use the shiftregisters for selecting rows also? Is that what your pseudo code means (the r = 1 << j thing seems to indicate that). Another thing is that the shiftout() function only shifts out bytes. To shift out two bytes, do something like this:

Set all column pins to LOW

for j=0-15{
 r = 1<<j
 r1 = r & 0xFF
 r2 = (r>>8) & 0xFF

 latchPin LOW
 shiftOut(data,clock,MSBFIRST,r2)
 shiftOut(data,clock,MSBFIRST,r1)
 latchPin HIGH
}

Note that to blank it (a different set of shiftregisters, I assume? - no schematics so I'm guessing), you must also latch it to the output (ST_CP, pin 12 if memory serves) after blanking it (even if using reset). And one more thing, if your LEDs are common anode (or, depending on what the LED drivers needs, if any), remember blanking it is the opposite of zero (all 1's. I guess you know but just in case).

I have a bit of a test pattern image, it's one row with every other column on, the top row is the one that is meant to be on, below that is the ghost: http://i.imgur.com/rRI3i.jpg (excuse the ugly solder and flux mess)

To control the columns i've simply connected them to digital pins on the uC with resistors.

The 1<<j in my head was doing this:

0000 0000 0000 0001
0000 0000 0000 0010
0000 0000 0000 0100
0000 0000 0000 1000 .. etc

but now that you mention it I really should be splitting that into two bytes, though it seemed to cycle through every bit just fine like this, but with ghosting. That is something to try.

I don't have a schematic but when I get home I can post one, along with the actual code.

Waaait a minute, you just said that shiftout sends BYTES, which makes absolute sense. I'm sending a shiftout per BIT with a full new two byte chunk of data. This is either very right as it certainly should set those previous bits to 0 or very wrong as if for some reason i'm getting a 'flip flop' of bits due to not aligning them right.

say the registers are getting this:

0001
0010
0001
0010

instead of this:
0001
0001
0001
0001

And due to the brightness I wonder if it's getting this:
0001
0001
0010
0001
0001
0010
0001
0001
0010.. etc

Wish I had an o-scope right about now.

More things to think about, which is good because my thoughts were at a stand still.

Okay, i'm at home now. Here's the code i'm running right now:

// These are the pins associated with the columns
#define RA 6
#define RB 5
#define RC 9
#define RD 14
#define RE 15
#define RF 16
#define RG 17
#define RH 18
#define RI 19
#define RJ 2
#define RK 3


// This is the image buffer, 1 = on, 0 = off.  Each index is a 'row' in which each bit is an LED.
// This pattern is horizontal stripes, due to the shadowing it's showing as bright/dim stripes.
int buffer[] = {   0xFFF,
                   0x0,
                   0xFFF,
                   0x0,
                   0xFFF,
                   0x0,
                   0xFFF,
                   0x0,
                   0xFFF,
                   0x0,
                   0xFFF,
                   0x0,
                   0xFFF,
                   0x0,
                   0xFFF,                 
                   0x0
                };


// Pins for the 74HC595
int latchpin = 12;
int clockpin = 11;
int datapin = 10;

void setup(void){
  // This is for a temperature sensor
  //ds1822_setup();
  //Serial.begin(9600);
  
  pinMode(latchpin, OUTPUT);
  pinMode(clockpin, OUTPUT);
  pinMode(datapin, OUTPUT);
  
  pinMode(13,OUTPUT);
  
  // SET COLS TO OUTPUT
  pinMode(RA,OUTPUT);
  pinMode(RB,OUTPUT);
  pinMode(RC,OUTPUT);
  pinMode(RD,OUTPUT);
  pinMode(RE,OUTPUT);
  pinMode(RF,OUTPUT);
  pinMode(RG,OUTPUT);
  pinMode(RH,OUTPUT);
  pinMode(RI,OUTPUT);
  pinMode(RJ,OUTPUT);
  pinMode(RK,OUTPUT);
  
}

//float temp;
int j,r,i,r1,r2;


void loop(void){
  
  draw_buffer();
  
}

void draw_buffer(){
  
  // Loop through the rows
  for(i = 0; i < 16; i++){
    
    // Set the 'column' LED bits according to buffer array and invert them - LOW = on
    digitalWrite(RA,!(buffer[i]&1));
    digitalWrite(RB,!(buffer[i]&2));
    digitalWrite(RC,!(buffer[i]&4));
    digitalWrite(RD,!(buffer[i]&8));
    digitalWrite(RE,!(buffer[i]&16));
    digitalWrite(RF,!(buffer[i]&32));
    digitalWrite(RG,!(buffer[i]&64));
    digitalWrite(RH,!(buffer[i]&128));
    digitalWrite(RI,!(buffer[i]&256));
    digitalWrite(RJ,!(buffer[i]&512));
    digitalWrite(RK,!(buffer[i]&1024));
    
    // create a number that corresponds to which row I want lit
    r = 1<<i;
    
    // Split this two byte number to single bytes
    r1 = 0xFF & r;
    r2 = 0xFF & (r>>8);
    
    digitalWrite(latchpin, LOW);
    shiftOut(datapin, clockpin, MSBFIRST, r1);
    shiftOut(datapin, clockpin, MSBFIRST, r2);
    digitalWrite(latchpin, HIGH);
    
  }
    
  
}

Huh.. I changed the buffer to display this:

int buffer[] = {   0x0,
                   0x0,
                   0x0,
                   0x0,
                   0x0,
                   0x0,
                   0xFFF,
                   0xFFF,
                   0xFFF,
                   0xFFF,
                   0xFFF,
                   0xFFF,
                   0xFFF,
                   0xFFF,
                   0xFFF,                 
                   0xFFF
                };

and was presented with this: http://i.imgur.com/4MiPr.jpg

I made a stupid somewhere.. now to find it.

How about the schematic as well... From your description it seems shift register output = high drives the anodes of a row, and the columns are driven low by individual pins.

Why not try a simpler test.
You're videos show a complete row turning on, then the next, then the next.
So, write all you column outputs low & leave them there to start.
Then change your shift out a little and see if the rows are actually turning off.
I may have the names a little off, but you can see the idea - shift out the 2 bytes with 1 bit high, wait a nit to see the row on, then shift out all 0s to turn the rows off. Move the on-bit and shift out again, then all off, etc.

i=1;
outdata = 1
void loop()
{
while (i<16) // same as your for loop, I just find it easier to follow
{
// shift out highbyte
shiftOut(shiftdatapin, serialclock, MSBFIRST, (outdata >> 8));  
// shift out lowbyte
shiftOut(shiftdatapin, serialclock, MSBFIRST, outdata);
// clock your latch pin
digitalWrite(latchpin, LOW);
digitalWrite(latchpin, HIGH);
delay(turnontime);
// turnoff the row
shiftOut(shiftdatapin, serialclock, MSBFIRST, 0);
shiftOut(shiftdatapin, serialclock, MSBFIRST, 0);
digitalWrite(latchpin, LOW);
digitalWrite(latchpin, HIGH);
delay(turnofftime); // short
i=i+1;
shiftdataout=shiftdataout*2;  // shifts 1 bit left
}
/ reset for the next go around
shiftdataout = 1; // reset
i=1; // reset
}

The 1<<j in my head was doing this:

0000 0000 0000 0001
0000 0000 0000 0010
0000 0000 0000 0100
0000 0000 0000 1000 .. etc

Thats what I was thinking too (but then I forgot about the column data, but it was kind of implied in my head on a subconscious level :stuck_out_tongue: ). But I dont get your next post about alternating 0001 00010 0001 etc.

One thing I noticed though, which makes sense in your last picture, the sequence for r1 and r2 is swapped:

    // Split this two byte number to single bytes
    r1 = 0xFF & r;
    r2 = 0xFF & (r>>8);
    
    digitalWrite(latchpin, LOW);
    shiftOut(datapin, clockpin, MSBFIRST, [glow]r1[/glow]);
    shiftOut(datapin, clockpin, MSBFIRST, [glow]r2[/glow]);
    digitalWrite(latchpin, HIGH);

Since it's MSBFIRST, this will first spew out the middle lines toward the first, then the last line towards the middle... LSBFIRST it would have worked (but making your display upside down). What you got now is a split display where each halves swapped place.

So one thing is simply swapping the r1 and r2 there.

Also, what CrossRoads said. Introduse a little wait at the end of the loop. I hate to recommend a delay(), but in this case I think it is perfectly OK. Actually, I think this is your main culprit for the very visible ghosting: As it is now your loop goes through as fast as it can. Thus, the next row's column data is set before the row shiftregisters are set, and will bleed through on the previous row, while the shiftregisters get their next row data. The 595 hold its output until the latch pin goes high, while clocking in new data, so the old row is still active during that time.

A little wait time at the end of the loop would make sure each row is lit a substantially larger portion of time, than the next row (column) data is lit on the same row. But it would probably not solve it completely, you should probably blank the output columns before setting the rows.

Set outputs to zero (or whatever turns your LEDs off)
shift in new row
Set outputs to corresponding column data
wait a few ms
repeat

Okay, so there were two problems. One was very very dumb, I had my latch and clock pin backwards in the code. I'm so surprised that it worked -at all- that way, but it did - and after doing as Crossroads said and slowing it down and simplifying everything I noticed that it was acting as if it were 'ticking' the data in instead of filling the whole register at once.

Set outputs to zero (or whatever turns your LEDs off)
shift in new row
Set outputs to corresponding column data

Yes! The mixed up pins were one thing, but that was not the cause of the ghosting as it was still ultimately giving me the scanning of rows even while malfunctioning. Blanking my COLUMN pins to zero is what fixed it, and it makes sense as there is a tiny bit of delay between switching the registers and updating the columns - so:

"columns -> blank -> next row -> new column data -> blank -> next row.." is the trick.

Here is my display running its first few font bitmaps:

and here is the final project (the video quality isn't too good but I didn't have time to record my own before I submitted the project - procrastination hah): http://www.youtube.com/watch?v=SI16lV6jZ7o

It's a temperature sensing christmas ornament (with a glitch in the boot animation that causes the first temperature reading to read 185F ... doh)

Thank you all so much for your suggestions, and if anybody has any questions while building their own matrix, though i'm no expert, i'd be glad to help. =)

Pretty cool! Glad you were able to work it all out. Pretty funny having the 2 pins swapped. Just enough clocking going on to make something happen, yet not quite what was expected ...