Midi interface help

Help ! I've acquired a pair of organ keyboards that had been wired up to a Mega 2560 R3. The wiring has been disconnected for some reason, and I need to figure out how it was intended to be connected.
Problem 1 is that the device doesn't want to talk to the PC. USB fires it up but it never appears as a Com port, so I can't access the programming. Is there any other way that I might get in ?
Assuming that was a stupid question I'll need to replace the device. However, the keyboards are not configured in the usual way ( one common line per octave and all notes of the same name bussed together ( via diodes) to form a matrix). These keyboards have 2 common lines and the notes are connected together in Octaves AND fifths ( C to G, D to A etc) . The first common covers c# to G and the second line G# to C. Does anybody have code that suits this configuration.
I'm a newcomer so be gentle with me !

Welcome to the forum!

Please provide a description and even better a photo of "the device" so we know what we are dealing with. Is it an Arduino? If so then what type? Are there any additional boards or "shields", e,g, a MIDI shield?

How is it wired to the keyboard? From your description is seems that it may not be via standard MIDI DIN connectors? Or that at least one end is open wired? It sounds like you may be describing some custom device or connection method?

Please be aware that we cannot see what you have in front of you unless you post photographs and other details. It might help to read this post titled How to get the best out of this forum to get some idea of the information that would help the volunteers on this site to better understand your problem.

Hello Bitseeker - thanks for the quick response. The connections made are very much "Homemade"as you can see in the Picture.

However, I've made some progress. The problem is the drivers - Windows is seeing the board as a usb composite device. Using an app called "Zadig" I've managed to associate some windows drivers that recognise that it's connected to Com1 and talk to it. I'm hopeful that I can extract some of the contents to figure out what each pin is programmed to expect as an input/output

Hi @johnloud !

You mentioned that your keyboards are wired in a matrix via diodes, correct?

You might have a look at this link

https://www.dribin.org/dave/keyboard/one_html/

Is that (the wiring that avoids ghosting and masking) the configuration of your equipment?

If yes you'd be lucky... ;-)

What you have there is a 3rd party (Elegoo) Mega 2560 board. I do actually have one of those and it has a 16u2 usb-to-serial IC. Usually those are recognized by Windows and the driver automatically installed from Windows update. It seems a bit strange that you had to use Zadig to install drivers. The 16u2 is programmable so its possible that it has been modified. Which driver did you have to install via Zadig?

The connections to pins 9, 10?, 11 and 13 could be for SPI communication - I can't quite tell whether there is a wire connected to pin 10. At the other end of the row, there are the I2C bus and serial pins all connected up and a lot of connections on the high pin numbers.

The code on the Mega 2560 chip will be stored in compiled machine level language rather than an actual readable sketch. Unless you are adept at assembly language, decoding the extracted data is going to be a time consuming and complex task. This also assumes that the IC has not been locked down by modifying its fuses and that it is still possible to read its contents.

As for tools for extracting and backing up of the code, you can use avrdude (with avrdudess if you prefer a GUI). You will also need an ICSP programmer of some sort like another Arduino or USBASP.

Does it print any welcome message or anything when you connect to the serial port?

Any further details on what "the keyboard" actually is? You mention octaves so I am assuming musical keyboard. Any brand name or model or anything?

Not sure how viable this will be to reverse engineer. Perhaps one other avenue, assuming that keyboards had been modified by the previous owner, is whether there any possibility of obtaining further information from them? Perhaps they had made some written notes or sketched a diagram?

Hello ec2021, Thanks for the reply. Yes, the matrix is created from contacts that have diodes ( all 1N4148). The problem is that the configuration is not usual, or one that I can find any information about. It's usual to have a "scan" line for each octave and then 12 common lines to which all the notes of the same name are connected. With diodes in place each note can be identfied and assigned it's midi note. In my case the octaves are divided into 2 - so there are 2 scan lines each of which covers half the octave. The individual notes are not simply bussed together, but connected in fifths ( all the C's and G's together, all the D's and A's together etc). So, the programming has to different - there are twice as many scan lines but only half the number of common lines. I hope I've explained that clearly !

I understand what you say, and it's my biggest fear that I'm unable to reverse engineer the thing. There's no welcome message or anything when I connect up. I'm trying to use avrdude, but it will take a bit time for me to understand how to use that properly. If I have to give up I'll be faced with two options. Firstly to rewire the keyboards in the usual way ( a nightmare task !) and then program the Mega 2560 for that ( Tom Scarff has published plenty on that). Alternatively try and work out for myself how to develop a suitable program. Neither option really appeals !!
I selected the winusb drivers in Zadig.

From your description I understood this:

(Further similar lines for the black keys of course ...).

In case I got you wrong could you provide a drawing?

Hello ec2021,

Nearly right. The common lines at the top cover 6 notes, not 5 which is actually what you have drawn. The scans are c# to f# and G to C for each octave. As the keyboards are 61 notes there's always one note that has a scan line to itself. In my case it looks to be bottom C.

Thanks for your help !

Do you say that it looks like this?

However, if I'm not mistaken, the G and C's would be ambiguous as both are in the same "six key range" ...

It would work with key pairs that belong to different common lines, e.g.

  • C# and G
  • D and G#
  • D# and G#
  • etc.

Yes, that conflict was a concern to me , and on reexamination you are correct - C connects to f# not G.

So it's actually

  • common lines (per six keys and per octave)
    • from C to F
    • from F# to B
  • connected notes over all octaves
    • C and F#
    • C# and G
    • D and G#
    • D# and A
    • E and A#
    • F and B

This way you can activate a group of six keys from the lowest to the highest group using the common lines and identify which key in this group is pressed.

Let's number the groups from low (group 0) to the highest (group 10). With 11 groups we cover 66 keys (the last five would be unused).

Every even group number (0, 2, 4, 6, 8, 10) covers the keys C to F, the odd groups ( 1, 3, 5, 7, 9) the keys F# to B.

The octave can easily be derived from the group number.

Good luck!
ec2021

I'll need it ! I used to be quite adeopt at computer programming in Fortran and VBA, but that was along time ago ! It's syntax that will floor me !

Ok, I might be able to support you tomorrow ...

But here is already an example at Wokwi

https://wokwi.com/projects/391627280518585345

Just assume the six pins are connected to the notes (the rows in the example) and each column forms a group of six notes ...

This is hopefully an appropriate start for you (I could not test the handling of several keys in parallel and the correct transmission of the midi command on Serial1):

/*

   Forum: https://forum.arduino.cc/t/midi-interface-help/1418834
   Wokwi: https://wokwi.com/projects/450423034175942657

  2025/12/15
  ec2021

  Midi notes: C0 = 24, C0# = 25, ... , C5 = 84

*/

#define DEBUG

constexpr unsigned long debounceTime{ 30 };
constexpr int LOWEST_NOTE{ 24 };  // C0 = 24

constexpr char noteNames[] = "C C#D D#E F F#G G#A A#B ";

void printNote(byte midiNote) {
  byte key = (midiNote - LOWEST_NOTE) % 12;
  byte octave = (midiNote - LOWEST_NOTE) / 12;
  Serial.print(noteNames[key * 2]);
  char c = noteNames[key * 2 + 1];
  if (c > ' ') Serial.print(c);
  Serial.print(octave);
}

//Keyboard Matrix
int keycol[] = { 7, 6, 5, 4, 3, 2 };  // (C to F) and (F# to B)
int keyrow[] = { 53, 51, 49, 47 };    // Octave 0 (C-F) , 0 (F#-B), Octave 1 (C-F), 1 (F#-B),...
int col_scan;

constexpr int noOfRows = sizeof(keyrow) / sizeof(keyrow[0]);
constexpr int noOfColumns = sizeof(keycol) / sizeof(keycol[0]);
constexpr int noOfKeys = noOfRows * noOfColumns;

void sendNote(byte note, byte velocity) {
  Serial1.write(0x90);
  Serial1.write(note);
  Serial1.write(velocity);
#ifdef DEBUG
  Serial.print("\nSend Note ");
  Serial.print(velocity > 0 ? "ON  " : "OFF ");
  printNote(note);
#endif  
};

class KeyClass {
  private:
    byte state = HIGH;
    byte lastState = HIGH;
    unsigned long lastChange = 0;
    byte _midiNote = 0;
    void (* _sendNote)(byte, byte) = &sendNote;
    void _sendOff() {
      _sendNote(_midiNote, 0x00);
    }
    void _sendOn() {
      _sendNote(_midiNote, 0x45);
    }
  public:
    void setMidiNote(byte note) {
      _midiNote = note;
    }
    void checkKey(byte actState) {
      if (actState != lastState) {
        lastState = actState;
        lastChange = millis();
      }
      if (state != lastState && millis() - lastChange > debounceTime) {
        state = lastState;
        if (state) {
          _sendOff(); //noteOff
        } else {
          _sendOn(); // noteOn
        }
      }
    };
};

KeyClass keyMatrix[noOfKeys];

void setup() {
  Serial.begin(115200);
  Serial1.begin(31250);
  for (int i = 0; i < noOfRows; i++) {
    digitalWrite(keyrow[i], HIGH);
    pinMode(keyrow[i], OUTPUT);
  }
  for (int i = 0; i < noOfColumns; i++) {
    pinMode(keycol[i], INPUT_PULLUP);
  }
  for (int i = 0; i < noOfKeys; i++) {
    keyMatrix[i].setMidiNote(i + LOWEST_NOTE);
  }
}

void loop() {
  checkKeys();
}

void checkKeys() {
  for (int i = 0; i < noOfRows; i++) {
    digitalWrite(keyrow[i], LOW);
    for (int j = 0; j < noOfColumns; j++) {
      col_scan = digitalRead(keycol[j]);
      int keyNo = i * noOfColumns + j;
      keyMatrix[keyNo].checkKey(col_scan);
    }
    digitalWrite(keyrow[i], HIGH);
  }
}

See on Wokwi: https://wokwi.com/projects/450423034175942657

  • keycol[] contains the six pins that go to the notes C to F and also F# to B for all octaves.
  • keyrow[] contains the pins for the common lines that each covers a half of an octave.
  • Each single key is debounced with (default 30 ms).
  • The lowest note of the keyboard is set to C0 (midi value = 24).
  • The sketch uses Serial1 of the MEGA to send midi note commands using the NoteOn command with "velocity" 0x00 to silence a note and with "velocity" 0x45 to switch the note on.

The Wokwi application has buttons and pins for two octaves and shows the wiring as I understood it.

If you like to test it in your hardware you will have to change the pin numbers depending on your wiring:

int keycol[] = { 7, 6, 5, 4, 3, 2 };  // (C to F) and (F# to B)
int keyrow[] = { 53, 51, 49, 47 };    // Octave 0 (C-F) , 0 (F#-B), Octave 1 (C-F), 1 (F#-B),...

For each further octave add two pins in keyrow[], one for the lower half and one for the upper half of the octave.

Please check also which Serial port is used for the midi commands!

Good luck!
ec2021

Wiring on Wokwi:

P.S.: And to show how easy it is to add an octave
https://wokwi.com/projects/450429364341969921

Thanks, that looks very promising. Thank you for all the effort you have made. I'll keep you informed how it goes - although it may be a few weeks before I get to a point where I'll know if it's all OK.