Cd4051 Multiplexer Tutorial Is Here!

really appreciate this tutorial

1 Like

Can you perhaps also show what adding such a multiplexer to a board.json file would look like?

1 Like

I would love to do a follow up to this tutorial for pd2dsy and oopsy~ eventually for sure!

In the meantime, here are the steps for anyone curious to try it out before I can:
-Include 3 digital outputs and 1 adc in the .json file.
-In the patcher, change the combination of digital outputs in sequence while reading the analog input

4 Likes

With the current json implemenations of pd2dsy, and the update staged for release on oopsy you can do the following, which is copied from the daisy field.json file:

"parents":
  "pot_mux": {
    "component": "CD4051",
    "mux_count": 8, // the number of pots connected
    "pin": {
      "adc": 16,  // the ADC input pin
      "sel0": 21, // The SEL0 digital output pin
      "sel1": 20, // The SEL1 digital output pin
      "sel2": 19  // The SEL2 digital output pin
    }
  }
},
"components": {
  "knob1": {
    "component": "CD4051AnalogControl",
    "index": 0, // which analog input pin on the CD4051 to read
    "parent": "pot_mux"
  },
  "knob2": {
    "component": "CD4051AnalogControl",
    "index": 3, // which analog input pin on the CD4051 to read
    "parent": "pot_mux"
  }
},

edit: updated to be more complete (using parents and components relationship).

3 Likes

I’m having difficulty implementing this example on the Patch SM. As far as I can tell, it looks like I would only need to change the hardware and the the pins for the example to work on the Patch SM. However, I’m getting a crash when my code gets to hw.adc.Init(&adc_cfg, 1);.

I’m attempting to use pin D9 as my COM OUT/IN and pins D6 and D7 as my selector pins. D9 is labeled as ADC_11 and D6 and D7 are both shown as Digital GPIO in the Patch SM pinout so I think this configuration should work?

Here’s my full code:

/** Example of using a CD4051 multiplexor to expand the ADC inputs */
#include "daisy_patch_sm.h"

/** This prevents us from having to type "daisy::" in front of a lot of things. */
using namespace daisy;
using namespace patch_sm;

/** Global Hardware access */
DaisyPatchSM hw;

int main(void)
{
    /** Initialize our hardware */
    hw.Init();

        /** Startup the USB Serial port */
    hw.StartLog(true);
    hw.PrintLine("Log Started");

    /** Configure the ADC
     * 
     *  One channel configured for 8 inputs via CD4051 mux. 
     * 
     */
    AdcChannelConfig adc_cfg;

    adc_cfg.InitMux(hw.GetPin(DaisyPatchSM::PinBank::D, 9), 4, hw.GetPin(DaisyPatchSM::PinBank::D, 5), hw.GetPin(DaisyPatchSM::PinBank::D, 6)); 

    /** Initialize the ADC with our configuration */
    hw.adc.Init(&adc_cfg, 1);

    /** Start the ADC conversions in the background */
    hw.adc.Start();

    /** Infinite Loop */
    while(1)
    {
        /** Print the values via Serial every 250ms 
         *  Values will be 0 when inputs are 0V
         *  Values will be 65536 when inputs are 3v3
         */
        System::Delay(250); 
        hw.Print("Input 1: %d   ", hw.adc.GetMux(0, 0)); 
        hw.Print("Input 2: %d   ", hw.adc.GetMux(0, 1)); 
        hw.Print("Input 3: %d   ", hw.adc.GetMux(0, 2));  
        hw.Print("Input 4: %d   ", hw.adc.GetMux(0, 3)); 
        hw.PrintLine("");

    }
}

For my adc config I’ve also tried:

adc_cfg.InitMux(DaisyPatchSM::D9, 4, DaisyPatchSM::D5, DaisyPatchSM::D6);

Is there something I’m missing? I see AdcHandle is an available class on the Patch SM so not sure where I’m going wrong with this example.

If I remember correctly, you may have to ground the S2 pin even if it’s unneeded (you only need to switch around the 2 selector pins for 4 total inputs). I think that’s why, in this tutorial, I connected a digital pin to it even though I’m only using 4 potentiometers. So, I believe you need to either connect that pin to ground or add another digital pin for the third selector pin (and also configure it in code).

And this thread could be a helpful reference to you as well: MUX on Patch SM.

Thanks, but would having the S2 pin ungrounded cause my Patch SM to crash when calling hw.adc.Init(&adc_cfg, 1) ? That’s what seems to be happening to me.

Unfortunately I won’t be able to test again until tomorrow or Tuesday, but I’ll report back here with the results.

For sure, it shouldn’t crash it, I don’t think.
Regardless, give all those a try and keep me posted :slight_smile:

@Takumi_Ogata I tried testing again today, this time without the MUX code and just initialising the ADC. I am still getting a crash at hw.adc.Init(adc_cfg, 1);

This is my code:

/** Example of initializing multiple ADC inputs */
#include "daisy_patch_sm.h"
/** This prevents us from having to type "daisy::" in front of a lot of things. */
using namespace daisy;
using namespace patch_sm;
/** Global Hardware access */
DaisyPatchSM hw;
int main(void)
{
   /** Initialize our hardware */
   hw.Init();
    hw.StartLog(true);
    hw.PrintLine("Log Started");
   /** Configure the ADC
    *
    *  Three CV inputs (-5V to 5V -> 3V3 to 0V)
    *  A0, A6, and A2
    *
    *  This example was made for the Daisy Seed2 DFM, but the pins can be swapped for other hardware.
    */
   AdcChannelConfig adc_cfg[1];
   adc_cfg[0].InitSingle(DaisyPatchSM::A2);
   hw.PrintLine("after init single");

   /** Initialize the ADC with our configuration */
    hw.adc.Init(adc_cfg, 1);
    hw.PrintLine("after adc init");

   /** Start the ADC conversions in the background */
   hw.adc.Start();
   hw.PrintLine("after adc start");

   /** Startup the USB Serial port */
   /** Infinite Loop */
   while(1)
   {
       /** Print the values via Serial every 250ms
        *  Values will be 0 when inputs are 0V
        *  Values will be 65536 when inputs are 3v3
        *
        *  Based on the CV input circuit this means that
        *  Values will be 0 when input is 5V
        *  Values will be ~32768 when input is ~0V
        *  Values will be 65536 when input is -5V
        */
       System::Delay(250);
       int val_0 = hw.adc.Get(0); 
// OR float val_0 = hw.adc.GetFloat(0); to get vals // from 0 to 1
       hw.PrintLine("Input 1: %d", val_0);
   }
}

Hey zyxy398!

Ok, I see why it crashed.
The Init function for the Daisy Patch SM inits and starts the adc. So you could try to stop the adc right after calling hw.Init().
There’s no deinit function unfortunately.

It could be a good idea to for me to make a Patch SM version of the multiplexer example code (especially since we may make a video tutorial in the near future).

Hey, I just tried this and no more crash! Except that all the other adc and cv inputs no longer worked after that. I figured out this was because the new adc_cfg i was initialising the adc with only had a single value, the mux. I’d have to manually configure the 11 other adc pins if I wanted to use them. So in the end I do have it working, but my big question is, Is there a better way to use adc with the patch sm than to manually configure all the adc pins?

Hi Stains!

I’m sorry for the delay in response. I double checked with the team and this code that you posted on Discord seems like the simplest way to handle it actually.

Ah, but that requires a modification to the libDaisy itself, meaning I can’t easily commit this change to my own repo. I can live with it for now! Is there plans for a nicer way to configure MUX with the the patch SM that doesn’t involve modifying libDaisy or reinitialising all ADC pins?

It should be possible to pull that code out of libdaisy for cleanliness.

Either way, thank you for bringing this to our attention. We’ll have more discussion about it especially when we create a more proper tutorial for using mux :slight_smile:

1 Like

Thank you for such a nice tutorial explaining multiplexer!
As I understood for pd2dsy you do all the code in PD and in custom json file you define analog and digital pins?
How do you add digital outs in custom json file for pin 0,1 and 3?
Could you show a simple PD patch for 1 or 2 knobs coming from the multiplexer?
Thank you

1 Like

Sure!

Here’s the json file:

{
  "name": "mux",
  "som": "seed",
  "parents": {
    "pot_mux": {
      "component": "CD4051",
      "mux_count": 8,
      "pin": {
        "adc": 15,
        "sel0": 0,
        "sel1": 1,
        "sel2": 2
      }
    }
  },
  "components": {
    "knob1": {
      "component": "CD4051AnalogControl",
      "index": 0,
      "parent": "pot_mux"
    },
    "knob2": {
      "component": "CD4051AnalogControl",
      "index": 3,
      "parent": "pot_mux"
    },
    "knob3": {
      "component": "CD4051AnalogControl",
      "index": 1,
      "parent": "pot_mux"
    },
    "knob4": {
      "component": "CD4051AnalogControl",
      "index": 4,
      "parent": "pot_mux"
    },
    "knob5": {
      "component": "CD4051AnalogControl",
      "index": 2,
      "parent": "pot_mux"
    },
    "knob6": {
      "component": "CD4051AnalogControl",
      "index": 5,
      "parent": "pot_mux"
    },
    "knob7": {
      "component": "CD4051AnalogControl",
      "index": 6,
      "parent": "pot_mux"
    },
    "knob8": {
      "component": "CD4051AnalogControl",
      "index": 7,
      "parent": "pot_mux"
    }
  },
  "aliases": {
    "knob": "knob1",
    "ctrl": "knob1",
    "ctrl1": "knob1",
    "ctrl2": "knob2",
    "ctrl3": "knob3",
    "ctrl4": "knob4",
    "ctrl5": "knob5",
    "ctrl6": "knob6",
    "ctrl7": "knob7",
    "ctrl8": "knob8"
  }
}

And your patch can be something like this. The [line~] is for smoothing out the sensor data, which is especially crucial for amplitude.

1 Like

This is just great Takumi, thank you very much!

What about using some other multiplexer? Do you just change the name in the json file or this works only with the CD4051?

What are these aliases for in the json file?

As long as it has 3 selector pins like the CD4051, you should be able to keep things the same in the json file.

Hi @Takumi_Ogata , thanks for the great tutorial. I managed to change it to work with the Pod.

One noob question, if you don’t mind:

Both the pots and the multiplexer chip are powered via 3V3 Digital. Aren’t the pots supposed to be powered to 3V3 Analog and the CD4051 via 3V3 Digital?

Thanks

Has anyone got this working with the Patch SM? I see the comments above and tried to follow by editing the daisy_patch_sm.cpp but I’m having no luck at all. Example code for the Patch SM would be greatly appreciated!