Strong flickering with multiplexed 10 x 10 LED matrix

It's also possible to add the display refresh code into an alternate millis() interrupt ISR so you don't waste time calling and returning from multiple ISRs. I do this by disabling the timer0 overflow interrupt, and instead enabling the compare interrupt with the compare register set to 249. In CTC mode this makes timer0 roll over every 250 counts, which will be a perfect 1ms if the crystal is right. The ISR is now only one line of code, and you can easily add the refresh code. Here's a Blink sketch using the revised millis() generator:

/*
This features a replacement for the ISR(TIMER0_OVF_vect)
interrupt that drives millis(). It disables the OVF
interrupt, enables the COMPA interrupt, sets OCR0A to 249,
and changes Timer0 to CTC mode.  This results in an
interrupt every 250 timer clock cycles, which is exactly 1ms
for a 16MHz crystal.  For 8MHz, OCR0A is set to 124.  The new
ISR increments millis, but since the interrupt rate is exactly
correct, no periodic double increment of millis is needed.

Using this code probably means you can't do any analog
writes that use Timer0, which would include pins 5 and 6.

Millis() should work as normal at 16MHz or 8MHz.
The effect on micros() is unknown.
*/

extern volatile unsigned long timer0_millis;   //this defined in wiring.c


byte MILLIS_INCB = (64 * 250) / (F_CPU / 1000);  // ms to 250 ticks

const int cycleTime = 500;                 // flash LED every second
unsigned long oldMillis = millis();
unsigned long newMillis = 0;

void setup() {                             //Set up alternate interrupt
                                           //   at 249 on timer0

  cli();                                   // disable interrupts while doing this

  TCCR0A = 0;                              // set entire TCCR0A register to 0
  TCCR0B = 0;                              // same for TCCR0B
  TCNT0  = 0;                              // initialize timer0 count to 0

  OCR0A   = (250/MILLIS_INCB) - 1;         // set top of counter (249 for 16MHz, 124 for 8MHz)
  TIMSK0 &= ~bit(TOIE0);                   // disable overflow interrupt
  TCCR0A |= bit(WGM01);                    // turn on CTC mode
  TCCR0B |= (bit(CS01)+bit(CS00));         // Set CS00&CS01 bits for prescaler = 64
  TIMSK0 |= bit(OCIE0A);                   // enable timer compare interrupt

  sei();                                   // enable interrupts

  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);

}


void loop() {                               // flashes LED for 1/2 second
                                            //    every second

  newMillis = millis();
  if ((newMillis - oldMillis) == cycleTime) {
    oldMillis = newMillis;
    digitalWrite(13,!digitalRead(13));    // invert pin 13 state
  }
}


ISR(TIMER0_COMPA_vect) {                    // this is the new ISR - much
                                            //   simpler than original

  timer0_millis++;
}

Thanks everyone for improving the code and the valuable suggestions. In the end, the problem was a combination of faulty components (two transistors and one register were actually broken) and probably wrong wiring. After carefully dissembling, testing each component and re-assembling it finally works flawlessly within the limits of the chosen hardware. So several lessons learned here.

it’s funny that green LEDs are so faint. We chose them because the human visual system sees green better than red but we weren’t aware that they also typically weaker.

I have the same square LEDs as you have used and they are also very dim.
Try green 5mm strawhat LEDs.
Leo..

1 Like

Thanks for the tip I will buy a couple and try them out.

The link I gave is $2 for a 100-pack.
Leo..

1 Like