Monday, September 4, 2017

Relay Bypass: final code

After the crowdfunding campaign, I decided to update the relay bypass code.

Indeed, this first version was nice, but one main drawback that was feedbacked to me is that the switch was activated on release, which was not always very intuitive or easy to handle. Moreover, I wanted to add a "temporary" bypass option in the Montagne Tremolo.

Montange Tremolo Relay Bypass

In this post, I am going to explain a bit the new code and to show you how I did it.

If you have not read my post about Relay Bypass, I highly recommend you to read it before reading this post. All the basics of microcontrollers are presented there.

  Tip! The full code is available on Github. With the relayonpress.c and header.h files, you will have everything needed to code or burn chips.

If you already have a GitHub account, you can Star the project for updates, or Fork it to modify it and make your own Relay Bypass code.

Lets go!




Schematic

The relay bypass code works only when the switch is released. I also wanted to add an option to make it temporarily activable trough a switch. Finally, I wanted to add the "anti pop" system that I used before to have a totally silent bypass.

In order to do that, I added a switch, and of course the photoFET needed for the anti noise system. Here is the schematic:
Relay bypass schematic
The microcontroller is the "conductor" of the circuit.

We still use our old 12F675, the NA5WK relay and the TLG222A photoFET. The second switch (SW2) is used to choose between the normal and "temporary" mode. When the switch number 1 is activated, the microcontroller activates the LED, the photoFET to remove the "pop" noise and the relay to activate the effect.


How to code it?

Lets go to the nice part: coding!

As usual, I recommend you to use the MPLabX software (with the XC8 compiler) to write and modify the code in C, then use the PicKit2 to burn the code (in .hex format) in the PIC12F675.

For more infos, please read my original post about the Relay Bypass if you forgot all of this.


Header : configuration bits

Classic config for the PIC here.
We use the internal clock of the PIC, no protection for the code and memory and we use all the pins as GPIOs. It is the folliwing code:

// CONFIG
#pragma config FOSC = INTRCIO // Oscillator Selection bits (Internal clock)
#pragma config WDTE = OFF // Watchdog Timer Enable bit
#pragma config PWRTE = OFF // Power-Up Timer Enable bit
#pragma config MCLRE = OFF // GP3/MCLR pin function select
#pragma config BOREN = OFF // Brown-out Detect Enable bit
#pragma config CP = OFF // Code Protection bit
#pragma config CPD = OFF // Data Code Protection bit

// Define Internal clock frequency
#define _XTAL_FREQ 4000000

(it is the "header.h" file in the Github repository)


Main code

We use the MPLabX software to code in .C, which is way easier to understand and write than assembly code!

The code is separated in several parts. Let's see each one of them in detail. Do not forget that you can download the full code on GitHub.

Librairies
We have several libraries to include in the code in order to make it work, and of course the header file:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <xc.h>
#include "header.h"


Initialization
Ok, so now we are in the real part of the code :) (main() function). Lets start by initializing all the GPIOs.
We do not need any analog GPIO, so lets also turn off all the converters. We need to define which GPIOs are going to be inputs (allow to sense a 5V or 0V voltage), or outputs (sends a 5 or 0V voltage)

// Initialization
void main(void) {
  ANSEL = 0; // no analog GPIOs
  CMCON = 0x07; // comparator off
  ADCON0 = 0; // Analog to Digital and Digital to Analog convertors off
  TRISIO0 = 0; // output LED
  TRISIO1 = 1; // input footswtich
  TRISIO2 = 0; // output TGP222A
  TRISIO5 = 0; // output activation relay
  TRISIO4 = 0; // output ground relay
  TRISIO3 = 1; // input temporary switch

  GPIO = 0; // set outputs as low level (0V)

It looks a lot like the old code we already wrote before. We added one input to have the second switch that allows us to choose between temporary and normal mode. Finally, we reset all the GPIOs to 0 when the pedal is powered.


Variable definition
We need to define several integer variables. A first "state" variable defines the state of the pedal (1="on", 0="off"), the "changestate" variable is used to change the state of the pedal (useful to avoid the noise when the pedal changes of state)

There are 2 new variables compared to the previous code: "temporary" which defines the activation mode of the pedal (normal or temporary), and "press_switch" that is used as a counter to know when the switch is pressed and allow the activation when we press the switch (and not on release)

  // Variables definition
  uint8_t state; // on-off state of the pedal (1 = on, 0 = off)
  state = 0;

  uint8_t changestate; // to change status of the pedal
  changestate = 0;

  uint8_t temporary; // define the mode of the pedal : classic or temporary activation
  temporary = 0;

  uint8_t press_switch; // variable to detect if the switch is pressed
  press_switch = 0;

All these variables are initially set to 0, which defines the following state of the pedal when powered: "off" state (state = 0), no state change (changestate =0), standard activation mode (temporary = 0) and the switch is considered not pressed of course (press_switch = 0). This variables will be detailed below


Temporary / Normal mode
The temporary variable is used to define whether we are in temporary or normal mode. Depending on the state of an external switch, the microcontroller can sense the state of the swtich (it is linked to ground - 0V - or to 5V). It can then change the value of the temporary variable.

  // Main loop
  while(1) {
    if(GP3 == 0) { // By default: normal mode
      temporary = 0;
    }
    else { // If the "hold" mode is activated through the switch
       temporary = 1;
    }


Normal mode : switch detection
This part detects when the switch is activated. Here is the code:

    // Normal mode
    if(temporary == 0) {
       if(GP1 == 0) { // footswitch pressed
         __delay_ms(15); // debouncing
         if(GP1 == 0) {
         press_switch = press_switch + 1; // switch is on
       if(press_switch>10) {
         press_switch = 10; // max value for press_switch
       }
      }
    }
        if(press_switch == 1) { // switch is pressed : lets turn the pedal on or off
          changestate = 1;
          press_switch = 2; // avoid bug if press_switch stays at 1
        }
        if(GP1 == 1) {
          __delay_ms(15); // debouncing
          if(GP1 == 1) {
            press_switch = 0;
          }
        }
      }

When you press the switch, there is first a debouncing to check that it is indeed a clic on the switch, using a simple __delay_ms(15). Finally, if the user have indeed pressed the switch, we increment the press_switch variable.

The next bits of the code define a maximum of 10 for press_switch. Indeed, if you do not add this part, the value of press_switch can increase way too much and cannot even be stored in the PIC memory!

When press_switch is equal to 1, changestate is changed to 1. The microcontroller knows that he has to change the state of the pedal now! Incrementing press_switch to 10 prevents the pedal to change state all the time if you press the switch for a long time... Similarly, press_switch is changed to 2 immediatly after setting changestate to 1 to avoid this.

Finally, when the switch is released (GP1 == 1), press_switch is reset to 0.


Temporary activation mode
This part works really similarily to the part shown above, except that the state of the pedal is reset to 0 (off) when you release the switch: temporary activation mode!

      // Temporary mode
      if(temporary == 1) {
        if(GP1 == 0) { // if switch is pressed : temporary activation
          __delay_ms(15); // debouncing
          if(GP1 == 0) {
            press_switch = press_switch + 1; // switch is on
            if(press_switch>10) {
              press_switch = 10; // max value for press_switch
            }
          }
        }
        if(GP1 == 1) { // if switch is not pressed, turn it off
          __delay_ms(15); // debouncing
          if(GP1 == 1) {
            state = 0;
            press_switch = 0;
          }
        }
        if(press_switch == 1) {
          changestate = 1; // if switch is pressed, turn the pedal on
          press_switch = 2; // avoids bug
        }
      }



Change the state of the pedal
This step changes the state of the pedal (on to off or on to off). It is during this step that the photoFE is activated.
The code is totally similar to what I have presented in my post about noiseless relay bypass.

      // Changing state of the pedal
      if(changestate == 1) {
        if(state == 0) { // change to on
          GP2 = 1; // photoFET on
          __delay_ms(20);
          GP0 = 1; // LED on
          GP5 = 1; // relay on
          GP4 = 0;
          __delay_ms(20);
          GP2 = 0; // photoFET off
          state = 1;
        }
        else { // change to off
          GP2 = 1;
          __delay_ms(20);
          GP0 = 0; // LED off
          GP5 = 0; // relay off
          GP4 = 0;
          __delay_ms(20);
          GP2 = 0;
          state = 0;
        }
      __delay_ms(10);
      changestate=0; // reset changestate
    }

It causes a very slight delay for the activation of the pedal (40ms). However, practically speaking, you really cannot tell!


On or off state of the pedal
Once the pedal has changed of state (on or off), we maintain the pedal in this state with this few lines of code:

    // To let the pedal in the good state (on or off)
    if (state == 1) { // effect on
      GP0 = 1; // LED on
      GP5 = 1; // relay on
      GP4 = 0;
    }
     else { // effect off
      GP0 = 0; // LED off
      GP5 = 0; // relay off
      GP4 = 0;
    }
  }
}



Full code

Here is the full code of the project (you can read it directly on GitHub):

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <xc.h>
#include "header.h"

// Initialization
void main(void) {
  ANSEL = 0; // no analog GPIOs
  CMCON = 0x07; // comparator off
  ADCON0 = 0; // Analog to Digital and Digital to Analog convertors off
  TRISIO0 = 0; // output LED
  TRISIO1 = 1; // input footswtich
  TRISIO2 = 0; // output TGP222A
  TRISIO5 = 0; // output activation relay
  TRISIO4 = 0; // output ground relay
  TRISIO3 = 1; // input temporary switch

  GPIO = 0; // set outputs as low level (0V)

  // Variables definition
  uint8_t state; // on-off state of the pedal (1 = on, 0 = off)
  state = 0;

  uint8_t changestate; // to change status of the pedal
  changestate = 0;

  uint8_t temporary; // define the mode of the pedal : classic of temporary activation
  temporary = 0;

  uint8_t press_switch; // variable to detect if the switch is pressed
  press_switch = 0;

  // Main loop
  while(1) {
    if(GP3 == 0) { // By default: normal mode
      temporary = 0;
    }
    else { // If the "hold" mode is activated through the switch
       temporary = 1;
    }

    // Normal mode
    if(temporary == 0) {
       if(GP1 == 0) { // footswitch pressed
         __delay_ms(15); // debouncing
         if(GP1 == 0) {
         press_switch = press_switch + 1; // switch is on
       if(press_switch>10) {
         press_switch = 10; // max value for press_switch
       }
      }
    }
        if(press_switch == 1) { // switch is pressed : lets turn the pedal on or off
          changestate = 1;
          press_switch = 2; // avoid bugs if press_switch stays at 1
        }
        if(GP1 == 1) {
          __delay_ms(15); // debouncing
          if(GP1 == 1) {
            press_switch = 0;
          }
        }
      }

      // Temporary mode
      if(temporary == 1) {
        if(GP1 == 0) { // if switch is pressed : temporary activation
          __delay_ms(15); // debouncing
          if(GP1 == 0) {
            press_switch = press_switch + 1; // switch is on
            if(press_switch>10) {
              press_switch = 10; // max value for press_switch
            }
          }
        }
        if(GP1 == 1) { // if switch is not pressed, turn it off
          __delay_ms(15); // debouncing
          if(GP1 == 1) {
            state = 0;
            press_switch = 0;
          }
        }
        if(press_switch == 1) {
          changestate = 1; // if switch is pressed, turn the pedal on
          press_switch = 2; // avoids bug
        }
      }

      // Changing state of the pedal
      if(changestate == 1) {
        if(state == 0) { // change to on
          GP2 = 1; // photoFET on
          __delay_ms(20);
          GP0 = 1; // LED on
          GP5 = 1; // relay on
          GP4 = 0;
          __delay_ms(20);
          GP2 = 0; // photoFET off
          state = 1;
        }
        else { // change to off
          GP2 = 1;
          __delay_ms(20);
          GP0 = 0; // LED off
          GP5 = 0; // relay off
          GP4 = 0;
          __delay_ms(20);
          GP2 = 0;
          state = 0;
        }
      __delay_ms(10);
      changestate=0; // reset changestate
    }

    // To let the pedal in the good state (on or off)
    if (state == 1) { // effect on
      GP0 = 1; // LED on
      GP5 = 1; // relay on
      GP4 = 0;
    }
     else { // effect off
      GP0 = 0; // LED off
      GP5 = 0; // relay off
      GP4 = 0;
    }
  }
}

  Tip! The full code is available on Github. With the relayonpress.c and header.h files, you will have everything needed to code or burn chips.

If you already have a GitHub account, you can Star the project for updates, or Fork it to modify it and make your own Relay Bypass code.


There it is! If you liked this post, like the Coda Effects Facebook page or the Coda Effects Instagram for more follow up about the blog.
If you have any question or remark, post a comment!

45 comments

  1. Benoit, you are awesome!

    Your relay bypass works like a charm w no noise at all.

    I've made a diy-ish layout for it and posted on FSB if you don't mind
    Link: http://freestompboxes.org/viewtopic.php?p=262810#p262810

    My regards

    ReplyDelete
    Replies
    1. This is great! Thank you, very nice initiative!
      I'll try to help people on this forum topic, I have not visited freestompboxes for a while these days...

      Delete
    2. I'm sorry, I did not notice that attachments on both fsb and madbean forum are only visible for registered users.

      I've made a short post on imgur, hope this would help the diy community: http://imgur.com/a/OFhf4

      Thanks for sharing your hard work with us, you deserve more credit.

      My regards,

      Delete
    3. Very nice! I really like the fact that you made it etchable. Could be nice to do a vero version as well.
      Can I place it in the blog post?
      I will of course credit you for the design.

      Delete
    4. Of course you can, it would be super cool.
      But I still think that my layout needs some tweaks and optimization. Can you give me some time to make sure it is compact and usable enough?

      Delete
    5. Of course! Let me know when you are satisfied with your design :)
      I'll work on a double sided version

      Delete
    6. This comment has been removed by the author.

      Delete
    7. Sadly, can't edit my comments.
      Here: https://drive.google.com/open?id=1qu_PngfD6v71O1tmEpZdfPxyM3qrDwwZ

      Delete
  2. Merci pour l'article.
    Thanks for the article.
    Did something similar but using assembly instead of C.
    Got everything to fit on a 10F200.
    Used internal pull-up resistors and also used the SLEEP capability to save power.

    One suggestion, instead of using two pins to activate your relay, put one side of the relay directly to the GND and use a transistor driver on GP5 to activate your relay. That will free GP4. Then you can use GP4 and GPO to turn on a 2 colors 2 pin LED. If GP4 is high and GP0 in low then the LED is one color, if GP4 is low and GP0 high then the LED is another color. That way you could flip the color af the LED to show is you are in Latching mode or in Momentary mode.

    Don't know if this is clear? I'm french so if you want to talk about this in french. I'm alparent on the Madbean and DIYStompbox forum.

    ReplyDelete
    Replies
    1. Very clear!
      And very good idea by the way, I should definitely try it

      Delete
  3. Hi Benoit,
    Is there somewhere you would recommend to find the relay and pic in Europe?
    I'm looking for a single shop where I can find both, but that's not that easy it seems.

    ReplyDelete
    Replies
    1. Hi Matthew,

      You could checkout UK-Electronic:

      http://www.uk-electronic.de

      PIC:
      http://uk-electronic.de/onlineshop/product_info.php?products_id=3028&osCsid=ad83064c6d9ff30eafde0473504f0786

      Relay:
      http://uk-electronic.de/onlineshop/product_info.php?products_id=3486&osCsid=ad83064c6d9ff30eafde0473504f0786

      Hope this helps!

      Regards,

      Arjan Kingma
      FWS Pedals Germany

      Delete
    2. Hello !

      It is also possible to find the relay on banzai music : https://www.banzaimusic.com/Takamisawa-NA05W-K.html

      The photoFET is harder to come by, I usually order it on mouser.com when I order other stuff (free delivery from 50€)

      Delete
  4. any chance that a different model of the photocell works? the ones ive found of those you stated are expensive where ive found them.

    ReplyDelete
    Replies
    1. Hi! You can buy them cheaply on aliexpress

      I've bought myself a couple of dozens here, they are all completely functional: https://aliexpress.com/item/Free-shipping-10pcs-lot-TLP222A-P222A-DIP-4-new-original/32675517837.html?spm=2114.13010608.0.0.A6e2jI

      Delete
    2. thanks a lot! have you tried the above code with 100% sucess btw?

      Delete
  5. Hi Benoit,

    I've just found another optocoupler, that might be used in this circuit for muting
    It's called CPC1017N
    It has 16ohm on resistance and 1pf capacitance which is very very low.

    ReplyDelete
    Replies
    1. Great indeed! I will definitely check that out!

      Delete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Just finished a vero layout for this and it's VERIFIED.
    https://goo.gl/DP2Cbi

    ReplyDelete
  8. This works great! Trying to work out a way to remember the state of the pedal before the power is removed so it powers up in the same state.

    ReplyDelete
    Replies
    1. I guess you could use the EEPROM to stock the value of the state in the internal memory of the PIC...

      Delete
    2. That's exactly what I've done, also a hold to enter temporary mode.

      Instill get a noise from releasing the switch though. No amount of decoupling or ferrite beads can stop it.

      Delete
  9. This comment has been removed by the author.

    ReplyDelete
  10. Hi Benoit,
    and thank you for sharing this project!

    Is it possible that some popping that I experience is because I am using TLP222G instead of TLP222A...?

    ReplyDelete
  11. Of course: To remove the temporary mode feature, just set the temporary variable to 0 and remove the condition loop at the begining (if(GP3==...etc).

    To omit the anti pop feature, remove all the GP2 references in the part that changes the state of the pedal (GP2=1 and GP2=0)

    ReplyDelete
  12. Hey Benoit, Great articles for us analog folks wanting to dip our toes into digital. I was wanting to implement your code into a pedal that uses both "latching" and momentary bypass switches. The idea is that I would like to use the momentary switch to temporarily (as long as the momentary switch is depressed" "punch in" when the latching switch isn't engaged or "punch out" when the latching switch IS engaged. I'm using the term latching to mean a standard relay bypass style.

    ReplyDelete
  13. Hello, Benoit, thanks a lot for your great articles.
    Already built your relay bypass and it works great (though I haven't put it in a pedal yet).
    But I have one concern: isn't the ldr resistor (the one which is 1k on the schematic) should be between the 7-th leg of microcontroller and led?

    ReplyDelete
  14. This comment has been removed by the author.

    ReplyDelete
  15. Hey Benoit,
    First off, thanks so much for this! I've got things initially working but am noticing that on initially engaging the pedal, it stays on for about 5-6 seconds and then shuts off, after which point it only works in a momentary fashion. If I touch the contacts on the back of the bypass board, this process resets. This seems like some sort of grounding issue, but do you have any other circuit specific suggestions? I've scoured the board I made for bridged spots and haven't found anything problematic yet.
    Thanks again,
    Brent

    ReplyDelete
    Replies
    1. That's weird! Did you power it up with enough current?

      Delete
  16. Hey Benoit,
    Thanks for getting back to me - I removed all the temporary conditionals and that seemed to fix the problem. I'm trying this with a pedal that has been giving me a lot of trouble with switch noise (Hudson Broadcast 24v clone) - still getting some audible pop with this, but it seems to be better. I'm going to try extending the delays inside the changeState to see if the noise is from the relay or just because it's a high gain pedal. Thanks again for such an awesome bypass solution!

    ReplyDelete
    Replies
    1. I actually manage to reproduce the problem! I am currently investingating to understand what is going on...

      Delete
    2. Hi Benoit!
      Thank you for this great piece of work. I love it!
      Did you ever get around on the cut-off problem mentioned by Brent?
      I got the same problem and can't find a solution.
      All the best, Tobias

      Delete
  17. This comment has been removed by the author.

    ReplyDelete
  18. Hey Benoit, I made a single-side pcb layout for your wonderful switching system, wouldn't you mind if I share a link on it here? Thanks again for your huge efforts!

    ReplyDelete
    Replies
    1. https://drive.google.com/open?id=1_XykA0-zp4ES01YXUa7Avt378kLzFjg0

      Delete
  19. For what it's worth, I even designed an SMD version of the schematic above, and had some prototypes made. I also used a better optocoupler, but I am still getting a pop whenever I engage/disengage.

    PCB was designed properly as far as I know. Plenty of decoupling caps near the PIC IC, with 100nf decoupling RIGHT at the VCC and GND pins of the IC. There was also a ground layer separating the IC and the relay.

    If I'm remembering correctly, I purchased one of your Coda Effects Relay Bypass PCBs, and I don't remember hearing pops (I used this to test relays and ICs. I should still have this around somewhere...).

    Would you mind sharing how you designed your PCB? Maybe there's something you did that helped with the digital ground currents, etc?

    ReplyDelete
  20. Any updates about version 2.1.? :)

    ReplyDelete
  21. Is it possible to get the code in hex?

    ReplyDelete
  22. Hey Benoit, Thanks for the PIC code and all your detailing and explaining. I am hoping to learn some C code to get something done similar to yours MCU bypass switching. Just was wondering do you know, would the PIC12F683 be interchangeable with the PIC12F509 ? Thanks
    Best Regards, TTay

    ReplyDelete