Once you've finished setting up your Feather RP2040 with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download to your computer as a zipped folder.
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries # SPDX-License-Identifier: MIT import time import board import digitalio import audiomixer import audiomp3 from audiopwmio import PWMAudioOut as AudioOut from adafruit_seesaw import seesaw, rotaryio, digitalio as seesaw_io, neopixel as seesaw_neopixel from adafruit_led_animation.animation.pulse import Pulse import neopixel # wait a little bit so USB can stabilize and not glitch audio time.sleep(3) # enable propmaker speaker output enable = digitalio.DigitalInOut(board.D10) enable.direction = digitalio.Direction.OUTPUT enable.value = True # enable fan pin fan_pin = digitalio.DigitalInOut(board.D11) fan_pin.direction = digitalio.Direction.OUTPUT fan_pin.value = True # speaker pin on the propmaker audio = AudioOut(board.A0) # create mixer instance mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050, channel_count=1, bits_per_sample=16, samples_signed=True) # attach mixer to audio playback audio.play(mixer) # open mp3 audio file audio_file = audiomp3.MP3Decoder(open("Enceladus_Hiss_NASA.mp3","rb")) # play audio file in first channel of mixer mixer.voice[0].play(audio_file, loop=True) # set mixer channel level mixer.voice[0].level = 0 # propmaker neopixel pin pixel_pin = board.D5 num_pixels = 40 pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False) # define neopixel colors RED = (255, 0, 0) BLUE = (0, 0, 255) # pulse animation pulse = Pulse(pixels, speed=0.1, color=RED, period=3) # i2c setup for rp2040 feather stemma port i2c = board.STEMMA_I2C() # rotary encoder enc0 = seesaw.Seesaw(i2c, addr=0x36) encoder0 = rotaryio.IncrementalEncoder(enc0) last_position0 = None # encoder button enc0.pin_mode(24, enc0.INPUT_PULLUP) enc_button = seesaw_io.DigitalIO(enc0, 24) enc_button_state = False # encoder neopixel pixel0 = seesaw_neopixel.NeoPixel(enc0, 6, 1) pixel0.brightness = 0.2 pixel0.fill(BLUE) # variables volume = 0 # volume pixel_level = 25 # pixel brightness for rings last_pos0 = 0 # position of the encoder ctrl_mode = 0 # control mode set with encoder while True: # run neopixel animation pulse.animate() # get encoder position pos0 = -encoder0.position # if the encoder button is pressed.. if not enc_button.value and not enc_button_state: enc_button_state = True # switch between control modes if ctrl_mode == 0: ctrl_mode = 1 else: ctrl_mode = 0 print("ctrl_mode is %d" % ctrl_mode) # button debounce if enc_button.value and enc_button_state: enc_button_state = False # if control mode is 0.. # control the volume of the white noise if ctrl_mode == 0: # encoder neopixel is blue pixel0.fill(BLUE) # if the encoder moves.. if pos0 != last_pos0: # if you increase the encoder # increase value by 0.1 # maxed out at 1 if pos0 > last_pos0: volume = volume + 0.1 if volume > 1: volume = 1 # if you decrease # decrease value by 0.1 # minimum value of 0 if pos0 < last_pos0: volume = volume - 0.1 if volume < 0: volume = 0 print(volume) # reset the position last_pos0 = pos0 # if control mode is 1.. # control the brightness of the neopixel rings # actually controlling the % of red, not brightness directly if ctrl_mode == 1: # set the encoder neopixel to red pixel0.fill(RED) # if you increase the encoder # increase value by 10 # max out at 255 if pos0 != last_pos0: if pos0 > last_pos0: pixel_level = pixel_level + 10 if pixel_level > 255: pixel_level = 255 # if you decrease the encoder # decrease value by 10 # minimum level of 25 if pos0 < last_pos0: pixel_level = pixel_level - 10 if pixel_level < 25: pixel_level = 25 print(pixel_level) # reset the position last_pos0 = pos0 # set the neopixel ring color pulse.color = (pixel_level, 0, 0) # set the audio volume mixer.voice[0].level = volume
Upload the Code and Libraries to the Feather RP2040
After downloading the Project Bundle, plug your Feather RP2040 into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the Feather RP2040's CIRCUITPY drive.
- lib folder
- code.py
- Enceladus_Hiss_NASA.mp3
Your Feather RP2040 CIRCUITPY drive should look like this after copying the lib folder, Enceladus_Hiss_NASA.mp3 file and the code.py file.
About the Enceladus Hiss mp3 File
The .mp3 file used for the white noise is a recording from NASA of Saturn's radio emissions:
Saturn is a source of intense radio emissions, which were monitored by the Cassini spacecraft. The radio waves are closely related to the auroras near the poles of the planet. These auroras are similar to Earth's northern and southern lights.
This recording is available from NASA's Soundcloud site and was featured in their Spooky Space Sounds collection. It is distributed with a CC BY-NC 3.0 license.
How the CircuitPython Code Works
Pins D10
and D11
and set to True
to enable hardware on the PropMaker FeatherWing to work properly. D10
enables the speaker pin and D11
turns on the R pin for the RGB LED, which is used by the fan since it has a 5V output.
# enable propmaker speaker output enable = digitalio.DigitalInOut(board.D10) enable.direction = digitalio.Direction.OUTPUT enable.value = True # enable fan pin fan_pin = digitalio.DigitalInOut(board.D11) fan_pin.direction = digitalio.Direction.OUTPUT fan_pin.value = True
The Mixer
An audiomixer.Mixer()
object is instantiated to allow for volume control of the audio file in software. The value of mixer.voice[0].level
can be a float from 0.0 to 1.0 and later in the code will be set by the rotary encoder.
# speaker pin on the propmaker audio = AudioOut(board.A0) # create mixer instance mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050, channel_count=1, bits_per_sample=16, samples_signed=True) # attach mixer to audio playback audio.play(mixer) # open mp3 audio file audio_file = audiomp3.MP3Decoder(open("Enceladus_Hiss_NASA.mp3","rb")) # play audio file in first channel of mixer mixer.voice[0].play(audio_file, loop=True) # set mixer channel level mixer.voice[0].level = 0
NeoPixels
The NeoPixel pin on the PropMaker FeatherWing (D5
) is instantiated as a NeoPixel()
object. The Pulse()
animation is used from the LED Animations library.
# propmaker neopixel pin pixel_pin = board.D5 num_pixels = 35 pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False) # define neopixel colors RED = (255, 0, 0) BLUE = (0, 0, 255) # pulse animation pulse = Pulse(pixels, speed=0.1, color=RED, period=3)
Rotary Encoder
The rotary encoder and its NeoPixel are setup over I2C. Since digitalio
and the standard NeoPixel library are being used alongside the adafruit_seesaw
library, the adafruit_seesaw
digitalio
and neopixel
portions of the library are imported as seesaw_io
and seesaw_neopixel
to avoid conflicts.
# i2c setup for rp2040 feather stemma port i2c = board.STEMMA_I2C() # rotary encoder enc0 = seesaw.Seesaw(i2c, addr=0x36) encoder0 = rotaryio.IncrementalEncoder(enc0) last_position0 = None # encoder button enc0.pin_mode(24, enc0.INPUT_PULLUP) enc_button = seesaw_io.DigitalIO(enc0, 24) enc_button_state = False # encoder neopixel pixel0 = seesaw_neopixel.NeoPixel(enc0, 6, 1) pixel0.brightness = 0.2 pixel0.fill(BLUE)
The Loop
In the loop, the Pulse animation is shown on the NeoPixels and the encoder button switches between ctrl_mode
0
and 1
.
# run neopixel animation pulse.animate() # get encoder position pos0 = -encoder0.position # if the encoder button is pressed.. if not enc_button.value and not enc_button_state: enc_button_state = True # switch between control modes if ctrl_mode == 0: ctrl_mode = 1 else: ctrl_mode = 0
Turn Up the Volume
If ctrl_mode
is 0
, then the volume of the audio file is affected by twisting the rotary encoder knob. Each position move either increases or decreases the audio level by 0.1
.
# if control mode is 0.. # control the volume of the white noise if ctrl_mode == 0: # encoder neopixel is blue pixel0.fill(BLUE) # if the encoder moves.. if pos0 != last_pos0: # if you increase the encoder # increase value by 0.1 # maxed out at 1 if pos0 > last_pos0: volume = volume + 0.1 if volume > 1: volume = 1 # if you decrease # decrease value by 0.1 # minimum value of 0 if pos0 < last_pos0: volume = volume - 0.1 if volume < 0: volume = 0 print(volume) # reset the position last_pos0 = pos0
Turn Up the Brightness
If ctrl_mode
is 1
, then the "brightness" of the NeoPixels are affected. The value affected by the rotary encoder is actually the red value of the RGB color value. Each position change by the rotary encoder increases or decreases the red value by 25
.
# if control mode is 1.. # control the brightness of the neopixel rings # actually controlling the % of red, not brightness directly if ctrl_mode == 1: # set the encoder neopixel to red pixel0.fill(RED) # if you increase the encoder # increase value by 10 # max out at 255 if pos0 != last_pos0: if pos0 > last_pos0: pixel_level = pixel_level + 10 if pixel_level > 255: pixel_level = 255 # if you decrease the encoder # decrease value by 10 # minimum level of 25 if pos0 < last_pos0: pixel_level = pixel_level - 10 if pixel_level < 25: pixel_level = 25 print(pixel_level) # reset the position last_pos0 = pos0
At the bottom of the loop, the NeoPixel color value is set, followed by the audio mixer level value.
# set the neopixel ring color pulse.color = (pixel_level, 0, 0) # set the audio volume mixer.voice[0].level = volume
Text editor powered by tinymce.