Control-Surface icon indicating copy to clipboard operation
Control-Surface copied to clipboard

matrix keyboard not working with mux

Open greenmen88 opened this issue 4 years ago • 6 comments

Hi! I build a midi controller using Your great library. Everything works except matrix keyboard. Electrically everything is correct, columns are 5V pulled up by internal resistors, rows are connected to mux inputs. During button press there is voltage transition LOW to HIGH on each row, measured by voltmeter Every other part of sketch is working correctly : 4 pots, 4 faders, 2 encoders, 5 CC buttons. Except keyboard.

Below there is full code, board is Arduino Leonardo

Cannot fight this issue, could You help, please?

// Include the library
#include <Encoder.h> // Include the Encoder library.
#include <Control_Surface.h>


// Instantiate a MIDI Interface to use
//USBMIDI_Interface midi;
USBDebugMIDI_Interface usbmidi(115200); // for serial monitor in ide

CD74HC4067 mux = {
	A0,               // analog pin
	{9, 10, 11, 12},  // Address pins S0, S1, S2, S3
	//NO_PIN, // Optionally, specify the enable pin
};
// Create an array of potentiometers that send out
// MIDI Control Change messages when you turn the
// potentiometers connected to the eight input pins of
// the multiplexer


CCPotentiometer volumePotentiometers[] = {
  {mux.pin(0), {MIDI_CC::Channel_Volume, CHANNEL_1}},
  {mux.pin(1), {MIDI_CC::Channel_Volume, CHANNEL_2}},
  {mux.pin(2), {MIDI_CC::Channel_Volume, CHANNEL_3}},
  {mux.pin(3), {MIDI_CC::Channel_Volume, CHANNEL_4}},
  {mux.pin(4), {MIDI_CC::Channel_Volume, CHANNEL_5}},
  {mux.pin(5), {MIDI_CC::Channel_Volume, CHANNEL_6}},
  {mux.pin(6), {MIDI_CC::Channel_Volume, CHANNEL_7}},
  {mux.pin(7), {MIDI_CC::Channel_Volume, CHANNEL_8}},		  
};

// Instantiate a CCButton object
CCButton button1 = { mux.pin(8),{MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};
CCButton button2 = { mux.pin(9),{MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};
CCButton button3 = { 15,{MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};
CCButton button4 = { 16,{MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};
CCButton button5 = { 17,{MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};

// Instantiate a CCAbsoluteEncoder object
CCAbsoluteEncoder enc1 = {
	{3, 2},       // pins
	MIDI_CC::Pan, // MIDI address (CC number + optional channel)
	1,            // optional multiplier if the control isn't fast enough
	4,			  //pulse per step
};

CCAbsoluteEncoder enc2 = {
	{1, 0},       // pins
	MIDI_CC::Pan, // MIDI address (CC number + optional channel)
	1,            // optional multiplier if the control isn't fast enough
	4,			  //pulse per step
};

const AddressMatrix<4, 5> addresses = {{
	{ 1,  2,  3,  4,  5},
	{ 6,  7,  8,  9, 10},
	{11, 12, 13, 14, 15},
	{16, 17, 18, 19, 20},
}};

NoteButtonMatrix<4, 5> buttonmatrix = {
	{mux.pin(10), mux.pin(11), mux.pin(12), mux.pin(13)}, // row pins	
	{4, 5, 6, 7, 8},    // column pins
	addresses,    // address matrix
	CHANNEL_1,    // channel and cable number
};

/*
// Instantiate a shift register as output for the LEDs
SPIShiftRegisterOut<24> sreg = {
	19,       // Latch pin (ST_CP)
	MSBFIRST, // Byte order
};

using namespace MIDI_Notes;

// Create a range of LEDs that listens for MIDI Note messages, turning on and off
// the LEDs connected to the eight output pins of the shift register
NoteRangeLEDs<24> leds = { sreg.pins(), note(C, 4) };
*/

// Initialize the Control Surface
void setup() {

  Control_Surface.begin();

}

// Update the Control Surface
void loop() {
  Control_Surface.loop();
}

greenmen88 avatar Mar 03 '21 23:03 greenmen88

You can only use the mux pins as inputs, not outputs. The row pins are outputs, the column pins are inputs, see https://tttapa.github.io/Control-Surface-doc/Doxygen/d2/daf/classNoteButtonMatrix.html#a7b57c72549e335d4aad8f364db6ef299.

Try moving the mux pins to the columns, and use the Arduino pins for the rows.

tttapa avatar Mar 03 '21 23:03 tttapa

You are completely right. swapping pins, and reordering code solves the keyboard issue.

I stumbled upon next fail in my project - inverted leds. I soldered them in opposite polarity. Is there any software trick to solve that, some logic inversion? I already resoldered common cathode/anode, so every led lights up after start. Unfortunately also they doesn't respond to MIDI Input i suppose. Recording pushbuttons and, playing them back doesn't switch led state. There are 20 leds connected to 3 shift register connected in series, to ISP port

But I need to admit that Your library is very well documented, pleasure to use... GREAT WORK!!! Thank You for that

Code:

// Include the library
#include <Encoder.h> // Include the Encoder library.
#include <Control_Surface.h>


// Instantiate a MIDI Interface to use
USBMIDI_Interface midi;
//USBDebugMIDI_Interface usbmidi(115200); // for serial monitor in ide

CD74HC4067 mux = {
	A0,               // analog pin
	{9, 10, 11, 12},  // Address pins S0, S1, S2, S3
	//NO_PIN, // Optionally, specify the enable pin
};
// Create an array of potentiometers that send out
// MIDI Control Change messages when you turn the
// potentiometers connected to the eight input pins of
// the multiplexer

const AddressMatrix<4, 5> addresses = {{
	{48, 49, 50, 51, 52},
	{53, 54, 55, 56, 57},
	{58, 59, 60, 61, 62},
	{63, 64, 65, 66, 67},
}};

NoteButtonMatrix<4, 5> buttonmatrix = {
	{ 7, 6, 5, 4}, // row pins
	{mux.pin(10), mux.pin(11), mux.pin(12), mux.pin(13), mux.pin(14)},    // column pins
	addresses,    // address matrix
	CHANNEL_1,    // channel and cable number
};


CCPotentiometer volumePotentiometers[] = {
  {mux.pin(0), {MIDI_CC::Channel_Volume, CHANNEL_1}},
  {mux.pin(1), {MIDI_CC::Channel_Volume, CHANNEL_2}},
  {mux.pin(2), {MIDI_CC::Channel_Volume, CHANNEL_3}},
  {mux.pin(3), {MIDI_CC::Channel_Volume, CHANNEL_4}},
  {mux.pin(4), {MIDI_CC::Channel_Volume, CHANNEL_5}},
  {mux.pin(5), {MIDI_CC::Channel_Volume, CHANNEL_6}},
  {mux.pin(6), {MIDI_CC::Channel_Volume, CHANNEL_7}},
  {mux.pin(7), {MIDI_CC::Channel_Volume, CHANNEL_8}},		  
};

// Instantiate a CCButton object
CCButton button1 = { mux.pin(8),{MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};
CCButton button2 = { mux.pin(9),{MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};
CCButton button3 = { 15,{MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};
CCButton button4 = { 16,{MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};
CCButton button5 = { 17,{MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};

// Instantiate a CCAbsoluteEncoder object
CCAbsoluteEncoder enc1 = {
	{3, 2},       // pins
	MIDI_CC::Pan, // MIDI address (CC number + optional channel)
	1,            // optional multiplier if the control isn't fast enough
	4,			  //pulse per step
};

CCAbsoluteEncoder enc2 = {
	{1, 0},       // pins
	MIDI_CC::Pan, // MIDI address (CC number + optional channel)
	1,            // optional multiplier if the control isn't fast enough
	4,			  //pulse per step
};



// Instantiate a shift register as output for the LEDs
SPIShiftRegisterOut<24> sreg = {
	19,       // Latch pin (ST_CP)
	MSBFIRST, // Byte order
};

using namespace MIDI_Notes;

// Create a range of LEDs that listens for MIDI Note messages, turning on and off
// the LEDs connected to the eight output pins of the shift register
NoteRangeLEDs<24> leds = { sreg.pins(), note(C, 4) };


// Initialize the Control Surface
void setup() {

  Control_Surface.begin();

}

// Update the Control Surface
void loop() {
  Control_Surface.loop();
}

greenmen88 avatar Mar 04 '21 23:03 greenmen88

Is there any software trick to solve that, some logic inversion? I already resoldered common cathode/anode, so every led lights up after start.

Not directly, but I think you should be able to override the SPIShiftRegisterOut::digitalWrite() method to invert the values:


template <uint16_t N>
class InvertedSPIShiftRegisterOut : public SPIShiftRegisterOut<N> {
  public:
    using SPIShiftRegisterOut<N>::SPIShiftRegisterOut;
    void digitalWrite(pin_t pin, PinStatus_t val) override {
      SPIShiftRegisterOut<N>::digitalWrite(pin, val == HIGH ? LOW : HIGH);
    }
    void digitalWriteBuffered(pin_t pin, PinStatus_t val) override {
      SPIShiftRegisterOut<N>::digitalWriteBuffered(pin, val == HIGH ? LOW : HIGH);
    }
    void begin() override {
      for (uint8_t i = 0; i < this->buffer.getBufferLength(); ++i)
        this->buffer.setByte(i, 0xFF);
      SPIShiftRegisterOut<N>::begin();
    }
};

Unfortunately also they doesn't respond to MIDI Input i suppose. Recording pushbuttons and, playing them back doesn't switch led state. There are 20 leds connected to 3 shift register connected in series, to ISP port

Time to use a simpler sketch then to isolate the problem. Have you tried the RGB-LED-Chaser example, for instance? Or just try a simple blink sketch to make sure that the shift registers are wired up correctly and that you can control the LEDs. If the LED chaser example works but the LEDs don't do anything when using the NoteLEDRange, you know somethings up with the MIDI input.

But I need to admit that Your library is very well documented, pleasure to use... GREAT WORK!!! Thank You for that

I'm glad to hear that, it's always a struggle to find a balance between a complete API reference, and examples/guides that are actually useful to get started easily and quickly.

tttapa avatar Mar 05 '21 00:03 tttapa

Must admit that I'm astonished by response time and accuracy of Your every reply.

Code that You posted works like a charm, and RGB-LED-Chaser example revealed another bug in sketch - wrongly named LatchPin port of Shift Registers (19/A5). Now everything blinks. You ROCK!

Last thing I need to figure out is to how to enable midi output in DAW(ableton), so that LED Change state during playback. But now I know that hardware is configured. Thank You very much for support!

greenmen88 avatar Mar 06 '21 17:03 greenmen88

Good afternoon @tttapa .

A question regarding this case.

we want to make a controller based on atmega 32u4

With two encoders and a potentiometer, everything is working perfectly.

But we want two button arrays the first of 4 rows by 10 columns

and the second matrix of 6 columns by 4 rows

The question is the following, we could use a CD74HC4067 multiplexer for the rows and another for the columns so we can put one as input and another as output.

If you could confirm that this is possible, I can send my pcb to be built.

Thank you very much for your great work

pmjcontroller1 avatar Mar 22 '23 16:03 pmjcontroller1

No, this is not possible. For future reference: #906

tttapa avatar Mar 25 '23 11:03 tttapa