Take your Feather nRF52840 and plug it into your computer via a known good data + power USB cable. Have your Circuit Playground Bluefruit handy as you'll be performing most of the same steps for each. Your operating system will show a drive named CIRCUITPY when a board is plugged in. If you get a drive named CPLAYBTBOOT or FTHR840BOOT, you'll likely need to install CircuitPython. This is easy, see the steps below to do this, get library files, and copy the code to each board.
First, to make sure you're running the most recent version of CircuitPython for the Feather nRF52840. You'll need at least version 5 for this project to work.
You'll need a few CircuitPython libraries in the lib folder on the Feather CIRCUITPY drive for the code to work. Head to https://circuitpython.org/libraries to download the latest library bundle matching the major version of CircuitPython now on your board (5 for CircuitPython 5.x, etc.).
Once you've downloaded the libraries bundle, add these libraries to the lib folder on the Feather:
- adafruit_ble
- adafruit_bluefruit_connect
- adafruit_bus_device
- adafruit_led_animation
Your Feather CIRCUITPY drive should look like this after you load the code below.:
Just like with the Feather, make sure you're running the most recent version of CircuitPython for the Circuit Playground Bluefruit. You'll need at least version 5 for this project to work.
Again, you'll need a few CircuitPython libraries in the lib folder on the Circuit Playground Bluefruit for the code to work. Head to https://circuitpython.org/libraries to download the latest library bundle matching the major version of CircuitPython now on your board (5 for CircuitPython 5.x, etc.).
Once you've downloaded the libraries bundle, add these libraries to the lib folder on the CPB:
- adafruit_ble
- adafruit_bluefruit_connect
- adafruit_bus_device
- adafruit_circuitplayground
- adafruit_led_animation
- adafruit_thermistor.mpy
- adafruit_lis3dh.mpy
- neopixel.mpy
Your Circuit Playground Bluefruit CIRCUITPY drive should look like this after loading the code file below:
Once your Circuit Playground Bluefruit and Feather nRF52840 are all setup with CircuitPython and the necessary libraries, you can click on the Download: Project Zip link above the code to get the code files for both boards.
The files will be named cpb_amp_code.py and feather_keyboard_code.py to avoid confusion. You'll need to rename the correct file to code.py when you load them onto the respective board CIRCUITPY flash drive.
Circuit Playground Bluefruit BLE Synth Code
'''BLE Synth File for the Circuit Playground Bluefruit Amp Portion''' from adafruit_circuitplayground.bluefruit import cpb from adafruit_led_animation.animation import Comet, AnimationGroup,\ AnimationSequence import adafruit_led_animation.color as color from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ProvideServicesAdvertisement from adafruit_ble.services.nordic import UARTService from adafruit_bluefruit_connect.packet import Packet from adafruit_bluefruit_connect.color_packet import ColorPacket from adafruit_bluefruit_connect.button_packet import ButtonPacket # easily call for NeoPixels to be off off = (0, 0, 0) # state to debounce on CPB end tone = False # Setup for comet animation COMET_SPEED = 0.04 # Lower numbers increase the animation speed CPB_COMET_TAIL_LENGTH = 5 # The length of the comet on the Circuit Playground Bluefruit CPB_COMET_BOUNCE = False # Set to True to make the comet "bounce" the opposite direction on CPB animations = AnimationSequence( AnimationGroup( Comet(cpb.pixels, COMET_SPEED, off, tail_length=CPB_COMET_TAIL_LENGTH, bounce=CPB_COMET_BOUNCE))) # note frequencies C4 = 261.63 Csharp4 = 277.18 D4 = 293.66 Dsharp4 = 311.13 E4 = 329.63 F4 = 349.23 Fsharp4 = 369.99 G4 = 392 Gsharp4 = 415.3 A4 = 440 Asharp4 = 466.16 B4 = 493.88 # note array note = [C4, Csharp4, D4, Dsharp4, E4, F4, Fsharp4, G4, Gsharp4, A4, Asharp4, B4] # colors to recieve from color packet & for neopixels color_C = color.RED color_Csharp = color.ORANGE color_D = color.YELLOW color_Dsharp = color.GREEN color_E = color.TEAL color_F = color.CYAN color_Fsharp = color.BLUE color_G = color.PURPLE color_Gsharp = color.MAGENTA color_A = color.GOLD color_Asharp = color.PINK color_B = color.WHITE # color array color = [color_C, color_Csharp, color_D, color_Dsharp, color_E, color_F, color_Fsharp, color_G, color_Gsharp, color_A, color_Asharp, color_B] # Setup BLE connection ble = BLERadio() uart = UARTService() advertisement = ProvideServicesAdvertisement(uart) while True: # connect via BLE ble.start_advertising(advertisement) # Start advertising. was_connected = False while not was_connected or ble.connected: if ble.connected: # If BLE is connected... was_connected = True # start animations animations.animate() # look for packets if uart.in_waiting: try: packet = Packet.from_stream(uart) # Create the packet object. except ValueError: continue # if it's a color packet: if isinstance(packet, ColorPacket): for i in range(12): colors = color[i] notes = note[i] # if the packet matches one of our colors: if packet.color == colors and not tone: # animate with that color animations.color = colors # play matching note cpb.start_tone(notes) tone = True # if it's a button packet aka feather's button has been released: elif isinstance(packet, ButtonPacket) and packet.pressed: if packet.button == ButtonPacket.RIGHT and tone: tone = False # stop playing the note cpb.stop_tone() # turn off the neopixels but keep animation active animations.color = off
Feather nRF52840 BLE Synth Code
'''BLE Synth File for the Feather nFR52840 Keyboard Portion''' import time import board import digitalio import adafruit_led_animation.color as color from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ProvideServicesAdvertisement from adafruit_ble.services.nordic import UARTService from adafruit_bluefruit_connect.color_packet import ColorPacket from adafruit_bluefruit_connect.button_packet import ButtonPacket # setup for LED to indicate BLE connection blue_led = digitalio.DigitalInOut(board.BLUE_LED) blue_led.direction = digitalio.Direction.OUTPUT # setting up the buttons switch_pins = [board.D5, board.D6, board.D9, board.D10, board.D11, board.D12, board.D13, board.A0, board.A1, board.A2, board.A3, board.A4] switch_array = [] # creating the button array for pin in switch_pins: switch_pin = digitalio.DigitalInOut(pin) switch_pin.direction = digitalio.Direction.INPUT switch_pin.pull = digitalio.Pull.UP switch_array.append(switch_pin) # states for button debouncing switch1_pressed = False switch2_pressed = False switch3_pressed = False switch4_pressed = False switch5_pressed = False switch6_pressed = False switch7_pressed = False switch8_pressed = False switch9_pressed = False switch10_pressed = False switch11_pressed = False switch12_pressed = False switches_pressed = [switch1_pressed, switch2_pressed, switch3_pressed, switch4_pressed, switch5_pressed, switch6_pressed, switch7_pressed, switch8_pressed, switch9_pressed, switch10_pressed, switch11_pressed, switch12_pressed] # colors from Animation library to send as color packets # named for notes color_C = color.RED color_Csharp = color.ORANGE color_D = color.YELLOW color_Dsharp = color.GREEN color_E = color.TEAL color_F = color.CYAN color_Fsharp = color.BLUE color_G = color.PURPLE color_Gsharp = color.MAGENTA color_A = color.GOLD color_Asharp = color.PINK color_B = color.WHITE # array for colors color = [color_C, color_Csharp, color_D, color_Dsharp, color_E, color_F, color_Fsharp, color_G, color_Gsharp, color_A, color_Asharp, color_B] # BLE send_packet function def send_packet(uart_connection_name, packet): """Returns False if no longer connected.""" try: uart_connection_name[UARTService].write(packet.to_bytes()) except: # pylint: disable=bare-except try: uart_connection_name.disconnect() except: # pylint: disable=bare-except pass return False return True ble = BLERadio() uart_connection = None if ble.connected: for connection in ble.connections: if UARTService in connection: uart_connection = connection break while True: blue_led.value = False # BLE connection if not uart_connection or not uart_connection.connected: # If not connected... print("Scanning...") for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=5): # Scan... if UARTService in adv.services: # If UARTService found... print("Found a UARTService advertisement.") blue_led.value = True # LED turns on when connected uart_connection = ble.connect(adv) # Create a UART connection... break ble.stop_scan() # And stop scanning. # while connected.. while uart_connection and uart_connection.connected: # iterate through buttons and colors for switch_pin in switch_array: i = switch_array.index(switch_pin) switches_pressed_state = switches_pressed[i] colors = color[i] # if the button is released # worked best if placed before the button press portion if switch_pin.value and switches_pressed_state: print("button off") # send button packet to stop tone & color (happens on CPB) if not send_packet(uart_connection, ButtonPacket(ButtonPacket.RIGHT, pressed=True)): uart_connection = None continue switches_pressed[i] = False # Set to False. # time delay for BLE, otherwise issues can arrise time.sleep(0.05) # if button is pressed: if not switch_pin.value and not switches_pressed_state: # If button A pressed... # send color packet if not send_packet(uart_connection, ColorPacket(colors)): uart_connection = None continue switches_pressed[i] = True # Set to True. time.sleep(0.05) # Debounce.