TLC5940 Multiplexing "anomaly"

Hi… I’m using 2 pins to pulse two rows (common anode) of 8 RGB LEDs (via a source driver chip to get enough current). The cathodes of each column go to a channel on 2 TLC5940s (24 channels total). I’ve slowed down my code with a long delay to debug the following issue…

After I pulse row one with a value other than 0, I get a split second of the row one values showing up on row two. This can be observed very easily by setting a 2000 ms delay between pulsing the two rows, and setting the row two values to all 0.

Here’s the code I’m using… the anomaly appears in the state_bridge() function. (I haven’t finished the others).

/* These two includes should go at the top of any file that uses the TLC5940 library */
#include "tlc_config.h"
#include "Tlc5940.h"

#define NUM_ROWS 2
#define NUM_COLUMNS 8
#define NUM_COLORS 3

#define BLUE 1
#define GREEN 2
#define RED 3

#define pot_source 12
#define b_pot_pin 6
#define n_pot_pin 7

#define R1 5
#define R2 4

#define S1 6
#define S2 2

#define MAX_INTENSITY 4095

#define DELAY_VAL 2000

// No longer used
int Value_Matrix[NUM_ROWS][NUM_COLUMNS][NUM_COLORS];

float p;

void setup()
{
  /* Tlc.init() has to be called before using any of the library functions */
  Tlc.init();
  pinMode(R1, OUTPUT);
  pinMode(R2, OUTPUT);
  digitalWrite(R1, LOW);
  digitalWrite(R2, LOW);
  pinMode(S1, INPUT);
  pinMode(S2, INPUT);
  pinMode(pot_source, OUTPUT);
  Serial.begin(115200);
  attachInterrupt(0, ISR_0, CHANGE);  //configures interrupt to trigger on state change on pin D2
  Tlc.clear();
}

void loop()
{
  
  state_select();
    
}


/************************************************************************* 
 * setLED() -- This is a wrapper function that turns on the LED          *
 * cooresponding to row #, column #, color, and intensity (0 - 4095)     *
 * sent to the function                                                  *
 *                                                                       *
 * Blue   -- Channels 0-7                                                *
 * Green  -- Channels 8-15                                               *
 * Red    -- Channels 16-23                                              *
 *************************************************************************/

int setLED(int row, int column, int color, int intensity) {           
  TLC_CHANNEL_TYPE channel;
 // if (intensity > 0 && intensity < 5) intensity = 3;
  if (intensity < 0) intensity = 0;
  if (intensity > 4095) intensity = 4095;

  if(column > NUM_COLUMNS || column < 1){
    return 1;  // to be used for debugging
  }
  else{  
    // This statement calculates and sets the TLC Channel value
    channel = color*NUM_COLUMNS-(NUM_COLUMNS-column)-1;

    // Set the proper LED to the called for intensity
    Tlc.set(channel, intensity);  
  }
  return 0;
}


/**********************************************************************************  
 * potRead() -- Function to return an ADC value from a potentiometer... values    *
 * passed to it are a digital pin number acting as the 5VDC source and an analog  * 
 * pin number to take the reading from                                            *
 **********************************************************************************/

int potRead(int source_pin, int read_pin){
  digitalWrite(source_pin, HIGH);
  int x = analogRead(read_pin);    // read the value from the pot and store in 'n'
  digitalWrite(source_pin, LOW);
  return x;
}


/***************************************************************************  
 * pulse() -- Function to clock a pin as described by the passed variable  *
 ***************************************************************************/

int pulse(int pin_num) {
  digitalWrite(pin_num, HIGH);
  digitalWrite(pin_num, LOW);
  return 0;
}


/***************************************************************************  
 * state_bridge() -- Function to display brigde pickup only configuration  *
 ***************************************************************************/

int state_bridge(){
  float b;
  float n;
      
  while(1){
    
    b = (((float)potRead(pot_source, b_pot_pin)*4.27)/MAX_INTENSITY);
    for (int i = 1; i <= 4; i++){
      setLED(0, i, RED, 4095);
      setLED(0, i, BLUE, 0); 
    }   
    digitalWrite(R2, LOW);        
    Tlc.update();
    digitalWrite(R1, HIGH); 

    delay(DELAY_VAL); // Delay 1

      
    digitalWrite(R1, LOW);
      
    Serial.println(Tlc.get(16));
 
    
    n = (((float)potRead(pot_source, n_pot_pin)*4)/MAX_INTENSITY);
    for (int i = 1; i <= 4; i++){
      setLED(0, i, RED, 0);
      setLED(0, i, BLUE, 0); 
    }
    Serial.println(Tlc.get(16));
    Tlc.update();
    
    digitalWrite(R2, HIGH);

    delay(DELAY_VAL);
       
 //   Tlc.clear();
   // Tlc.update();
      
  }
  
}


/************************************************************************  
 * state_neck() -- Function to display neck pickup only configuration   *
 ************************************************************************/
 
int state_neck(){
  int b;
  int n; 
  
  while(1){ 
    // NEED CODE
    Serial.println("Neck");
    delay(1000);
  }
  
}


/**************************************************************************************  
 * state_both() -- Function to display brigde and neck together pickup configuration  *
 **************************************************************************************/
 
int state_both(){
  int b;
  int n;
  
  while(1){
    // NEED CODE
    Serial.println("Both");
    delay(1000);
  }
  
}


/**************************************************************************************  
 * ISR_0() -- Function that detects a pickup selector switch change and chooses       *
 * the correct action to take                                                         *
 **************************************************************************************/
 
void ISR_0(){

  // Turns off LED display so that now anomolous flickering appears during switch turning
  Tlc.clear();
  Tlc.update();
  
  // Goto function that will pick the new state to display
  state_select();
}


/**************************************************************************************  
 * state_select() -- Function is called from the ISR that "waits" for the switch to   * 
 * settle to it's new position and then chooses the appropriate state                 *
 **************************************************************************************/
 
int state_select(){
  // Initialize variables to store pin states
  int pin1, pin2;
  
  // Assign current switch pin values to variables
  pin1 = digitalRead(S1);
  pin2 = digitalRead(S2);
  
  // Wait to do anything until the until the switch finishes "bouncing"
  delay(50);
  
  // Choose which state to send to the display
  switch (pin2) {
    case LOW:
      if (pin1 == LOW){
        state_bridge();
      }else{
        state_neck(); 
      }
      break;
    case HIGH:
      state_both();    
      break;
  }
  
}

If I put a delay in between the pulses, this anomaly goes away, but I’m having trouble getting an absolute flicker free performance, so I didn’t want to use a delay here. If you have any questions about the purpose of any of the rest of the code that may be pertinent to solving this problem, I’ll be glad to explain.

Many thanks in advance.

lqbert