LED Matrix 7x96 reuse suggestions please

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

Ah, I see. That's easy to fix. Either re-wire the '595, reversing the connections between that and the display, swapping 1 and 7, 2 and 6, 3 and 5 etc. Or change this line of code:

int rowbit = 1 << row;

to

int rowbit = 1 << (7-row);

then you can use LSBFIRST throughout.

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

Both types of register should work fine with the same SPI mode.

eptheca:
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?

Yes, you still need to set the SS pin to be an output. If you don't, the Arduino will read that pin to decide if it should be "master" or "slave", and we always want it to be master.

When using SPI, the clock and data lines are fixed (11 and 13 on Uno, as you say). But you will need to change your code to use pin 10 for the latch for the 595. In the short term, you will need to use (and specify in your code) which pins to use as clock & data for the 595.

I just had a thought. When you attempted to use SPI for both the 595 and 164s, did you daisy-chain the data line? i.e. Arduino SPI DATA --> 595 SER and 595 QH' --> Data input on the display?

Arduino UNO Pin 11(SPI DATA) --> 595 Pin 14(DATA IN) --> 164 Pin 1+2 (DATA IN)
Arduini UNO Pin 13(SPI CLOCK) --> 595 Pin 11(CLOCK) --> 164 Pin (CLOCK)

Arduino UNO Pin 9 latchPin OUTPUT --> 595 Pin 12(LATCH)
Arduino UNO Pin 6 enablePin OUTPUT --> 595 Pin 13 (Enable)

Which Pin is QH?

Is it Pin 9 Data Out?

That is not connected to anything

The datasheet for 74HC164 says : clock input (LOW-to-HIGH, edge-triggered)

I am not sure about the 595, but I think it's also LOW-to_HIGH.

The SPI page says:

The four modes combine polarity and phase according to this table:

Mode Clock Polarity (CPOL) Clock Phase (CPHA) Output Edge Data Capture
SPI_MODE0 0 0 Falling Rising
SPI_MODE1 0 1 Rising Falling
SPI_MODE2 1 0 Rising Falling
SPI_MODE3 1 1 Falling Rising

So should it be SPI_MODE1 ?

9.1 Overview
The SNx4HC595 is ...
Both the shift register clock (SRCLK) and storage register clock (RCLK) are positive-edge triggered.

9.1 Overview
The SN74HC164 is ...
The CLK pin of the SN74HC164 is triggered on a positive or rising-edge signal, from LOW to HIGH.

So you are right and both chips are the same in this respect. I suspect that SPI mode 0 and mode 1 will both work.

eptheca:
Is it Pin 9 Data Out?

That is not connected to anything

I think that must be why it did not work. For daisy-chaining, the data-out of one register goes to the data in of the next in the chain. The sequence in which the data is sent determines which shift register receives it.

If you connect the data-in of two registers to the data-out pin from the Arduino, that is not daisy-chaining, and they will receive the same data, and there is no way for the 595 to know which data is intended for it rather than the 164 registers.

OK, I get it.
No, I didn't chain them, I connected them in parallel. Silly mistake :frowning:

I'll try that tomorrow with the other changes in the code.

Cheers, Hal

Hi,

With the wiring fixed and this code, it works pretty good :slight_smile:

In some letters there are "missing pixels" but not consistent.

There is still the fault in the code where it uses 8 rows, and I have 7

I have tried to change the places where it relates to Row and 8 to 7, but that causes more flickering.

#include <SPI.h>

int x;
int y;

int ssPin = 10; //Arduino pin connected to Latch 12 RCLK 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 12 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(enablePin, OUTPUT);
  pinMode(ssPin, OUTPUT);
  
  SPI.begin();
  SPI.beginTransaction(SPISettings(1000000, LSBFIRST, SPI_MODE0));
  
 
  //-- 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 = 0; zone <= maxZoneIndex; zone++) {
      SPI.transfer (bitmap[row][zone]);
    }
    digitalWrite(ssPin, LOW);  //Hold latchPin LOW for as long as we're transmitting data
    int rowbit = 1 << (7-row);
    SPI.transfer (rowbit);  

    //-- Done sending Row bytes, flip latche to eliminate flicker
    digitalWrite(ssPin, 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();
}

What about this part:

//=== 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][12]; // Change the 12 to however many matrices you want to use.
int numZones = sizeof(bitmap) / 8;
int maxZoneIndex = numZones-1;
int numCols = numZones * 8;

Does this work?

If I understand it correctly, and there is a good chance I don't :wink:
this will result in this:

7x12/8=10,5 x 8 =84

So 10,5 Zones and 84 Columns

Cheers, Hal

The rows are now connected to outputs 0 to 7 of the 595?

If so, just make this change:

void RefreshDisplay()
{
  for (int row = 0; row < 7; row++) {

You may not notice much difference, but the leds should in theory by 12.5% brighter.

In some letters there are "missing pixels" but not consistent.

What do you mean? Do the missing pixels move with the scrolling, or stay with the same led, or neither?

Try changing the message to all spaces, and change this part:

for (int zone = 0; zone <= maxZoneIndex; zone++) {
      SPI.transfer (~bitmap[row][zone]);
    }

This should light every led on the display at once. What do you see?

The Rows are connected to outs 1-8, but changing to this worked

void RefreshDisplay()
{
  for (int row = 0; row < 7; row++) {

What about the other places in the code where it refers to 8 Rows, like in:

void setup

void AlphabetSoup

The missing pixels moves with the Bitmap Letter

I did not get the whole display to light up
I can make a letter like {127,127,127,127,127}, and just write that. That makes a 5x7 filled rectangle that moves along.
All the pixels are showing, so no bad LEDs

What about the other places in the code where it refers to 8 Rows

Don't worry about them. A little extra unnecessary processing is being done, but it won't be worthwhile trying to remove that. The change you did means that no time is wasted trying to light the 8th row of leds, which does not exist.

I did not get the whole display to light up

Odd, that should have worked. But never mind, you proved that no leds are faulty, which was the point of the test.

So, when you said

In some letters there are "missing pixels" but not consistent.

did you mean that for a given letter, say "N", the pixel is consistently missing from the same place in the letter as it scrolls. But the missing pixel is not consistent between letters, so for example the pixel missing in "N" is not missing from "H"?

If so, sounds like the letter pattern codes have mistakes in them.

However, if we look at the pattern for "N":

  {127, 32, 16, 8, 127},

it translates into binary as:

  {0b01111111,
   0b00100000,
   0b00010000,
   0b00001000,
   0b01111111},

which looks fine (if you look at it sideways, in a mirror).

You can see it in this photo

Look on the Right PCB, the Left has faulty 3rd row

The O and the N have missing pixels and the top row of the Z has one extra on each side, and they follow those letters

eptheca:
The O and the N have missing pixels and the top row of the Z has one extra on each side, and they follow those letters

And that's completely repeatable, every time the sketch runs? If so, its got to be a software fault in my opinion.

I may have spotted it. Try this

// 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 = col % 8;
  byte colBit = 1 << colBitIndex;
  if (isOn)
    bitmap[row][zone] =  bitmap[row][zone] | colBit;
  else
    bitmap[row][zone] =  bitmap[row][zone] & (~colBit);
}

The weird thing is, now I spotted that, how did it ever work at all?!?

It was using variables called x and y, that don't seem to be used anywhere else in the sketch. Their values would always be zero...

That didn't work, do difference.

I have tied to write just O, that works fine.
And just an N, also fine, but ON, pixels are missing ?????

I haven't tried all letters, but I can see it with these

Dang, thought I had it.

Your latest findings make me believe that the code is accessing some memory it should not be.

Can you post the complete latest code.

#include <SPI.h>

int x;
int y;

int ssPin = 10; //Arduino pin connected to Latch 12 RCLK 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 12 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(enablePin, OUTPUT);
  pinMode(ssPin, OUTPUT);
  
  SPI.begin();
  SPI.beginTransaction(SPISettings(1000000, LSBFIRST, SPI_MODE0));
  
 
  //-- 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 = 0; zone <= maxZoneIndex; zone++) {
      SPI.transfer (bitmap[row][zone]);
    }
    digitalWrite(ssPin, LOW);  //Hold latchPin LOW for as long as we're transmitting data
    int rowbit = 1 << (7-row);
    SPI.transfer (rowbit);  

    //-- Done sending Row bytes, flip latche to eliminate flicker
    digitalWrite(ssPin, 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();
}

Hmm... I know you said they made no difference, but the code changes I suggested in post #32 should still go in, because it was definitely wrong before. Prove it to yourself. Delete these lines:

int x;
int y;

Then compile. You will soon see that those two variables are initialised to zero and then never set to any other value. A sure sign the original coder got confused.

In the mean time, I'll read through the code again...

I also tried with Rows using shiftOut() and Columns using SPI, but still the same problem with those letters.

Also it starts writing from Column 9

eptheca:
Also it starts writing from Column 9

What do you mean?

The first 8 Columns show nothing, and the text starts writing and scrolling from Column 9