Strange behavior with multiplexers

Status
Not open for further replies.

alexandros

Well-known member
I'm building a modular synthesizer and I'm using Teensy 3.6 for the control interface. I'm using one 16-channel multiplexer which receives data from various 8-channel multiplexers. Each 8-channel multiplexer receives data from the potentiometers of the respective module. Things were working OK until I put 9 or 10 modules. That's when I started getting weird behavior.
I've broken down the code and below I'm trying to provide everything necessary (the active_modules array is declared in the original code and its values are set in another function that reads connections between modules. Since this feature is working I thought I shouldn't post it cause it will make the whole thing too big. The whole code is around 600 lines):
Code:
#define BAUDRATE 57600

// number of control pins the master multiplexers have (no accumulation for more than one mux used)
// for a 16-channel mux it's 4 (2^4 = 16)
const int num_master_ctl_pins = 4;
// the next two arrays will have their elements calculated in the setup function
// and they will be used in the read_pots() function to set the control pins of the master multiplexers
int master_ctl_pins[num_master_ctl_pins];
int master_ctl_values[num_master_ctl_pins];
// number of control pins the slave multiplexers have (no accumulation for more than one mux used)
// for an 8-channel mux it's 3 (2^3 = 8)
const int num_slave_ctl_pins = 3;
// the next two arrays will have their elements calculated in the setup function
// and they will be used in the read_pots() function to set the control pins of the slave multiplexers
int slave_ctl_pins[num_slave_ctl_pins];
int slave_ctl_values[num_slave_ctl_pins];
// variable to hold the total number of potentiometers which will be calculated in the setup function
int total_pots = 0;
// pointer to create an array with values that will be used for smoothing
// its size is calculated in the setup() function and it contains one element per potentiometer
float *smoothedVals;

void setup() {
  // find the greatest number of modules between the two master multiplexers
  int greatest_num_of_slave_mux = 0;
  for(int i = 0; i < num_of_master_mux; i++) greatest_num_of_slave_mux = max(greatest_num_of_slave_mux, num_of_slave_mux[i]);
  // total_pots and smoothedVals array
  for(int i = 0; i < num_of_master_mux; i++){
    for(int j = 0; j < greatest_num_of_slave_mux; j++)
      total_pots += num_of_pots[i][j];
  }
  smoothedVals = new float [total_pots];

  // set multiplexers control pins and values
  for(int i = 0; i < num_master_ctl_pins; i++){
    master_ctl_values[i] = pow(2, (i + 1)) - 1;
    // master multiplexers have their control pins wired to digital pins 2 to 5
    master_ctl_pins[i] = (num_master_ctl_pins - i) + 1;
    pinMode(master_ctl_pins[i], OUTPUT);
  }

  for(int i = 0; i < num_slave_ctl_pins; i++){
    slave_ctl_values[i] = pow(2, (i + 1)) - 1;
    // slave multiplexers have their control pins wired to digital pins 6 to 8
    slave_ctl_pins[i] = (num_slave_ctl_pins - i) + 5;
    pinMode(slave_ctl_pins[i], OUTPUT);
  }

  // open the serial port
  Serial.begin(BAUDRATE);
}

// function to read potentiometers of active modules
void read_pots(){
  // set local index to global index's current value
  int local_index = ndx;
  // set row index for 2D array multiple pots
  int pot_index = 0;
  int module_index = 0;
  //static byte smooth_index = 0;
  // run througn all master multiplexers
  for(int master_mux = 0; master_mux < num_of_master_mux; master_mux++){
    // run through all slave multiplexers
    for(int slave_mux = 0; slave_mux < num_of_slave_mux[master_mux]; slave_mux++){
      // if this module is active, store its index, the number of bytes to expect
      // and a 0 to denote that the following values are potentiometer values
      // and route its output to its master multiplexer
      // activity of modules is being stored in the check_connections function
      if(active_modules[module_index]){
        transfer_data[local_index++] = module_index;
        transfer_data[local_index++] = (num_of_pots[master_mux][slave_mux] * 2) + 1;
        transfer_data[local_index++] = 0;
        // set the control pins of the current master multiplexer
        for(int i = 0; i < num_master_ctl_pins; i++)
          digitalWrite(master_ctl_pins[i], (slave_mux & master_ctl_values[i]) >> i);
      }
      // run through the pins used on each slave multiplexer
      // the active module test needs to be separate here in order to be able
      // to increment the row_index variable at every iteration of the loop below
      for(int pot = 0; pot < num_of_pots[master_mux][slave_mux]; pot++){
        // if this module is active store the values of its potentiometers
        if(active_modules[module_index]){
          // set the control pins of the current slave multiplexer
          for(int i = 0; i < num_slave_ctl_pins; i++)
            digitalWrite(slave_ctl_pins[i], (pot & slave_ctl_values[i]) >> i);
          // read the corresponding analog pin of the Teensy
          int pot_val = analogRead(master_mux);
          // smooth out the analog reading
          int smoothed = smooth(pot_val, pot_index);
          // clip the values for a more unified result
          if(smoothed > CLIP) smoothed = CLIP;
          // and store the smoothed value to the transfer_data array
          transfer_data[local_index++] = smoothed & 0x007f;
          transfer_data[local_index++] = smoothed >> 7;
        }
        pot_index++; // update the 2D array row index anyway
      }
      // the module index is independent of activity as well, it should always increment
      module_index++;
    }
  }
  
  ndx = local_index;
}

void loop() {
  ndx = 1;

  check_switches();

  // write data to the serial port, if there is any activity
  if(ndx > 1) Serial.write(transfer_data, ndx);
}

The problem I'm facing is that when I connect more than two modules, it seems that the middle "slave" multiplexer control pin (digital pin 7) is not responding, and the first potentiometer of each modules write values to the first and third array element, the second potentiometer to the second and fourth, the fifth potentiometer to the fifth and sevent, and the sixth potentiometer to the sixth and eighth. The third, fourth, seventh and eights potentiometers are not functioning at all.
If I use only two modules everything works fine.
This has been driving me crazy. Any help much appreciated.

Note: in the whole setup I'm also using input and output shift registers, one per module (74HC165 and 74HC595). The problem though appears in the multiplexer readings (at least for now...).
 
Maybe you'll need to add a brief delay between changing the many mux chips and actually reading the analog voltage?

Even if you don't add any capacitor (which normally helps without mux chips, but really hurts if added between the mux chips and Teensy), there's still some capacitance due to the Teensy ADC input and the pins and wires. Those mux chips act as resistors when they are on, which means it takes a little time from selecting a mux channel to actually getting Teensy's pin driven to the analog voltage.

If you have an oscilloscope, you could measure the voltage settling time. But 50 microseconds is probably a good but blind guess.
 
Also, you might look at the ResponsiveAnalogRead library for post-measurement processing. It has some really nice algorithms that might help you might than just simple smoothing.
 
Thanks for your reply and sorry for my late reply. In the end the problem was in the hardware. One wire from a ribbon cable I use to connect modules (which wire was grounded), was scratched and its exposed part was touching the middle control pin of a multiplexer. Since these multiplexers all share the same control pins on the Teensy, it resulted in grounding the middle control pin of all these chips, hence this behavior! It's now corrected.

About the ResponsiveAnalogRead library, is it this one https://github.com/dxinteractive/ResponsiveAnalogRead ?
Can you use it with multiplexers? I'm asking cause multiplexers all end up in the same analog pin of the Teensy, so one reading can be completely different from the next one, and I can't really understand how using this library could be possible this way.
 
Yes, that's the right library.

It should work with a mux. Just configure the channel correctly and wait a brief delay for the signal to settle before you call the update() function.

Of course, you'll need a separate ResponsiveAnalogRead instance for each mux channel.
 
Status
Not open for further replies.
Back
Top