Categories
My Designs Pico Midi

PICO MIDI – External Switches

Let’s continue working on Pico MIDI – a Raspberry Pi Pico based MIDI pedal. In my previous posts I covered how to send MIDI commands, how to support footswitch and LED and how to support external expression pedal.

Today, let’s add support for external switches. I’ll demonstrate that with RC-500 Boss looper, but I also controlled Digitech Whammy so make sure you check that out too.

In this post, I used Digitech FX3S, a 3 footswitch unit. The approach is similar for other external footswitches like Boss FS-5, FS-6 and FS-7. I don’t own one of those so some tweaking might be necessary for them. Boss pedals support different options so it’s a matter of trying them out really.

As usual – you can skip directly to the video and come back later for more details if you wish so.

Here’s the ToC:

External Footswitches

I dismantled my pedal to see what’s in it. Please don’t do it … that will void your warranty … on top of that, shematics for most of the pedals can be found online. Anyway, here’s what we’re dealing with:

Schematic of FS3X pedal that I traced
External Footswitch pedal

There isn’t much to it, two diodes, 3 switches and a stereo audio jack. The switches are normally open, but if you have a different pedal, that may not be given. Some Boss pedals are normally closed, and on some you might have a switch to control this. But whatever it is, our software should be able to handle it.

How Does it Work?

Expanding the schematic a bit to include connection to Pico:

Schematic of a connected external switchpedal
Expanded schematic of the pedal connected to a microcontroller

If we connect sleeve to ground, and then we connect ring and tip to a GPIO of our microcontroller each, we get the above schematic. Since one end of the switch is connected to ground we activate internal pull-up resistors.

When the switch is not pressed, there is no connection to ground and the microcontroller reads high level on GPIO. When the switch is pressed (stomped on), the GPIO input is driven down. Simple ?.

The diodes isolate tip and ring, and only if the 3rd switch (UP) is pressed, both are active and both tip and ring are driven low. If we did not connect it this way, if we connected sleeve to positive supply and we configured our GPIOs with pull-down resistors instead, our 3rd button would not work.

Connecting to Pico

Previous time, we finished with this schematic:

Schematic showing how to wire up external switches
Wiring up for external switches

So sleeve is already grounded, and we have tip and ring connected to two GPIOs. Well, that looks like we’re done! No need to change the schematic, only software ?.

We did switches before, so if I just update the code slightly we should be good to go:

from machine import UART, Pin, ADC
import uasyncio as asyncio
from primitives import Pushbutton, AADC
pc_1 = b'\xc0\x00'
pc_2 = b'\xc0\x01'
pc_22 = b'\xc0\x15'
pc_23 = b'\xc0\x16'
pc_33 = b'\xc0\x20'
pc_34 = b'\xc0\x21'
pc_49 = b'\xc0\x30'
pc_50 = b'\xc0\x31'
class midi_command:
    def __init__(self, cmd_on, cmd_off, print_on, print_off):
        self.is_on = False
        self.on = cmd_on
        self.off = cmd_off
        self.print_on = print_on
        self.print_off = print_off
    
    def toggle(self):
        self.is_on = not self.is_on

def toggle(led, midi, cmd):
    cmd.toggle()
    if led != None:
        led.value(1 if cmd.is_on else 0)
    
    if cmd.is_on:
        midi.write(bytearray(cmd.on))
        print(cmd.print_on)
    else:
        midi.write(bytearray(cmd.off))
        print(cmd.print_off)

async def my_app():
    btn_pin = Pin(14, Pin.IN, Pin.PULL_UP)
    red = Pin(15, Pin.OUT)
    midi = UART(0, baudrate=31250, bits=8, parity=None, stop=1, tx=Pin(16), rx=Pin(17), invert=0)
    ext_btn_pin1 = Pin(26, Pin.IN, Pin.PULL_UP) #tip
    ext_btn_pin2 = Pin(27, Pin.IN, Pin.PULL_UP) #ring
    
    pb = Pushbutton(btn_pin)
    pb.press_func(toggle, (red, midi, midi_command(pc_1, pc_2, 'pc_1', 'pc_2'),))
    
    pb_mode = Pushbutton(ext_btn_pin1)
    pb_mode.press_func(toggle, (None, midi, midi_command(pc_22, pc_23, 'pc_22', 'pc_23'),))
    
    pb_down = Pushbutton(ext_btn_pin2)
    pb_down.press_func(toggle, (None, midi, midi_command(pc_33, pc_34, 'pc_33', 'pc_34'),))
    
    while True:
        await asyncio.sleep(60)
asyncio.run(my_app())  # Run main application code

Most of the code is just copy-pasted from previous posts. There’s more to it because I added more code so the demo is more exciting ?. It’s not a great demo if I’m not playing anything and just pressing switches randomly.

Watch the video for more details on how the code works, but hopefully the code is not too hard to follow. This code does not support the third button just yet, but I’ll work on that in future.

Configuration

OK, buttons are there, how does all of this fit together, because I kind of have everything to complete the pedal? Let me combine today’s code with last video’s code, but this time, I’ll add extra code to read configuration I stored to a file to indicate whether I’m using an external switches or expression pedal.

MicroPython supports reading from and writing to a file so the expanded code looks like this:

from machine import UART, Pin, ADC
import uasyncio as asyncio
from primitives import Pushbutton, AADC
pc_1 = b'\xc0\x00'
pc_2 = b'\xc0\x01'
pc_22 = b'\xc0\x15'
pc_23 = b'\xc0\x16'
pc_33 = b'\xc0\x20'
pc_34 = b'\xc0\x21'
pc_49 = b'\xc0\x30'
pc_50 = b'\xc0\x31'
# CC#11 - toe up/down
cc_toe_up = b'\xb0\x0b\x00'
cc_toe_down = b'\xb0\x0b\x7f'
cc_partial = b'\xb0\x0b'
class midi_command:
    def __init__(self, cmd_on, cmd_off, print_on, print_off):
        self.is_on = False
        self.on = cmd_on
        self.off = cmd_off
        self.print_on = print_on
        self.print_off = print_off
    
    def toggle(self):
        self.is_on = not self.is_on

def toggle(led, midi, cmd):
    cmd.toggle()
    if led != None:
        led.value(1 if cmd.is_on else 0)
    
    if cmd.is_on:
        midi.write(bytearray(cmd.on))
        print(cmd.print_on)
    else:
        midi.write(bytearray(cmd.off))
        print(cmd.print_off)
#linear
def translate_pot_value(val):
    (x2, y2) = (65_535.0, 65_535.0)
    taper = [(0.0,0.0)]
    
    for (x1, y1) in taper:
        if val >= x1: #detect piecewise linear function
            piecewise_portion = (val-x1)/(x2-x1) #portion of that piecewise function
            piecewise_value = (y2-y1)*piecewise_portion + y1
            return piecewise_value
        
        (x2, y2) = (x1, y1)
    
    return 0.0
def express(aadc, midi):
    while True:
        value = await aadc(512)
        cmd = bytearray(cc_partial)
        adc_value = int(translate_pot_value(value)/512)
        cmd.append(adc_value)
        print(adc_value)
        out_len = midi.write(cmd) #setting out_len so count is not printed out

async def my_app():
    btn_pin = Pin(14, Pin.IN, Pin.PULL_UP)
    red = Pin(15, Pin.OUT)
    midi = UART(0, baudrate=31250, bits=8, parity=None, stop=1, tx=Pin(16), rx=Pin(17), invert=0)
    
    pb = Pushbutton(btn_pin)
    pb.press_func(toggle, (red, midi, midi_command(pc_1, pc_2, 'pc_1', 'pc_2'),))
    
    f = open('config.txt')
    line = f.readline()
    print(line)
    f.close()
    
    if line != '':
        if line == 'BTN':
            ext_btn_pin1 = Pin(26, Pin.IN, Pin.PULL_UP) #tip
            ext_btn_pin2 = Pin(27, Pin.IN, Pin.PULL_UP) #ring    
            
            pb_mode = Pushbutton(ext_btn_pin1)
            pb_mode.press_func(toggle, (None, midi, midi_command(pc_22, pc_23, 'pc_22', 'pc_23'),))
            
            pb_down = Pushbutton(ext_btn_pin2)
            pb_down.press_func(toggle, (None, midi, midi_command(pc_33, pc_34, 'pc_33', 'pc_34'),))
        elif line == 'EXP':
            aadc = AADC(ADC(Pin(27)))
            driver = Pin(26, Pin.OUT)
            driver.on()
            asyncio.create_task(express(aadc, midi))
    
    while True:
        await asyncio.sleep(60)
asyncio.run(my_app())  # Run main application code

See the video for longer explanation of code, but in essence, the code uses config.txt to read configuration. In this very simple example this configuration is either BTN or EXP. If BTN is read, our Pico is configured to use the external jack for FS3X pedal. If EXP is read, Pico is configured to use ADC and expect expression pedal to be connected.

Now, this is super simplistic for the demo, I would imagine a full product would have some kind of a configuration tool with snazzy UI for this. Also, the code looks a bit complex, but all I really did was copy pasted from posts we covered before.

Warnings

I would like to point out one thing at this stage. It is a question of connecting external devices directly to your microcontroller like this. It’s a bit dangerous for your microcontroller because you don’t really know what is going to be connected to it. One of the sure ways to burn your Pico is to connect active inputs and drive your inputs with say 5V levels. That will damage your GPIOs.

Passive devices will be just fine, but there’s also a thing when you connect two GPIOs directly – which may not be immediatelly apparent but as you saw, 3rd button is kind of doing this. For this post, we’re using GPIOs as inputs so not such a big deal. But for CMOS devices,
if you configure GPIOs as outputs and drive one HIGH and the other LOW, there is a great chance of damaging your device due to excessive current.

Pico does list out maximum output current, but this is misleading, that is
maximum output current that will still preserve correct output voltage levels. So in this kind of situation, current may well go over that value. Just something to be aware of, at the moment I’ll finish with that.

Action

Here’s a (not so) quick demo of what I covered here:

Action time

This one was relatively small (well I still manage to make the video too long) advancement towards our finished pedal. Next time I’ll cover some more flashy stuff (Neopixels and RGB LEDs). Subscribe so you don’t miss out ?

2 replies on “PICO MIDI – External Switches”

Followed your FS3X schematic. Plugged into my Trio. And it did nothing. Hard reset the Trio, still did not take control of the Trio.

Hey Bill, that’s unfortunate. Did you try checking if you have open connection between sleeve and tip for example, and when you step on the first button you get closed circuit? Simple multimeter with continuity check should help with checking this. You’re using momentary switches, right?
If you can’t figure it out just send me a message through Contact Us (it should really be Contac Me … it’s royal us :D) form and I’ll get back to you and you can send me photos of your build.
Cheers

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.