MAX6953, driving 4 5x7 matrix displays

Hey gang, took a couple of nights, finally got MAX6953 working to drive four 5x7 led matrix displays. My application is to read the time coming out of a fencing scoring machine and to display it in big digits. (Previously remote displayed the 6 score lights just using individual pins to turn on discrete transistors for banks of LEDs).
Was having trouble getting the digits to be as bright as during the display test (all LEDs on at half power), finally realized need two nibbles of info in two locations to control 4 digits.

The 6953 supports 2 registers per digit (Plane0 & Plane1) and allows one blink back & forth between them. I am not doing that, I only write to Plane0 and don’t do any blinking.

To breadboard, needed 3 strips of protoboards with 5x7s mounted 2 above the 6953 and two below. The 5x7s span the full width of the 3 strips, so all the interconnections were done at the sides of the 40-pin dip in the middle of the board. MAX6953 & Displays are wired per MAX6953 datasheet. 5V Power is from Duemilanove. Colon is 2 LEDs in series with 390R from +5V to D3.
Have 4.7K pullups on SCD, SDA, Blink.
Have 22K for Rset & some small cap for Osc-set, not sure of value but the display is rock solid, can’t see any flickering.

Goal for this program - grab serial xmissions from PC’s USB port, send out the time parts to MAX6953 for display on four LITEON LTP-2057 5x7 displays.
MAX6953 & Displays are wired per MAX6953 datasheet. 5V Power is from Duemilanove. Colon is 2 LEDs in series with 390R from +5V to D3.

Looking for these bytes

  • Byte with MSBs = 0000
  • Byte with MSBs = 0001
  • Byte with MSBs = 0010
  • Byte with MSBs = 0011

Using IIC (I2C) for interfacing to MAX6953

  • Arduino analog 5 - I2C SCL, pin 24
  • Arduino analog 4 - I2C SDA, pin 23

#include <Wire.h> // bring in Wire Library

// I2C device address is 1 0 1 A3 A2 A1 A0 with AD1, AD0 both low so looking for A3-2-1-0 to be all low also.
#define COMMAND_ADDRESS 0x50 // (B1010000), 7 bits
#define CONFIG_ADDRESS 0x04
#define INTENSITY10_ADDRESS 0x01
#define INTENSITY32_ADDRESS 0x02
#define DIGIT0_ADDRESS 0x20 // write Plane 0
#define DIGIT1_ADDRESS 0x21 // write Plane 0
#define DIGIT2_ADDRESS 0x22 // write Plane 0
#define DIGIT3_ADDRESS 0x23 // write Plane 0
// just realized I never defined the Display Test as 0x07, just put it in.

unsigned int val = 0; // variable to store the 5 bytes that come in, a byte every 5 ms (200 Hz rate)

int maskupperbyte = 0;
int masklowerbyte = 0;

int Minutes_Tens;
int Colon;
int Minutes_Ones;
int Seconds_Tens;
int Seconds_Ones;
int numberToDisplay;

int ColonLED=3;
void setup() {

// no need to define pinMode for A4, A5, set up by library
pinMode(ColonLED, OUTPUT);

// start up I2C, uses Analog 5 for Clock, Analog 4 for data
Wire.begin(); // nothing in () because we are the master

// write config register
// 0000 0001 => 0 shutdown, 1 = normal mode, no fooling with blink modes & stuff
// 0000 0010 = not used
// 0000 0100 => 0 slow blink, 1 = fast blink
// 0000 1000 => 0 = global blink disabled (Plane 1 data ignored), 1 global blink enabled Plane 1 data used)
// 0001 0000 => 0 = blink unaffected during I2C acknowledge
// 0010 0000 => 0 = data unaffected during I2C ack, 1 = data cleared
// 0100 0000 => not used
// 1000 0000 => blank phase - blink status is read back

// for this use: 0000 0101 => normal operation, fast blink


// write intensity10 register
Wire.send(0xEE); // E = 15/16 (max), 1 nibble each for digit 0 & 2

// write intensity32 register
Wire.send(0xEE); // E = 15/16 (max), 1 nibble each for digit 1 & 3

// write scanlimit register
Wire.send(0x01); // 01 = 4 display digits

//display test
Wire.send(0x01); // 01 = display test on
delay (1500); // for # of milliseconds
Wire.send(0x00); // 00 = normal operatiom
Wire.endTransmission(); // does not change loaded data tho

Serial.begin(4800); // open the serial port
// Need 4800 for Firefly operation.
// PC COMx uses 57600 for downloading via USB.
} // end of void setup

void loop() {

// read the incoming byte:
val =;

// search for a message -interestingly, will not work correctly using Arduino -0019
// serial monitor function to send bytes out - need to use program like RS232 Monitor,
// better simulates the actual device that will be sending us data.
// Wonder if due to val being declared as unsigned int?

maskupperbyte = val & 0xF0; // looking for 1xxx and 0000-0011 in real application.
masklowerbyte = val & 0x0F; // looking for 0000-1010 in real application

// MSB=0+000 → data has weapon 00-01-10, Colon bit, Ten-Minute bit
if (maskupperbyte == 0x00)
// lowerbyte bit 0 = tens of minutes, only 0 or 1
// lowerbyte bit 1 = colon, 1 = on, 0 = off
// other bits are don’t cares

// if LSB is high, display a 1, otherwise blank it, font is per table 15
// write 0x20 (blank) or 0x31 (1) depending on Tens bit
int Minutes_Tens = val & 0x01;
if (Minutes_Tens == 0)
numberToDisplay = 0x20;
numberToDisplay = 0x31;

// sequence needed is Command, Data Pointer, Data
// write digit0 register

Colon = masklowerbyte & 0x02; // see if colon is on or off
if (Colon == 0x02)
{digitalWrite(ColonLED,LOW);} // pulling cathode of LED low to turn it on.
} // end of maskupperbyte == 00

// MSB=0+001 → data = single minutes, 0-A, A is command to blank the digit, B-F will not be sent
if (maskupperbyte == 0x10)
if (masklowerbyte == 0x0A)
// write 0x20 for blank
numberToDisplay = 0x20;
Minutes_Ones = masklowerbyte;
numberToDisplay = 0x30|Minutes_Ones; // add 0011 for upper nibble per Table 15
// write digit1 register

} // end of maskupperbyte = 10

// MSB=0+010 → data = Ten-Seconds, 0-A, A is command to blank the digit, B-F will not be sent
if (maskupperbyte == 0x20){
if (masklowerbyte == 0x0A){ // write 0x20 for blank
numberToDisplay = 0x20;
else {
Seconds_Tens = masklowerbyte;
numberToDisplay = 0x30|Seconds_Tens;
// write digit2 register
Wire.send(numberToDisplay); //

} // end of maskupperbyte == 20

// MSB=0+011 → data = single seconds, 0-A, A is command to blank the digit, B-F will not be sent
if (maskupperbyte == 0x30){
if (masklowerbyte == 0x0A){ // write 0x20 for blank
numberToDisplay = 0x20;
else {
Seconds_Ones = masklowerbyte;
numberToDisplay = 0x30|Seconds_Ones;
// write digit3 register
Wire.send(numberToDisplay); //

} // end of maskupperbyte == 30

// for testing, I commented out the serial read, and incremented val here by 0x11 to give the displays something to show, with a slight delay. makes for odd looking results, but just wanted to see that it worked.

} // end if available

} // end void


Great job!. I've interfaced the same IC with an ATMEGA uC. I'm confused with the addresses for using multiple chips. The datasheet says connecting AD1 & AD0 to VCC & GND(without using the SDA &SCL for address) should be 0xA0, 0xA2, 0xA8 and 0xAA. But when I connect the third chip it fails to work properly, it just shows up garbage on the display. Can you show some light on this.

You have changed the address in your equivalent of this line to have 3 unique addresses? 0x50 0x51 0x52 with the AD1 & AD0 lines tied to Gnd/Gnd; Gnd/Vcc; and Vcc/Gnd on the 3 chips?

// I2C device address is 1 0 1 A3 A2 A1 A0 with AD1, AD0 both low so looking for A3-2-1-0 to be all low also.

define COMMAND_ADDRESS 0x50 // (B1010000), 7 bits


Thanks for your reply. I find that interfacing a single IC will work fine since the address will be 7 bit (1010 000)+(1bit of Read/ write'). So for writing into this IC, I think the address will be 1010 0000 = 0xA0. Kindly refer timing diagram - Fig.6, Page 8. of datasheet.


Well, maybe I was just lucky then and the Stop bit was treated as the 8th bit.

You could try these then 0b101 0000 0 with A1/A0 = 0, 0 chip 1 0b101 0001 0 with A1/A0 = 0, 1 chip 2 0b101 0010 0 with A1/A0 = 1, 0 chip 3

I only wired up & tested 1 chip driving 4 displays.


I've interfaced 4 chips now, but I'm facing problem with the "ISET" resistor.What value have you used? If I use a 57K then the displays show some garbage things & when I decreased it down to 30K, it worked OK but the intensity was poor. Then further reducing it to 10K it gives me the desired intensity. Can you guide me through this. I'm using a 27pF capacitor for "CSET". What is the Osc. frequency gets above 8MHz as specified?

I had these notes in the schematic I did and an excel worksheet:

Fosc = Kf / (Rset x (Cset (pF) + Cstrat (pF) )) x10E6 MHz, limit is 1 to 8 8.802052786, 6003, 22000, 0.000000027, 0.000000004, 1,000,000.00 MHz

So 8.8MHz with 22K, 27pF, 4pF of stray capacitance


I too made a Excel Worksheet to get the calculations done, but I was a bit concerned with the values of RSET & CSET. You were lucky to get the DIP package, I've got an SMD package when I purchased them.

Any ways great we got this tricky IC working! :D :D :D

Oooh, the SMD - was that intentional or did you not get the correct suffix on the order?

No it was not intentional, but that DIP part was not in stock when I ordered them, so I had to go for the SMD package! :(

Maxim makes a lot of nice stuff but a lot of it is only SMD, which can be a pain. I have bought SMD to DIP adapters from this place to make breadboarding easier (and it was no fun soldering 0.025 spaced pins down! - tho it did make 0.05 seem pretty easy!)

This place also has them

Another option is this, SOIC breakout board.

I think for a completed system, l prefer until I start making my own boards up.

Hey, a great link! :) Thanks for sharing! I find it really useful for starting with the proto type version of my developments... Logical.sys seems to have good quality PCB's.