hi,
I'm in the process of building a controller for the sparkfun rgb led matrix. So far I've decided to use 4 74HC595 shift registers to drive the leds. Right now there's code to drive 1 row at one color with 4bit pwm (2 leds stored in 1 byte) using a timer2 overflow interrupt. The isr routine needs 2.3ms to complete. Extrapolating to 8 rows and 3 colors I think I'd get a refresh rate of 18Hz. Somehow I think the isr routine could run faster, maybe I got some of the WGM?? registers set wrong. If just setting the prescaler to smaller values, the program just hangs.
#define __spi_clock 10
#define __spi_latch 11
#define __spi_data 12
#define __rows 1
#define __leds_per_row 8
#define __max_led __leds_per_row-1
#define __brightness_levels 16 // 0...15
#define __max_brightness __brightness_levels-1
#define __fade_delay 5
#define INIT_TIMER_COUNT 100
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT
#include <avr/interrupt.h>
#include <avr/io.h>
byte brightness_red[__leds_per_row*__rows/2]; // 4bit pwm --> 1 byte = 2 leds
ISR(TIMER2_OVF_vect) {
RESET_TIMER2; // precharge TIMER2 to maximize ISR time --> max led brightness
byte cycle;
for(cycle = 0; cycle < __max_brightness; cycle++) {
byte led;
byte out = 0;
for(led = 0; led <= __max_led; led++) {
if(cycle < (brightness_red[(led>>1)]>>(4*!(led&B00000001))&B00001111)) {
out |= 1<<led;
}
}
digitalWrite(__spi_latch,LOW);
shiftOut(__spi_data,__spi_clock,LSBFIRST,out);
digitalWrite(__spi_latch,HIGH);
}
// turn off all leds when ISR is not running
// otherwise leds will flash to full brightness when 1111 is set, which
// stays on outside the ISR !
digitalWrite(__spi_latch,LOW);
shiftOut(__spi_data,__spi_clock,LSBFIRST,B00000000);
digitalWrite(__spi_latch,HIGH);
// better replace this with a line to 585's 'enable/disable'
}
void setup(void) {
//Serial.begin(9600);
byte ctr;
pinMode(__spi_clock,OUTPUT);
pinMode(__spi_latch,OUTPUT);
pinMode(__spi_data,OUTPUT);
digitalWrite(__spi_latch,LOW);
digitalWrite(__spi_data,LOW);
digitalWrite(__spi_clock,LOW);
for(ctr = 0; ctr < __max_brightness; ctr++) {
brightness_red[ctr] = 0;
}
brightness_red[0] = B00010010; // led 0 + 1 red level
brightness_red[1] = B00010001; // led 2 + 3
brightness_red[2] = B00010001; // led 4 + 5
brightness_red[3] = B00010001; // led 6 + 7
// set irq to 244 Hz: CS22-bit = 1, CS21-bit = 1, CS20-bit = 0
TCCR2B |= ( (1<<CS22) | (1<<CS21));
TCCR2B &= ~( (1<<CS20) );
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TIMSK2 |= (1<<TOIE2);
TIMSK2 &= ~( (1<<OCIE2A) | (1<<OCIE2B) );
RESET_TIMER2;
sei();
}
void loop(void) {
byte ctr1;
for(ctr1 = 0; ctr1 <= 15; ctr1++) {
set_led_red(0,ctr1);
set_led_red(1,ctr1);
set_led_red(2,ctr1);
set_led_red(3,ctr1);
set_led_red(4,ctr1);
set_led_red(5,ctr1);
set_led_red(6,ctr1);
set_led_red(7,ctr1);
delay(__fade_delay);
}
for(ctr1 = 15; (ctr1 >= 0) & (ctr1 != 255); ctr1--) {
set_led_red(0,ctr1);
set_led_red(1,ctr1);
set_led_red(2,ctr1);
set_led_red(3,ctr1);
set_led_red(4,ctr1);
set_led_red(5,ctr1);
set_led_red(6,ctr1);
set_led_red(7,ctr1);
delay(__fade_delay);
}
}
void set_led_red(byte led, byte value) {
byte not_to_change = brightness_red[(led>>1)] & (B00001111<<(4*(led&B00000001)));
byte tmp = value << (4*!(led&B00000001));
value = tmp + not_to_change;
brightness_red[(led>>1)] = value;
}