Get maxximum controllers on one small arduino micro

Thread Starter

foruuser

Joined Oct 31, 2021
50
hi,
I would like to make a midi controller with a micro 32u4 and I need 42 controllers (faders and knobs and switches) is there a way to get more connections than this project DIY USB Midi Controller With Arduino: a Beginner's Guide : 10 Steps (with Pictures) - Instructables
because this project uses 12 controllers so I would need 4 arduino micro's and 4 usb plugs, so ideally if I could get it all in one arduino and one usb cable that would be great.
Is. there a way to do this ? thank you

details
9 potentiometers
23 faders
10 toggle switches

total 42 components,
 

MrChips

Joined Oct 2, 2009
30,824
There are many ways to do this. You don't need four Ardunios. One will do.

You can go with a single 32-channel MUX (multiplexer),
or two 16-channel MUX
or four 8-channel MUX.
 

Thread Starter

foruuser

Joined Oct 31, 2021
50
thanks for your answer
so with this device by using 11 pins from like say a micro 32u4, I get 32 pins !
sounds good
Can i fit 2 x 32 mux on one single arduino micro 32u4?
thanks
 

MrChips

Joined Oct 2, 2009
30,824
I am focusing on the pots and faders for the moment.

Assuming these are varying voltage inputs they are presumably being read by one or multiple ADC inputs.
You can choose to multiplex all channels into one ADC input or you can split it into multiple channels.

Digital switch inputs can be read individually or they also can be muliplexed into one input.

There is nothing to stop you from feeding all analog and digital inputs into one ADC channel except for response time.
Taken to the limit, you only need one ADC input pin for everything.
 

Thread Starter

foruuser

Joined Oct 31, 2021
50
that sounds good to be able to get that many ports !
so if i understood correctly with 12 analog inputs on the micro
I could get 12 X 32 inputs max = 384 controllers ?
 

Thread Starter

foruuser

Joined Oct 31, 2021
50
do you know approximately how many ms ? (I hope it is in ms..)
delay is not that crucial for this project since it is not triggering notes (that needs short latency)

also, can you send me a link to the mux 32 you are talking about so I can check how to connect it to my arduino micro 32u4?
thanks
 

be80be

Joined Jul 5, 2008
2,072
That chip doesn't have 12 ADC it has 12 pins that are mux to one ADC Look at page 298 of data sheet but the reading is us 65-260

Features • 10/8-bit Resolution • 0.5LSB Integral Non-linearity • ±2LSB Absolute Accuracy • 65 - 260µs Conversion Time • Up to 15kSPS at Maximum Resolution • Twelve Multiplexed Single-Ended Input Channels • One Differential amplifier providing gain of 1x - 10x - 40x - 200x • Temperature sensor • Optional Left Adjustment for ADC Result Readout • 0 - VCC ADC Input Voltage Range • Selectable 2.56V ADC Reference Voltage • Free Running or Single Conversion Mode • ADC Start Conversion by Auto Triggering on Interrupt Sources • Interrupt on ADC Conversion Complete • Sleep Mode Noise Canceler
 

Thread Starter

foruuser

Joined Oct 31, 2021
50
can someone help know how to connect 3 x16 mux to the arduino micro 32u4 ?

also I am a beginner so i'm lost with code so i have
the mux code for one 16



//Mux control pins
int s0 = 8;
int s1 = 9;
int s2 = 10;
int s3 = 11;

//Mux in "SIG" pin
int SIG_pin = 0;


void setup(){
pinMode(s0, OUTPUT);
pinMode(s1, OUTPUT);
pinMode(s2, OUTPUT);
pinMode(s3, OUTPUT);

digitalWrite(s0, LOW);
digitalWrite(s1, LOW);
digitalWrite(s2, LOW);
digitalWrite(s3, LOW);

Serial.begin(9600);
}


void loop(){

//Loop through and read all 16 values
//Reports back Value at channel 6 is: 346
for(int i = 0; i < 16; i ++){
Serial.print("Value at channel ");
Serial.print(i);
Serial.print("is : ");
Serial.println(readMux(i));
delay(1000);
}

}


int readMux(int channel){
int controlPin[] = {s0, s1, s2, s3};

int muxChannel[16][4]={
{0,0,0,0}, //channel 0
{1,0,0,0}, //channel 1
{0,1,0,0}, //channel 2
{1,1,0,0}, //channel 3
{0,0,1,0}, //channel 4
{1,0,1,0}, //channel 5
{0,1,1,0}, //channel 6
{1,1,1,0}, //channel 7
{0,0,0,1}, //channel 8
{1,0,0,1}, //channel 9
{0,1,0,1}, //channel 10
{1,1,0,1}, //channel 11
{0,0,1,1}, //channel 12
{1,0,1,1}, //channel 13
{0,1,1,1}, //channel 14
{1,1,1,1} //channel 15
};

//loop through the 4 sig
for(int i = 0; i < 4; i ++){
digitalWrite(controlPin, muxChannel[channel]);
}

//read the value at the SIG pin
int val = analogRead(SIG_pin);

//return the value
return val;
}








and the midi controller code:




Based on Sketch built by Gustavo Silveira (aka Music Nerd)
Modified by Dolce Wang

This code is only for Arduinos that use ATmega32u4 (like Micro, Pro Micro, Leonardo...)
Remember to also assign the correct board in the IDE (like Tools / Boards / Sparkfun AVR / Pro Micro...)

*/

// Change any fields with //**


// LIBRARY

#include "MIDIUSB.h"

// BUTTONS
const int NButtons = 4; //*** total number of buttons
const int buttonPin[NButtons] = {2, 3, 5, 7}; //*** define Digital Pins connected from Buttons to Arduino; (ie {10, 16, 14, 15, 6, 7, 8, 9, 2, 3, 4, 5}; 12 buttons)

int buttonCState[NButtons] = {}; // stores the button current value
int buttonPState[NButtons] = {}; // stores the button previous value


// debounce
unsigned long lastDebounceTime[NButtons] = {0}; // the last time the output pin was toggled
unsigned long debounceDelay = 50; //** the debounce time; increase if the output flickers


// POTENTIOMETERS
const int NPots = 8; //*** total number of pots (knobs and faders)
const int potPin[NPots] = {A9, A8, A7, A6, A3, A2, A1, A0}; //*** define Analog Pins connected from Pots to Arduino; Leave nothing in the array if 0 pots {}
int potCState[NPots] = {0}; // Current state of the pot; delete 0 if 0 pots
int potPState[NPots] = {0}; // Previous state of the pot; delete 0 if 0 pots
int potVar = 0; // Difference between the current and previous state of the pot

int midiCState[NPots] = {0}; // Current state of the midi value; delete 0 if 0 pots
int midiPState[NPots] = {0}; // Previous state of the midi value; delete 0 if 0 pots

const int TIMEOUT = 300; //* Amount of time the potentiometer will be read after it exceeds the varThreshold
const int varThreshold = 10; //* Threshold for the potentiometer signal variation
boolean potMoving = true; // If the potentiometer is moving
unsigned long PTime[NPots] = {0}; // Previously stored time; delete 0 if 0 pots
unsigned long timer[NPots] = {0}; // Stores the time that has elapsed since the timer was reset; delete 0 if 0 pots


// MIDI Assignments
byte midiCh = 1; //* MIDI channel to be used
byte note = 36; //* Lowest note to be used; 36 = C2; 60 = Middle C
byte cc = 1; //* Lowest MIDI CC to be used


// SETUP
void setup() {

// Baud Rate
// 31250 for MIDI class compliant | 115200 for Hairless MIDI

// Buttons
// Initialize buttons with pull up resistors
for (int i = 0; i < NButtons; i++) {
pinMode(buttonPin, INPUT_PULLUP);
}

}

////
// LOOP
void loop() {

buttons();
potentiometers();

}

////
// BUTTONS
void buttons() {

for (int i = 0; i < NButtons; i++) {

buttonCState = digitalRead(buttonPin); // read pins from arduino

if ((millis() - lastDebounceTime) > debounceDelay) {

if (buttonPState != buttonCState) {
lastDebounceTime = millis();

if (buttonCState == LOW) {

// Sends the MIDI note ON

// use if using with ATmega32U4 (micro, pro micro, leonardo...)
noteOn(midiCh, note + i, 127); // channel, note, velocity
MidiUSB.flush();


}
else {

// Sends the MIDI note OFF accordingly to the chosen board

// use if using with ATmega32U4 (micro, pro micro, leonardo...)
noteOn(midiCh, note + i, 0); // channel, note, velocity
MidiUSB.flush();

}
buttonPState = buttonCState;
}
}
}
}

////
// POTENTIOMETERS
void potentiometers() {


for (int i = 0; i < NPots; i++) { // Loops through all the potentiometers

potCState = analogRead(potPin); // reads the pins from arduino

midiCState = map(potCState, 0, 1023, 0, 127); // Maps the reading of the potCState to a value usable in midi

potVar = abs(potCState - potPState); // Calculates the absolute value between the difference between the current and previous state of the pot

if (potVar > varThreshold) { // Opens the gate if the potentiometer variation is greater than the threshold
PTime = millis(); // Stores the previous time
}

timer = millis() - PTime; // Resets the timer 11000 - 11000 = 0ms

if (timer < TIMEOUT) { // If the timer is less than the maximum allowed time it means that the potentiometer is still moving
potMoving = true;
}
else {
potMoving = false;
}

if (potMoving == true) { // If the potentiometer is still moving, send the change control
if (midiPState != midiCState) {

// Sends MIDI CC
// Use if using with ATmega32U4 (micro, pro micro, leonardo...)
controlChange(midiCh, cc + i, midiCState); // (channel, CC number, CC value)
MidiUSB.flush();

potPState = potCState; // Stores the current reading of the potentiometer to compare with the next
midiPState = midiCState;
}
}
}
}


// if using with ATmega32U4 (micro, pro micro, leonardo...)


// Arduino MIDI functions MIDIUSB Library
void noteOn(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
MidiUSB.sendMIDI(noteOn);
}

void noteOff(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
MidiUSB.sendMIDI(noteOff);
}

void controlChange(byte channel, byte control, byte value) {
midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
MidiUSB.sendMIDI(event);
}
 

Thread Starter

foruuser

Joined Oct 31, 2021
50
1024 buttons with one ADC ??!!


One technique commonly used by Sony (I repair lots of their gear) is to use a switched reference supply through a resistance ladder. You can design a series of resistors with values designed to create analog voltages when a button is pressed, which shorts one point in the ladder down to zero volts. The simplest example is just one switch and two resistors. The resistors are in series across the power supply, and are of equal value. The common connection between the resistors is sent to an anolog ADC input on the Arduino. When no button is pressed the voltage is VCC / 2. When the button, which is connected across the lower resistor, is pressed, the input becomes ZERO volts.

This can be expanded for two buttons using three equal resistors in series, by splitting the lower resistor into two and strapping another button across the new lower resistor in the chain. No buttons closed, and the ADC input voltage is 2 x VCC/3 (ie two-thirds of VCC). Press button one, which shorts the two lower resistors to ground and the input voltage is again zero, but press the second button and the voltage at input becomes VCC/2 again. This can continue until the voltage difference between steps becomes unreliable for accurate determining by the ADC, but in theory it allow for up to 1023 buttons with a 10-bit ADC.

In practice a chain of same-value resistors is not suitable unless the number of buttons is small. Practical applications use a non-linear ladder so that the voltage generated at the reference point becomes more linear and simpler to read by the ADC. I am sure there is a simple mathematical function to work out the resistor value ratios, but I am a non-mathematician I am afraid to say.

Hope this helps. Jim.

PS - one downfall of this technique is when worn switches become ohmic. Users of in-line remote controls on their earphone cables will have experienced this, when pressing play is incorrectly interpreted as next track or some other function. Or worse still, record!
 

MrChips

Joined Oct 2, 2009
30,824
In order to estimate the max conversion speed of the MCU you need to examine the ADC specifications as given in the datasheet, page 297-318.

Assuming the ADC clock frequency is 200kHz (5μs period), each conversion takes 13 clock cycles, i.e. 65μs.
If you allow the ADC to continuously sample all 12 channels, it would take 780μs.

This does not take into account the overhead required by the code. Let's take a worse case scenario of 2ms for every 12 samples.

Suppose you put two DG406 MUX on two input channels, we assume the shortest time to acquire 32 samples is 65x32 = 2080μs or about 2ms. Hence a worse case scenario is about 10ms to cycle through all 32 inputs.
 

Thread Starter

foruuser

Joined Oct 31, 2021
50
In order to estimate the max conversion speed of the MCU you need to examine the ADC specifications as given in the datasheet, page 297-318.

Assuming the ADC clock frequency is 200kHz (5μs period), each conversion takes 13 clock cycles, i.e. 65μs.
If you allow the ADC to continuously sample all 12 channels, it would take 780μs.

This does not take into account the overhead required by the code. Let's take a worse case scenario of 2ms for every 12 samples.

Suppose you put two DG406 MUX on two input channels, we assume the shortest time to acquire 32 samples is 65x32 = 2080μs or about 2ms. Hence a worse case scenario is about 10ms to cycle through all 32 inputs.
i would say anything below 20 ms is acceptable for this project
 
Top