Saturday, January 22, 2011

Well, it's all come down to this: a clone of the FCB1010 based on the Arduino MEGA2560 microcontroller.

I got the MEGA2560 in the mail the other day and it is a real pain to use at first. NewSoftSerial.h is a necessary include. On a side note: I would like to thank Arduino for NOT pointing that out anywhere in the documentation and let me assume my brand new microcontroller was bricked for about 3 hours. Jeeze!

Hardware

Before hooking everything up, I had to first do some soldering. Well, not some. A ton. Everything hooked to the resistor packs in the image of my hardware setup below had to be hooked into a daughter board.


And here is the finished daughter board.
Top

Bottom


And here is the Arduino with everything hooked up to it and everything being insulated/held-on by good old-fashioned electrical tape.

I opted for pin/ribbon cable connections between the boards to avoid any spaghetti wiring. It keeps everything organized and neat. And I think it looks cool.

Software

OK so I'm not an experienced electronics engineer or claim to know very much about the topic. As such, I wasn't sure which switch went to which digital pin after I soldered them all in. So I wrote some code to easily tell me. I knew the input pins were 22-33 so I wrote this code, uploaded, opened the serial monitor and started pressing buttons on the footswitch boards.

#include <NewSoftSerial.h>

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if(digitalRead(22) == LOW){
    Serial.println("22 pressed.");
  }
  if(digitalRead(23) == LOW){
    Serial.println("23 pressed.");
  }
  if(digitalRead(24) == LOW){
    Serial.println("24 pressed.");
  }
  if(digitalRead(25) == LOW){
    Serial.println("25 pressed.");
  }
  if(digitalRead(26) == LOW){
    Serial.println("26 pressed.");
  }
  if(digitalRead(27) == LOW){
    Serial.println("27 pressed.");
  }
  if(digitalRead(28) == LOW){
    Serial.println("28 pressed.");
  }
  if(digitalRead(29) == LOW){
    Serial.println("29 pressed.");
  }
  if(digitalRead(30) == LOW){
    Serial.println("30 pressed.");
  }
  if(digitalRead(31) == LOW){
    Serial.println("31 pressed.");
  }
  if(digitalRead(32) == LOW){
    Serial.println("32 pressed.");
  }
  if(digitalRead(33) == LOW){
    Serial.println("33 pressed.");
  }
}



That step was quick. Figuring out the LED pins was a trail and error test that took a while longer.

The next step was to marry the test effect change code with the wah/volume code. This was no easy task and took hours of troubleshooting with a sniper rifle to get it right. Here is the final functional code to produce a clone of the FCB1010.


#include <NewSoftSerial.h>

int bank = 0x00;//Default bank of 0
int number_in_bank = 0x0A;//10 effects per bank
const int volume_pin = 0;// Pot connected to analog pin 0
const int wah_pin = 1;// Pot connected to analog pin 1
const int pot_threshold = 7;// Threshold amount to guard against false values
const int midi_channel = 0;

void setup() {
  for(int i = 34; i <= 43; i++)//Set up the LED pins and make them float high right off the bat
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH);
  }

  Serial.begin(31250);//  Set MIDI baud rate:

  changeProgram(0x00,43);//Homed to program 1
}

void loop() {
  ///////////
  //EFFECTS//
  ///////////

  //
  //Lower Button Bank
  //

  //Button 1
  if(digitalRead(23) == LOW)
  {
    changeProgram(0x00,43);
  }
  //Button 2
  if(digitalRead(25) == LOW)
  {
    changeProgram(0x01,41);
  }
  //Button 3
  if(digitalRead(29) == LOW)
  {
    changeProgram(0x02,39);
  }
  //Button 4
  if(digitalRead(27) == LOW)
  {
    changeProgram(0x03,37);
  }
  //Button 5
  else if(digitalRead(33) == LOW)
  {
    changeProgram(0x04,35);
  }
  //Bank Down
  else if(digitalRead(31) == LOW)
  {
    if(bank != 0x01)
    {
      bank -= number_in_bank;
      changeProgram(0x00,43);
      delay(250);
    }
  }

  //
  //Upper Bank
  //

  //Button 6
  else if(digitalRead(22) == LOW)
  {
    changeProgram(0x05,42);
  }
  //Button 7
  else if(digitalRead(24) == LOW)
  {
    changeProgram(0x06,40);
  }
  //Button 8
  else if(digitalRead(26) == LOW)
  {
    changeProgram(0x07,38);
  }
  //Button 9
  else if(digitalRead(28) == LOW)
  {
    changeProgram(0x08,36);
  }
  //Button 10 (0)
  else if(digitalRead(30) == LOW)
  {
    changeProgram(0x09,34);
  }
  //Bank Up
  else if(digitalRead(32) == LOW)
  {
    if(bank != 0x19)
    {
      bank += number_in_bank;
      changeProgram(0x00,43);
      delay(250);
    }
  }
  //////////
  //VOLUME//
  //////////
  expression(volume_pin);
  ///////
  //WAH//
  ///////
  expression(wah_pin);
}

void changeProgram(int effect_number, int LED) {
  int program = bank + effect_number;//Program 1 would be bank(0)+effect_button(0) so 0x00 with 10 effects in the bank
  Serial.print(0xC0, BYTE);//Program Change
  Serial.print(program, BYTE);
  digitalWrite(LED,LOW);  //Light the associated LED

  for(int i =34; i <= 43; i++)//Turn off all the rest of the LEDs
  {
    if(i != LED)
    {
      digitalWrite(i, HIGH);
    }
  }
  delay(250);//Some debounce
}

void changeVolume(byte channel, byte volume)
{
  Serial.print(0xB0 | (channel & 0x0F), BYTE); //Control Change
  Serial.print(0x07, BYTE);//Volume CC number        
  Serial.print(volume & 0x7F, BYTE);//Volume level (0-127)
}


void wahCharacter(byte channel, byte wah)
{
  Serial.print(0xB0 | (channel & 0x0F), BYTE);//Control Change
  Serial.print(0x1B, BYTE);//Wah character CC number
  Serial.print(wah & 0x7F, BYTE);//Wah tone character (0-127)
}

void expression(int pin)
{
  static int s_nLastPotValue = 0;
  static int s_nLastMappedValue = 0;
  int nCurrentPotValue = analogRead(pin);
  if(abs(nCurrentPotValue - s_nLastPotValue) < pot_threshold)
    return;
  s_nLastPotValue = nCurrentPotValue;
  int nMappedValue = map(nCurrentPotValue, 0, 1023, 0, 127); // Map the value to 0-127
  if(nMappedValue == s_nLastMappedValue)
    return;
  s_nLastMappedValue = nMappedValue;
  if(nMappedValue >= 15){
    if (pin == volume_pin)
    { 
     changeVolume(midi_channel, nMappedValue);
    }
    else
    {
      wahCharacter(midi_channel, nMappedValue);
    }
  }
}


Extra

While messing with the code, I discovered that you can run 2 wah pedals off of the same controller. The effects processor takes the setpoints from both of the expression pedals and bounces in between them. It sounds like this [link]

Just change void expression to this:


void expression(int pin)
{
  static int s_nLastPotValue = 0;
  static int s_nLastMappedValue = 0;
  int nCurrentPotValue = analogRead(pin);
  if(abs(nCurrentPotValue - s_nLastPotValue) < pot_threshold)
    return;
  s_nLastPotValue = nCurrentPotValue;
  int nMappedValue = map(nCurrentPotValue, 0, 1023, 0, 127); // Map the value to 0-127
  if(nMappedValue == s_nLastMappedValue)
    return;
  s_nLastMappedValue = nMappedValue;
  if(nMappedValue >= 15){
    wahCharacter(midi_channel, nMappedValue);
  }
}


Still to Come

I have an LCD display on the way. This should be fun.

Possibly messing with shift keys.

<-Part 3   Part 5->
Reactions:
Categories: , , , ,

6 comments:

  1. Keeps getting better and better

    ReplyDelete
  2. very good read! i also playing around with the code but the threshold method will not work. i have a permanent midi stream. im just about to have 2 pedals.

    ReplyDelete
  3. Just a question. Could you not just attach a single 330k resistor to the power line feeding the leds and switches rather than running it through the dil.

    ReplyDelete
    Replies
    1. Wow. This is an 8 year old project and I haven't really thought about it in a while. It's good to see people still reading about it and taking an interest.
      I seem to remember having issues with the switches in the FCB1010 being bouncy. That might have something to do with my final design decision on that one.
      While the advancement of this project is stalled, the thing is still in use to this day!

      I did however have a thought to convert the whole lot of this to I2C to simplify wiring and programming.

      Delete
  4. Cool. Yeah its brilliant I used it for a while on a bread board. Just wondering if there was a way to simplify wiring as it's a stand alone. Do you still have a layout for the daughter board?

    I'm wondering to wire the pull up resistors to the pins as they exit the arduino. Or closer to the switch.

    ReplyDelete
    Replies
    1. I have the week off next week. I'll set some time aside to tear everything apart and get that layout. My drawings have been lost to time. I think it's just making a 16 bit shift register out of 2 8 bit SRs and wiring inputs to them.

      Delete

Subscribe to RSS Feed Follow me on Twitter!