Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 10 of 10

Thread: cd74hc4067 16 channel MUX - eyes needed!

  1. #1

    cd74hc4067 16 channel MUX - eyes needed!

    Click image for larger version. 

Name:	mux.jpg 
Views:	41 
Size:	136.8 KB 
ID:	24910

    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/47074...iplexer-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");
    }

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    24,452
    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);

  3. #3
    @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.

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    24,452
    Quote Originally Posted by snowsh View Post
    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.

  5. #5
    yes delays were the first thing I tried. after 24 hours with this I'm doubting everything.... Does my schematic look ok?

  6. #6
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    8,568
    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.

  7. #7
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,101
    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...

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    24,452
    Quote Originally Posted by snowsh View Post
    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.

  9. #9
    Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    75
    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

  10. #10
    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.
    Click image for larger version. 

Name:	mux logig.JPG 
Views:	11 
Size:	52.9 KB 
ID:	24914

    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 by snowsh; 05-26-2021 at 11:32 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •