Getting Started

Adafruit Playground is a wonderful and safe place to share your interests with Adafruit's vibrant community of makers and doers. Have a cool project you are working on? Have a bit of code that you think others will find useful? Want to show off your electronics workbench? You have come to the right place.
The goal of Adafruit Playground is to make it as simple as possible to share your work. On the Adafruit Playground users can create Notes. A note is a single-page space where you can document your topic using Adafruit's easy-to-use editor. Notes are like Guides on the Adafruit Learning System but guides are high-fidelity content curated and maintained by Adafuit. Notes are whatever you want them to be. Have fun and be kind.
Click here to learn more about Adafruit Playground and how to get started.
-
Zephyr Quest: ST7789 Display with Feather RP2350 As part of a series on Zephyr with Adafruit hardware, this guide shows how to configure Zephyr to use an ST7789 TFT display with a Feather RP2350. By connecting the display with a breadboard, we can use a logic analyzer to verify that the Zephyr display driver pin configuration agrees with the CircuitPython display driver. This guide is meant for people interested in adding support for Adafruit displays to Zephyr.
Parts
-
jq - now as a webservice! 🌍🎣🕸️ Filtering large JSON data jq for all...?
If you've not heard of or used `jq`, then count yourself lucky, as it is the tool of choice for data scientists up a creek with no paddle... If you find yourself wresting a 2GB JSON file then you'll probably end up using jq to help. See more details of the jq command-line tool at https://jqlang.org/Using jq can be really quick and simple, but sometimes finding the right incantation to return a subset of the data can leave you feeling a bit like you've been learning FFMPEG (another great tool where I found myself deep in a tutorial one weekend).
Don't do it yourself, get AI to write that query!
Fortunately we live in the days of Large Language Models ("AI" LLMs), which like nothing more than answering humans need for the correct FFMPEG/jq arguments to solve some "critical" problem.
So don't feel like you need to learn the syntax, just throw your data and desired output format at the machines and ask for the jq syntax to achieve that!Here's an example where I threw a slightly truncated version of the 80kb json at chatGPT and asked for the output format I wanted: https://chatgpt.com/share/67c1c7a6-bf5c-8000-823c-d422593d2ed8
There's also a jq playground website, allowing you to submit your JSON and "query" or fetch the data from a website URL, and it runs entirely in the browser (WASM version of jq) at https://play.jqlang.org/
It's great, but not what I was looking for... I needed something that would allow a microcontroller with very little RAM (random access memory) to get some values from large JSON payloads, without having to download and process all the JSON data just to find a couple of values.
Microcontrollers are usually too underpowered to load a full web browser with javascript and WASM support, so ideally we need something more like a web-service that would allow a simple web request to trigger all the work and return the subset of data we're looking for.
-
Piece Of Pi with a NeoTrinkey! Estimate Pi with the Monte Carlo method and a neotrinkey
The power of randomness can be harnessed! Estimating the area of a circle by throwing darts at random gives you the means to estimate the value of Pi! I first learned about using the Monte Carlo back in the '80's and even used it in software development to estimate timing of events. You can use it with you NeoTrinkey to estimate the valueof Pi. You can find my github repository here: https://github.com/mrklingon/PieceOfPi/
Monte Carlo methods are a broad class of computational algorithms that rely on repeated random sampling to obtain numerical results. One of the basic examples of getting started with the Monte Carlo algorithm is the estimation of Pi. (https://www.geeksforgeeks.org/estimating-value-pi-using-monte-carlo/)
This project iterates over a unit circle of radius one and "throws" darts at random from -1 to 1 x, and -1 to 1 y, then counts how many land IN the circle. Pi is estimated by multiplying 4 * "darts inside circle"/all darts thrown
The more iterations (darts) thrown, the closer you approach the value of Pi.
The program runs continuously, pausing 5 seconds between runs. While the program is running/estimating, the neopixels flash random colors. When it finishes an estimate, the neopixel displays the answer by blinking the neopixels green for the value (three times for three, one time for one and so on.). Zeroes are indicated by turning all pixels pink briefly. The pixels flash blue to indicate the decimal point.
If the program is run inside a REPL like Mu, it will print out the results:
I will estimate Pi. it is around : 3.14139 I will estimate Pi. it is around : 3.13818 I will estimate Pi. it is around : 3.13422 I will estimate Pi. it is around : 3.1313
The default value of Iterations is 100 - you can change that to higher or lower values.
Files
- findPi.py - copy to code.py to run
- ncount.py - helper file, provides color definitions and blinknum() to blink the digit values.
For more about the Monte Carlo Method: https://en.wikipedia.org/wiki/Monte_Carlo_method
Random points are generated only few of which lie outside the imaginary circle -
supervisor.runtime.display in CircuitPython 9.2.5+ CircuitPython 9.2.5 adds a new property to the supervisor Runtime object,
display
.If your board has a built in display that is automatically configured by the CircuitPython core (e.g., boards like the Feather ESP32-S3 Reverse TFT), then this display is available as
supervisor.runtime.display
in addition toboard.DISPLAY
.So what's different about the new
supervisor.runtime.display
?- This property is available on all boards that support
displayio
, not just boards with built in displays - Unlike
board.DISPLAY
, this property is settable, and remembers its value after your code file finishes running. This means you can set this property once in boot.py and then use the display each time yourcode.py
runs, or re-use a display set by a previous run of code.py. - Due to technical limitations in CircuitPython, when a display is released,
board.DISPLAY
becomes a "None-like object": one that prints asNone
but fails the checkboard.DISPLAY is None
.supervisor.runtime.display is None
works correctly to check whether a default display is configured.
Setting
supervisor.runtime.display
There are two approaches:
- Do it unconditionally in boot.py and depend on this in code.py
- Do it conditionally in code.py, if
supervisor.runtime.display is None
... in boot.py
Here's a code snippet that shows configuring a 240x240 ST7789 display connected to an EyeSpi BFF on a QT Py board like the QT Py RP2040:
- This property is available on all boards that support
-
Media hub: Media control w/opt Bluetooth Overview
Physical controls for a more enjoyable media playback experience.
Features
- Responsive volume knob & mute button.
- Transport controls (play/pause, stop, FF/REW, skip tracks).
- Pair up with your favourite Bluetooth® speakers.
- Quick, physical connection (don't have to go through menu system to pair with keypad & speakers).
- Customizable controls/scheme.
- Customizable setup: Optionally connect USB hub/dock for added features, for example:
- mirror phone to TV w/HDMI out: Watch videos on a bigger screen
- add keyboard: Better typing experience for texts/emails.
- Solderless project.
Main hardware
Program your device
To get your RP2040 macropad to act as a media controller, it needs to:
- detect keypresses and changes in the knob position
- send out corresponding keyboard messages to the attached USB host device (ex: a phone).
My own implementation for this "media hub" is written for Adafruit's CircuitPython, and can be found here:
- 💾 MediaController project README (see MediaHub_AFMacropad). 🚀 Installation instructions.
-
Zephyr Quest: SWD Pogo Adapter for CLUE As part of a series on Zephyr with Adafruit hardware, this guide shows how I made a pogo pin SWD debug probe adapter for the CLUE board so I can conveniently program it with Zephyr firmware. My other SWD option was soldering wires to the test points, but I like how pogo pins are neater and less fragile. This guide is meant for people interested in adding support for Adafruit boards to Zephyr. It might also be useful for folks who want to fix a bricked bootloader.
Overview
-
Zephyr Quest: Feather RP2350 Board Def As part of a series on Zephyr with Adafruit hardware, this guide shows how to write a Zephyr board definition for the Adafruit Feather RP2350 with an I2C SHT41 temperature and humidity sensor. Future guides will look more at using sensors and displays. This is intended for developers who want to know about adding support for Adafruit boards to Zephyr. If you just want to write CircuitPython code, you can safely ignore this stuff.
Overview
-
Weather Display Using Open-Meteo's API The OM Weather Display periodically updates and displays the following local weather conditions:
- Day, date, and time (AM/PM)
- Tomorrow's sunrise and sunset times
- Temperature
- Relative Humidity
- Wind speed and direction
- Wind gust speed
- Condition description and graphic icon
Location, time zone, and measurement units settings are stored in the
settings.toml
file. Either "METRIC" or "IMPERIAL" measurement units can be specified.Weather condition query and internet clock refresh interval rates are set by parameters in the
code.py
module. The default interval for updating weather conditions is 5 minutes. The local time is updated from the Adafruit Network Time Protocol (NTP) server hourly.The CircuitPython code runs on an ESP32-S3 4MB/2MB Feather attached to a 2.4-inch TFT FeatherWing. An optional ALS-PT19 ambient light sensor can be used to automatically adjust display brightness.
CircuitPython Code
The Weather Display's CIRCUITPY root directory contains the following files and folders.
- files:
- settings.toml -- Wi-Fi and location parameters
- om_query.py -- OM API URL query string builder
- who_to_map_icon.py -- parses the WMO weather code for descriptions and icons
- code.py -- the primary code module
- folders:
- fonts -- contains the font files
- icons_160x160 -- the weather icon bitmap graphics files
- lib -- the CircuitPython library modules
- sd -- a placeholder for the unused SD storage drive
A downloadable bundle of code files and folders can be found in the OM Weather Display GitHub repository.
-
Guide: Build a 'MiniMarquee' WiFi Text Scroller Materials
The following parts are used to build the MiniMarquee:
- QT Py ESP32-S2
- IS31FL3741 13x9 PWM RGB LED Matrix
- 50mm Stemma QT cable
- Black LED acrylic, 2-3 mm thick, cut to 41mm x 29mm
- 4 M2x12 nylon screws and nuts
- Little rubber feet
- Nitto double-sided adhesive tape (or other tape with similar adhesive strength)
- 2 1-ounce wheel weights (optional)
Installing Firmware
The MiniMarquee's firmware is written for Arduino in PlatformIO. There are two ways to install the firmware onto the QT Py ESP32-S2:
- Drag-and-drop UF2 installation
- Build source code and install onto device
The UF2 method is recommended, as it is very simple and does not require downloading any additional software or dealing with any code at all. However, if you wish to customize your MiniMarquee's firmware, you'll need to go for option 2 and build it from source.
-
Circuit Playground: Galaxy Explorer Galaxy Explorer
Here's a project that combines ideas from my one-dimensional arcade game and orrery project. Think "1930's pulp science fiction" and you'll get the idea: The Circuit Playground lets you navigate a galaxy defined in a 100 element array with around 60 stars. You can stop at any one of the solar systems and observe an orrery-like display of the movement of the planets.
For me, the fun here is creating a UI with the CPX controls:
The program has three states:
travel - move through the galaxy
stop - choose a star displayed on the ten neopixels
explore - goes into orrery mode showing the planets in the chosen star-systemWhen in travel state, the A and B buttons increase the speed of the movement of the stars. A: clockwise, B: counter-clockwise. Multiple clicks increase the speed.
When in stop state, the A and B buttons move a blinking white pixel to select a star. A:move counter-clockwise, and B:clockwise. (yes, the opposite of travel mode).
Change state by pressing A+B - state cycles from travel to stop to explore and back to travel. In stop mode, you cannot move to explore unless the blinking pixel is on one of the stars.
At any point, shifting the switch to the left, turns off all the neopixels and switches the system to travel mode.
When the switch is shifted to the left, shaking the CPX will show all neopixels in green and generate a new galaxy.
Both versions, CircuitPython or Makecode work the same.
The generation of the galaxy creates two 100 element arrays. One defines the stars, and the other the "type" of solar system. When in explore mode, the defined colors and speed of the planets is set based on an algorithm.
Files
- explore.js - or makecode version: https://makecode.com/_Wt9P3udHMKjR
- explore.py - copy to code.py on a Circuit Playground with CircuitPython
1940 "Planet" Pulp SF magazine cover -
CNC Rotary Encoder Internals I was working with one of Adafruit's CNC Rotary Encoders and made a mistake wiring. Well, long story short, I killed it. I am not sure exactly what I did, but I suspect I accidentally drove its outputs with an improper voltage.
To prevent the experience from being a total loss, I took the time to partially disassemble it.
The plastic cover around the screw terminals can easily be removed, exposing a PCB. 3 pins hold this PCB onto the rest of the assembly. After desoldering them, the component side of the board can be seen.
The board features a "7550" voltage regulator. The incoming supply is regulated down from whatever it is to 5V for the internal circuitry. C2 is the input smoothing capacitor, and C1 is the output smoothing capacitor.
D1 and D2 are light emitting diodes in series (likely IR) which are positioned under matching sensors in the upper part of the assembly. A "331" (330Ω) resistor limits the current through the LEDs.
The 3 soldered positions are a supply and 2 returns from the sensor package in the upper part of the assembly. Resistors R2 & R3 are pull ups, while caps C3 and C4 smooth out any spurious transitions of the signals. It seems most likely that the sensor assembly consists of two phototransistors, which can pull the pins of the "HC14", a schmitt-trigger inverter. This creates the signals A and B at a dependable logic level, and also the inverted A/ and B/ signals.
Diode D3 is a reverse current protection diode; in case VCC and GND are swapped, no current can flow. Interestingly it's on the GND side, while I thought it was more common to see on the VCC side.
If I cared to determine which component(s) I damaged, this is totally a board that could be reworked by hand. However, I don't plan to spend the time and instead will just pick up a fresh encoder from the store—and double check my wiring next time.
-
Zephyr Quest: Troubleshooting a Pi Pico2 build error As part of a series on Zephyr with Adafruit hardware, this guide documents the process I used to diagnose a problem with building Zephyr's hello_world sample app for Raspberry Pi Pico 2. By the time you read this, there's a good chance the Zephyr folks may have already fixed the problem that tripped me up. But, perhaps my troubleshooting process will be a useful reference.
TLDR: Use
west build ... -- -DCONFIG_PICOLIBC_USE_MODULE=y
to build picolibc from source, or delete the~/.cache/zephyr
cache directory.The Linker Error
Working towards the goal of writing a new board definition for the Adafruit Feather RP2350, I've been looking at how the device tree setup for the existing Raspberry Pi Pico 2 board definition works. When I got around to trying to build the hello world sample app for the Pico 2, which also uses the RP2350, I got stuck on a linker error.
Below, I've included a console log which is a bit long. But, it shows some interesting details. The main error messages come in pairs that follow this pattern:
...arm-zephyr-eabi/lib/./libc.a(strcmp.S.o): conflicting CPU architectures 17/2
...ld: failed to merge target specific data of file ... /libc.a(strcmp.S.o)
After the console log, I'll explain how I tracked this down and found a workaround.
-
Greenhouse Temperature Logger This guide shows how to build cheap data loggers to help keep plants happy in greenhouses or other indoor growing spaces. I developed this design to help a community garden group control temperatures in greenhouses for starting new plants in winter. By charting the temperatures, we were able to identify and fix problems with air sealing and heater thermostat settings. This logger design uses manual data collection over USB serial because there is no WiFi at the greenhouses.
Wiring
If you are unfamiliar with soldering stacking headers, you might want to read:
Fritzing Diagram
This diagram shows the core circuit for the temperature logger, omitting the pin header and perma-proto stuff, and using a toggle switch to represent the jumper:
-
7" Sunton ESP32S3 8048S070 Circuit Python Very basic primer to get your 7" Sunton ESP32S3 8048S070 display up and running on Circuit Python with displayio.
Installation
Since this board only comes with a .bin from CircuitPython.org the easiest way to install Circuit Python is to have a full Python/PIP/ESPTool environment on your PC. Then you can run esptool.py. I have a section in my personal repository on the steps to flash an ESP device on a Windows PC once you have Python and PIP installed. The other method is to use the web installer on CircuitPython.org with a Google Chrome browser.
WCH (CH340) USB Serial
Unlike most Circuit Python boards the 8048S070 does not have native usb... there is no USB drive. It's more like a classic ESP32 where you have to communicate with it via serial only. If you miss the good old days of FTDI cables and serial (no one misses those days) then you'll feel right at home.
Device Manager CH340 Driver
After installing Circuit Python and getting the board recognized in device manager it should automatically install the CH340 driver. It's a good idea to double check the serial communication speed.
-
Adventure Engine: Mapping a World in a NeoTrinkey This project is my first draft of being able to squeeze an adventure world into the NeoTrinkey. Here's a link to the project repository. The code lets you build a map in a text file that defines a space to navigate. NOTE: the initial load of the repository had the wrong version of intput.py - the correct version is now in the repository.
Adventure-Engine
NeoTrinkey code for simple adventure gaming
- intput.py - pass a string "choices" to intpt(choices) and return one of the letters to calling routine. eg intpt("nsew") and you'll get back n,s,e,or w. This can be navigation.
- wise.py - choose a line from a text file. This file will be a linear list of an AxA array. Program will be used for description of current location
- advent.py - (code.py when running). Tracks user location in AxA array, calls wise.py to find and print location, then offers chance to move to N,S,E,W direction and retrieves choice from intpt(), calculates new location and prints it.
- prt.py - allows printing to REPL or via HID as typed output.
- ship.adv - sample map for a 3x3 ship
- magic.adv - sample map for a 5x5 magical realm. WRAP should be set to True, and radius to 5.
Code is a framework for having the NeoTrinkey navigate a space - dungeon, forest, spaceship.
Set map=[file name] of list of room descriptions
set radius=X where X is the size of the matrix. 3x3 or 5x5 for example
set px and py to starting room. eg. for a 3x3 map px=1 py=1 will set the start in the center of the map
set WRAP = True for the map being a torus, and False for the map having edges you can't go beyond.
sample map "ship.adv" defines a 3x3 map:communications bay|e cockpit|wse computer and navigation bay|w sleeping quarters|e wardroom galley|w storage|e engines|new power resources|w
Note some lines end with a "|" plus directions that can be followed from the room. If the room ends with "|e" for example, you can only leave to the East. If the line ends with no |+direction(s) the default is you can leave NSEW. (for example, the wardroom in this case).
The map below shows the rooms for ship.adv, and the gaps in the walls show which directions you can go. Only the wardroom allows passage in all four directions, NSEW.
When running, you are given "Current location:" and then offered the directions you can go. Touching pad #1 toggles between choices, touching pad #2 chooses the current one.
For example:Current location: wardroom Next action? nsew? n! Current location: cockpit Next action? wse ? w! s! Current location: wardroom Next action? nsew? n! s! Current location: engines Next action? new ? n! e! Current location: power resources Next action? w ? w!
# Magic Adventure Map
Here's another map, that is defined in the repository file "magic.adv"