LED Matrix 7x96 reuse suggestions please

Hi,

I have an old Scrolling Text Message Sign from Text Lite called MM700.
It's a 7x96 LED matrix.
Some parts had fried when I got it. I replaced them, but it's still not working. I assume some vital parts have short circuit as well, so I have given up on the controller part.

The Matrix it self consists of 32 3x7 LED matrix modules with 10mm red LEDs. They are called LTP4137 E
They are Common Cathode.
The Rows are powered from the 16V AC going through a Bridge Rectifier = 18,5 DC. This goes through a BD 436 Power Transistor connected to some resistors and a BC338 Switching Transistor. This circuit is for each row. The base of each BC338 goes to the 12 pin ribbon cable that goes back to the "Mother Board". When I feed the Base of the BC338 5V, the BD436 feeds about 10V to the LED Matrix Modules.

The 3 Common Cathodes for each 3x7 module goes through a 39 Ohm resistor to 3 separate pins on a DS75492N LED Driver. One LED driver drives 2 modules. The LED Driver is connected to a 74HC164 Shift Register. This controls the 6 "ports" on the first LED Driver, and 2 on the next, then the next 74HC164 controls 4 on the second LED Driver and 4 on the next etc.
In total the 96 Columns are driven by 16 LED Drivers controlled by 12 daisy chained 74HC164.

On the ribbon cable connector 7 pins go to each Base of the BC338 Switch Transistors that powers the Rows, one pin is Ground, one is 5V, one goes to the Clock pins of all the SR's and one goes to the Data In of the first SR. The last pin feeds 18,5V DC back to the "Mother Board".

If you have any suggestions on how to control this LED Matrix Circuit, I would really appreciate it.

I had a look at this example, is this a good way to go?

The Shift Registers and LED Drivers circuit seems fairly common, at least I understand the theory of how it connects the cathodes to Ground when that Bit goes High.

The part I am not so sure about is the Power part. About 10V seems a lot for LEDs.
Could it be that the BC 338's should get a lower power of maybe minus to feed less from the 18,5V rail?

There is a lot of parts on the "Mother Board". Could some of them maybe be for that?

Cheers, Hal

Hal, great detail on the description of the circuit. But probably no one can picture it as a whole in their head. We would have to draw out a schematic diagram, following your description. But why should we do that? It's you that needs the help. Can you please draw the schematic? That would avoid mistakes and make it easier for everyone to understand and therefore help you.

Hi,

Here is part of the schematic. It continues in the same way.

LED MATRIX

I have drawn it upside down sort of. See photo.

DSC_0852

I have tested the power circuit for each row, and that works.
When I feed the base of the BC338 transistor 5V, the row gets about 10V

I have also tested the LED Driver DS75492N. When I feed a A input 5V, the Y output connects to Ground.
So doing this at the same time, the correct LED lights up.

I am not so sure about the Shift Registers, I suspect they could be broken. The reason is that sometimes when I feed the row transistor 5V, lots of LEDs in that row lights up. I don't see how they can when the cathodes are not connected to Ground?

Any suggestions on how to test the SR's in circuit?

Or how to best drive this matrix with the parts in it, so I can get some fancy scrolling text back :slight_smile:

Cheers, Hal

The random LEDs could be simply because the shift registers contain random data when the power is supplied. They may not be damaged.

It sounds quite straight forward to drive. You need only 9 Arduino digital outputs.

Your code would need to send 12 bytes of serial data, then enable one of the seven rows. After a small delay, disable the row and repeat for the next row and so on. Since the serial data must be sent during the period when no leds are lit (the '164 has no latch register), it will be important to shift out the data quickly to keep the display bright. This is best done with the Arduino's SPI hardware and the SPI library rather than the shiftOut() command, which is much slower (implemented in software).

Hi again,

I have tried getting something to light up with SPI library
Not sure if I'm doing this right, but here is the code I have tested with

#include <SPI.h>

//Arduino UNO SPI
//data pin 11
//clock pin 13

const int rowPin = 8;

void setup() {
  pinMode(rowPin, OUTPUT);
  digitalWrite(rowPin, LOW);
  
  SPI.begin();
}

void loop() {
SPI.transfer(1); // (B00000001)
digitalWrite(rowPin, HIGH);
delay(1000);
digitalWrite(rowPin;LOW);
}

Pin 11 on the Arduino is connected to Pin 1(&2) on the 74HC164 and Pin 13 to Pin 8.
The Master Reset, Pin 9 on the SR is HIGH on all of them, and they are chained from last output to next input.

I can get the first 8 LEDs to light up changing SPI.transfer(1); to (2) (4) etc but I am not sure how to address the other SR's.

Is there an example or library that already does scrolling text on LED Matrix that I could edit to work with the circuit I have?
I mostly find stuff using MAX72xx, but I found this:

It uses 74HC595 SR's to drive Rows and Columns, and in some way it looks similar to my circuit.
Those SRs have a Latch Pin, and the code uses shiftOut and not SPI.

Would this be a good way to start, and try to edit the code to fit?

Here's the code

int x;
int y;
int latchPin1 = 5; //Arduino pin connected to blue 12 RCLK of 74HC595
int clockPin1 = 6; //Arduino pin connected to green 11 SRCLK of 74HC595
int dataPin1 = 7;  //Arduino pin connected to violet 14 SER of 74HC595

//-- Rows (Positive Anodes) --
int latchPin2 = 9; //Arduino pin connected to yellow Latch 12 RCLK of 74HC595
int clockPin2 = 10; //Arduino pin connected to white Clock 11 SRCLK of 74HC595
int dataPin2 = 8;  //Arduino pin connected to grey Data 14 SER of 74HC595

//=== B I T M A P ===
//Bits in this array represents one LED of the matrix
// 8 is # of rows, 7 is # of LED matrix we have
byte bitmap[8][7]; // Change the 7 to however many matrices you want to use.
int numZones = sizeof(bitmap) / 8;
int maxZoneIndex = numZones-1;
int numCols = numZones * 8;

byte alphabets[][5] = {
  {0,0,0,0,0},
  {31, 36, 68, 36, 31},
  {127, 73, 73, 73, 54},
  {62, 65, 65, 65, 34},
  {127, 65, 65, 34, 28},
  {127, 73, 73, 65, 65},
  {127, 72, 72, 72, 64},
  {62, 65, 65, 69, 38},
  {127, 8, 8, 8, 127},
  {0, 65, 127, 65, 0},
  {2, 1, 1, 1, 126},
  {127, 8, 20, 34, 65},
  {127, 1, 1, 1, 1},
  {127, 32, 16, 32, 127},
  {127, 32, 16, 8, 127},
  {62, 65, 65, 65, 62},
  {127, 72, 72, 72, 48},
  {62, 65, 69, 66, 61},
  {127, 72, 76, 74, 49},
  {50, 73, 73, 73, 38},
  {64, 64, 127, 64, 64},
  {126, 1, 1, 1, 126},
  {124, 2, 1, 2, 124},
  {126, 1, 6, 1, 126},
  {99, 20, 8, 20, 99},
  {96, 16, 15, 16, 96},
  {67, 69, 73, 81, 97},
};

//=== S E T U P ===

void setup() {
  pinMode(latchPin1, OUTPUT);
  pinMode(clockPin1, OUTPUT);
  pinMode(dataPin1, OUTPUT);

  pinMode(latchPin2, OUTPUT);
  pinMode(clockPin2, OUTPUT);
  pinMode(dataPin2, OUTPUT);
 
  //-- Clear bitmap --
  for (int row = 0; row > 8; row++) {
    for (int zone = 0; zone <= maxZoneIndex; zone++) {
      bitmap[row][zone] = 0;
    }
  }
}

//=== F U N C T I O N S ===
// This routine takes whatever we've setup in the bitmap array and display it on the matrix
void RefreshDisplay()
{
  for (int row = 0; row < 8; row++) {
    int rowbit = 1 << row;
    digitalWrite(latchPin2, LOW);  //Hold latchPin LOW for as long as we're transmitting data
    shiftOut(dataPin2, clockPin2, MSBFIRST, rowbit);   //Transmit data

    //-- Start sending column bytes --
    digitalWrite(latchPin1, LOW);  //Hold latchPin LOW for as long as we're transmitting data

    //-- Shift out to each matrix (zone is 8 columns represented by one matrix)
    for (int zone = maxZoneIndex; zone >= 0; zone--) {
      shiftOut(dataPin1, clockPin1, MSBFIRST, bitmap[row][zone]);
    }

    //-- Done sending Column bytes, flip both latches at once to eliminate flicker
    digitalWrite(latchPin1, HIGH);
    digitalWrite(latchPin2, HIGH);

    //-- Wait a little bit to let humans see what we've pushed out onto the matrix --
    delayMicroseconds(500);
  }
}

// Converts row and colum to actual bitmap bit and turn it off/on
void Plot(int col, int row, bool isOn)
{
  int zone = col / 8;
  int colBitIndex = x % 8;
  byte colBit = 1 << colBitIndex;
  if (isOn)
    bitmap[row][zone] =  bitmap[y][zone] | colBit;
  else
    bitmap[row][zone] =  bitmap[y][zone] & (~colBit);
}
// Plot each character of the message one column at a time, updated the display, shift bitmap left.
void AlphabetSoup()
{
  char msg[] = "YOUR TEXT ";

  for (int charIndex=0; charIndex < (sizeof(msg)-1); charIndex++)
  {
    int alphabetIndex = msg[charIndex] - '@';
    if (alphabetIndex < 0) alphabetIndex=0;
   
    //-- Draw one character of the message --
    for (int col = 0; col < 6; col++)
    {
      for (int row = 0; row < 8; row++)
      {
        bool isOn = 0;
        if (col<5) isOn = bitRead( alphabets[alphabetIndex][col], 7-row ) == 1;
        Plot( numCols-1, row, isOn);
      }
     
      //-- The more times you repeat this loop, the slower we would scroll --
      for (int refreshCount=0; refreshCount < 7; refreshCount++) //change  this value to vary speed
        RefreshDisplay();
      //-- Shift the bitmap one column to left --
      for (int row=0; row<8; row++)
      {
        for (int zone=0; zone < numZones; zone++)
        {
          bitmap[row][zone] = bitmap[row][zone] >> 1;
                    // Roll over lowest bit from the next zone as highest bit of this zone.
          if (zone < maxZoneIndex) bitWrite(bitmap[row][zone], 7,
bitRead(bitmap[row][zone+1],0));
        }
      }
    }
  }
}

//=== L O O P ===
void loop() {
  AlphabetSoup();
}

Thank you for your direction and suggestions.

Hal

Hi Hal,

Yes, that code you found looks worth trying.

You have a couple of options for getting it working.

  1. Use a 74hc595 to drive the row lines. The code may then work as-is.
  2. Use 8 Arduino digital outputs to drive the row lines. Code changes would then be needed. Put the Arduino pin numbers in an array to make this neat & easy.

It makes sense to use a 74HC595 to drive the Rows as it's incorporated into the code already.

Should I still use SPI? or stick to the shiftOut?

Can I use the SPI port to write to both Rows and Columns Shift Registers?

Maybe use the shiftOut code for the Rows like it is and edit the Columns code with SPI.transfer?

Try not to change the code at first, other than the minimum to get it working. Once it is working, it can be improved by using SPI, chaining the row and column shift registers etc.

Hi again,

I tried it with a few changes in the code

int x;
int y;
//int latchPin1 = 5; //Arduino pin connected to blue 12 RCLK of 74HC595
int clockPin1 = 13; //Arduino pin connected to green 11 SRCLK of 74HC595
int dataPin1 = 11;  //Arduino pin connected to violet 14 SER of 74HC595

//-- Rows (Positive Anodes) --
int latchPin2 = 9; //Arduino pin connected to yellow Latch 12 RCLK of 74HC595
int clockPin2 = 10; //Arduino pin connected to white Clock 11 SRCLK of 74HC595
int dataPin2 = 8;  //Arduino pin connected to grey Data 14 SER of 74HC595

//=== B I T M A P ===
//Bits in this array represents one LED of the matrix
// 8 is # of rows, 7 is # of LED matrix we have
byte bitmap[8][7]; // Change the 7 to however many matrices you want to use.
int numZones = sizeof(bitmap) / 8;
int maxZoneIndex = numZones-1;
int numCols = numZones * 8;

byte alphabets[][5] = {
  {0,0,0,0,0},
  {31, 36, 68, 36, 31},
  {127, 73, 73, 73, 54},
  {62, 65, 65, 65, 34},
  {127, 65, 65, 34, 28},
  {127, 73, 73, 65, 65},
  {127, 72, 72, 72, 64},
  {62, 65, 65, 69, 38},
  {127, 8, 8, 8, 127},
  {0, 65, 127, 65, 0},
  {2, 1, 1, 1, 126},
  {127, 8, 20, 34, 65},
  {127, 1, 1, 1, 1},
  {127, 32, 16, 32, 127},
  {127, 32, 16, 8, 127},
  {62, 65, 65, 65, 62},
  {127, 72, 72, 72, 48},
  {62, 65, 69, 66, 61},
  {127, 72, 76, 74, 49},
  {50, 73, 73, 73, 38},
  {64, 64, 127, 64, 64},
  {126, 1, 1, 1, 126},
  {124, 2, 1, 2, 124},
  {126, 1, 6, 1, 126},
  {99, 20, 8, 20, 99},
  {96, 16, 15, 16, 96},
  {67, 69, 73, 81, 97},
};

//=== S E T U P ===

void setup() {
  //pinMode(latchPin1, OUTPUT);
  pinMode(clockPin1, OUTPUT);
  pinMode(dataPin1, OUTPUT);

  pinMode(latchPin2, OUTPUT);
  pinMode(clockPin2, OUTPUT);
  pinMode(dataPin2, OUTPUT);
 
  //-- Clear bitmap --
  for (int row = 0; row > 8; row++) {
    for (int zone = 0; zone <= maxZoneIndex; zone++) {
      bitmap[row][zone] = 0;
    }
  }
}

//=== F U N C T I O N S ===
// This routine takes whatever we've setup in the bitmap array and display it on the matrix
void RefreshDisplay()
{
  for (int row = 0; row < 8; row++) {
    int rowbit = 1 << row;
    digitalWrite(latchPin2, LOW);  //Hold latchPin LOW for as long as we're transmitting data
    shiftOut(dataPin2, clockPin2, MSBFIRST, rowbit);   //Transmit data

    //-- Start sending column bytes --
    //digitalWrite(latchPin1, LOW);  //Hold latchPin LOW for as long as we're transmitting data

    //-- Shift out to each matrix (zone is 8 columns represented by one matrix)
    for (int zone = maxZoneIndex; zone >= 0; zone--) {
      shiftOut(dataPin1, clockPin1, MSBFIRST, bitmap[row][zone]);
    }

    //-- Done sending Column bytes, flip both latches at once to eliminate flicker
    //digitalWrite(latchPin1, HIGH);
    digitalWrite(latchPin2, HIGH);

    //-- Wait a little bit to let humans see what we've pushed out onto the matrix --
    delayMicroseconds(500);
  }
}

// Converts row and colum to actual bitmap bit and turn it off/on
void Plot(int col, int row, bool isOn)
{
  int zone = col / 8;
  int colBitIndex = x % 8;
  byte colBit = 1 << colBitIndex;
  if (isOn)
    bitmap[row][zone] =  bitmap[y][zone] | colBit;
  else
    bitmap[row][zone] =  bitmap[y][zone] & (~colBit);
}
// Plot each character of the message one column at a time, updated the display, shift bitmap left.
void AlphabetSoup()
{
  char msg[] = "YOUR TEXT ";

  for (int charIndex=0; charIndex < (sizeof(msg)-1); charIndex++)
  {
    int alphabetIndex = msg[charIndex] - '@';
    if (alphabetIndex < 0) alphabetIndex=0;
   
    //-- Draw one character of the message --
    for (int col = 0; col < 6; col++)
    {
      for (int row = 0; row < 8; row++)
      {
        bool isOn = 0;
        if (col<5) isOn = bitRead( alphabets[alphabetIndex][col], 7-row ) == 1;
        Plot( numCols-1, row, isOn);
      }
     
      //-- The more times you repeat this loop, the slower we would scroll --
      for (int refreshCount=0; refreshCount < 7; refreshCount++) //change  this value to vary speed
        RefreshDisplay();
      //-- Shift the bitmap one column to left --
      for (int row=0; row<8; row++)
      {
        for (int zone=0; zone < numZones; zone++)
        {
          bitmap[row][zone] = bitmap[row][zone] >> 1;
                    // Roll over lowest bit from the next zone as highest bit of this zone.
          if (zone < maxZoneIndex) bitWrite(bitmap[row][zone], 7,
bitRead(bitmap[row][zone+1],0));
        }
      }
    }
  }
}

//=== L O O P ===
void loop() {
  AlphabetSoup();
}

Result:

-The first 16 Columns light up
-The text "YOUR TEXT" scrolls from Left to Right and Mirrored
-The text is one LED/Pixel low

I have tried changing:

byte bitmap[8][7]; // Change the 7 to however many matrices you want to use.
Changing the last number does not make use of the whole display
I guess that has to do with it being Mirrored

MSBFIRST to LSBFIRST, no text just flickering

Do you have any suggestions on where to start?
What part of the the code that can flip the scrolling and text and move it one pixel up.

All the 7x16 LEDs light up, but the Text is a little "brighter" , do you have a suggestion on how to "Dim" the rest?
Could this be improved with ISP?

Thanks for your help

Hal

OK, did some guessing-editing

Now the Text is at the correct place, (7 pixels high) and the scrolling and "plotting" the correct way, so Right to Left and letters the correct way :slight_smile:

But still just the Right side 16 LEDs.

Seems like it doesn't get that the whole display is 96 Columns, but just "wraps around" after 16

int x;
int y;
int clockPin1 = 13; //Arduino pin connected to Pin 8, CLK of the 74HC164
int dataPin1 = 11;  //Arduino pin connected to Pin 1&2, DATA IN of the first 74HC164

//-- Rows (Positive Anodes) --
int latchPin2 = 9; //Arduino pin connected to yellow Latch 12 RCLK of 74HC595
int clockPin2 = 10; //Arduino pin connected to white Clock 11 SRCLK of 74HC595
int dataPin2 = 8;  //Arduino pin connected to grey Data 14 SER of 74HC595

//=== B I T M A P ===
//Bits in this array represents one LED of the matrix
// 8 is # of rows, 7 is # of LED matrix we have
byte bitmap[7][7]; // Change the 7 to however many matrices you want to use.
int numZones = sizeof(bitmap) / 8;
int maxZoneIndex = numZones-1;
int numCols = numZones * 8;

byte alphabets[][5] = {
  {0,0,0,0,0},
  {31, 36, 68, 36, 31},
  {127, 73, 73, 73, 54},
  {62, 65, 65, 65, 34},
  {127, 65, 65, 34, 28},
  {127, 73, 73, 65, 65},
  {127, 72, 72, 72, 64},
  {62, 65, 65, 69, 38},
  {127, 8, 8, 8, 127},
  {0, 65, 127, 65, 0},
  {2, 1, 1, 1, 126},
  {127, 8, 20, 34, 65},
  {127, 1, 1, 1, 1},
  {127, 32, 16, 32, 127},
  {127, 32, 16, 8, 127},
  {62, 65, 65, 65, 62},
  {127, 72, 72, 72, 48},
  {62, 65, 69, 66, 61},
  {127, 72, 76, 74, 49},
  {50, 73, 73, 73, 38},
  {64, 64, 127, 64, 64},
  {126, 1, 1, 1, 126},
  {124, 2, 1, 2, 124},
  {126, 1, 6, 1, 126},
  {99, 20, 8, 20, 99},
  {96, 16, 15, 16, 96},
  {67, 69, 73, 81, 97},
};

//=== S E T U P ===

void setup() {

  pinMode(clockPin1, OUTPUT);
  pinMode(dataPin1, OUTPUT);

  pinMode(latchPin2, OUTPUT);
  pinMode(clockPin2, OUTPUT);
  pinMode(dataPin2, OUTPUT);
 
  //-- Clear bitmap --
  for (int row = 0; row > 7; row++) {
    for (int zone = 0; zone <= maxZoneIndex; zone++) {
      bitmap[row][zone] = 0;
    }
  }
}

//=== F U N C T I O N S ===
// This routine takes whatever we've setup in the bitmap array and display it on the matrix
void RefreshDisplay()
{
  for (int row = 0; row < 7; row++) {
    int rowbit = 1 << row;
    digitalWrite(latchPin2, LOW);  //Hold latchPin LOW for as long as we're transmitting data
    shiftOut(dataPin2, clockPin2, MSBFIRST, rowbit);   //Transmit data

    //-- Start sending column bytes --
    //digitalWrite(latchPin1, LOW);  //Hold latchPin LOW for as long as we're transmitting data

    //-- Shift out to each matrix (zone is 8 columns represented by one matrix)
    for (int zone = maxZoneIndex; zone >= 0; zone--) {
      shiftOut(dataPin1, clockPin1, LSBFIRST, bitmap[row][zone]);
    }

    //-- Done sending Column bytes, flip both latches at once to eliminate flicker

    digitalWrite(latchPin2, HIGH);

    //-- Wait a little bit to let humans see what we've pushed out onto the matrix --
    delayMicroseconds(500);
  }
}

// Converts row and colum to actual bitmap bit and turn it off/on
void Plot(int col, int row, bool isOn)
{
  int zone = col / 8;
  int colBitIndex = x % 8;
  byte colBit = 1 << colBitIndex;
  if (isOn)
    bitmap[row][zone] =  bitmap[y][zone] | colBit;
  else
    bitmap[row][zone] =  bitmap[y][zone] & (~colBit);
}
// Plot each character of the message one column at a time, updated the display, shift bitmap left.
void AlphabetSoup()
{
  char msg[] = "YOUR TEXT ";

  for (int charIndex=0; charIndex < (sizeof(msg)-1); charIndex++)
  {
    int alphabetIndex = msg[charIndex] - '@';
    if (alphabetIndex < 0) alphabetIndex=0;
   
    //-- Draw one character of the message --
    for (int col = 0; col < 6; col++)
    {
      for (int row = 0; row < 7; row++)
      {
        bool isOn = 0;
        if (col<5) isOn = bitRead( alphabets[alphabetIndex][col], 6-row ) == 1;
        Plot( numCols-1, row, isOn);
      }
     
      //-- The more times you repeat this loop, the slower we would scroll --
      for (int refreshCount=0; refreshCount < 10; refreshCount++) //change  this value to vary speed
        RefreshDisplay();
      //-- Shift the bitmap one column to left --
      for (int row=0; row<7; row++)
      {
        for (int zone=0; zone < numZones; zone++)
        {
          bitmap[row][zone] = bitmap[row][zone] >> 1;
                    // Roll over lowest bit from the next zone as highest bit of this zone.
          if (zone < maxZoneIndex) bitWrite(bitmap[row][zone], 6,
bitRead(bitmap[row][zone+1],0));
        }
      }
    }
  }
}

//=== L O O P ===
void loop() {
  AlphabetSoup();
}

I can't see anything in your code that would limit the display to 16 columns. Could this be a hardware fault? Maybe the data line from the second to the third shift register is broken? Or the third shift register is faulty?

I can see why the LEDs that should be off are glowing dimmer than the LEDs that should be on. You need to switch all rows off before you shift out the column data. Then switch the required row on. This is because your column shift registers do not have a latch line. So while the data is being shifted, it is "visible" to the LEDs, causing them to appear to glow dimly.

Using SPI will help maximize the display brightness and reduce flickering, but it won't fix the problems you have now, so forget SPI until you have the display working correctly.

Hi Paul,

Yes the 3rd SR was faulty.
Desoldered and replaced, to realize SR 6 is faulty as well :frowning:
I'll have to replace that another day, to probably discover more.
I had a feeling they where, so I bought enough.

Tried to get only the Text LEDs to show by changing this part of the code, but it didn't make any difference.

//=== F U N C T I O N S ===
// This routine takes whatever we've setup in the bitmap array and display it on the matrix
void RefreshDisplay()
{
  for (int row = 0; row < 7; row++) {
    int rowbit = 1 << row;
    
        //-- Shift out to each matrix (zone is 8 columns represented by one matrix)
    for (int zone = maxZoneIndex; zone >= 0; zone--) {
      shiftOut(dataPin1, clockPin1, LSBFIRST, bitmap[row][zone]);
    }
    digitalWrite(latchPin2, LOW);  //Hold latchPin LOW for as long as we're transmitting data
    shiftOut(dataPin2, clockPin2, MSBFIRST, rowbit);   //Transmit data

    //-- Start sending column bytes --
    //digitalWrite(latchPin1, LOW);  //Hold latchPin LOW for as long as we're transmitting data



    //-- Done sending Column bytes, flip both latches at once to eliminate flicker
    
    digitalWrite(latchPin2, HIGH);

    //-- Wait a little bit to let humans see what we've pushed out onto the matrix --
    delayMicroseconds(500);
  }
}

I thought this is where the switching on and off and the shifting was happening?

So I moved the columns first, but it didn't help.

Do I need to introduce some delays anywhere?

Cheers, Hal

You moved switching on the new row until after shifting out the column data, which is good. But you are not switching off the previous row before shifting the column data, so the problem is still there.

You could shift out zero to the 595 and latch it, before shifting the column data, so try that first. But I think a better way would be to connect the Output Enable (OE) pin on the 595 to an Arduino pin and use that to disable the rows while new row & column data is shifted.

If you use a pwm pin to connect to OE, this will also give you a way to dim the whole display.

Hi,

Thanks for the continuing help

I replaced 9 of the 12 Shift Registers, but I still had a hardware problem.
After some more testing I found a faulty Power circuit.
The BD 436 Transistor was faulty, so for now I removed the two transistors and three resistors that was connected to Anodes for Row 3 on the second PCB.

Now there should be no hardware problems.

But I think a better way would be to connect the Output Enable (OE) pin on the 595 to an Arduino pin and use that to disable the rows while new row & column data is shifted.

I tried to implement this here:

void RefreshDisplay()
{
  for (int row = 0; row < 8; row++) {
    
        //-- Start sending column bytes --
        //-- Shift out to each matrix (zone is 8 columns represented by one matrix)
    for (int zone = maxZoneIndex; zone >= 0; zone--) {
      shiftOut(dataPin1, clockPin1, MSBFIRST, bitmap[row][zone]);
    }
    digitalWrite(latchPin2, LOW);  //Hold latchPin LOW for as long as we're transmitting data
    int rowbit = 1 << row;
    shiftOut(dataPin2, clockPin2, MSBFIRST, rowbit);   //Transmit data

    //-- Done sending Column bytes, flip both latches at once to eliminate flicker
    digitalWrite(latchPin2, HIGH);
    
      analogWrite(enablePin,0); 
    //-- Wait a little bit to let humans see what we've pushed out onto the matrix --
    delayMicroseconds(500);
          analogWrite(enablePin,255);
  }
}

That seem to work :slight_smile:
Only the text lights up.

But there is still a problem in the code, so I have gone back to the original code, with the changes that gets it to work.

int x;
int y;

int clockPin1 = 13; //Arduino pin connected to Pin 8, CLK of the 74HC164
int dataPin1 = 11;  //Arduino pin connected to Pin 1&2, DATA IN of the first 74HC164

//-- Rows (Positive Anodes) --
int latchPin2 = 9; //Arduino pin connected to yellow Latch 12 RCLK of 74HC595
int clockPin2 = 10; //Arduino pin connected to white Clock 11 SRCLK of 74HC595
int dataPin2 = 8;  //Arduino pin connected to grey Data 14 SER of 74HC595
int enablePin = 6; //Arduino pin connected to output enable pin 13 of 74HC595

//=== B I T M A P ===
//Bits in this array represents one LED of the matrix
// 8 is # of rows, 7 is # of LED matrix we have
byte bitmap[8][12]; // Change the 7 to however many matrices you want to use.
int numZones = sizeof(bitmap) / 8;
int maxZoneIndex = numZones-1;
int numCols = numZones * 8;

byte alphabets[][5] = {
  {0,0,0,0,0},
  {31, 36, 68, 36, 31},
  {127, 73, 73, 73, 54},
  {62, 65, 65, 65, 34},
  {127, 65, 65, 34, 28},
  {127, 73, 73, 65, 65},
  {127, 72, 72, 72, 64},
  {62, 65, 65, 69, 38},
  {127, 8, 8, 8, 127},
  {0, 65, 127, 65, 0},
  {2, 1, 1, 1, 126},
  {127, 8, 20, 34, 65},
  {127, 1, 1, 1, 1},
  {127, 32, 16, 32, 127},
  {127, 32, 16, 8, 127},
  {62, 65, 65, 65, 62},
  {127, 72, 72, 72, 48},
  {62, 65, 69, 66, 61},
  {127, 72, 76, 74, 49},
  {50, 73, 73, 73, 38},
  {64, 64, 127, 64, 64},
  {126, 1, 1, 1, 126},
  {124, 2, 1, 2, 124},
  {126, 1, 6, 1, 126},
  {99, 20, 8, 20, 99},
  {96, 16, 15, 16, 96},
  {67, 69, 73, 81, 97},
};

//=== S E T U P ===

void setup() {
  
  pinMode(clockPin1, OUTPUT);
  pinMode(dataPin1, OUTPUT);

  pinMode(latchPin2, OUTPUT);
  pinMode(clockPin2, OUTPUT);
  pinMode(dataPin2, OUTPUT);
  pinMode(enablePin, OUTPUT);
  
  //digitalWrite(enablePin, HIGH);
 
  //-- Clear bitmap --
  for (int row = 0; row > 8; row++) {
    for (int zone = 0; zone <= maxZoneIndex; zone++) {
      bitmap[row][zone] = 0;
    }
  }
}

//=== F U N C T I O N S ===
// This routine takes whatever we've setup in the bitmap array and display it on the matrix
void RefreshDisplay()
{
  for (int row = 0; row < 8; row++) {
    
        //-- Start sending column bytes --
        //-- Shift out to each matrix (zone is 8 columns represented by one matrix)
    for (int zone = maxZoneIndex; zone >= 0; zone--) {
      shiftOut(dataPin1, clockPin1, MSBFIRST, bitmap[row][zone]);
    }
    digitalWrite(latchPin2, LOW);  //Hold latchPin LOW for as long as we're transmitting data
    int rowbit = 1 << row;
    shiftOut(dataPin2, clockPin2, MSBFIRST, rowbit);   //Transmit data

    //-- Done sending Column bytes, flip both latches at once to eliminate flicker
    digitalWrite(latchPin2, HIGH);
    
      analogWrite(enablePin,0); 
    //-- Wait a little bit to let humans see what we've pushed out onto the matrix --
    delayMicroseconds(500);
          analogWrite(enablePin,255);
  }
}

// Converts row and colum to actual bitmap bit and turn it off/on
void Plot(int col, int row, bool isOn)
{
  int zone = col / 8;
  int colBitIndex = x % 8;
  byte colBit = 1 << colBitIndex;
  if (isOn)
    bitmap[row][zone] =  bitmap[y][zone] | colBit;
  else
    bitmap[row][zone] =  bitmap[y][zone] & (~colBit);
}
// Plot each character of the message one column at a time, updated the display, shift bitmap left.
void AlphabetSoup()
{
  char msg[] = "ONE TWO THREE";

  for (int charIndex=0; charIndex < (sizeof(msg)-1); charIndex++)
  {
    int alphabetIndex = msg[charIndex] - '@';
    if (alphabetIndex < 0) alphabetIndex=0;
   
    //-- Draw one character of the message --
    for (int col = 0; col < 6; col++)
    {
      for (int row = 0; row < 8; row++)
      {
        bool isOn = 0;
        if (col<5) isOn = bitRead( alphabets[alphabetIndex][col], 7-row ) == 1;
        Plot( numCols-1, row, isOn);
      }
     
      //-- The more times you repeat this loop, the slower we would scroll --
      for (int refreshCount=0; refreshCount < 7; refreshCount++) //change  this value to vary speed
        RefreshDisplay();
      //-- Shift the bitmap one column to left --
      for (int row=0; row<8; row++)
      {
        for (int zone=0; zone < numZones; zone++)
        {
          bitmap[row][zone] = bitmap[row][zone] >> 1;
                    // Roll over lowest bit from the next zone as highest bit of this zone.
          if (zone < maxZoneIndex) bitWrite(bitmap[row][zone], 7,
bitRead(bitmap[row][zone+1],0));
        }
      }
    }
  }
}

//=== L O O P ===
void loop() {
  AlphabetSoup();
}

Now that only the text lights up it's easier to see what the problems are.

-The text is one pixel to low
-It writes and scrolls from Left to Right mirrored

I have tried earlier to change the parts of the code that relates to using 8 Rows to move the text one row up.
I have also tried to use LSBFIRST to get it to write and scroll the right way.

Any pointers to where in the code I can fix this?

Cheers, Hal

Your display has 7 rows but the 595 has 8 outputs. Are you using outputs 0 to 6? Try using outputs 1 to 7.

To un-mirror the display, you need to reverse the entire column data. So as well as switching to LSBFIRST, you also need to send the 12 bytes in reverse order.

for (int zone = 0; zone <= maxZoneIndex; zone++)

PaulRB:
Your display has 7 rows but the 595 has 8 outputs. Are you using outputs 0 to 6? Try using outputs 1 to 7.

To un-mirror the display, you need to reverse the entire column data. So as well as switching to LSBFIRST, you also need to send the 12 bytes in reverse order.

That did the trick

You can see that Row 3 is not working on the Left PCB.
Waiting for the parts.

Once it is working, it can be improved by using SPI, chaining the row and column shift registers etc.

So is it possible to do this with the two different Shift Registers?
Will it improve the display?

Cheers, Hal

You're welcome.

Looks like the 2nd row has some problems too, just on that A in THANKS.

Yes, you could use SPI and daisy chain the 595 with the 164s. The 595 would still need it's latch line, unfortunately. Using SPI would speed up the shifting process, meaning that the LEDs could spend more of their time on, making the display brighter and less likely to flicker.

At the moment, I feel the display is being refreshed too fast. You could try changing that delayMicroseconds(500) to 1000 or 2000. If it starts to flicker, go back to the shorter delay again.

Also, the code assumes the display is 8 LEDs high, but it is only 7, so fixing that will increase the brightness a little too.

Looks like the 2nd row has some problems too, just on that A in THANKS.

Yes, and Row 4 in the N.
Not sure what is happening there.
I'll see what happens when I replace the missing parts.

OK. Tried this, but a lot of scrambled letters

#include <SPI.h>


int x;
int y;

//int clockPin1 = 13; //Arduino pin connected to Pin 8, CLK of the 74HC164
//int dataPin1 = 11;  //Arduino pin connected to Pin 1&2, DATA IN of the first 74HC164

//-- Rows (Positive Anodes) --
int latchPin2 = 9; //Arduino pin connected to yellow Latch 12 RCLK of 74HC595
//int clockPin2 = 10; //Arduino pin connected to white Clock 11 SRCLK of 74HC595
//int dataPin2 = 8;  //Arduino pin connected to grey Data 14 SER of 74HC595
int enablePin = 6; //Arduino pin connected to output enable pin 13 of 74HC595

//=== B I T M A P ===
//Bits in this array represents one LED of the matrix
// 8 is # of rows, 7 is # of LED matrix we have
byte bitmap[8][12]; // Change the 7 to however many matrices you want to use.
int numZones = sizeof(bitmap) / 8;
int maxZoneIndex = numZones-1;
int numCols = numZones * 8;

byte alphabets[][5] = {
  {0,0,0,0,0},
  {31, 36, 68, 36, 31},
  {127, 73, 73, 73, 54},
  {62, 65, 65, 65, 34},
  {127, 65, 65, 34, 28},
  {127, 73, 73, 65, 65},
  {127, 72, 72, 72, 64},
  {62, 65, 65, 69, 38},
  {127, 8, 8, 8, 127},
  {0, 65, 127, 65, 0},
  {2, 1, 1, 1, 126},
  {127, 8, 20, 34, 65},
  {127, 1, 1, 1, 1},
  {127, 32, 16, 32, 127},
  {127, 32, 16, 8, 127},
  {62, 65, 65, 65, 62},
  {127, 72, 72, 72, 48},
  {62, 65, 69, 66, 61},
  {127, 72, 76, 74, 49},
  {50, 73, 73, 73, 38},
  {64, 64, 127, 64, 64},
  {126, 1, 1, 1, 126},
  {124, 2, 1, 2, 124},
  {126, 1, 6, 1, 126},
  {99, 20, 8, 20, 99},
  {96, 16, 15, 16, 96},
  {67, 69, 73, 81, 97},
};

//=== S E T U P ===

void setup() {
  
  //pinMode(clockPin1, OUTPUT);
  //pinMode(dataPin1, OUTPUT);

  pinMode(latchPin2, OUTPUT);
  //pinMode(clockPin2, OUTPUT);
  //pinMode(dataPin2, OUTPUT);
  pinMode(enablePin, OUTPUT);
  
  SPI.begin();
  
 
  //-- Clear bitmap --
  for (int row = 0; row > 8; row++) {
    for (int zone = 0; zone <= maxZoneIndex; zone++) {
      bitmap[row][zone] = 0;
    }
  }
}

//=== F U N C T I O N S ===
// This routine takes whatever we've setup in the bitmap array and display it on the matrix
void RefreshDisplay()
{
  for (int row = 0; row < 8; row++) {
    
        //-- Start sending column bytes --
        //-- Shift out to each matrix (zone is 8 columns represented by one matrix)
    //for (int zone = maxZoneIndex; zone >= 0; zone--) {
      for (int zone = 0; zone <= maxZoneIndex; zone++) {
      //shiftOut(dataPin1, clockPin1, LSBFIRST, bitmap[row][zone]);
      SPI.beginTransaction(SPISettings(14000000, LSBFIRST, SPI_MODE0));
      SPI.transfer (bitmap[row][zone]);
      SPI.endTransaction();
    }
    SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0));
    digitalWrite(latchPin2, LOW);  //Hold latchPin LOW for as long as we're transmitting data
    int rowbit = 1 << row;
    //shiftOut(dataPin2, clockPin2, MSBFIRST, rowbit);   //Transmit data
      SPI.transfer (rowbit);
      SPI.endTransaction();   

    //-- Done sending Column bytes, flip both latches at once to eliminate flicker
    digitalWrite(latchPin2, HIGH);
    
      analogWrite(enablePin,0); 
    //-- Wait a little bit to let humans see what we've pushed out onto the matrix --
    delayMicroseconds(1000);
          analogWrite(enablePin,255);
  }
}

// Converts row and colum to actual bitmap bit and turn it off/on
void Plot(int col, int row, bool isOn)
{
  int zone = col / 8;
  int colBitIndex = x % 8;
  byte colBit = 1 << colBitIndex;
  if (isOn)
    bitmap[row][zone] =  bitmap[y][zone] | colBit;
  else
    bitmap[row][zone] =  bitmap[y][zone] & (~colBit);
}
// Plot each character of the message one column at a time, updated the display, shift bitmap left.
void AlphabetSoup()
{
  char msg[] = " PRINZTRONIX ";

  for (int charIndex=0; charIndex < (sizeof(msg)-1); charIndex++)
  {
    int alphabetIndex = msg[charIndex] - '@';
    if (alphabetIndex < 0) alphabetIndex=0;
   
    //-- Draw one character of the message --
    for (int col = 0; col < 6; col++)
    {
      for (int row = 0; row < 8; row++)
      {
        bool isOn = 0;
        if (col<5) isOn = bitRead( alphabets[alphabetIndex][col], 7-row ) == 1;
        Plot( numCols-1, row, isOn);
      }
     
      //-- The more times you repeat this loop, the slower we would scroll --
      for (int refreshCount=0; refreshCount < 10; refreshCount++) //change  this value to vary speed
        RefreshDisplay();
      //-- Shift the bitmap one column to left --
      for (int row=0; row<8; row++)
      {
        for (int zone=0; zone < numZones; zone++)
        {
          bitmap[row][zone] = bitmap[row][zone] >> 1;
                    // Roll over lowest bit from the next zone as highest bit of this zone.
          if (zone < maxZoneIndex) bitWrite(bitmap[row][zone], 7,
bitRead(bitmap[row][zone+1],0));
        }
      }
    }
  }
}

//=== L O O P ===
void loop() {
  AlphabetSoup();
}

You probably changed too many things at once. Go back to how it was, get it working again. Then move forward one small step at a time, testing after each small change. Maybe start with using SPI to drive the 164s. Leave the 595 on the other pins & shiftOut(). Get that working. Then daisy chain the 595 to the 164s.

Also, don't use SPI.beginTransaction() and SPI.endTransaction() around each SPI.transfer(). You have only one "device" on the SPI bus (the string of shift registers), so just put the SPI.beginTransaction() in setup() and forget the SPI.endTransaction() altogether. Start with a lower clock speed, perhaps 500000. Once that works, double the clock speed until it stops working, then go back to the fastest that works. The speed you specify is the maximum. The Arduino will choose, from the limited set of speeds it can support, the nearest to your maximum without going beyond it. For Uno, I think the absolute max is 8000000. But your 164s, because there are 12 of them and the length of the wires, may or may not be able to keep up with that, so some experimentation will be required.

I just remembered: the Arduino pin also called "SS" (slave select). I can't remember which pin number that is. It's important to set that as an output, or strange stuff can happen. So why not use that for the 595's latch pin.

Yes, bad idea to throw it all in there at once.

I thought I needed the SPI.beginTransaction() and SPI.endTransaction() because I need to change the LSBFIRST to MSBFIRST for the different Shift Registers.

Also, how can I find out which SPI_MODE the different SRs are? I just used SPI_MODE0, but that might be wrong.

The 74HC164 does not have a Latch Pin. It has a Clear, but in my circuit they are all connected to 5V, so not active.

So if I first try keeping the Rows like it is, using shiftOut() and the Enable Pin, and change the Columns code to SPI like

SPI.transfer (bitmap[row][zone]);

can I then define the settings like

void setup() {

SPI.begin();
SPI.beginTransaction(SPISettings(500000, LSBFIRST, SPI_MODE0));
}

Do I still need to set the SS Pin?

#include <SPI.h> will set the SPI port to Pin 11 (DATA) and 13 (CLOCK) on the UNO I think, will it also set the SS Pin to 10?

Then I should probably first keep the Latch Pin for the 595 on Pin 9 and move the 595 CLOCK Pin away from Pin 10?

Cheers, Hal