I was a bit unsure about where to post this, but as I'm over to the software side now, I posted it here.
I've been playing with my 8x8 red-green LED display lately, and used some external ciruitry to minimize the connections to the Arduino. It currently uses 5 pins to PWM control an 8 by 8 LED matrix.
In short I'm using two chained 74HC595 shiftregisters, one for each color on the anode side of the LED's. And one 74HC161 4-bit binary counter connected to a 74HC138, 3-to-8 line decoder. This is for multiplexing the GND to the cathode rows of the display.
Now I'm not entirely sure if I'm within specs of the chips, as I drive the display directly from the 74HC595 and 74HC138 IC's. It seems to work so far
Then again, I haven't tested a full yellow display yet...
To make a nice yellow color found that 1k ohm for the red led's, and about 130 ohm for the green led's, worked well. Vcc is 5V, of course.
This is my current breadboard setup with a quick crude schematics by the side (I'm using the Freeduino BBB from moderndevices):

Here is a test with 2, 3, 4 and finally 8 PWM levels. This is just a proof-of-concept test, the code is not optimised in any particularl way.
Tthe photos not too clear with respects to the colors. The flash have something to do with that I guess.

At 8 PWM levels there is virtually,well, almost no flickering when looking right at the display. I haven't measured exactly, but some tests suggests that for a frame interval of 20ms, there seems to be about 10-12 ms available for some code to execute between each frame. Also, at 8 PWM levels, I don't use any timer between rows, it goes as fast as it can in its present implementation.
For 4 or less PWM's, about 1 ms between rows makes it flicker a bit, but the colors are brighter than without..
I haven't learned anything about interrupts or any advanced features of the arduino language yet, nor have I used any form of direct port manipulation, so this obviously have room for improvement. For now I'm just happy I managed to get my RG display going PWM ![]()
Here is my code.
// Shiftregister PWM RG LED 8x8 matrix
// Red-Green LED 8x8 matrix display via two chained 74HC595 shiftregisters with latch
// and 74HC161 4-bit counter connected to 74HC138 3-to-8 line decoder for multiplexed row GND's.
// This is not optimised code, just bare-bones proof-of-concept.
// Copyright 2009 raron
/*
GNU GPLv3 license
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Unneccesarily detailed history:
// 2009.10.18 - v.0.1 - raron - Started tinkering with it.
// 2009.10.19 - v.0.2 - raron - works in simple row-by-row mode
// 2009.10.20 - v.0.3 - raron - changed to per-frame display
// 2009.10.20 - v.0.4 - raron - Arbitrary nr. of PWM implemented!
// 2009.10.21 - v.0.4b- raron - Improved PWM. Added potmeter control for test.
const int ledPin = 8; // just a power-on LED
const int potPin = 0;
const int rowResetPin = 9; // connected to 74CH161 4-bit counter ~MCLR input
const int rowClockPin = 10; // 74HC161
const int srDataPin = 11; // connected to 74HC595 shiftregister with latch
const int srLatchPin = 12; // 74HC595
const int srClockPin = 13; // 74HC595
int rowCounter;
unsigned long rowTimer;
unsigned long rowInterval = 0 ; // one row interval time in ms
const unsigned long frameInterval = 20 ; // milliseconds, or 1/framerate
unsigned long frameTimer;
unsigned char greenByte;
unsigned char redByte;
unsigned char PWMres = 8 ; // PWM resolution/levels
unsigned char PWMcontrol;
unsigned char redBitmap[8][8];
unsigned char greenBitmap[8][8];
unsigned char x,y;
int potValue;
int normalize;
void setup()
{
frameTimer = millis();
pinMode(ledPin,OUTPUT);
pinMode(rowResetPin,OUTPUT);
pinMode(rowClockPin,OUTPUT);
pinMode(srDataPin,OUTPUT);
pinMode(srLatchPin,OUTPUT);
pinMode(srClockPin,OUTPUT);
digitalWrite(rowResetPin,LOW); // reset row counter, active low
digitalWrite(rowResetPin,HIGH);
digitalWrite(ledPin,HIGH); // power-on LED
digitalWrite(srDataPin,LOW);
digitalWrite(srLatchPin,LOW);
digitalWrite(srClockPin,LOW);
}
void loop()
{
potValue = analogRead(potPin);
PWMres = 1 + (unsigned char)(potValue/128);
if ( PWMres < 2 ) PWMres = 2;
if ( PWMres > 8 ) PWMres = 8;
if ( PWMres < 4 ) rowInterval = 1;
if ( PWMres > 4 ) rowInterval = 0;
normalize = 8 / PWMres ;
// Make the same color test pattern over and over...
for (y=0;y<8;y++)
{
for (x=0;x<8;x++)
{
redBitmap[x][y] = (7-x) / normalize ;
greenBitmap[x][y] = y / normalize ;
}
}
//delay(10); // wasting some time as usual
// Display a frame
if ( millis() - frameTimer > frameInterval )
{
frameTimer = millis();
digitalWrite(rowResetPin,LOW); // Reset / re-sync physical row counter/decoder
digitalWrite(rowResetPin,HIGH);
for ( rowCounter = 0 ; rowCounter < 8 ; rowCounter++)
{
for ( PWMcontrol = 0 ; PWMcontrol < PWMres - 1 ; PWMcontrol++)
{
// get row data into shiftout bytes and PWM the colors.
// PWM = colorvalue / (PWMres-1)
// Example: With 8 PWM levels (PWMres = 8): max red value = 7 = 7/7 red = full on.
redByte = 0; greenByte = 0;
for ( x = 0 ; x < 8 ; x++)
{
redByte *= 2; // "<< 1" would'nt work for some reason
greenByte *= 2;
if ( redBitmap[x][rowCounter] > PWMcontrol ) redByte |= 1 ;
if ( greenBitmap[x][rowCounter] > PWMcontrol ) greenByte |= 1 ;
}
shiftOut(srDataPin,srClockPin,LSBFIRST,greenByte);
shiftOut(srDataPin,srClockPin,LSBFIRST,redByte);
// ----- Increase physical row counter -----
if ( (rowCounter > 0) && !PWMcontrol )
{
digitalWrite(rowClockPin,HIGH); // Row counter clockpuls
digitalWrite(rowClockPin,LOW);
}
// Show new bitpattern on new row ASAP
digitalWrite(srLatchPin,HIGH);
digitalWrite(srLatchPin,LOW);
rowTimer = millis();
while (millis()-rowTimer < rowInterval); // Display the line for a little while
}
}
}
// Clear shiftregister between frames (prevents last line bleed-through to first line, and last line brighter than the others)
shiftOut(srDataPin,srClockPin,LSBFIRST,0x00);
shiftOut(srDataPin,srClockPin,LSBFIRST,0x00);
digitalWrite(srLatchPin,HIGH);
digitalWrite(srLatchPin,LOW);
}