Once you've finished setting up your RP2040 Prop-Maker Feather 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 audiocore import audiobusio import audiomixer import pwmio from digitalio import DigitalInOut, Direction from adafruit_ticks import ticks_ms, ticks_add, ticks_diff from adafruit_motor import servo import adafruit_lis3dh time.sleep(2) # enable external power pin # provides power to the external components external_power = DigitalInOut(board.EXTERNAL_POWER) external_power.direction = Direction.OUTPUT external_power.value = True # i2s playback wave_file = open("dune_thumper_sfx.wav", "rb") wave = audiocore.WaveFile(wave_file) audio = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA) mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050, channel_count=1, bits_per_sample=16, samples_signed=True) audio.play(mixer) mixer.voice[0].play(wave, loop=True) mixer.voice[0].level = 0 # servo control pwm = pwmio.PWMOut(board.EXTERNAL_SERVO, frequency=10) prop_servo = servo.ContinuousServo(pwm) servo_move = False i2c = board.I2C() int1 = DigitalInOut(board.ACCELEROMETER_INTERRUPT) lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, int1=int1) lis3dh.range = adafruit_lis3dh.RANGE_2_G clock = ticks_ms() prop_time = 4000 while True: if not servo_move: mixer.voice[0].level = 0.0 prop_servo.throttle = 0.0 else: prop_servo.throttle = 0.5 mixer.voice[0].level = 0.5 if ticks_diff(ticks_ms(), clock) >= prop_time: servo_move = False if lis3dh.shake(shake_threshold=20): servo_move = True clock = ticks_ms() clock = ticks_add(clock, prop_time)
Upload the Code and Libraries to the RP2040 Prop-Maker Feather
After downloading the Project Bundle, plug your RP2040 Prop-Maker Feather 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's CIRCUITPY drive:
- lib folder
- dune_thumper_sfx.wav
- code.py
Your RP2040 Prop-Maker Feather CIRCUITPY drive should look like this after copying the lib folder, wav fileĀ and the code.py file.

How the CircuitPython Code Works
The code begins by enabled the EXTERNAL_POWER
pin. This pin enables power to all of the external component pins, which includes the servo header and speaker output.
# enable external power pin # provides power to the external components external_power = DigitalInOut(board.EXTERNAL_POWER) external_power.direction = Direction.OUTPUT external_power.value = True
Audio Setup
Next is I2S audio setup. The dune_thumper_sfx.wav audio file is passed to a Mixer
object. The Mixer
is setup to play the sound effect in a loop, but with the volume initially at 0
. Later on in the code loop, the volume will be adjusted so that you can hear the audio. This is one technique you can use to incorporate playing and pausing audio in a non-blocking way in your code.
# i2s playback wave_file = open("dune_thumper_sfx.wav", "rb") wave = audiocore.WaveFile(wave_file) audio = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA) mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050, channel_count=1, bits_per_sample=16, samples_signed=True) audio.play(mixer) mixer.voice[0].play(wave, loop=True) mixer.voice[0].level = 0
# servo control pwm = pwmio.PWMOut(board.EXTERNAL_SERVO, frequency=10) prop_servo = servo.ContinuousServo(pwm) servo_move = False
Accelerometer
Last but not least, the onboard LIS3DH is initialized over I2C. In the loop, the LIS3DH will be able to affect the prop by detecting shake
.
i2c = board.I2C() int1 = DigitalInOut(board.ACCELEROMETER_INTERRUPT) lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, int1=int1) lis3dh.range = adafruit_lis3dh.RANGE_2_G
The Loop
In the loop the servo_move
state determines what all of the components are doing. If servo_move
is False
, then the speaker is silent and the servo does not move.
if not servo_move: mixer.voice[0].level = 0.0 prop_servo.throttle = 0.0
If the LIS3DH detects a shake
, then servo_move
is set to True
.
if lis3dh.shake(shake_threshold=20): servo_move = True clock = ticks_ms() clock = ticks_add(clock, prop_time)
When servo_move
is True
, the servo spins and the speaker output is set to 0.5
with the Mixer
object. ticks
is used to keep time in a non-blocking way. After three seconds have passed, servo_move
is set back to False
.
else: prop_servo.throttle = 0.5 mixer.voice[0].level = 0.5 if ticks_diff(ticks_ms(), clock) >= prop_time: servo_move = False
Page last edited January 21, 2025
Text editor powered by tinymce.