MAX6971 LED Controller

Hello, I'm new to the Arduino and electronics in general so forgive me if I sound amateurish :wink:

I want to control a 4x4x4 LED cube (one layer at a time) with the MAX6971 (http://www.mouser.com/ds/2/256/MAX6971-90327.pdf). I couldn't find any sort of library or tutorial on this chip on the web, and the datasheet is a little bit too complicated for me (at least the part with the timing diagrams, and I think those are important...).

Can someone point me to a library or give me a hint on how to talk to the chip without destroying it or my arduino (It's an arduino DUE (3.3v))?

I successfully built a 3x3x3 cube without any chip, using 12 Arduino outputs, 9 for the Cathode columns and 3 (using transistors) for the anode layers with an Arduino UNO.
For the next Step (4x4x4, and later possibly 8x8x8) I'd like to use as few pins as possible and that's why I bought the LED controller. Is this chip even the right thing for the job (I saw it used in 7-Segment-Display-Projects, but not in LED-Arrays)?

Put this in a loop, 5mS on for each layer:

digitalWrite(LEpin, HIGH);
SPI.transfer(first8bits);
SPI.transfer(second8bits);
digitalWrite(LEpin, LOW);

Thanks for the tip, I'll try this tonight. Sadly it will just be a test, the cube isn't finished yet:

The SPI Library seems to be the right tool for this.

It's good & fast. Can also replace the digitalWrite's with direct port manipulation to go even faster:

PORTD = PORTD | B00000100; // set bit 3
SPI.transfer ...
PORTD = PORTD & B11111011; // clear bit 3

find the appropriate port/bit for the LE pin you are using. Use pinMode for that pin in void setup.
D10 must be an output for SPI when you are in SPI master mode, even if you use another pin for LEpin.

I couldn't open the picture before - are those Lego parts that you're using for spacing?

Yes, they are :wink: I found out that a 5mm LED can be pushed into these holes in the Lego Technic bars. They are a tiny bit too large to push them in completely, but you can push them in about halfways and they are fixed in place.

This made it easy to build a frame with perfectly equal distance from LED to LED for soldering the layers and now for connecting the layers with wire columns (photo).

Thanks CrossRoads, it works, I can control the LEDs. A few questions:

  • In the datasheet it states that the chip can take both 5 or 3.3 volts. If I use 3.3 volts I get much dimmer LEDs though (only about 5mA, although I set the output to 30 with the resistor on SET which is what my LEDs need). Shouldn't the chip output a constant 30mA (up to 55mA according to the Datasheet), no matter what Voltage I use? Only when I supply 5V it delivers the full 30 mA. Can I do anything about that?
  • When i only activate 1 LED it is visibly a bit lighter than If I activate all of them. It's not just a visual illusion, it gets mor mA as well... It's not a big difference but it's clearly visible and I don't know if I'm doing something wrong...
  • The OE Pin on the chip can be used to send PWM signals. It works, I can set the brightness of my leds using this pin. Is it somehow possible to set the brightness for individual LEDs? This is not a 100% necessary for me but it would be nice.
  • When I wiggle the power and gnd cables that connect the arduino to the breadboard the LEDs flicker quite a bit. I changed the breadboard and the cables but it still happens. Is this normal?

Do you have this in place?

Power-Supply Considerations
The MAX6971 operates with a chip supply V+, and one
or more LED supplies. Bypass each supply to GND
with a 0.1?F capacitor as close to the MAX6971 as possible.
This is normally adequate for static LED driving.
For multiplex or PWM applications, it is necessary to
add an additional bulk electrolytic capacitor of 4.7?F or
more to each supply for every 4 to 16 MAX6971s. The
necessary capacitance depends on the LED load current,
PWM switching frequency, and serial-interface
speed. Inadequate V+ decoupling can cause timing
problems, and very noisy LED supplies can affect LED
current regulation.

Individual LEDs - read the datasheet, see what it says about that.
Wiggly wires - yes, you only have a piece of wire in between two plates that are weakly sprung together.
If you want it more secure, wirewrap it up.
Sockets, tools, wire here, is how I build up my stuff for anything I want together for a while.
http://www.king-cart.com/phoenixent/product=SOCKETS+WIRE+WRAP+DIP+%2526+SIP/exact_match=exact

Yes, I put a 0.1μF ceramic capacitor between V+ and GND of the chip (see Fritzing-Image below), that shouldn't be the problem.

However I'm now just running the LEDs from the 5v connector on the arduino DUE and this seems to work properly.

The next thing I wanted to test was the layer switching using transistors (NPN). I included a transistor to switch the V+ path on or off. From what I've read so far it shouldn't be a problem to switch a 5V circuit using a 3V pin. However, as soon as I connect it like in the picture below, I only get VERY dim LEDs, even without multiplexing or PWM. I measured the current drawn from the Switch pin (yellow cable) and it's just 0.1 mA. That's of course far too low to saturate the transistor. according to the Arduino DUE Pinout this pin should be able to deliver 15 mA. And it surely can, because when I connect it directly to a LED, it draws about 10 mA.
The same thing happens when I connect the base of the transistor to 3.3v directly. Only if I connect the base to 5v, the transistor seems to get saturated. But to be able to control the base, I need to connect it to a 3.3v i/o pin on the DUE.
I'm sure the transistor is the right kind, all the values are below the tolerance. I tried several types that should work according to their datasheets, but none worked properly. I even tried a Darlington Transistor, this one had an even worse result (LED light almost not visible).
Should I try a MOSFET? Sadly I don't have any at the moment but ordered some different types for testing, they should arrive next week.

I'm sure I'm missing something crucial here (as I said, I'm a beginner, and many things, like transistors, are still a bit mysterious to me). Maybe I should just order another Arduino UNO. At least there everything runs on 5V. But I'm quite eager to get this to work on the DUE...

This is my current test setup:

How about a schematic? Wires connected to unmarked pins telll you nothing - that's my big gripe with fritzing, you don't the information needed.

  1. SPI library:

#include <SPI.h>
#include "Streaming.h"

/* Notes on SPI:
https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi/all

*/

  1. pin outs

// define SPI pins
// Due pin out: http://www.robgray.com/temp/Due-pinout-WEB.png
#define CLK 110 // clock pin. CLK. SCK.
#define DATA 109 // data in. DIN. MOSI.
#define OPERATE 25 // operation. OE.
#define LATCH 52 // latch. LE. CS pin, but inverted.
// use a NPN transistor to invert the CS pin for LE usage.
// Inverter schematic: transistors - How to invert a digital signal - Electrical Engineering Stack Exchange
// kind of a trick, but otherwise you have to wait some amount of time for the data to propogate before latching.
// this way, the CS (slave select) will toggle low when starting to write then low after writing completes.
// this is the opposite logic from what you need with LE, so use a NPN to invert.

  1. support functions:

// OE pin must be low to allow latched data to have effect
void startOperation(){
digitalWrite(OPERATE, LOW);
}
void stopOperation(){
digitalWrite(OPERATE, HIGH);
}

  1. setup()
    pinMode(OPERATE, OUTPUT);

SPI.setDataMode(LATCH, SPI_MODE0); // CPOL=0, CPHA=0
// "DIN is the serial-data input, and must be stable when it is sampled on the rising edge of CLK."
// see Serial Peripheral Interface - Wikipedia
// At CPOL=0 the base value of the clock is zero.
// For CPHA=0, data are captured on the clock's rising edge (low?high transition) and data is propagated on a falling edge (high?low clock transition).

// this ought to work. MAXIM claims 30 MHz.
SPI.setClockDivider(LATCH, 4); // 82/4=20.5 MHz on the DUE

// "Data is shifted in, MSB first. This means that data bit D15 is clocked in
// first, followed by 15 more data bits finishing with the LSB, D0."
SPI.setBitOrder(LATCH, LSBFIRST);
// tinker as needed.

// begin
SPI.begin(LATCH);

// I have 2 Maxims, so 4 bytes of data
SPI.transfer(LATCH, 0, SPI_CONTINUE );
SPI.transfer(LATCH, 0, SPI_CONTINUE );
SPI.transfer(LATCH, 0, SPI_CONTINUE );
SPI.transfer(LATCH, 0 );

// OE enable
startOperation();

  1. loop()

// two Maxims, so 32 bits, which is the size of a long.
static unsigned long sl = 0;

SPI.transfer(LATCH, sl >> 24, SPI_CONTINUE );
SPI.transfer(LATCH, sl >> 16, SPI_CONTINUE );
SPI.transfer(LATCH, sl >> 8, SPI_CONTINUE);
SPI.transfer(LATCH, sl );

delay(100);
sl++;

Transistors. You need to use PNP (p-channel). The chips are open drain, meaning they sink current (not a voltage source). N-channels won't trigger unless you do some zany inversion. Hook the gate of the p-channel to OUTn, source to ground and drain to the led cathode. +V to led anode.