# Max7221 x 3 cascading problem

Status
Not open for further replies.

#### Superdat

##### Member
Hi
I've built a pcb as part of a bigger project which has 3 x Max7221 driving 3 banks of 7 segment LEDs x 8 digits
I.e. 8 digits per Max7221.
It is being driven with an Atmega328P on a development board using SPI.
This is the 1st time I've tried cascading and after fixing the pcb problems and figuring out how to cascade, I've got it working.
However there is one problem, the LEDs on the 3rd bank flicker.
I noticed that the flicker is the difference between the character displayed in bank 1 and its equivalent digit in bank 3.
E.g. If bank 1 digit 1 is 7 and bank 3 digit 1 is 1, the top of the 7 (-) flickers in bank 3 digit 1
If I make bank 1 digit 1 blank, the flicker in bank 3 stops.

I thought it might be a timing problem and tried numerous variations but no success.
It's not the pcb hardware because I strung 3 ready made 8 digit 7 segment LEDs together and I get the same problem.

Any suggestions? Preferably based on some sort of logic

Last edited:

#### Tony Stewart

##### Well-Known Member
need schematic , timing details.

#### Superdat

##### Member
need schematic , timing details.
Schematic as per data sheet, As I said before I've tried numerous variations on timing. E.g. after each 16 bit word, after each digits set of data, separately and together, vaious durations, makes no difference.
What I didn't mention is I'm using an 8Mhz crystal oscillator, but I've tried lower speeds and Int RC, again no difference so I don't think that's relevant.
What exactly do you mean by "need timing details"?

#### throbscottle

##### Well-Known Member
Assuming there's no strange stray connection between the bank 3 anodes and the bank 1 anodes...
It might be worth your while to draw a timing diagram showing exactly when each segment is supposed to be on, based on working through the code you have written. Tedious (and in your case, a huge task) I know but you might have a magic face-palm moment!
It might also be worth getting the code pulse through each digit at a speed you can actually see, this might reveal what's going on. You might find your bank 3 digits are being lit at the same time as bank 1 on every 23rd loop, or something along those lines. Impossible to spot at full speed, but obvious if it is happening at human speed.

#### Tony Stewart

##### Well-Known Member
Is NO DECODE mode being used?

Bank sequence is 123...123...repeating
problem is .. flicker on Bank 3 sometimes shows Bank1
Can you determine exact flicker rate? Random ? Interleaved? relative to refresh rate?

Sounds like a crosstalk issue. Does touching the digits alter the flickering?

#### Superdat

##### Member
Decode mode is being used. Flicker is maybe every 500Ms and very consistent. It's like there's an overlap of bank1 and bank3 but only bank 3 flickers.
Can't say if it's Interleaved or not, I can't see anything in the Max7221 datasheet that allows you to change it. Once it's been latched the Max7221 seems to handle everything.
So slowing down SPI data delivery as I think was suggested before won't achieve anything, if my understanding is correct.
I've also swapped the 3 x Max7221 about to see if one was not working properly, same result.
I've reduced the program down to Bank 1-3 and digit 1 only so not much to get in the way, I'll try some experiments with that.
It can't be hardware because it does it on my pcb and 3 x cascaded 8 digit 7 segment displays (bought not made).

#### Tony Stewart

##### Well-Known Member
I can't see how to do it even if one tried. Is it possible to look at the data and addresses on a DSO with CS?

#### Superdat

##### Member
I've solved the problem!
Seems I didn't understand how to send the cascade data well enough.
I was trying to send data to one digit at a time. I should have send data to 3 digits in each column in one SPION/OFF block
e.g. For simplicity I haven't shown address register data which goes before the digit data.
Method that did not work well:
SPIOn
C1data
SPIOFF
SPIOn
C2data
NOP
SPIOFF
SPIOn
C3data
NOP
NOP
SPIOFF
The method that works is:
SPION
C3data
C2data
C1data
SPIOFF

YaaHoo!

#### JimB

##### Super Moderator
I've solved the problem!
Seems I didn't understand how to send the cascade data well enough.
.
.
.
YaaHoo!
Nothing to beat that feeling of elation when you find the quick and easy way to do something, and it works far better than the hard way!

Been there, done that, many times.

JimB

#### throbscottle

##### Well-Known Member
Am I right in thinking you got confused by bit about no-op codes in the datasheet? I just read through it and it took me a minute to realise it refers to addressing a chip in isolation. Your second method just ripples the data through, which is what it says should happen, elsewhere in the sheet.
Well done for getting there

#### Superdat

##### Member
Am I right in thinking you got confused by bit about no-op codes in the datasheet? I just read through it and it took me a minute to realise it refers to addressing a chip in isolation
Well I didn't get confused by the references to No-Op, this is how it suggests multiple Max7221/7219 should be addressed and that is exactly what their written example shows (N0-Op Register). This is how I programmed it.
It isn't referring to single chips at this point, you can't cascade to a single chip.

All data is loaded into a Load buffer while CS/Load is low, when CS goes high it is transferred into the buffer used to display the data and latched. So even if the MicroP is removed the LEDs continue to display data.
Single chips are easy(ish) just send the digit address followed by its value (Decode Mode).
Non decode is harder because each segment has to be selected so you have to work out the data value.
If you send 32 bits (4 x 8 bits using SPI) to a single chip the 1st 16 bits (addr + data) get pushed out of the load buffer by the 2nd 16 bits. It is pushed out of the data out pin. When CS goes high the 2nd set of data is transferred to the LEDs buffer. The term "ripples through"sounds nice but doesn't really explain what's happening.

This all seems incredibly obvious now but it's taken me quite some time to figure it out.
Once you get it clear in your mind it all makes sense, hence the solution!!
Data sheets aren't IMO the most friendly documents I've ever seen.

Must say I'm pretty pleased with myself having gone from being totally confused by the data sheet (some time ago) to
being able to explain what parts of it mean I won't claim enlightenment for all of the datasheet.
Lessons now available for a fee ;-)

Think I'll change my name to Super7SEGMan LOL

#### throbscottle

##### Well-Known Member
Well I didn't get confused by the references to No-Op, this is how it suggests multiple Max7221/7219 should be addressed and that is exactly what their written example shows (N0-Op Register). This is how I programmed it.
It isn't referring to single chips at this point, you can't cascade to a single chip.
I meant a single chip within the cascade, Mr Super7SEGMan

I agree about datasheets. You have to read them with care. A bit like reading man pages.

#### Superdat

##### Member
I meant a single chip within the cascade, Mr Super7SEGMan

I agree about datasheets. You have to read them with care. A bit like reading man pages.
Yes it was a bit confusing using the method suggested which is data to one chip in the cascade only, and this method is what casued the flicker.
There's a clue in the name of Man pages, Real Men only
I think the main problem with data sheets is that the person writing them either:
a. Understands exactly how it works and can't see any difficulty. To them it's totally obvious.
b. doesn't fully understand what they are trying to explain.
The result either way is a document that's difficult to understand especially when people just want a quick reference to make "it" go.

Last edited:

#### Superdat

##### Member
Follow up to above. The circuit works perfectly with one annoying "feature". At power on either all Segments show zero and stick on zero or only the first column of 2 x 8 7segs (outputs from 1 x 7221). If I powered off and waited until all LEDs had turned off, then powered on quickly, all 6 x 8 7segment displays worked as intended. Although the LEDs didn't work as expected, the rest of the circuit, temperature monitoring etc all worked OK. So it looked like the programming rather than the electronics. Who did the programming? Oh, it was me ;-)

After a few hours of fiddling I made the following discovery:
Both methods of addressing the 3 x 7221/7219 work i.e. 3 sequential commands or using No Op.
Don't know what was different this time but no flicker.
The method without No Op is much more compact, so I stayed with it.

The fix was rediculously easy but I'm not sure why it was necessary.
Test On x3, a small delay of 10ms followed by Test Off x 3, both after all the other Setup commands, just before loop:

I also did some experiments with the setup commands e.g. Intensity, scan length, Normal mode On/Off. etc to see if they all needed x3 of each.

They did, if you don't, the push out to the next 7221/7219 gets out of sync with odd results. Each 7221/7219 needs its own command

Hope this helps someone else!

##### Well-Known Member
Hi super... I understand your 'fiddling' I've been using 3 x 7921 +3 x 8x8 led matrix for a clock,( 4 digits and colon ) it took me hours of fiddling to get the two middle leds to flash for the colon... (PIC24 & C ) , I hope to 'pinch' two unused matrix columns to show seven seg seconds, or date .

#### Superdat

##### Member
Hi G
I'm assuming 7921 is a typo? 7219 I hope. I would think 8x8 matrix are even more of challenge to visualise. I've not done much with 8x8 matrix, only a few proof of concept programs, but you've just given me a thought I have a couple of them I've done several 3/4 x 7 segs with DIY character sets though which is similar. Do you use "Lookup" to define what each row/column (depending which way up the array is mounted)? Bit of work needed to see what code does what, but then way easier to trouble shoot if things don't work out. You don't have to keep trying to visualise everything.
n.b. "Super" is just my lazy way of getting the user name I want i.e. dat, it's not meant to imply any special ability.

##### Well-Known Member
Typo ! Hi S. My sw (C) is that of a 4 year old, so what i post here is what i got to work , that's all . http://www.electro-tech-online.com/threads/just-a-clock.149289/page-2#post-1281287

One of several arrays ... this one for the time ....
Code:
                           //------ digit Posiiton 1--|                     |--------digit 2------|
unsigned int Time_frame[]={0x0600,0x0500,0x0400,0x0300,0x0800,0x0700,0x0200,0x0100,0X0800,0x0700,
//--d2|----- GAP  ---------//------- D3----------------|      |------------- D4----------|
0x0600,0x0500,0x0400,0x0300,0x0200,0x0100,0x0800,0x0700,0x0600,0x0500,0x0400,0x0300,0x0200,0x0100}; //
several font characters.
Code:
// SMOOTH FONT
unsigned char SM_font[]={0x3E,0x41,0x41,0x3E,    0x40,0x7F,0x42,0x00,  0x6E,0x49,0x49,0x72,
// ZERO                    ONE                   TWO
0x3E,0x49,0x49,0x22,    0x7E,0x08,0x08,0x0F,  0x30,0x49,0x49,0x2F,
// THREE                   FOUR                   FIVE
0x30,0x49,0x49,0x3E,    0x7F,0x01,0x01,0x03,  0x36,0x49,0x49,0x36,
// SIX                     SEVEN                 EIGHT
0x3E,0x49,0x49,0x26,    0x00,0x7C,0x10,0x7C,  0x00,0x7C,0x08,0x7C,
// NINE                    'H'10                 'M'11
0x78,0x14,0x78,0x00,    0x62,0x14,0x08,0x7F,  0x00,0x00,0x00,0x00,
// 'A'12                    'K'13                 ' blank' 14
0x09,0x09,0x09,0x7F,    0x30,0x48,0x48,0x30,  0x70,0x08,0x08,0x70,
// 'F' 15                   'o'16                'n' 17
0x02,0x42,0x7F,0x02,    0x41,0x41,0x41,0x3E,  0x00,0x68,0x14,0x7C,
// 't' 18                  'C'19                 'R' 20
0x48,0x30,0x30,0x48,    0x41,0x41,0x41,0x41,  0x00,0x68,0x14,0x41};
// 'x' 21                  ''22                 ''23
then fills frame with font for digits set positions.
Code:
void Load_dots(unsigned int position,unsigned char value, unsigned int *frame)
{
unsigned int dotp;
int x;
int Blank=0;
value=value*4;
if(position==1)dotp=0;
if(position==2)dotp=7;
if(position==3)dotp=14;
if(position==4)dotp=19;
if((position==4)&&(value==0x00)) Blank=1;
if(C_Font==1) // Square font
{
for ( x = 0; x < 4 ; x++)
{
frame[dotp+x]=frame[dotp+x]&(0xFF00);
if(!Blank)
{
frame[dotp+x]=frame[dotp+x]|(SQ_font[value+x]);
}
}
}else{  // Smooth font
for ( x = 0; x < 4 ; x++)
{
frame[dotp+x]=frame[dotp+x]&(0xFF00);
if(!Blank)
{
frame[dotp+x]=frame[dotp+x]|(SM_font[value+x]);
}
}
}
}
send to MAX chips.
Code:
void Send_dots(unsigned int  *frame)
{
int x;
for ( x = 0; x <= 7; x++)
{
MAX_dot_bb(frame[x],0);    // send to MAXIM display chip...
MAX_dot_bb(frame[x+8],0);    //
MAX_dot_bb(frame[x+16],1);
}
}
The BitBang.
Code:
void MAX_dot_bb(unsigned int test,int chip_load)
{
#define MAX_data LATBbits.LATB1
#define MAX_clock LATBbits.LATB2

unsigned int x ;
for ( x = 0; x <= 15 ; x++)
{
if (test & 0x8000) {
MAX_data = 1;
}else{
MAX_data = 0;
}
Nop();
MAX_clock = 1;       // Clock high
Nop();
MAX_clock = 0;       // low
test = test << 1;
}
{
MAX_data = 0;  // drop data line
}
}
The PIC24FV32KA302 @ 4MIPS has loads of spare memory so I want to do more with the date and alarm / sleep stuff .

Last edited:

#### Superdat

##### Member
Hi
Didn't realise you were using C, Oshonsoft uses Basic so you're likely in the wrong forum. I can just about make out what a C program is doing, but I don't know enough to comment on your program.

##### Well-Known Member
Hi Super, C is not that far removed from Basic , I found the move from basic with Z80 to asm harder, than going from basic to C . I commented because i saw your reference to a delay 10ms solving your problems, and I don't have any delays coded for data or initialization.....

#### Superdat

##### Member
Hi
Well Basic has different flavours, e.g. Proton, GCB, MEL etc each one slighlty different. Sufficiently so that there is usual a forum for each.
From what I've seen Basic is more similar to JAL or Arduino than it is to C. I've looked at C and find it quite a lot different, sufficiently so that I decided not to invest any time learning it. I''m not exactly in the first flush of youth and can't see any real benefit, Basic is fine for my needs.
I can understand JAL and other Basics but I can't understand C
So I don't agree with your comment.
C is not that far removed from Basic
I have programmed with JAL, but I don't think giving someone a working example in JAL is very useful to someone who has a problem with any other type of language unless it is very generic and well commented.

If an example is specific to an IC that's fair enough, but if it's in code, it needs to be well commented, otherwise IMO it's just showing off or laziness.

Your example has some comment and I can figure out the general flow but I would not be able to readily convert it into Basic. To be cruel, why did you post it? It didn't help me and I can't help you. Neither of us had a problem.

To answer my own question "Did you use Lookup?"
"No because I'm using C, but I did use C's version of lookup tables."

I'm sure you are very pleased with your program as am I with most of mine, but I don't think posting it here is very helpful.
The program I wrote for this project includes routines for Max7221, ADC with thermisters, DHT22, Very Low Frequency PWM etc and it is enormous. Because of this I would not consider posting it. Bits of it maybe if someone had problems in that area and asked.

The fix wasn't a delay of 10mS, it was turning Test ON then Test Off.

Status
Not open for further replies.