Created
February 5, 2020 20:54
-
-
Save UriShX/ac12b4dfd76a2afa1785bcdb08027061 to your computer and use it in GitHub Desktop.
Revisions
-
UriShX created this gist
Feb 5, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,213 @@ /* * Depends on https://github.com/sumotoy/gpio_expander library for operating MCP23x17 port expander * Depends on https://github.com/MajicDesigns/MD_CirQueue/blob/master/src/MD_CirQueue.h for circular queue operation. * Algorithm based on Microchip app note AN1081, checked & working. * * Written by Uri Shani, 2018. Part of AB4MC project, see: https://hackaday.io/project/109296-arduino-blocks-for-midi-controllers */ #include <Arduino.h> #include <mcp23s17.h> #include <MD_CirQueue.h> #include <MIDI.h> #include <SPI.h> #define MCP_CSPIN 4 #define MCP_ADRS_1 B0100010//0x22 //const byte MCP_ADRS_1 = B0100010; #define QUEUE_SIZE 24 //Following depend of the processor you are using!!!! #define INTused 0 #define INTpin 2 // array of buttons mapped similarly to Mackie control (based on http://www.jjlee.com/qlab/Mackie%20Control%20MIDI%20Map.pdf) const byte buttonToNote[8][8] = { {0, 8, 16, 24, 40, 42, 44, 46}, // Ch.1 (Rec/rdy, solo, mute, select), I/O, pan, EQ, fader bank left {1, 9, 17, 25, 41, 43, 45, 47}, // Ch.2 (Rec/rdy, solo, mute, select), sends, plug-ins, dyn, fader bank right {2, 10, 18, 26, 48, 49, 50, 51}, // Ch.3 (Rec/rdy, solo, mute, select), ch. left, ch. right, flip, edit {3, 11, 19, 27, 91, 92, 93, 94}, // Ch.4 (Rec/rdy, solo, mute, select), rewind, ff, stop, play {4, 12, 20, 28, 95, 96, 97, 99}, // Ch.5 (Rec/rdy, solo, mute, select), rec, cursor up, cursor down, zoom {5, 13, 21, 29, 100, 101, 75, 82}, // Ch.6 (Rec/rdy, solo, mute, select), cursor left, cursor right, rec/rdy, marker {6, 14, 22, 30, 83, 84, 85, 86}, // Ch.7 (Rec/rdy, solo, mute, select), mixer, < frame, > frame, loop {7, 15, 23, 31, 87, 88, 89, 90} // Ch.8 (Rec/rdy, solo, mute, select), PI, PO, home, end }; volatile bool keyPressed; volatile bool handledPress = false; volatile bool intPinState = 0xFF; volatile bool functionDone = false; byte column = 0x00; byte buttonPress[8] = {0, 0 ,0, 0, 0, 0, 0, 0}; byte DAWpressed[8] = {0, 0 ,0, 0, 0, 0, 0, 0}; const byte midiChannel = MIDI_CHANNEL_OMNI; // MIDI channel can be 1 thru 16, or MIDI_CHANNEL_OMNI unsigned int mcpState = 0xFF00;//0b1111111100000000;// bank A is rows, bank B is columns in app note AN1081 mcp23s17 mcp1(MCP_CSPIN,MCP_ADRS_1); //MIDI_CREATE_DEFAULT_INSTANCE(); // Define a queue that's 24 signed 8 bit values. MD_CirQueue Q(QUEUE_SIZE, sizeof(int8_t)); void setup() { Serial.begin(115200); Serial.println("start"); Q.begin();// begin circular buffer mcp1.begin(); //IOCON = BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL -NC- // (0=16bit) (0=separate interrupt) (0=not sequential) (0=for i2c) (1=use addr. in SPI) (0=no open drain int) (0=int polarity LOW) mcp1.gpioRegisterWriteByte(mcp1.IOCON, 0b00001000); mcp1.gpioRegisterWriteByte(mcp1.IPOL, 0x00);// make sure polarity of bank A is set to reflect the same state as the pin (used to be:invert polarity of bank A (GPIO register bit reflects the opposite logic state of the input pin)) mcp1.gpioRegisterWriteByte(mcp1.IPOL + 1, 0x00);// make sure polarity of bank B is set to reflect the same state as the pin mcp1.gpioPort(mcpState);// set GPIO, bank A as HIGH, bank B as LOW mcp1.gpioPinMode(mcpState);// Set IODIR, bank A as input, bank B as output mcp1.gpioRegisterWriteByte(mcp1.INTCON, 0x00);// set interrupt for bank A as pin value is compared against the previous pin value mcp1.gpioRegisterWriteByte(mcp1.INTCON + 1, 0x00);// set interrupt for bank A as pin value is compared against the previous pin value mcp1.gpioRegisterWriteByte(mcp1.DEFVAL, 0xFF);// set interrupt compare for bank A as HIGH mcp1.gpioRegisterWriteByte(mcp1.DEFVAL + 1, 0x00);// set interrupt compare for bank B as LOW mcp1.gpioRegisterWriteByte(mcp1.GPPU, 0x00);// make sure pull-up resistor for switch of bank A is LOW mcp1.gpioRegisterWriteByte(mcp1.GPPU + 1, 0xFF);// make sure pull-up resistor for bank B is HIGH mcp1.gpioRegisterWriteByte(mcp1.GPINTEN, 0xFF);// enable all interrupt for bank A mcp1.gpioRegisterWriteByte(mcp1.GPINTEN + 1, 0x00);// disable all interrupt for bank B mcp1.gpioRegisterReadByte(mcp1.INTCAP);// read from interrupt capture ports to clear them for bank A //now prepare interrupt pin on processor pinMode(INTpin, INPUT_PULLUP); digitalWrite(INTpin, HIGH); keyPressed = false; attachInterrupt(digitalPinToInterrupt(INTpin), keypress, FALLING); Serial.println("mcp1 setup OK"); // MIDI.begin(midiChannel); } void loop () { if (keyPressed == true) { Serial.println("interrupt"); handleKeypress(); keyPressed = false; } pressedKeyToMatrix(); // delay(50); for (byte i = 0; i < 8; i++) { //need to make number of iterations based on size if (buttonPress[i] != 0) { uint8_t pressed; Q.pop((uint8_t *) & pressed); for (byte j = 0; j < 8; j++) { if (bitRead(buttonPress[i], j)) { //find bit of pressed button, then check if need to send note on or off byte sendVar = buttonToNote[i][j]; if (!bitRead(DAWpressed[i], j)) { // MIDI.sendNoteOn(sendVar, 127, 1); //send midi note on of the note value respective to the button pressed Serial.print("note on: "); } else { // MIDI.sendNoteOff(sendVar, 0, 1); //send midi note off of the note value respective to the button pressed Serial.print("note off: "); } Serial.println(sendVar); bitWrite(DAWpressed[i], j, ~bitRead(DAWpressed[i], j)); bitWrite(buttonPress[i], j, 0); } } } } } // end of loop void keypress() { boolean intPinNow = digitalRead(INTpin); Serial.print("interrupt pin state:\t"); Serial.println(intPinNow); keyPressed = true; } void pressedKeyToMatrix() { if (!Q.isEmpty()) { uint8_t row; uint8_t column; // uint8_t pressed; Q.pop((uint8_t *) & row); Q.pop((uint8_t *) & column); // Q.pop((uint8_t *) & pressed); buttonPress[column] = row; } } void handleKeypress() { cli(); uint8_t bankA = 0; uint8_t bankB = 0; uint8_t keyState = 0; boolean currStateA; boolean currStateB; if (bankA = ~mcp1.gpioRegisterReadByte(mcp1.INTCAP)){ // int intfRegVal = mcp1.gpioRegisterReadByte(mcp1.INTF); // Serial.print("INTF register value:\t"); Serial.println(intfRegVal); // read from interrupt capture ports to clear them for bank A Serial.print("bank A value:\t"); Serial.println(bankA, BIN); // debug mcp1.gpioRegisterWriteByte(mcp1.GPINTEN, 0x00);// disable all interrupt for bank A mcpState ^= 0xFFFF;// reverese state of all gpio pins mcp1.gpioPort(mcpState); mcp1.gpioPinMode(mcpState);// Set banks A and B to reversed state bankB = ~mcp1.gpioRegisterReadByte(mcp1.GPIO + 1);// read from interrupt capture ports to clear them for bank B Serial.print("bank B value:\t"); Serial.println(bankB, BIN); // debug for (byte buttonRecieve = 0; buttonRecieve < 8; buttonRecieve++) { // this key down? if (bankA & (1 << buttonRecieve)) { Serial.print ("Row "); Serial.print (buttonRecieve + 1, DEC); Serial.print (" "); delay(1); } // end of if this bit changed } for (byte buttonRecieve2 = 0; buttonRecieve2 < 8; buttonRecieve2++) { // this key down? if (bankB & (1 << buttonRecieve2)) { bitWrite(column, buttonRecieve2, (currStateA ? 1:0)); Serial.print ("Column "); Serial.print (buttonRecieve2 + 1, DEC); Serial.println (currStateB ? " now pressed":" now depressed"); delay(1); } // end of if this bit changed } // Q.push((uint8_t *) & bankA);// place data from bank A into stack // Q.push((uint8_t *) & bankB);// place data from bank B into stack // Q.push((uint8_t *) & keyState);// place the on/off status of bank A into stack mcpState ^= 0xFFFF;// reverese state of all gpio pins mcp1.gpioPort(mcpState);// set GPIO, bank A as HIGH, bank B as LOW mcp1.gpioPinMode(mcpState);// Set IODIR, bank A as input, bank B as output // mcp1.gpioRegisterWriteByte(mcp1.INTCON, 0xFF);// set interrupt for bank A as pin value is compared against the previous pin value // mcp1.gpioRegisterWriteByte(mcp1.INTCON + 1, 0x00);// set interrupt for bank A as pin value is compared against the previous pin value // mcp1.gpioRegisterWriteByte(mcp1.DEFVAL, 0xFF);// set interrupt compare for bank A as HIGH // mcp1.gpioRegisterWriteByte(mcp1.DEFVAL + 1, 0x00);// set interrupt compare for bank B as LOW // mcp1.gpioRegisterWriteByte(mcp1.GPPU, 0x00);// make sure pull-up resistor for switch of bank A is LOW // mcp1.gpioRegisterWriteByte(mcp1.GPPU + 1, 0xFF);// make sure pull-up resistor for bank B is HIGH mcp1.gpioRegisterWriteByte(mcp1.GPINTEN, 0xFF);// enable all interrupt for bank A // mcp1.gpioRegisterWriteByte(mcp1.GPINTEN + 1, 0x00);// disable all interrupt for bank B mcp1.gpioRegisterReadByte(mcp1.INTCAP);// read from interrupt capture ports to clear them for bank A } functionDone = true; delay (5); // de-bounce before we re-enable interrupts sei(); // mcp1.gpioRegisterWriteByte(mcp1.GPINTEN, 0xFF);// enable all interrupt for bank A }