Universal MIDI Expression Pedal

So I'm really struggling with getting this to work, and the thing is, the way the schematic is currently, it appears that T&R are permanently shorted via this:
T&R Permanently Shorted.jpg



It appears that TCTRL is not actually controlling shorting T&R at all. And the expression pedal analog section only works when I set TCTRL to LOW, not high.

I wonder if this is an error in the schematic, or an error in my understanding? Perhaps should pins 9-8 be controlled through TCTRL as well?

I also cannot seem to get the foot switches to work AT ALL in any configuration whatsoever.

Sorry to be dense, but I'm not sure what's going on at the moment or what I may be doing wrong...does anyone have any insights? I hate to ask @Pio but if you can be bothered to chime in I would be grateful.

Thanks,
Mike

EDIT: I broke out the multimeter. With no pedal jack inserted, just applying power T&R are shorted no matter whether TCTRL is set to HIGH or LOW. However, if I insert a pedal, then TCTRL does control whether T&R are shorted, as advertised: HIGH and T&R are NOT shorted; LOW and T&R are shorted.

I'm more confused than ever. Why is the expression pedal even working with TCTRL set to LOW, and not working when set to HIGH? Why can I not get the foot switches to work with the logic in the schematic. Sorry if I'm being dense...
 
Last edited:
Well, many hours later, lots of multimeter probing and experimenting, everything is working! I have a Yamaha FC7 working, a single foot switch, and a dual foot switch.

The only caveat that mystifies me is why the TCTRL pin logic is backwards from the schematics. You have to use LOW for expression pedals and HIGH for foot switches.

I still need to test with more pedals, and obvs the code is just very rudimentary at the moment. In practice I'll do some noise reduction by adding some hysteresis (using absolute value of difference between values has to be greater than a certain amount before outputting MIDI), and also in hardware add some capacitance to the ADC pins.

Additionally I'll add the ability to switch between pedals while the sketch is running, make it nice, even perhaps add some velocity curves.

In the meantime, as a huge thank-you to @Pio and everyone who worked on this with me, here's the completed working sketch:
C++:
#include <Wire.h>
#include <ResponsiveAnalogRead.h>
#include <MIDI.h>
#include <DS_MCP4018.h>

MCP4018 MCP;

const byte LinearRegulatorControlPin = 23;
const byte TCTRL_Pedal_Type_Pin = 30;//determine which type of pedal
const byte Pedal_Sense_Pin = 31;//detect when pedal is inserted
const byte ADC1 = 15;//Pin 15 (A1) for continuous expression pedal data - OR digital pin for footswitch operation
const byte RS_ADC2_Pin = 32;

const unsigned long debounceTime = 35;

bool PedalDetected = false;
bool PedalStatusChanged = false;
bool PedalPluggedIn = false;

int rawData;

int CurPedalVal = 0;
int PrevPedalVal = 1;

int VoltageLow = 7;
int VoltageHigh = 970;

const byte ExprPed = 0;
const byte SingleFS = 1;
const byte DualFS = 2;
byte PedalMode = SingleFS;

ResponsiveAnalogRead analog(ADC1, true);

void setup() {

    Serial.begin(115200);

    //Turn on power for Pedal (Using external voltage regulator)
    pinMode(LinearRegulatorControlPin, OUTPUT);
    digitalWrite(LinearRegulatorControlPin, HIGH);
    delay(10);
    //Test digital pot nMCP4018 and set resistance
    MCP.reset();
    if(!MCP.begin()) Serial.print("\nMCP4018 could not be found...");
    else Serial.println("MCP found!");
    MCP.setWiperResistance(10000);
    MCP.setWiperPercent(93);//93 is good for Roland FC7
    Serial.println("MCP resistance set to:" + String(MCP.getWiperResistance()));
    Serial.println("MCP wiper percent set to:" + String(MCP.getWiperPercent()));

    pinMode(Pedal_Sense_Pin, INPUT_PULLUP);//Button to detect if pedal is plugged in
    pinMode(TCTRL_Pedal_Type_Pin, OUTPUT);

    if (PedalMode == ExprPed) {
      digitalWrite(TCTRL_Pedal_Type_Pin, LOW);//LOW sets pedal as EXPR pedal; HIGH sets as footswitch(es)
      pinMode(RS_ADC2_Pin, INPUT);

      analog.setActivityThreshold(12);//12 is very stable and a good compromise//4 is very sensitive
      analog.enableEdgeSnap();
    }
    else if (PedalMode == SingleFS) {
      digitalWrite(TCTRL_Pedal_Type_Pin, HIGH);//LOW sets pedal as EXPR pedal; HIGH sets as footswitch(es)
      pinMode(ADC1, INPUT_PULLUP);
      pinMode(RS_ADC2_Pin, INPUT);
     
    }
    else if (PedalMode == DualFS) {
      digitalWrite(TCTRL_Pedal_Type_Pin, HIGH);//LOW sets pedal as EXPR pedal; HIGH sets as footswitch(es)
      pinMode(ADC1, INPUT_PULLUP);
      pinMode(RS_ADC2_Pin, INPUT_PULLUP);
    }

}//end void Setup

void loop() {
  PedalDetect();
  if (PedalDetected) {
    OutputMIDI();
  }
}

void OutputMIDI() {

  if (PedalMode == ExprPed){
    analog.update();
    if (analog.hasChanged()) {
      rawData = analog.getValue();
      rawData = constrain(rawData, VoltageLow, VoltageHigh);
      CurPedalVal = map(rawData, VoltageLow, VoltageHigh, 0, 127);//CurPedalVal[y] = map(rawData[y], VoltageLow, VoltageHigh, MIDIMin[y], MIDIMax[y]);
      CurPedalVal = constrain(CurPedalVal, 0, 127);//CurPedalVal[y] = constrain(CurFaderVal[y], MIDIMin[y], MIDIMax[y]);
      if (CurPedalVal != PrevPedalVal) {
        PrevPedalVal = CurPedalVal;
        Serial.println("MIDI Value: " + String(CurPedalVal));
        //Serial.println("Current Pedal Raw Value:" + String(rawData));
        usbMIDI.sendControlChange(64, CurPedalVal , 1);
      }
    }// if
  }//if (PedalMode == ExprPed){
  else if (PedalMode == SingleFS){
    FS1State();
  }//else if (PedalMode == SingleFS){
  else if (PedalMode == DualFS) {
    FS1State();
    FS2State();
  }

}//end void OutputMIDI

void PedalDetect(){
  //const unsigned long debounceTime = 35;
  static unsigned long Last_Reading_Time_Pedal_Detect = 0;
  unsigned long Current_Reading_Time_Pedal_Detect = millis();

  if (Current_Reading_Time_Pedal_Detect - Last_Reading_Time_Pedal_Detect > debounceTime) {
    if (digitalRead(Pedal_Sense_Pin) == HIGH) {
      PedalDetected = true;
      if (!PedalPluggedIn) {
        PedalPluggedIn = true;
        PedalStatusChanged = true;
      }
      else PedalStatusChanged = false;
    }
    else {
      PedalDetected = false;
      if (PedalPluggedIn) {
        PedalPluggedIn = false;
        PedalStatusChanged = true;
      }
      else PedalStatusChanged = false;
    }
   
    Last_Reading_Time_Pedal_Detect = millis();
  }//if

  if (PedalStatusChanged) {
    PedalStatusChanged = false;
    if (PedalPluggedIn) Serial.println("A pedal was inserted.");
    else Serial.println("A pedal was removed.");
  }

}//end void PedalDetect

void FS1State(){
  static unsigned long Last_Reading_Time_Pedal_DetectFS1 = 0;
  unsigned long Current_Reading_Time_Pedal_DetectFS1 = millis();
  static bool FS1_Data_Sent = false;

  if (Current_Reading_Time_Pedal_DetectFS1 - Last_Reading_Time_Pedal_DetectFS1 > debounceTime) {
    if(digitalRead(ADC1) == HIGH){
      if (!FS1_Data_Sent){
        Serial.println("ADC1 is HIGH!");
        Serial.println("Sending MIDI Note ON");
        Serial.println("");
        FS1_Data_Sent = true;
      }
    }
    else {    
      if (FS1_Data_Sent){
        Serial.println("ADC1 is LOW!");
        Serial.println("Sending MIDI Note OFF");
        Serial.println("");
        FS1_Data_Sent = false;
      }
    }
   
    Last_Reading_Time_Pedal_DetectFS1 = millis();
  }//if
}//end void FS1State

  void FS2State(){
    static unsigned long Last_Reading_Time_Pedal_DetectFS2 = 0;
    unsigned long Current_Reading_Time_Pedal_DetectFS2 = millis();
    static bool FS2_Data_Sent = false;

    if (Current_Reading_Time_Pedal_DetectFS2 - Last_Reading_Time_Pedal_DetectFS2 > debounceTime) {
      if(digitalRead(RS_ADC2_Pin) == HIGH){
        if (!FS2_Data_Sent){
          Serial.println("RS_ADC2_Pin is HIGH!");
          Serial.println("Sending MIDI Note OFF");
          Serial.println("");
          FS2_Data_Sent = true;
        }
      }
      else {    
        if (FS2_Data_Sent){
          Serial.println("RS_ADC2_Pin is LOW!");
          Serial.println("Sending MIDI Note ON");
          Serial.println("");
          FS2_Data_Sent = false;
        }
      }
     
      Last_Reading_Time_Pedal_DetectFS2 = millis();
    }//if

}//end void FS2State

If I have more issues or discover more useful things to share in conjunction with this project, I'll share them here.

Thank you again everyone! I was sweating bullets over this! Nothing like dropping several days of your life into something!

Cheers!

Mike
 
"TCTRL pin logic is backwards from the schematics. You have to use LOW for expression pedals and HIGH for foot switches."

That's because the text comment was correct for schematic in msg#32.
But, you added another switch (U1.4) that acts like an invertor and never changed the comments to reflect this. Hence a bit of confusion.

Glad to hear you have it working. Lots of work to achieve this! Nice pcb.
 
"TCTRL pin logic is backwards from the schematics. You have to use LOW for expression pedals and HIGH for foot switches."

That's because the text comment was correct for schematic in msg#32.
But, you added another switch (U1.4) that acts like an invertor and never changed the comments to reflect this. Hence a bit of confusion.

Glad to hear you have it working. Lots of work to achieve this! Nice pcb.
Thank you Bill for the explanation.

I really can’t take credit here - it’s all Pio’s work (with me egging him on!). I admit I don’t understand the whole circuit well. Which explains how I didn’t catch or understand the logic change.

I knew Pio knew what he was doing.

I did spend a lot of time trying to understand the schematic.

In any case if I find more nuances to share I will, and hopefully someone finds this useful.

Thanks again Bill; I really appreciate your time and wisdom. And you’re right, this is a lovely little PCB and project.
 
What Bill said, i forgot to change the comments on the schematic. My bad. Will fix the repo asap.
LOW (Exp pedal mode) should be the default setting even if there is no logic signal applied at TRCTRL, R12 keeps it low if the input is floating.
 
What Bill said, i forgot to change the comments on the schematic. My bad. Will fix the repo asap.
LOW (Exp pedal mode) should be the default setting even if there is no logic signal applied at TRCTRL, R12 keeps it low if the input is floating.
No need to apologize @Pio - your work is stellar! It was good for me to hone some troubleshooting skills too.

I'm even going to try to make it to automatically calibrate an expression pedal. Maybe have the user press the expression pedal to the top and then use some kind of loop that tests various values of the digital pot. When the voltage is highest, scrape that value for the digital pot and use that to calibrate it.

Not sure if I can autodetect single or dual foot switches; I might need to have the user specify the type.

The ULTIMATE would be for a user to plug in an expression pedal, and it auto calibrates in a few seconds, figuring out the type and if an expression pedal figuring out the polarity and setting the range of output to full.

That may be a bridge too far but I'm going to strive for that.

Also I'm going to let the user save a pedal configuration and recall it for future (which will be unnecessary if I can get a complete auto calibration working).

Thank you again Pio; this is such a cool project!
 
Back
Top