Go Down

Topic: [FTTB] 16x16 rgb matrix part 2 (Read 3756 times) previous topic - next topic

xforce30164

Nov 17, 2011, 11:10 pm Last Edit: Nov 17, 2011, 11:16 pm by xforce30164 Reason: 1
As the original thread is bugged, the second page is just blank ill continue posting in this thread until the old one is fixed or the problem is solved in any other way;)
==========================================================================================================================================


Hi all, I havent been online for some time due to the start of my study at the technical universty Eindhoven, (electrical engineering  ;) ) However i have made some progress in the meantime.

I made a clear layout for how i want to controll my matrix. for now i will have four modes:
1) 'normal' arduino visualizer mode, works like a normal matrix controlled by nested and linked shift registers (details further on)
2a) lm3914 mode; lm3914 collumwise controlled; lower 6 rows are blue and controlled by low freqs, 6 rows above that are green and controlled by middle freqs, top 4 rows are red and controlled by high freqs. Arduino controlls which rows are on or off. 'loudness' is shown from center outwards.
2b) lm3914 mode; same as above only that the loudness is shown from the sides towards the center.
3) graphic equalizer mode, arduino controlled, inputdata generated from the dual mseq7 shield.

the basic representation of how the matrix is controlled is like this:
Code: [Select]

[audio]-{3}->\#\-{3}->[mseq7 shield]-{?}->[arduino]--{10}-->[shift register module]--{64}-->/$a/[mode selector mux logic]-{64}->[matrix]
             \#\-{3}->[lm3914 board]-----------------------{48}--------------------------->/$b/
           
were the \#\ thing is a duplication of the signal and the /$(a|b)/ things are inputs for the mux logic board. the numbers in the curled brackets show the bus-width.
it looks relatively simple until now but to get all the ideas worked out took me quite some time, and i still am not yet done with the mux logic.
(partly because i have a load of logic ic's lying around i decided to build the multiplexor-like circuit myself!)

now about the shift register module (as the rest is quite straight foward compared to it)
i have devided the matrix inputs into 4 groups, 16 row v+ inputs, 16 red collum ground 'inputs', 16 green collum ground 'inputs' and 16 blue collum ground 'inputs'.
the v+ are controlled by 2 74hc595 shiftregisters, serialdata linked through, latch and clock on each chip combined to the latch and clock of the other chip.
the columns are controlled by 2 74hc595 shiftregs aswell, same config but the outputs are connected to two uln2803 chips to make them inderectly sink the collums when turned on.
the problem is that if i want to control these 4 sets or shift registers i would need 12 pins, 4x[serial data, clock, latch] which was just not practical. so i came up with
the following solution:
i added an extra shift register which controls the clock and latch of each of the 4 pairs of shift registers. now i only need 7 datalines to control all the shift registers.
serial data, clock and latch for the 'controlling' shift register and only serial data for each of the four pairs as the clock and latch signals of those are managed by the controlling shift register.
connected in the following way:
Q0 = clock v+ regs
Q1 = latch v+ regs
Q2 = clock red regs
Q3 = latch red regs
Q4 = clock green regs
Q5 = latch green regs
Q6 = clock blue regs
Q7 = latch blue regs

I realize this isn't the smartest or fastest way but i liked the idea and want to see if i can get it to work. (if it doesnt im thinking of using a 27c256 EEPROM IC which i found a few days ago.

i've already started on coding the first mode and this is what i've got until now, it would be great if someone could look through it (when they have time left or feel like doing that) to see if
it seems sort of reasonable to work or not.

I'll keep you guys posted on further updates!!

the code:
Code: [Select]
const int ctrl_latchPin = 2, ctrl_clockPin = 3, ctrl_dataPin = 4;
const int a = 5, b = 6, c = 7, d = 8;

void setup() {
 pinMode(ctrl_latchPin, OUTPUT);  
 pinMode(ctrl_clockPin, OUTPUT);
 pinMode(ctrl_dataPin, OUTPUT);
 pinMode(a, OUTPUT);
 pinMode(b, OUTPUT);
 pinMode(c, OUTPUT);
 pinMode(d, OUTPUT);

 Serial.begin(9600);
 Serial.println("reset");
}

int bit_int(int bitarray[]){
int tempdata = 0;
for(int i = 0; i < 8; i++)
{
if(bitarray[i]==1)
tempdata += 1 << i;
else
tempdata = tempdata;
}
return tempdata;
}

void shiftreg(int whichReg, byte bitdata){
int data = int(bitdata), clktemp = 0;
int datarray[8] = {0};
int ctrlarray[8] = {0}; // = {clk vss, latch vss, clk red, latch red, clk green, latch green, clk blue, latch blue}

for(int i = 0; i<8; i++)
datarray[i] = bitRead(data, i); //placing data into the array, LSB will end up on place 0 of the array

for(int j = 8; j>0; j--)
{
ctrlarray[(2*whichReg)]=0; //reg clk = low
clktemp = bit_int(ctrlarray);

shiftOut(ctrl_dataPin, ctrl_clockPin, LSBFIRST, clktemp);
digitalWrite(char('a'+whichReg), datarray[j]);

ctrlarray[(2*whichReg)]=1; //reg clk = high
clktemp = bit_int(ctrlarray);

shiftOut(ctrl_dataPin, ctrl_clockPin, LSBFIRST, clktemp);
}
}

void loop() {
registerWrite(0,0,HIGH);
delay(250);
registerWrite(1,7,HIGH);
delay(250);
registerWrite(1,7,LOW);
delay(250);
registerWrite(0,0,LOW);
delay(250);
}

void registerWrite(int whichReg, int whichPin, int whichState) { //vss = 0, red = 1, green = 2, blue = 3;
 unsigned int bitsToSend = 0;    
 int controlbits = 0, tempdata = 0;
 int ctrlarray[8] = {0}; // = {clk vss, latch vss, clk red, latch red, clk green, latch green, clk blue, latch blue}
 
 digitalWrite(ctrl_latchPin, LOW);

ctrlarray[(1+(2*whichReg))] = 0; //set data to make latchpin low
tempdata = bit_int(ctrlarray);

shiftOut(ctrl_dataPin, ctrl_clockPin, LSBFIRST, tempdata); //vss latchpin high

bitWrite(bitsToSend, whichPin, whichState);

byte registerOne = highByte(bitsToSend);
byte registerTwo = lowByte(bitsToSend);

shiftreg(whichReg, registerOne);
shiftreg(whichReg, registerTwo);

  ctrlarray[(1+(2*whichReg))] = 1; //set data to make latchpin high
tempdata = bit_int(ctrlarray);

shiftOut(ctrl_dataPin, ctrl_clockPin, LSBFIRST, tempdata);
 digitalWrite(ctrl_latchPin, HIGH);
}


xforce30164

On my way back home in the train yesterday i got a kind of brainwave and it was about the controlling shift register.
I've now found a much more simple way to control my four pairs of shift registers. the idea is that im going to use three 1-to-4 demuxers for the clock, latch and datasignal from the arduino. I'll make a function where i pass the data i want to send and to which register. This function then puts the correct signal on controllines A and B for the demuxers and then just calls the shiftOut function.

I've added a quick sketch to give you an idea if you dont get it from my very short explanation;)

Grumpy_Mike

You don't need to go to that much trouble. You can do one of two things:-
1) Cascade the shift registers. You are having to write to them all every refresh so why not?

2) Have common data and clocks for all shift registers and just have a separate latch for each shift register.

xforce30164

Hey Grumpy_Mike,
With cascading i gues you mean to chain them all together in one long link?
If that is what you mean, ill explain why i havent chosen for that option, in other threads about the shift registers and multiplexing here on arduino.cc and other sites i came
Across many different designs; however as i was/am planning on implementing pwm i came to the conclusion that 4x 2 linked shift regs would be faster for my usage than all 8 linked together. Because i can now change just the blue leds if i only need to change the blue ones and i dont need to think about the datq for the other 6 shift registers; which means i only need to send out 2 bytes instead of 8 of which 6 bytes have to be stored somewhere to be kept the same. However i will see how this will work and otherwise ive got an nxp 32bits uC i cam borrow from a friend of mine which should be mpre than fast enough (80~100mhz clock).
However i like to get it to work with the arduino and this (relatively) small matrix and later upgrade it to an even bigger one.

The second option also came across my mind but i (maybe incorrectly) threw it away again cus i thought that you then still need to send all the 8 bytes of data (or am i wrong here). Furthermore if i would use a shared clock and data and 4 seperate latch lines this would result into six pins being used whilst with the demux way i only use five pins and there is hardly any change needed in my code.

(by heart i recall solving it like this:)
Code: [Select]

Void registerWrite(int whichRegister, int whichPin, int whichstate){
int mux_0[4] = {0,0,1,1};
int mux_1[4] = {0,1,0,1};

digitalWrite(mux_0Pin, mux_0[whichRegister]);
digitalWrite(mux_1Pin, mux_1[whichRegister]);

And then the rest of the code which puts the data into an unsigned int and bitwrites the pin and state and then splits the 16bits into two bytes; one for the first and the other for the second shiftreg of the pair.

However if i am thinking weird or basing it upon wrong info/assumptions please let me know!

Grumpy_Mike

Quote
With cascading i gues you mean to chain them all together in one long link?

Yes.

Quote
i thought that you then still need to send all the 8 bytes of data

You always do with shift registers.
Quote
and data and 4 seperate latch lines this would result into six pins being used whilst with the demux way i only use five pins

Well you are balancing one pin versus two chips, I know what I would take.
However, if you used a 74LS138 then the 4 latch pins goes to 2 and the solution only uses 4 pins, if pins are that valuable to you.

Quote
Because i can now change just the blue leds if i only need to change the blue ones

No that is not the way you should think about it. You must separate the mechanism for updating your matrix from the pattern of what you are actually displaying. Mixing the two up will ultimately tangle you up. You need a section of memory that contains the bits you are going to display and code that displays that memory. Then all you do is to interact with that memory to generate your patterns by program algorithm or by predefined blocks of memory or frames.
Have you seen this:-
http://www.thebox.myzen.co.uk/Workshop/LED_Matrix.html

xforce30164

Hey Grumpy_Mike,
Ah i get it. Indeed if i think about it now it is smarter to make the update routine 'universal' instead of wanting to split it up. So that would mean i just cascade all the shift registers and then only need three pins? Is it smart to buffer the clock and serialdata and latch signals or is that not needed? (as all the shift registers are on one pcb/perfboard arranged around the edges, size of the pcb is around 10x15cm or something similar). So it is best/easiest to have some kind of 64bits [8bytes] buffer which i write the new values which need to be updated, and f.e. i use an array to store them i only need to change the bits i want to change and the rest of the data will be unchanged.

I'll also read your link again even though (i guess) i know the rough basics but it can't hurt to refresh them every once in a while! And it seems to be explained in a very structured way on your site (after scanning through it quickly).

Thanks for the help man!

Grumpy_Mike

Quote
So that would mean i just cascade all the shift registers and then only need three pins?

Yes.
Quote
Is it smart to buffer the clock and serialdata and latch signals or is that not needed?

Not needed when using under 10 to 20 shift registers. But I would add decoupling capacitors across the supply of all shift registers and don't have any capacitors on the latch pin (or any other signal pin) no matter what some tutorials say.

Quote
So it is best/easiest to have some kind of 64bits [8bytes] buffer which i write the new values which need to be updated

Yes have an array and you can either access individual bytes by index or just get the pointer (start of the array) and work out your own offset and bit position. Again a separate routine helps you package your ideas neatly.

Quote
i use an array to store them i only need to change the bits i want to change and the rest of the data will be unchanged.

Yes that's the way to do it.  :)

xforce30164

Ok thanks man! Then ill resolder the caps from the latch to the supply of the chips! thanks for letting me know. Maybe its an idea to have someone change it on the arduino playground tutorial too? Ill keep you (and other readers) posted on how im progressing! ;)

Grumpy_Mike

Quote
Maybe its an idea to have someone change it on the arduino playground tutorial too?

We have been trying for years to get it changed but the powers that be for some reason don't want it corrected.

xforce30164

Hi all,
I've been coding a bit and tried to make my own simple routine instead of trying to implement ElcoJacob's shiftpwm/shiftmatrix lib (as i thought that would be easier  :smiley-sweat:. This is not really working yet so im going to try and see if i can get elco's library working!

btw for the curious ones, this is the code i have written so far for my own implementation (which quite doesnt work yet)
Code: [Select]

const int dataPin = 8, latchPin = 9, clockPin = 10; //latch = rood
//V+[1-8] V+[9-16] R[1-8] R[9-16] G[1-8] G[9-16] B[1-8] B[9-16]
int v_reg[2]={0,0};
int r_reg[2]={0,0};
int g_reg[2]={0,0};
int b_reg[2]={0,0};
int buffer[8]={0,0,0,0,0,0,0,0};

void setup() {
  pinMode(latchPin, OUTPUT); 
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {
for (int i = 0; i < 8; i++){
v_reg[1] = 0;
g_reg[0] = 0;
                r_reg[1] = 0;
bitWrite(v_reg[1],i,1);
bitWrite(g_reg[0],i,1);
                bitWrite(r_reg[1],(7-i),1);
rgbWrite();
// delay(200);
}
}

void regWrite(int b_array[]) {
  digitalWrite(latchPin, LOW);
    for(int i = 7; i>=0; i--) //last reg in chain <=> first data | first reg in chain <=> last data;
      shiftOut(dataPin, clockPin, MSBFIRST, b_array[i]);
  digitalWrite(latchPin, HIGH);
}

void regClear(){
  digitalWrite(latchPin, LOW);
   for(int i = 0; i<8; i++)
     shiftOut(dataPin, clockPin, MSBFIRST, 0);
  digitalWrite(latchPin, HIGH);
}

void bufferUpdate(){
  buffer[0] = v_reg[0];
  buffer[1] = v_reg[1];
  buffer[2] = r_reg[0];
  buffer[3] = r_reg[1];
  buffer[4] = g_reg[0];
  buffer[5] = g_reg[1];
  buffer[6] = b_reg[0];
  buffer[7] = b_reg[1];
}

void rgbWrite(){
  int rgb_buffer[3][8] = {0,0,0,0,0,0,0,0}; // [0][n] = red | [1][n] = green | [2][n] = blue
 
  for(int i = 0; i < 2;i++){
    rgb_buffer[i][0] = v_reg[0];
    rgb_buffer[i][1] = v_reg[1];
  }
 
  rgb_buffer[0][2] = r_reg[0];
  rgb_buffer[0][3] = r_reg[1];
  rgb_buffer[1][4] = g_reg[0];
  rgb_buffer[1][5] = g_reg[1];
  //rgb_buffer[2][6] = b_reg[0];
  //rgb_buffer[2][7] = b_reg[1];
 
  for(int j = 0; j < 2; j++){
  regWrite(rgb_buffer[j]);
  }
}

Grumpy_Mike

Code: [Select]
regWrite(rgb_buffer[j]);
Treats rgb_buffer as a one dimensional array where as in the rest of the code you have it as a two dimensional array, that's not right.

xforce30164

thanks for spotting that one, i've solved it like this:
Code: [Select]

  for(int j = 0; j < 2; j++){
  regWrite(rgb_buffer, j);
  }

and edited the regWrite to
Code: [Select]

void regWrite(int b_array[3][8], int index) {
  digitalWrite(latchPin, LOW);
    for(int i = 7; i>=0; i--) //last reg in chain <=> first data | first reg in chain <=> last data;
      shiftOut(dataPin, clockPin, MSBFIRST, b_array[index][i]);
  digitalWrite(latchPin, HIGH);
}

Grumpy_Mike

Code: [Select]
void regWrite(int b_array[3][8], int index) {
Does that work? I would have thought you were passing a pointer to an array.

xforce30164

whoops, i copy-pasted the old version /facepalm xD!
this is my code:
Code: [Select]

void regWrite(int b_array[]) {
  digitalWrite(latchPin, LOW);
    for(int i = 7; i>=0; i--) //last reg in chain <=> first data | first reg in chain <=> last data;
      shiftOut(dataPin, clockPin, MSBFIRST, b_array[i]);
  digitalWrite(latchPin, HIGH);
}

and changed my rgbwrite to this:
Code: [Select]

void rgbWrite(){
  int rgb_buffer[3][8] = {0,0,0,0,0,0,0,0}; // [0][n] = red | [1][n] = green | [2][n] = blue
 
  for(int i = 0; i < 2;i++){
    rgb_buffer[i][0] = v_reg[0];
    rgb_buffer[i][1] = v_reg[1];
  }
 
  rgb_buffer[0][2] = r_reg[0];
  rgb_buffer[0][3] = r_reg[1];
  rgb_buffer[1][4] = g_reg[0];
  rgb_buffer[1][5] = g_reg[1];
  rgb_buffer[2][6] = b_reg[0];
  rgb_buffer[2][7] = b_reg[1];
 
  for(int j = 0; j < 2; j++){
    digitalWrite(latchPin, LOW);
    for(int i = 7; i>=0; i--) //last reg in chain <=> first data | first reg in chain <=> last data;
      shiftOut(dataPin, clockPin, MSBFIRST, rgb_buffer[j][i]);
  digitalWrite(latchPin, HIGH);
  }
}

Go Up