Adafruit Industries Raspberry Pi Pico and LED Arcade Button MIDI Controller User Manual

Raspberry Pi Pico and LED Arcade Button MIDI Controller
Created by Ruiz Brothers
Last updated on 2021-04-15 10:02:00 AM EDT
2 5
5 5 5 6 6 6 7 8 9
10
10 11
12
12 18
20
20 20 20 21 22 23 24 24 25 25
29
29
31
31 31 32 32 33 33 33 34
35
35 35 35
Guide Contents
Guide Contents Overview
DIY MIDI Controller Buttons and LEDs Edit MIDI on the Fly Intuitive UI/UX Kickstand Handle Prerequisite Guides Parts from Adafruit Hardware List Author Credits
Installing CircuitPython
CircuitPython Quickstart Flash Resetting UF2
Coding the Raspberry Pi Pico MIDI Controller
Installing the CircuitPython Library Bundle Review
CircuitPython Code Walkthrough
Import the Libraries I2C and MIDI Setup Display Setup MIDI Note Labels Secondary GUI Menu 5-Way Navigation Switch State Machines GUI Navigation Setup MIDI Note Array The Loop
Switch Debouncing MIDI Input Main GUI Navigation Track the Button Selecting a Button to Edit Secondary GUI: Edit the Arcade Button's MIDI Note Number MIDI Note Number Range Adjusting the MIDI Note Update the MIDI Note Save the New MIDI Note
Circuit Diagram
Adafruit Library for Fritzing
3D Printing
CAD Files CAD Parts List Window Options Install Window Install Handle to Frame Handle Kickstand Secure Handle to Frame Install Bottom Cover to Frame
PCB Mount Assembly
Hardware for PCB Mount Install M3 hardware Install M2 Hardware
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 2 of 63
36 36
37
37 37 38 38 38 39 39
40
40 40 40
41
41 41 42 42
43
43 43 43 44 44 45 45 46
47
47 47 47 48 48 48
49
49 49 49 50 50
51
51 51 51 52 52
53
53 53 53 54 54
55
Install M2.5 Hardware Assembled PCB Mount
Wiring the 5-Way Navigation Switch
Wires for 5-Way Nav Switch Install 5-Way Switch to PCB 5-Way Navigation Switch Schematic Solder Wires to 5-Way Nav Switch PCB Soldering 5-Way Switch to Pico Solder Wires to 5-Way Switch Soldered 5-Way Switch
Wiring STEMMA for Pico
STEMMA Wire Solder STEMMA to Raspberry Pi Pico Soldered Pico STEMMA cable
Install Buttons
Installing Buttons Panel Mount Buttons Numbering Buttons for Wiring Installed Buttons
Wiring Grounds
Ground Wires Tinning Pins First Ground Wires Sharing Ground Wiring Grounds Button Switches Shared Ground LED and Switch Shared Ground Button LED Ground Wiring
Wiring Button Switches
Wire Planning Wires for Switches Wiring Buttons 1-4 Wiring Buttons 5-8 Wiring Buttons 9-12 Wiring Buttons 13-16
Wiring Button LEDs
Wires for LEDs Wiring LEDs 1-4 Wiring LEDs 5-8 Wiring LEDs 9-12 Wiring LEDs 13-16
Wiring Button Switches to Pico
Wiring Button LEDs and Switches to Pico Solder Button Switches 1-4 Solder Button Switches 5-8 Solder Button Switches to 9-12 Solder Button Switches 13-16
Install OLED
Solder Ground to OLED Connect STEMMA Cables to OLED Hardware for OLED Install OLED to Top Cover Secure OLED
Install 5-Way Nav Switch
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 3 of 63
55 55 55
56
56 56 56 56 56 57
58
58 58 58 59 59 59 60 60
61
61 61 61
62
Install Rubber Nub for 5-Way Nav Switch Screws for 5-Way Nav Switch Secure 5-Way Nav Switch
Install PCB Mount
Installing PCB Mount Secure Pico to PCB Mount Connect USB Extension Cable to Pico Screws for Securing PCB mount to Top Cover Secure PCB Mount to Top Cover Secured PCB Mount
Install and Wire LED Driver
Screws for LED Driver Secure LED Driver to PCB Mount Wire Button LEDs 1-4 to LED Driver Wire Button LEDs 5-8 to LED Driver Wire Button LEDs 9-12 to LED Driver Wire Button LEDs 13-16 to LED Driver Connect STEMMA Cable to LED Driver Wiring Complete
Final Assembly
Secure USB Extension Cable Close Case Final Build
Jam Out
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 4 of 63
Overview
DIY MIDI Controller
Build your own CircuitPython powered MIDI controller! This "MIDI fighter"-like controller features 16 arcade buttons with built-in LEDs, an OLED screen and joystick. Play drums, synthesizers or anything MIDI related! All of the electronics are housed in a snap-fit 3D printed case.
Buttons and LEDs
The Raspberry Pi Pico has plenty of GPIO for connecting 4x4 buttons. The AW9525 GPIO expander / LED driver powers the LEDs and connects to the Raspberry Pi Pico over I2C.
The LEDs light up when the buttons are pressed and stay lit until released. Awesome!
Edit MIDI on the Fly
This MIDI controller's special sauce is the ability to change and save MIDI notes directly on the device. This allows quick MIDI notes remapping. Perfect for crafting your own kits and setups for performances.
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 5 of 63
Intuitive UI/UX
The OLED screen shows the 16 buttons as little circles with numbers. The numbers are the MIDI notes assigned to each button. Use the joystick to select a button and edit the MIDI note. In edit mode, the button will blink the LED, letting you know it's been activated. While in edit mode, the buttons can be pressed to compare MIDI notes.
Kickstand Handle
Lunchbox vibes? Yes! The handle is 3d printed, print-in-place, with no support material. Can you handle it? It also works great as a kickstand to prop up the case.
Prerequisite Guides
Take a moment to walk through the following guides:
Raspberry Pi Pico RP2040 (https://adafru.it/RaD) AW9523 GPIO Learn Guide (https://adafru.it/RaE)
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 6 of 63
1.5" OLED Display Guide (https://adafru.it/RaF)
Parts from Adafruit
List of parts required for this build.
Raspberry Pi Pico (https://adafru.it/QOF) AW9523 GPIO Expander and LED Driver (https://adafru.it/RaG)
1.5" OLED Display (https://adafru.it/RaH) 5-way Navigation Switch (https://adafru.it/RaI) 30mm Arcade Button with LED (https://adafru.it/RaJ)
Raspberry Pi Pico RP2040
The Raspberry Pi foundation changed single-board computing when they released the Raspberry Pi computer, now they're ready to... Out of Stock
Your browser does not support the video tag. Adafruit AW9523 GPIO Expander and LED Driver Breakout
Expand your project possibilities, with the Adafruit AW9523 GPIO Expander and LED Driver Breakout - a cute and powerful I2C expander with a lot of tricks up its... $4.95 In Stock
Out of
Stock
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 7 of 63
Your browser does not support the video tag. Adafruit Grayscale 1.5" 128x128 OLED Graphic Display
This OLED goes out to all the fans who want more pixels! Normally our 128x64 OLEDs are the biggest ones we've stocked that can use I2C. This one is a whopping 128x128... $22.50 In Stock
Your browser does not support the video tag. Arcade Button with LED - 30mm Translucent Clear
A button is a button, and a switch is a switch, but these translucent arcade buttons are in a class of their own. Particularly because they have LEDs built right... $2.50 In Stock
1 x STEMMA QT / Qwiic JST SH 4-pin Cable - 100mm Long STEMMA QT / Qwiic JST SH 4-pin Cable - 100mm Long
1 x Thru-hole 5-way Navigation switch Thru-hole 5-way Navigation switch
1 x Panel Mount Extension USB Cable - Micro B Male to Micro B Female Panel Mount Extension USB Cable - Micro B Male to Micro B Female
1 x Black Nylon Screw and Stand-off Set – M2.5 Thread Black Nylon Screw and Stand-off Set – M2.5 Thread
1 x Silicone Cover Stranded-Core Ribbon Cable - 10 Wire 1 Meter Long - 28AWG Black Silicone Cover Stranded-Core Ribbon Cable - 10 Wire 1 Meter Long - 28AWG Black
Hardware List
Screws, nuts and standoffs used in this build.
Handle
4x M3 x 10mm long screws
USB Extension Cable
2x M3 x 10mm long screws 2x M3 locknuts
OLED
4x M2.5 x 12mm long screws
Add to Cart
Add to Cart
Add to Cart
Add to Cart
Add to Cart
Add to Cart
Add to Cart
Add to Cart
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 8 of 63
4x M2.5 nuts
5-way navigation PCB
2x M3 x 4mm long screws
PCB Mount
4x M3 x 12mm long FF standoffs 4x M2.5 x 8mm long FF standoffs 4x M2 x 6mm long FF standoffs 8x M3 x 6mm long screws 8x M2.5 x 4mm long screws 8x M2 x 4mm long screws
Author Credits
CAD by Noe Ruiz (https://adafru.it/GsA) and Code by Liz Clark (https://adafru.it/JEP).
Inspired by MIDI Fighter by DJTechTools (https://adafru.it/Rc5)
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 9 of 63
Installing CircuitPython
CircuitPython (https://adafru.it/tB7) is a derivative of MicroPython (https://adafru.it/BeZ) designed to
simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the CIRCUITPY drive to iterate.
CircuitPython Quickstart
Follow this step-by-step to quickly get CircuitPython working on your board.
https://adafru.it/QaP
Click the link above and download the latest UF2 file.
Download and save it to your desktop (or wherever is handy).
Start with your Pico unplugged from USB. Hold down the BOOTSEL button, and while continuing to hold it (don't let go!), plug the Pico into USB. Continue to hold the BOOTSEL
button until the RPI-RP2 drive appears!
If the drive does not appear, unplug your Pico and go through the above process again.
A lot of people end up using charge-only USB cables and it is very frustrating! So make sure you have a USB cable you
know is good for data sync.
https://adafru.it/QaP
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 10 of 63
You will see a new disk drive appear called RPI-RP2.
Drag the adafruit_circuitpython_etc.uf2 file to RPI-RP2.
The RPI-RP2 drive will disappear and a new disk drive called CIRCUITPY will appear.
That's it, you're done! :)
Flash Resetting UF2
If your Pico ever gets into a really
weird
state and doesn't even show up as a disk drive when installing CircuitPython, try installing this 'nuke' UF2 which will do a 'deep clean' on your Flash Memory. You will lose all the files on the board, but at least you'll be able to revive it! After nuking, re-install CircuitPython
https://adafru.it/QAJ
https://adafru.it/QAJ
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 11 of 63
Coding the Raspberry Pi Pico MIDI Controller
Installing the CircuitPython Library Bundle
We're constantly updating and improving our libraries, so we don't (at this time) ship our CircuitPython boards with the full library bundle. Instead, you can find example code in the guides for your board that depends on external libraries. Some of these libraries may be available from us at Adafruit, some may be written by community members!
Either way, as you start to explore CircuitPython, you'll want to know how to get libraries on board.
You can grab the latest Adafruit CircuitPython Bundle release by clicking the button below.
https://adafru.it/ENC
Once you've finished setting up your Raspberry Pi Pico with CircuitPython, you can add the libraries to the lib folder of the Pico's CIRCUITPY drive which should appear when the board is plugged into your computer via USB. Copy these folders:
adafruit_bus_device
adafruit_display_shapes
adafruit_display_text
adafruit_midi
adafruit_register
And these files:
adafruit_aw9523.mpy
adafruit_ssd1327.mpy
simpleio.mpy
To the CIRCUITPY flash drive /lib directory (create the directory if it doesn't exist).
Then, you can click on the Download: Project Zip link in the window below to download the code file.
import time import board import displayio import terminalio import adafruit_aw9523 import busio import adafruit_ssd1327 import digitalio from adafruit_display_text import label from adafruit_display_shapes.circle import Circle from adafruit_display_shapes.rect import Rect import usb_midi import adafruit_midi from adafruit_midi.note_on import NoteOn from adafruit_midi.note_off import NoteOff
displayio.release_displays()
# i2c setup, higher frequency for display refresh i2c = busio.I2C(board.GP1, board.GP0, frequency=1000000)
https://adafru.it/ENC
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 12 of 63
# i2c display setup display_bus = displayio.I2CDisplay(i2c, device_address=0x3D) # i2c AW9523 GPIO expander setup aw = adafruit_aw9523.AW9523(i2c) # MIDI setup as MIDI out device midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0)
# display dimensions WIDTH = 128 HEIGHT = 128 # display setup display = adafruit_ssd1327.SSD1327(display_bus, width=WIDTH, height=HEIGHT, brightness = 0.01)
# main display group, shows default GUI menu splash = displayio.Group(max_size=60) # group for circle icons circle_group = displayio.Group(max_size=30) # group for text labels on circles text_group = displayio.Group(max_size=30)
# list of circle positions spots = ( (16, 16), (48, 16), (80, 16), (112, 16), (16, 48), (48, 48), (80, 48), (112, 48), (16, 80), (48, 80), (80, 80), (112, 80), (16, 112), (48, 112), (80, 112), (112, 112), )
# creating the circles & pulling in positions from spots for spot in spots: circle = Circle(x0=spot[0], y0=spot[1], r=14, fill=0x888888) # adding circles to their display group circle_group.append(circle) # square to show position on menu rect = Rect(0, 0, 33, 33, fill=None, outline=0x00FF00, stroke = 3)
splash.append(circle_group) splash.append(rect)
# strings and positions for the MIDI note text labels texts = [ {'num': "60", 'pos': (12, 16)}, {'num': "61", 'pos': (44, 16)}, {'num': "62", 'pos': (76, 16)}, {'num': "63", 'pos': (108, 16)}, {'num': "64", 'pos': (12, 48)}, {'num': "65", 'pos': (44, 48)}, {'num': "66", 'pos': (76, 48)}, {'num': "67", 'pos': (108, 48)}, {'num': "68", 'pos': (12, 80)}, {'num': "69", 'pos': (44, 80)},
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 13 of 63
{'num': "70", 'pos': (76, 80)}, {'num': "71", 'pos': (108, 80)}, {'num': "72", 'pos': (12, 112)}, {'num': "73", 'pos': (44, 112)}, {'num': "74", 'pos': (76, 112)}, {'num': "75", 'pos': (108, 112)}, ] text_labels = []
for text in texts: text_area = label.Label(terminalio.FONT, text=text['num'], color=0xFFFFFF) text_area.x = text['pos'][0] text_area.y = text['pos'][1] text_labels.append(text_area) text_group.append(text_area) splash.append(text_group)
# secondary display group, shows large circle when button is selected big_splash = displayio.Group(max_size=60) # large circle to fill display big_circle = Circle(x0=64, y0=64, r=62, fill=0x888888) big_splash.append(big_circle) # large text to fill circle big_text = label.Label(terminalio.FONT, text=' ', color=0xFFFFFF) big_text.x = 43 big_text.y = 62 big_text.scale = 4 big_splash.append(big_text)
# array for LEDs on AW9523 leds = [] led_pins = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] # setup to create the AW9523 outputs for LEDs for led in led_pins: led_pin = aw.get_pin(led) led_pin.direction = digitalio.Direction.OUTPUT leds.append(led_pin)
# button pins, all pins in order skipping GP15 note_pins = [board.GP7, board.GP8, board.GP9, board.GP10, board.GP11, board.GP12, board.GP13, board.GP14, board.GP16, board.GP17, board.GP18, board.GP19, board.GP20, board.GP21, board.GP22, board.GP26]
note_buttons = []
for pin in note_pins: note_pin = digitalio.DigitalInOut(pin) note_pin.direction = digitalio.Direction.INPUT note_pin.pull = digitalio.Pull.UP note_buttons.append(note_pin)
# note states note0_pressed = False note1_pressed = False note2_pressed = False note3_pressed = False note4_pressed = False note5_pressed = False note6_pressed = False note7_pressed = False note8_pressed = False
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 14 of 63
note9_pressed = False note10_pressed = False note11_pressed = False note12_pressed = False note13_pressed = False note14_pressed = False note15_pressed = False # array of note states note_states = [note0_pressed, note1_pressed, note2_pressed, note3_pressed, note4_pressed, note5_pressed, note6_pressed, note7_pressed, note8_pressed, note9_pressed, note10_pressed, note11_pressed, note12_pressed, note13_pressed, note14_pressed, note15_pressed] # pins for 5-way switch select = digitalio.DigitalInOut(board.GP6) up = digitalio.DigitalInOut(board.GP5) down = digitalio.DigitalInOut(board.GP4) left = digitalio.DigitalInOut(board.GP3) right = digitalio.DigitalInOut(board.GP2) # array for 5-way switch joystick = [select, up, down, left, right]
for joy in joystick: joy.direction = digitalio.Direction.INPUT joy.pull = digitalio.Pull.UP # states for 5-way switch select_state = None up_state = None down_state = None left_state = None right_state = None midi_state = None
# coordinates for navigating main GUI select_x = [0, 32, 64, 96] select_y = [0, 32, 64, 96]
# y coordinate for 5-way switch navigation y_pos = 0 # x coordinate for 5-way switch navigation x_pos = 0 sub_state = False # default midi number midi_num = 60 # default MIDI button button_num = 0 # default MIDI button position button_pos = 0 # check for blinking LED led_check = None # time.monotonic() device clock = time.monotonic()
# coordinates for tracking location of 5-way switch up_scroll = 0 down_scroll = 0 left_scroll = 0 right_scroll = 0 switch_coordinates = [(0, 0), (1, 0), (2, 0), (3, 0), (0, 1), (1, 1), (2, 1), (3, 1), (0, 2), (1, 2), (2, 2), (3, 2), (0, 3), (1, 3), (2, 3), (3, 3)]
# array of default MIDI notes midi_notes = [60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75]
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 15 of 63
# show main display GUI display.show(splash)
while True:
# debouncing for 5-way switch positions if up.value and up_state == "pressed": print("Button pressed.") up_state = None if down.value and down_state == "pressed": print("Button pressed.") down_state = None if left.value and left_state == "pressed": print("Button pressed.") left_state = None if right.value and right_state == "pressed": print("Button pressed.") right_state = None if select.value and select_state == "pressed": print("Button pressed.") select_state = None
# MIDI input for i in range(16): buttons = note_buttons[i] # if button is pressed... if not buttons.value and note_states[i] is False: # send the MIDI note and light up the LED midi.send(NoteOn(midi_notes[i], 120)) note_states[i] = True leds[i].value = True # if the button is released... if buttons.value and note_states[i] is True: # stop sending the MIDI note and turn off the LED midi.send(NoteOff(midi_notes[i], 120)) note_states[i] = False leds[i].value = False
# if we're on the main GUI page if not sub_state: # if you press up on the 5-way switch... if not up.value and up_state is None: up_state = "pressed" # track the switch's position up_scroll -= 1 if up_scroll < 0: up_scroll = 3 y_pos = up_scroll down_scroll = up_scroll # if you press down on the 5-way switch... if not down.value and down_state is None: down_state = "pressed" # track the switch's position down_scroll += 1 if down_scroll > 3: down_scroll = 0 y_pos = down_scroll up_scroll = down_scroll # if you press left on the 5-way switch... if not left.value and left_state is None: # print("scroll", down_scroll) left_state = "pressed" # track the switch's position
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 16 of 63
left_scroll -= 1 if left_scroll < 0: left_scroll = 3 x_pos = left_scroll right_scroll = left_scroll # if you press right on the 5-way switch... if not right.value and right_state is None: # print("scroll", down_scroll) right_state = "pressed" # track the switch's position right_scroll += 1 if right_scroll > 3: right_scroll = 0 x_pos = right_scroll left_scroll = right_scroll
# update square's position on the GUI rect.y = select_y[y_pos] rect.x = select_x[x_pos]
# update the currently highlighted button on the GUI for coords in switch_coordinates: if x_pos == coords[0] and y_pos == coords[1]: button_pos = switch_coordinates.index(coords) # print(button_pos) button_num = text_labels[button_pos].text
# if you press select on the 5-way switch... if not select.value and select_state is None: select_state = "pressed" # grab the selected button's MIDI note midi_num = int(button_num) # change into the secondary GUI menu sub_state = True
# if an arcade button is selected to change the MIDI note... if sub_state: # display the secondary GUI menu display.show(big_splash) # display the selected button's MIDI note big_text.text = str(midi_num)
# blink the selected button's LED without pausing the loop if (time.monotonic() > (clock + 1)) and led_check is None: leds[button_pos].value = True led_check = True clock = time.monotonic() if (time.monotonic() > (clock + 1)) and led_check is True: leds[button_pos].value = False led_check = None clock = time.monotonic()
# blocks the MIDI number from being set above 128 if midi_num >= 128: midi_num = 128 # blocks the MIDI number from being set below 0 if midi_num <= 0: midi_num = 0
# if you press right on the 5-way switch... if not right.value and right_state is None: # increase the MIDI number midi_num += 1
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 17 of 63
right_state = "pressed" # if you press up on the 5-way switch... if not up.value and up_state is None: # increase the MIDI number midi_num += 1 up_state = "pressed" # if you press left on the 5-way switch... if not left.value and left_state is None: # decrease the MIDI number midi_num -= 1 left_state = "pressed" # if you press down on the 5-way switch... if not down.value and down_state is None: # decrease the MIDI number midi_num -= 1 down_state = "pressed"
# update arcade button's MIDI note # allows you to check note while you're adjusting it midi_notes[button_pos] = midi_num
# if you press select on the 5-way switch... if not select.value and select_state is None: select_state = "pressed" # change back to main menu mode sub_state = False # update new MIDI number text label text_labels[button_pos].text = str(midi_num) # show main GUI display display.show(splash) # turn off blinking LED leds[button_pos].value = False
Review
Make sure you've followed these steps:
Loaded all the required library files and directories into the CIRCUITPY /lib directory Copied code.py to the main (root) directory of the CIRCUITPY drive
Your Raspberry Pi Pico CIRCUITPY drive should look like this after you load the libraries and code.py file:
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 18 of 63
© Adafruit Industries https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter Page 19 of 63
Loading...
+ 44 hidden pages