Controlling 595 shift register SPI vs ShiftOut


I've been doing some POV work lately see
POV math - #8 by system - Project Guidance - Arduino Forum and thought I'd share this:

To refresh 64 LEDs with SPI and bitSet and bitClear for latching on a 16MHz 328 at 8MHz SPI, I get 56KHz Max:

To refresh 64 LEDs with shiftOut and digitalWrite,I get 1KHz Max:

For the second test I just replaced the code from the thread mentioned with digitalWrite on latch and shiftOut instead of SPI.transfer otherwise it's exactly the same...

Rather astounding I thought, 56 times faster on SPI .. :astonished:

Yep, hardware vs software will do that for ya ...

Mmm .. so shiftOut has no built-in limitations for example a 'hard coded' clock speed that may cause this?

Nope, its just a function of how fast the software can write a bit to a port, then toggle the clock line up & down on another port, etc.
SPI uses built in hardware shift register, so can go much quicker.
If you were to write shiftout in assembler code, it might go a little quicker, depends what the compiler does with it.

From the POV Math thread referenced in the original post:

  1. I would then add say 64 LEDS along the length of the cylinder driven by 8 x 595 shift registers or similar.

Have you considered using four of the MCP23017(I2C) or MCP23S17(SPI) I/O expanders? These may be faster since you are writing a byte at a time to the device.


Don't the IO expanders use a similar idea? Use SPI to talk to addressable registers?
If he has 8 free lines for chip selects, the HC595 being driven by SPI can be addressed individually, or just connect in series with 1 chip select if the flicker down the line isn't an issue.

I think the I2C expanders may be a bit handicapped by bus speed but I'll try the SPI version when I get my hands on one. As I recall an additional byte transfer is needed for addressing and such as well but its definitely worth a look. Certainly drops the chip count ..

Yeah using individual latch pins for each 595 is something I've been looking at.
However consider this scneario: I have two byte arrays 8 bytes each (for 64 leds) one is 'active' and one is 'new'. I want to do a comparison between the active displayed array and the 'new to be displayed' array and only shift out the changes where bytes have changed.

So for example if only bytes 6 and 8 has changed I will only send the data for register 1 (because it's connected to SPI) together with data for register 7 and 8. Leaving the rest untouched.

Might save a bit of time since the POV display by nature changes slowly..

Question is how can one quickly connect or disconnect 7 of the registers from the first register's 'common' serial out line,? There must be a fast IC solution for this .. OR ..and I'm holding thumbs here, if a 595 is not latched does the data on the serial in pin go directly to the serial out pin?

@CrossRoads: I think the light just went on here. You were saying to connect all 595's to the same SPI Clock and data line as the first one (serial is the way I was thinking previously) and only latch those that need to 'listen' when sending data?
Please correct me if this is not possible.

If it is, one can go one step furher, after the comparison of the 'current' and 'new' arrays, to determine what has changed, also look at which bytes are the same in the 'new' array. With this determined I can then latch mulitple 595s and send the same byte to all of them simultaneously instead of addressing each one individually (which adds the address byte overhead again ..)

Better sharpen up on my bit math .. :astonished:

Shift out is slow because it uses the Arduino portability code through digitalWrite(). It's much quicker if you write directly using the port registers.


JMetal, You're getting the idea!
You can use shift registers with common clock and data and individual output latch clocks (so yes, all input registers get loaded, but only the selected register gets its output updated) or you can use a part with multiple internal registers that takes cares of multiplexing for you (like MAX7221, you have 1 24-pin DIP driving up to 64 LEDs, arranged as 8 groups of 8 LEDs).
Logic wise, you could do a loop that sets/clears bits in 8 byte variables representing the state of your 64 LEDs in the first half, each time you change a bit set a flag to indicate that byte had changed. In the second half, you check each flag and do an SPI write (and latch, if not using 7221) for each byte that changed, and clear the flag.

Thanks Crossroads, I'll look into that part as well.

In my case, I have several sections - 2 digits for left score, 2 digits for right score, 4 digits for time, and the decimal points used as different flags.
If any are updated, I set the "update needed" flag and the refresh section updates each register as needed.