cd74hc4067 16 channel MUX - eyes needed!

Status
Not open for further replies.

snowsh

Well-known member
mux.jpg

I am at the end of my tether. I have spent the last day trying to get this work.....

I'm developing a project using a teensy 4.1....

I have my mux running using 2 cd74hc4067 16 channel MUX. I based my MUx on this page https://forum.pjrc.com/threads/47074l-Teensy-LC-and-74HC4067-16-channel-multiplexer-wiring

Its all good and been working fine for weeks. My project has grown so I have added a third MUX and built a new vero board prototype.. I suspect this is where my issue lies, but I am not sure...

Please take a glance over my schematic....

issue:

the mux is working, but only registering preses on odd number channels, which then trigger the next channel too. ie pressing button 0, triggers 0 and 1.

I have put a counter on my debug, and I see that the serial.print is outputting the 0 read on the correct loop, and then the following loop it goes and fires channel 1.....

I have tested my wiring, tried another teensy 4.1. Everything seems to be right. Whatever I do I keep getting this double hit problem.

My suspicion is the 2.2k pull up resistor is maybe too low? Should I add diodes? But then again these have worked rock solid for weeks now on my two mux board. also, the total lack of response from the odd channels, ie 1,3,5,7....15 is making me doubt its a problem in the board and there is somthing glaring me in the face in the code that I am not seeing because i have gone totally crosseyed....

Stumped.

here is my code (stripped out somewhat as my project is huge) There are several timers that really pay no function in this example, they are for elsewhere in my project.

Code:
/*
  

   http://www.thebox.myzen.co.uk/Tutorial/Inputs.html --------------------   !!  IMPORTANT !! ------------------

   https://forum.pjrc.com/threads/47074l-Teensy-LC-and-74HC4067-16-channel-multiplexer-wiring

*/

elapsedMillis currentMillis = 0;

unsigned long buttonDebounceDelay = 250; 

int MuxDumpCounter = 0;

const int muxTimeMin = 200;                                // minimum micro-seconds between MUX reads - higher values should be more stable but less responsive

const int M_PINS = 16;                                    // number of MUX PINS

const int MUX_COUNT = 3;                                  // number of MUX

const int SO_PINS[4] = {32, 31, 30, 29}; // {29, 30, 31, 32};                  //array size is (M_PINS)^-2

const int MUX_READ[MUX_COUNT] = {40, 23, A17};                // Pins to SIGNAL on MUX - I only have one MUX to test so I ran all to A0 for testing

const bool muxAnalogType[MUX_COUNT] = {false, false, true};      // false digital. true analog

const int dbt = 12;                                       // a threshold value for how big the dead-band is before recalc - set higher to minimize excess MIDI if inputs are noisy

//------------------------------------------------------------------------  MUX variables

unsigned long lastMuxReading[MUX_COUNT][M_PINS] = {0};

int muxReading[MUX_COUNT][M_PINS] = {0};

int muxReadingLagged[MUX_COUNT][M_PINS] = {0};

int lastKeypadMuxPress = 0;                               // used to track the data input keyboard for multiple presses. assume mux 0 for the key

int muxPressAr[MUX_COUNT][M_PINS] = {0};                  // to  track if the buttons have been pressed

int muxAnalogAr[MUX_COUNT][M_PINS] = {0};                 // to track if a knob value has changed

bool muxHoldAr[MUX_COUNT][M_PINS] = {false};              // used to override reset of the mux - if its being held down

unsigned long muxDown[MUX_COUNT][M_PINS] = {0};           // used to track key down of the mux -  the time it was pressed

elapsedMicros muxUpdated;                                 // timer counter (micros)

int j = 0;                                                // index for mux chanel select loop - needs to be global THIS IS KEY! - 'j' is not used in a 'for' statement but is incremented with each main loop call



void setup()
{
  setupMuxPins();

}

void loop()
{
  currentMillis = millis();
  getMUXData();
}




//------------------------------------------------------------------------  setup

void setupMuxPins()
{
  for (int i = 0; i < 4; i++)                                                   //set SO pins for MUX control as output
  {
    pinMode(SO_PINS[i], OUTPUT);
  }
  for (int i = 0; i < MUX_COUNT; i++)
  {
    pinMode(MUX_READ[i], INPUT);
  }
}

//------------------------------------------------------------------------  mux

void getMUXData()
{
  if (muxUpdated > muxTimeMin)
  {
    for (int i = 0; i < MUX_COUNT; i++)
    {
      if (muxAnalogType[i] == true)
      {
        muxReading[i][j] = analogRead(MUX_READ[i]);

        if (abs(muxReading[i][j] - muxReadingLagged[i][j]) > dbt )              // analog read
        {
          if (currentMillis - lastMuxReading[i][j] > buttonDebounceDelay)
          {
            muxAnalogChannelfuctionHandler(i, j);

            muxReadingLagged[i][j] = muxReading[i][j];

            muxPressAr[i][j] = muxReading[i][j];
            
            lastMuxReading[i][j] = currentMillis;
          }
        }
      }
      else                                                                      // digital pins
      {
        muxReading[i][j] = digitalRead(MUX_READ[i]) == LOW ? 1 : 0;

        if (muxReading[i][j] == 1)                                              // digital read
        {
          if (currentMillis - lastMuxReading[i][j] > buttonDebounceDelay)
          {
            muxDown[i][j] = currentMillis;                                     // log the keydown

            muxHoldAr[i][j] = true;

            muxReadingLagged[i][j] = muxReading[i][j];

            muxPressAr[i][j] = 1;

            muxDigitalChannelfuctionHandler(i, j);                              // this will handle things like enable,solo,mute etc using the channel buttons

            lastMuxReading[i][j] = currentMillis;
          }
        }
        else
        {
          muxDown[i][j] = 0;                                                   // the key is not pressed set to 0

          muxHoldAr[i][j] = false;
        }
      }
    }

    muxUpdated = 0;                                                             //reset timer

    j++;                                                                        // increment global counter variable before setting up MUX control for the next pass!

    if (j >= M_PINS)
    {
      j = 0;                                                                    // rollover at 16
    }

    for (int i = 0; i < 4; i++)
    {
      
      digitalWrite(SO_PINS[i], (boolean) (j & (int) pow(2, i)));                // bit-fiddle to set the i-th pin to HIGH IFF binary version of j contains i-th multiplier (i-th power of 2)
    }
  }
}




//------------------------------------------------------------------------  analog faders

void muxAnalogChannelfuctionHandler(int muxId, int muxPin)
{
// commented out for this example.  usbMIDI.sendControlChange(ccControllerArrayMessageId[muxPin], muxReading[muxId][muxPin] >> 3, ccControllerArrayMidiChannel[muxPin]);
}

//------------------------------------------------------------------------  digital mux buttons



void muxDigitalChannelfuctionHandler(int muxId, int muxPin)
{
    Serial.print("MuxDumpCounter");
    Serial.println(MuxDumpCounter);

    Serial.print("muxId: ");
    Serial.print(muxId);
    Serial.print("  muxPin: ");
    Serial.println(muxPin);

    MuxDumpCounter++;
}






void resetMux(int i, int j)
{
  muxPressAr[i][j] = 0;
}

void initMux()
{
  for (int i = 0; i < MUX_COUNT; i++)
  {
    for (int j = 0; j < M_PINS; j++)
    {
      muxPressAr[i][j] = 0;

      muxAnalogAr[i][j] = {0};
    }
  }
  dumpMux();
}

void resetAllMux()
{
  for (int i = 0; i < MUX_COUNT; i++)
  {
    for (int j = 0; j < M_PINS; j++)
    {
      if (!muxHoldAr[i][j]) muxPressAr[i][j] = 0;
    }
  }
}

void dumpMux()
{
  for (int i = 0; i < MUX_COUNT; i++)
  {
    for (int j = 0; j < M_PINS; j++)
    {
      Serial.print("MUX_COUNT : ");
      Serial.print(i);
      Serial.print(" M_PINS : ");
      Serial.print(j);
      Serial.print(" : ");
      Serial.println(muxPressAr[i][j]);
    }
    Serial.println("-------------------------------------------------------- ");
  }
  Serial.println("-------------------------------------------------------- end dump");
}
 
Try adding a short delay right after you change the mux control pins.

Also, while it probably doesn't matter, best to use integer math so you avoid any surprising floating point round-off vs truncation issues.

So try changing this:

Code:
    for (int i = 0; i < 4; i++)
    {
      
      digitalWrite(SO_PINS[i], (boolean) (j & (int) pow(2, i)));                // bit-fiddle to set the i-th pin to HIGH IFF binary version of j contains i-th multiplier (i-th power of 2)
    }

to something like this:

Code:
    for (int i = 0; i < 4; i++)
    {
      digitalWrite(SO_PINS[i], ((j & (1 << i)) ? HIGH : LOW));               // bit-fiddle to set the i-th pin to HIGH IFF binary version of j contains i-th multiplier (i-th power of 2)
    }
    delayMicroseconds(50);

Or even just this (simpler to just copy the digitalWrite 4 times....)

Code:
      digitalWrite(SO_PINS[0], ((j & 0x01) ? HIGH : LOW));               // bit-fiddle to set the i-th pin to HIGH IFF binary version of j 
      digitalWrite(SO_PINS[1], ((j & 0x02) ? HIGH : LOW));
      digitalWrite(SO_PINS[2], ((j & 0x04) ? HIGH : LOW));
      digitalWrite(SO_PINS[3], ((j & 0x08) ? HIGH : LOW));
      delayMicroseconds(50);
 
@PaulStoffregen, yes I have tried delays to try to hunt it down.... still nothing. If its running too quick I will have to add a timer as I cant have any delays running to interrupt the rest of my program.
 
If its running too quik I will have to add a timer as I cant have any delays running to interrupt the ret of my program.

Sure, but for the sake of troubleshooting, do things the simplest way first.

The most common problem with muxes is lack of setting time between changing the mux control pins and reading the input signals. It can be tempting to try adding delays in lots of different ways, but the delay is generally needed is right after the mux select pins change.
 
yes delays were the first thing I tried. after 24 hours with this I'm doubting everything.... Does my schematic look ok?
 
This is just a tip:
You should really write a new, small program that really only takes care of the mux.
This simplifies the troubleshooting a lot. And remember to add the delays. You will see that you will find problems much easier then.
 
I'd reiterate the avoidance of pow(), which returns double, as you shouldn't rely on exact floating point
behaviour.

You need to buzz out your circuit to check for shorts between adjacent pins I think...
 
Does my schematic look ok?

Yes, your schematic looks ok.

To troubleshoot, I'd recommend writing a new and very simple program which uses 4 digitalWrite in setup() to set the muxes to 1 of the odd number channels which isn't working. Leave the muxes set to that 4 bit config. Then in loop, just repetitively read the 3 input pins and use Serial.print() to show their values in the serial monitor.

Then use a voltmeter to also watch each of those 3 input pins while you press the buttons and turn the knob for the 1 channel you've selected.

The idea is to keep this test as simple as possible and fixed to only 1 of the 16 channels. Then you can verify if that 1 channel really is working by watching the voltages your circuitry delivers to the 3 pins, and the numbers you code prints to the serial monitor. Repeat as needed for the other 15 channels. While that is some work, hopefully it isn't confusing. By keeping the mux set to only 1 of the 16 channels, you can take your time to carefully check whether the hardware really is working and whether your code really is reading the voltages which appear at the pins.
 
Not 100% clear if you added your new veroboard mux to the existing hardware, or built a new 3-mux system; or if the fault is with both switch muxes or just the added one. But ... sounds like hardware to me, specifically the S0 / pin 10 wiring or pin soldering, which results in it appearing to be stuck at 0. Thus when channel 0 is read, you get channel 0; channel 1, you get channel 0 again; 2 => 2; 3 => 2 ... and so on. It could be static damage to the chip, which wouldn't show up on a wiring test.

Cheers

Jonathan
 
SOLVED!!!

I had a short from S0 on mux 3 to an en pin (GND)
looking at the logic table it now makes perfect sense.
mux logig.JPG

That was a wasted day yesterday.... Thanks to everyone who offered advice, especially to Paul for your help and amazing contribution to this community - the teensy is an amazing platform

For anyone else who may be experiencing odd behaviour in their MUX, that follows a pattern, check your logic signal paths!

EDIT, just saw the last post from Jonathan, yes you were bang on, S0 short......
 
Last edited:
Status
Not open for further replies.
Back
Top