Struggling with making an arduino nano midi controller

Started by Esppse, January 20, 2023, 12:19:40 PM

Previous topic - Next topic

Esppse

Hello,

I have been trying to create a tiny midi keyboard that supposed to be installed into one of my projects. I have come close to getting it to work but have not fully completed it.

Basically, most of the buttons are just Note on/off messages. However when I press one button, it shoots out for example A2, A#2, B3 all at once instead of just the assigned A2 note.

This key has 27 buttons, and I am using 2 multiplexers:
https://www.digikey.com/en/products/detail/e-switch/TL1105EF250Q7-3RED/10371?utm_medium=email&utm_source=oce&utm_campaign=4251_OCE22RT&utm_content=productdetail_US&utm_cid=3297766&so=78637232&mkt_tok=MDI4LVNYSy01MDcAAAGH-elfm9y1eAZbHdq1hCFkVa62ie4oErS80ftLVnWY-MTAg7RnYHCWNhLOdJGfLP30tSF50fVUiWwAn3ucNgSr2BeZogcXdLfOts_4jRmm

https://www.digikey.com/en/products/detail/onsemi/MC74HC4067ADWR2G/2512516?utm_medium=email&utm_source=oce&utm_campaign=4251_OCE22RT&utm_content=productdetail_US&utm_cid=3297766&so=78738185&mkt_tok=MDI4LVNYSy01MDcAAAGIG7jmufc3TCC4wp6MjiCfCjYvcK64lETjFqDnhzcs9n8JoRBQBpeajz8ZFd4tQEbPB2Dx_rfjZIJeK2P-NzcscpZ78RJlOkhClxSTLmk4

I used the code from here:
https://www.youtube.com/watch?v=NmxoBdEJG28&t=902s

Here was when the Nano was used:
https://www.youtube.com/watch?v=ellhUszaMZs

The code was specifically for the Arduino Uno, however in one of the other tutorials from the same channel, the Nano was supposed to be compatible as well. I followed the instructions for the code exactly as shown in the tutorial. 1 button works right, the others either shoot out multiple notes, or nothing at all.

Here is the schematic and pcb(double sided, only top shown below):







I am not sure what is wrong, but I must inquire about the multiplexers. Should I have used a digital multiplexer or an analog multiplexer? I went with analog for the midi keys. Only 1 button works correctly (the middle All Notes Off button). I checked the soldering with a multimeter and the schematic, I think it is all good there. Very simple, one side of button is GND, one side goes to an input pin on a multiplexer.

2 multiplexers, so S0, S1, S2, and S3 on both multiplexers are parallel, go to Nano Pin 2-3-4-5. E and GND on both multiplexers are grounded. Output of 1st multiplexer to Nano Pin 9. Output of 2nd multiplexer to Nano Pin 10.

Is there another midi keyboard code template that already exists that I can try with the Nano controller?

ElectricDruid

It doesn't look too impossible to sort out.

There's two 1-to-16 multiplexers (did you use the 74HC4067 like in the schematic?), both permanently enabled. There's four address lines to select one of the inputs on each of the multiplexers, and then there's the two multiplexer outputs (MUX1 & 2) going back to the Arduino.

There's no pull-ups on the schematic, so the Arduino code will need to specify pull-ups on the chip's two MUX inputs. Without a default "high" level, you can't detect when a switch pulls it low.

Have you got a link to the code? It sounds like something isn't configured right.

Esppse

Quote from: ElectricDruid on January 20, 2023, 01:18:03 PM
It doesn't look too impossible to sort out.

There's two 1-to-16 multiplexers (did you use the 74HC4067 like in the schematic?), both permanently enabled. There's four address lines to select one of the inputs on each of the multiplexers, and then there's the two multiplexer outputs (MUX1 & 2) going back to the Arduino.

There's no pull-ups on the schematic, so the Arduino code will need to specify pull-ups on the chip's two MUX inputs. Without a default "high" level, you can't detect when a switch pulls it low.

Have you got a link to the code? It sounds like something isn't configured right.

Yep I used 2 of those multiplexers.

This is the original template from notes & volts:
https://drive.google.com/file/d/0BwnVMB_6yujwR1dydVJ6MHJib2M/view?resourcekey=0-pn-udeWBz6syK75kNbdIkg

And here is my modified one for the notes/cc messages I wanted:
https://easyupload.io/kk629u

ElectricDruid

Ok, thanks, that's good.

When I open the MIDI_Controller_v1_2 folder, I see an Arduino sketch MIDI_Controller_v1-2.ino, whichopens and show me the assignments and so on, with Controller.cpp, and Controller.h  in the windows in the background.

When I open your 20 Key MIDI Controller folder, I see an Arduino sketch called 20 Key MIDI Controller.ino, but when I open that, I only see Controller.cpp and Controller.h. What happened to the main file with all the definitions and assignments and stuff?

Esppse

Quote from: ElectricDruid on January 20, 2023, 03:54:15 PM
Ok, thanks, that's good.

When I open the MIDI_Controller_v1_2 folder, I see an Arduino sketch MIDI_Controller_v1-2.ino, whichopens and show me the assignments and so on, with Controller.cpp, and Controller.h  in the windows in the background.

When I open your 20 Key MIDI Controller folder, I see an Arduino sketch called 20 Key MIDI Controller.ino, but when I open that, I only see Controller.cpp and Controller.h. What happened to the main file with all the definitions and assignments and stuff?

I am unsure what the definitions and assignments are. I basically zipped up the entire arduino sketch folder.

Does it look like this when you open 20 Key Midi controller?



Which file am I missing to add to the zip? There are a total of 3 files right?

Esppse

Hmm, when I open the file from the zip, its shows one tab. The 20 Key Midi Controller.

When the files are all extracted, it shows all 3 tabs. Did you try to extract all files first? Or double clicked the 20 key Midi controller from inside Winzip?


ElectricDruid

#6
Quote from: Esppse on January 20, 2023, 04:33:19 PM
Hmm, when I open the file from the zip, its shows one tab. The 20 Key Midi Controller.

When the files are all extracted, it shows all 3 tabs. Did you try to extract all files first? Or double clicked the 20 key Midi controller from inside Winzip?

I unzipped, then opened "20 Key Midi Controller.ino". This is what I see:


Only two files. I can see three in the zip, but the one that I clicked on doesn't show up for some reason.

It looks like the Arduino environment doesn't like that file maybe? I can open it with other applications ok. I'll have a look and see if I can spot anything.

At least I can see your button definitions and so on now.

Esppse

This is what it look like when all files are extracted first:



And if only 1 file is double clicked, see how the Controller tabs are missing:




Is this what you mean?

Esppse

Hmm odd, I am not sure why its showing up like that. Is it a different version of Arduino IDE that would do this? Im very new to this coding arduino stuff. I downloaded the latest version recently.

Esppse


Kevin Mitchell

#10
I've actually breadboarded my own midi controller using analog multiplexers recently. Got pretty far before the next shiny thing came along to distract me  :icon_lol:
Without getting into the code right now, I will say that it would be ideal to have pullup resistors on the mux pins for each button. 10K to +5v should be fine. This will help stabilize the readings to avoid false presses.

Alternatively, when plugging the buttons straight into the MCU you would do this with the atmega's internal pullup resistors through code.

FYI - anything UNO ready is also NANO ready. The main difference between the two dev boards is that the nano uses a resonator instead of a quartz crystal. Typically the timing between the two is negligible, until it isn't.
They also use different USART to USB chips for serial communications.
  • SUPPORTER

Esppse

This is what should be in the main 20 Key Midi Controller file:

anotherjim

If you want to show code here, open the sketch in Arduino and control A to select all the text, copy it then use the "Code" tags in the reply (the one with the #). Paste the text in the tags. It shouldn't mess with the formatting.

Esppse

#include <MIDI.h>
#include "Controller.h"

/*************************************************************
  MIDI CONTROLLER

  by Notes and Volts
  www.notesandvolts.com

  Version 1.2 **Arduino UNO ONLY!**
*************************************************************/

MIDI_CREATE_DEFAULT_INSTANCE();

//************************************************************
//***SET THE NUMBER OF CONTROLS USED**************************
//************************************************************
//---How many buttons are connected directly to pins?---------
byte NUMBER_BUTTONS = 0;
//---How many potentiometers are connected directly to pins?--
byte NUMBER_POTS = 0;
//---How many buttons are connected to a multiplexer?---------
byte NUMBER_MUX_BUTTONS = 27;
//---How many potentiometers are connected to a multiplexer?--
byte NUMBER_MUX_POTS = 0;
//************************************************************

//***ANY MULTIPLEXERS? (74HC4067)************************************
//MUX address pins must be connected to Arduino UNO pins 2,3,4,5
//A0 = PIN2, A1 = PIN3, A2 = PIN4, A3 = PIN5
//*******************************************************************
//Mux NAME (OUTPUT PIN, , How Many Mux Pins?(8 or 16) , Is It Analog?);


Mux M1(9, 16, false); //Digital multiplexer on Arduino pin 10
Mux M2(10, 16, false); //Analog multiplexer on Arduino analog pin A0
//*******************************************************************


//***DEFINE DIRECTLY CONNECTED POTENTIOMETERS************************
//Pot (Pin Number, Command, CC Control, Channel Number)
//**Command parameter is for future use**

//Pot PO1(A0, 0, 1, 1);
//Pot PO2(A1, 0, 10, 1);
//Pot PO3(A2, 0, 22, 1);
//Pot PO4(A3, 0, 118, 1);
//Pot PO5(A4, 0, 30, 1);
//Pot PO6(A5, 0, 31, 1);
//*******************************************************************
//Add pots used to array below like this->  Pot *POTS[] {&PO1, &PO2, &PO3, &PO4, &PO5, &PO6};
Pot *POTS[] {};
//*******************************************************************


//***DEFINE DIRECTLY CONNECTED BUTTONS*******************************
//Button (Pin Number, Command, Note Number, Channel, Debounce Time)
//** Command parameter 0=NOTE  1=CC  2=Toggle CC **

//Button BU1(2, 0, 60, 1, 5 );
//Button BU2(3, 0, 61, 1, 5 );
//Button BU3(4, 0, 62, 1, 5 );
//Button BU4(5, 0, 63, 1, 5 );
//Button BU5(6, 0, 64, 1, 5 );
//Button BU6(7, 0, 65, 1, 5 );
//Button BU7(8, 1, 64, 1, 5 );
//Button BU8(9, 2, 64, 1, 5 );
//*******************************************************************
//Add buttons used to array below like this->  Button *BUTTONS[] {&BU1, &BU2, &BU3, &BU4, &BU5, &BU6, &BU7, &BU8};
Button *BUTTONS[] {};
//*******************************************************************


//***DEFINE BUTTONS CONNECTED TO MULTIPLEXER*************************
//Button::Button(Mux mux, byte muxpin, byte command, byte value, byte channel, byte debounce)
//** Command parameter 0=NOTE  1=CC  2=Toggle CC **

Button MBU1(M1, 0, 0, 57, 1, 5);
Button MBU2(M1, 1, 0, 58, 1, 5);
Button B3(M1, 2, 0, 59, 1, 5);
Button C4(M1, 3, 0, 60, 1, 5);
Button CS4(M1, 4, 0, 61, 1, 5);
Button D4(M1, 5, 0, 62, 1, 5);
Button Eb4(M1, 6, 0, 63, 1, 5);
Button E4(M1, 7, 0, 64, 1, 5);
Button F4(M1, 8, 0, 65, 1, 5);
Button FS4(M1, 9, 0, 66, 1, 5);
Button G4(M1, 10, 0, 67, 1, 5);
Button GS4(M1, 11, 0, 68, 1, 5);
Button MBU13(M1, 12, 0, 69, 1, 5);
Button Bb4(M1, 13, 0, 70, 1, 5);
Button B4(M1, 14, 0, 71, 1, 5);
Button C5(M1, 15, 0, 72, 1, 5);
Button CS5(M2, 0, 0, 73, 1, 5);
Button D5(M2, 1, 0, 74, 1, 5);
Button Eb5(M2, 2, 0, 75, 1, 5);
Button E5(M2, 3, 0, 76, 1, 5);
Button CCA(M2, 4, 1, 102, 1, 5);
Button CCB(M2, 5, 1, 103, 1, 5);
Button CCC(M2, 6, 1, 104, 1, 5);
Button CCD(M2, 7, 1, 105, 1, 5);
Button CCE(M2, 8, 1, 106, 1, 5);
Button CCF(M2, 9, 1, 107, 1, 5);
Button ANO(M2, 10, 1, 123, 1, 5);

//*******************************************************************
////Add multiplexed buttons used to array below like this->  Button *MUXBUTTONS[] {&MBU1, &MBU2, &MBU3, &MBU4, &MBU5, &MBU6.....};
Button *MUXBUTTONS[] {&MBU1, &MBU2, &B3, &C4, &CS4, &D4, &Eb4, &E4, &F4, &FS4, &G4, &GS4, &MBU13, &Bb4, &B4, &C5, &CS5, &D5, &Eb5, &E5, &CCA, &CCB, &CCC, &CCD, &CCE, &CCF, &ANO};

//*******************************************************************


//***DEFINE POTENTIOMETERS CONNECTED TO MULTIPLEXER*******************
//Pot::Pot(Mux mux, byte muxpin, byte command, byte control, byte channel)
//**Command parameter is for future use**

//Pot MPO1(M2, 0, 0, 1, 1);
//Pot MPO2(M2, 1, 0, 7, 1);
//Pot MPO3(M2, 2, 0, 50, 1);
//Pot MPO4(M2, 3, 0, 55, 2);
//Pot MPO5(M2, 4, 0, 50, 1);
//Pot MPO6(M2, 5, 0, 55, 2);
//Pot MPO7(M2, 6, 0, 50, 1);
//Pot MPO8(M2, 7, 0, 55, 2);
//Pot MPO9(M2, 8, 0, 50, 1);
//Pot MPO10(M2, 9, 0, 55, 2);
//Pot MPO11(M2, 10, 0, 50, 1);
//Pot MPO12(M2, 11, 0, 55, 2);
//Pot MPO13(M2, 12, 0, 50, 1);
//Pot MPO14(M2, 13, 0, 55, 2);
//Pot MPO15(M2, 14, 0, 50, 1);
//Pot MPO16(M2, 15, 0, 55, 2);
//*******************************************************************
//Add multiplexed pots used to array below like this->  Pot *MUXPOTS[] {&MPO1, &MPO2, &MPO3, &MPO4, &MPO5, &MPO6.....};
Pot *MUXPOTS[] {};
//*******************************************************************


void setup() {
  MIDI.begin(MIDI_CHANNEL_OFF);
}

void loop() {
  if (NUMBER_BUTTONS != 0) updateButtons();
  if (NUMBER_POTS != 0) updatePots();
  if (NUMBER_MUX_BUTTONS != 0) updateMuxButtons();
  if (NUMBER_MUX_POTS != 0) updateMuxPots();
}


//*****************************************************************
void updateButtons() {

  // Cycle through Button array
  for (int i = 0; i < NUMBER_BUTTONS; i = i + 1) {
    byte message = BUTTONS[i]->getValue();

    //  Button is pressed
    if (message == 0) {
      switch (BUTTONS[i]->Bcommand) {
        case 0: //Note
          MIDI.sendNoteOn(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
          break;
        case 1: //CC
          MIDI.sendControlChange(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
          break;
        case 2: //Toggle
          if (BUTTONS[i]->Btoggle == 0) {
            MIDI.sendControlChange(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
            BUTTONS[i]->Btoggle = 1;
          }
          else if (BUTTONS[i]->Btoggle == 1) {
            MIDI.sendControlChange(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
            BUTTONS[i]->Btoggle = 0;
          }
          break;
      }
    }

    //  Button is not pressed
    if (message == 1) {
      switch (BUTTONS[i]->Bcommand) {
        case 0:
          MIDI.sendNoteOff(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
          break;
        case 1:
          MIDI.sendControlChange(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
          break;
      }
    }
  }
}
//*******************************************************************
void updateMuxButtons() {

  // Cycle through Mux Button array
  for (int i = 0; i < NUMBER_MUX_BUTTONS; i = i + 1) {

    MUXBUTTONS[i]->muxUpdate();
    byte message = MUXBUTTONS[i]->getValue();

    //  Button is pressed
    if (message == 0) {
      switch (MUXBUTTONS[i]->Bcommand) {
        case 0: //Note
          MIDI.sendNoteOn(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
          break;
        case 1: //CC
          MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
          break;
        case 2: //Toggle
          if (MUXBUTTONS[i]->Btoggle == 0) {
            MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
            MUXBUTTONS[i]->Btoggle = 1;
          }
          else if (MUXBUTTONS[i]->Btoggle == 1) {
            MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
            MUXBUTTONS[i]->Btoggle = 0;
          }
          break;
      }
    }
    //  Button is not pressed
    if (message == 1) {
      switch (MUXBUTTONS[i]->Bcommand) {
        case 0:
          MIDI.sendNoteOff(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
          break;
        case 1:
          MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
          break;
      }
    }
  }
}
//***********************************************************************
void updatePots() {
  for (int i = 0; i < NUMBER_POTS; i = i + 1) {
    byte potmessage = POTS[i]->getValue();
    if (potmessage != 255) MIDI.sendControlChange(POTS[i]->Pcontrol, potmessage, POTS[i]->Pchannel);
  }
}
//***********************************************************************
void updateMuxPots() {
  for (int i = 0; i < NUMBER_MUX_POTS; i = i + 1) {
    MUXPOTS[i]->muxUpdate();
    byte potmessage = MUXPOTS[i]->getValue();
    if (potmessage != 255) MIDI.sendControlChange(MUXPOTS[i]->Pcontrol, potmessage, MUXPOTS[i]->Pchannel);
  }
}


ElectricDruid

Quote from: Esppse on January 20, 2023, 04:37:09 PM
Is this what you mean?

No. I'm using Arduino 1.8.8 on a Mac, so it's not the latest version. But this doesn't look like a "latest version" issue, to be honest. If you want I suppose I can try upgrading it.

Esppse

I just uploaded the code, hopefully it posted ok. Strange that it wasn't showing up on yours. Im not sure if the assignments are broken after zipping from 7zip?

ElectricDruid

The bit that most struck me suspicious was this part from Controller.cpp:


void Button::muxUpdate()
{
  byte temp = _muxpin;
  temp = temp << 2;
  if (_numMuxPins > 8) PORTD = PORTD & B11000011;
  else PORTD = PORTD & B11100011;
  PORTD = PORTD | temp;
}


That's *very* specific. Are you sure you have your Muxes wired up to exactly the pins they're using? If not, the muxes might finish up scanning through some sub-group of inputs multiple times (like doing buttons 1 to 4 over and over, or doing buttons 1-8 twice through, instead of doing all 16). That would lead to several "software buttons" being triggered by the same "hardware button" - the code thinks it's reading button 8, but really it's reading button 0 again because the Mux isn't addressed correctly.

Do you see what I mean?


Esppse

Yes, I checked the pin to the proper destination with a multimeter. The PCB created was auto routed using EasyEDA. I also checked for solder bridges, it all looks clean. It uses 27 out of 32 input pins. I put 27 in the section that asks how many are attached. Is that correct?




Esppse

The last button in the series of all buttons works right for some reason. The ANO (all notes off) one.

Esppse

Does the middle pin of the Midi jack need to be grounded? I am using a UM-One midi interface. I left the Ground from the midi Out of the controller disconnected. The USB cable grounds the controller and the keybed. Does the UM-One interface require that?