Daisy Seed comes with 12 ADC pins.
But what if you need more??
Introducing cd4051 multiplexer!
In short, this multiplexer will allow us to turn 1 ADC into 8 ADCs. Let’s learn how to use it!!
How Does It Work?
Ok, this thing looks…a bit intimidating. There are lot of pins and they’re not labeled like in a typical breakout board.
So, let’s have a look at a diagram like this.
Still a bit daunting, but we are getting closer to understanding how it works!
Let’s have a look at pin 3, which is labeled “COM OUT/IN”. For our purpose of expanding the ADC, that’s the pin where we connect Daisy’s ADC.
So, let’s connect to ADC 0!
Green wire is Daisy’s ADC 0 pin
Next, we see those “Channels I/O” pins with a number next to each. For our purpose of expanding the ADC, think of these as the expanded ADC.
For example, we can connect a potentiometer’s analog out to pin 13, which we can think of as input 0. Then, we can connect a 2nd potentiometer to pin 14, which we can think of as input 1. And so on up to 8 total inputs!
Let’s start with 4 potentiometers for now. Edit: I should’ve used 3V3 Analog for the potentiometers instead of using 3V3 Digital for both CD4051 and the potentiometers like in these diagrams, I’m sorry about that!
But, if we have data from 8 potentiometers all at once into a single ADC, that’s not gonna end pretty, right?
Enter Selector Pins
Pins 11, 10, and 9 are called “select” pins (S0, S1, and S2).
These pins will help us give order to the multiple inputs (maximum of 8 sensor data) coming into a single stream (Daisy’s ADC).
It works by sending digital outs from Daisy to these pins!!
From digital out pins, Daisy can output either a 0 (low) or 1 (high).
Let’s connect Daisy’s digital pin 0 (D0) to multiplexer’s pin 11 (S0). Then, Daisy’s pin D1 to multiplexer’s pin 10 (S1). Finally, Daisy’s D2 to multiplexer’s pin 9 (S2). Note: any pin with the label ‘D’ can be used as a Digital GPIO.
While at it, connect 3.3 volt to multiplexer’s VDD input (pin 16). And also ground pins 6, 7, and 8 together like this.
Well, look at that!! We actually finished hooking up Daisy to the multiplexer!
But, we still need to understand what these select pins are.
Let’s think of doors
Again, we’ll start with 4 inputs for now.
Each multiplexer inputs have 3 different combination of “doors” or “gates”. And a door opens when a matching “key” (digital outs from Daisy’s digital pins) is given. What the heck is this analogy?
Color blue is “digital out LOW or 0” and red is “digital out HIGH or 1”. The first potentiometer on the left is connected to input 0 of the multiplexer. And the next potentiometer to the right is connected to input 1 of the multiplexer and so on…
Let’s take a look at an example.
For S0 = low, S1 = low, and S2 = low, all 3 doors for input 0 will open. For all the other inputs, at least one door is closed, so the data cannot go through; it is gated off!
For S0 = high, S1 = low, and S2 = low, all 3 doors for input 1 will be opened.
And so on…
SO! Multiplexer works by selecting which input on the multiplexer can go through one at a time. And this input is selected by sending different combination of the digital outputs to the selector pins. Let’s take a closer look with a code!
Code (Arduino IDE)
Here’s the whole code for 8 inputs
#include "DaisyDuino.h"
#define analogPin0 A0 //ADC 0
#define pinS2 2 //Pin D2
#define pinS1 1 //Pin D1
#define pinS0 0 //Pin D0
void setup()
{
Serial.begin(9600);
//Set pins D0, D1, and D2 as digital outs
pinMode(pinS2, OUTPUT);
pinMode(pinS1, OUTPUT);
pinMode(pinS0, OUTPUT);
}
void loop()
{
//Only reading input 0 of the multiplexer
digitalWrite(pinS2, LOW);
digitalWrite(pinS1, LOW);
digitalWrite(pinS0, LOW);
Serial.print(analogRead(analogPin0));
Serial.print(" ");
//Only reading input 1 of the multiplexer
digitalWrite(pinS2, LOW);
digitalWrite(pinS1, LOW);
digitalWrite(pinS0, HIGH);
Serial.print(analogRead(analogPin0));
Serial.print(" ");
//Only reading input 2 of the multiplexer
digitalWrite(pinS2, LOW);
digitalWrite(pinS1, HIGH);
digitalWrite(pinS0, LOW);
Serial.print(analogRead(analogPin0));
Serial.print(" ");
//Only reading input 3 of the multiplexer
digitalWrite(pinS2, LOW);
digitalWrite(pinS1, HIGH);
digitalWrite(pinS0, HIGH);
Serial.print(analogRead(analogPin0));
Serial.print(" ");
//Only reading input 4 of the multiplexer
digitalWrite(pinS2, HIGH);
digitalWrite(pinS1, LOW);
digitalWrite(pinS0, LOW);
Serial.print(analogRead(analogPin0));
Serial.print(" ");
//Only reading input 5 of the multiplexer
digitalWrite(pinS2, HIGH);
digitalWrite(pinS1, LOW);
digitalWrite(pinS0, HIGH);
Serial.print(analogRead(analogPin0));
Serial.print(" ");
//Only reading input 6 of the multiplexer
digitalWrite(pinS2, HIGH);
digitalWrite(pinS1, HIGH);
digitalWrite(pinS0, LOW);
Serial.print(analogRead(analogPin0));
Serial.print(" ");
//Only reading input 7 of the multiplexer
digitalWrite(pinS2, HIGH);
digitalWrite(pinS1, HIGH);
digitalWrite(pinS0, HIGH);
Serial.println(analogRead(analogPin0));
delay(50);
}
We can set pins D0, D1, and D3 as digital outs by using the pinMode() function like this.
//Set pins D0, D1, and D2 as digital outs
pinMode(pinS2, OUTPUT);
pinMode(pinS1, OUTPUT);
pinMode(pinS0, OUTPUT);
By setting all three digital pins to “LOW”, the analogRead() will exclusively be reading the data from multiplexer’s input 0. The data is then displayed using Serial.print().
//Only reading input 0 of the multiplexer
digitalWrite(pinS2, LOW);
digitalWrite(pinS1, LOW);
digitalWrite(pinS0, LOW);
Serial.print(analogRead(analogPin0));
Serial.print(" ");
Here’s input 0 of the multiplexer being displayed in Arduino IDE’s Serial Monitor. I should mention that the first knob on the left is connected to input 0 of the multiplexer. Then, the knob next to it on the right is connected to input 1 of the multiplexer and so on…
Notice how twisting the second knob does not affect the displayed output?
To only read multiplexer’s input 1, set the digital pins to a combination of S2 = LOW, S1 = LOW, and S0 = HIGH.
//Only reading input 1 of the multiplexer
digitalWrite(pinS2, LOW);
digitalWrite(pinS1, LOW);
digitalWrite(pinS0, HIGH);
Serial.print(analogRead(analogPin0));
Serial.print(" ");
This time, twisting the first knob does not affect the displayed output
And I believe you get the idea for analyzing the rest of the code!
Let’s use 4 knobs all at once! Again, keep in mind that only 1 ADC is being used right now!!
The inputs are being read one after the other almost simultaneously, which results in this expansion of ADC inputs!
Code (C++)
There is a multiplexer function in libDaisy that we can use in C++. Here’s a code that utilizes it!
/** Example of using a CD4051 multiplexor to expand the ADC inputs */
#include "daisy_seed.h"
/** This prevents us from having to type "daisy::" in front of a lot of things. */
using namespace daisy;
/** Global Hardware access */
DaisySeed hw;
int main(void)
{
/** Initialize our hardware */
hw.Init();
/** Configure the ADC
*
* One channel configured for 8 inputs via CD4051 mux.
*
*/
AdcChannelConfig adc_cfg;
adc_cfg.InitMux(seed::A0, 8, seed::D0, seed::D1, seed::D2);
/** Initialize the ADC with our configuration */
hw.adc.Init(&adc_cfg, 1);
/** Start the ADC conversions in the background */
hw.adc.Start();
/** Startup the USB Serial port */
hw.StartLog();
/** 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(" ");
hw.Print("Input 2: %d", hw.adc.GetMux(0, 1));
hw.Print(" ");
hw.Print("Input 3: %d", hw.adc.GetMux(0, 2));
hw.Print(" ");
hw.Print("Input 4: %d", hw.adc.GetMux(0, 3));
hw.Print(" ");
hw.Print("Input 5: %d", hw.adc.GetMux(0, 4));
hw.Print(" ");
hw.Print("Input 6: %d", hw.adc.GetMux(0, 5));
hw.Print(" ");
hw.Print("Input 7: %d", hw.adc.GetMux(0, 6));
hw.Print(" ");
hw.PrintLine("Input 8: %d", hw.adc.GetMux(0, 7));
}
}
We initialize using adc_cfg.InitMux().
adc_cfg.InitMux(seed::A0, 8, seed::D0, seed::D1, seed::D2);
First argument is Daisy’s ADC pin. Second argument is how many multiplexer inputs we’re using. If you put 4, you may need to ground the third select pin. Rest of the arguments are for Daisy’s digital out pins. If you put 4 for the 2nd argument, you only need to put two pins.
Use the GetMux() function to read one multiplexer input at a time. Notice the second argument corresponding to the multiplexer input pins.
hw.Print("Input 1: %d", hw.adc.GetMux(0, 0));
Let’s see if this works! Here’s what the serial monitor should look like. I’m using Arduino IDE’s Serial Monitor and only printing out 4 potentiometer data at once.
The values will be 0 when inputs are 0V and 65536 when inputs are 3v3.
What’s Next?
Hopefully this tutorial was helpful enough for you to get started!!
Mapping these expanded input data to synth parameters is going to be a fun next step!
Adding more multiplexer is another step that you could take!
I believe we can use the same digital pins on Daisy for newly added mutiplexers.
As for the code, this should be straightforward to do in Arduino IDE.
And for C++, you can reference here to get an idea of how to add more Mux functions.
Finally for Arduino IDE, there are bunch of multiplexer codes online, so I recommend checking them out for optimization (making the code succinct/clean)!
Have fun!!
Please feel free to share if you end up using a multiplexer for your next project!! And if you have experience using multiplexer, please let us know about any tips that’ll be helpful!! Thanks!!
Credits/references:
1
2
First photo