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.
-
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"
-
Circuit Python Matrix Portal S3 NTP Clock Make a highly accurate Circuit Python Matrix Panel clock quick and easy with a Matrix Portal S3 microcontroller and a 64x32 Matrix Panel.
Skill Level: Beginner
Fonts and code updates can be found in my Github Repository.
-
Forward IO data to google sheets, using google forms (via 3rd party) 1. Create a new form at https://docs.google.com/forms/
2. Add some questions on the Questions tab, which use the Short Answer (simple values) or paragraph type (multi-line support).
3. On the Responses tab click the Link to Sheet button/link to set the responses to goto a sheet, create a new one or choose existing
-
Make Logic Analyzer Connector Blocks Do you have a logic analyzer like Saleae, or even one of those rp2040-based ones?
Do you hate plugging up all the signals when you want to use your logic analyzer on a multi-channel problem?
While working on RGB matrix support on the Pi 5, I sure did! But then I remembered that Adafruit has the parts I need to make some cables that are quick to connect & disconnect from my logic analyzer.
In my case, I'm plugging into a Rigol MSO1074, but I might also want to use my Saleae in the future, so I made up two 2x4 blocks. This way, I can use the connectors on either device.
It's quick and easy and best of all you don't have to crimp any connectors because the pre-crimped jumper wires are right there in the Adafruit store.
Start by grabbing the parts you need. Get a packet of housings for the "project end" and the "logic analyzer" end, as well as the correct jumper wires (male/male, male/female, or female/female) for the connectors.
For instance, I was connecting the 2 row male header of my logic analyzer to the 2 row male header on the Adafruit RGB Matrix Bonnet, so I used Female/Female jumper wires, a pair of 2x4 housings from the small dual row wire housing pack, and a single 2x10 housing from the large dual row wire housing pack. (there are actually 2x8 pins, but the 2x10 housing fits the space of the keyed connector better, reducing the chance of plug mistakes. A keyed housing would be better, but then I'd be off to digikey to look for one)
Now, tear off some wires from the set of jumper wires. I worked in groups of 5, so that each 2x4 housing for the logic analyzer end had 4 signal wires & 1 GND wire.
I connected 8 different signals, somewhat arbitarily: 4 RGB data lines, 1 address line, and 3 control lines.
Double check the position of each signal & GND, and make sure you have at least one GND signal (but more ground wires are better for signal integrity! The ideal is to have one GND between each signal)
Once you're satisfied you've got the correct wire at the correct position, insert the wire into the housing until it clicks firmly into place. The orientation of the crimped pin is important, it will only latch one way.
If you make a mistake, it's not the end of the world. Frequently it's possible to free a "locked in" connector. Here's the procedure I follow: First, push the pin as far forward in the housing as possible, opening a gap under the plastic latch. Then, carefully insert a jeweler's screwdriver under the latch. Then, pull back on the pin. When done properly, this frees the wire & leaves the latch intact. However, if you bend the latch out too far it deforms and will no longer retain a wire when one is re-inserted.
-
Zephyr Shell over USB or BLE + Bluefruit Connect Like Linux, Zephyr can route serial console streams to various hardware interfaces. This guide shows how to run the Zephyr Shell sample program on a QT Py ESP32-S3 using either USB serial or BLE with the Adafruit Bluefruit Connect app.
Prerequisites
To follow along with this guide, you will need:
- Linux computer running Debian 12, Ubuntu 22 LTS, Ubuntu 24 LTS, or similar
- Zephyr workspace including west and the Zephyr SDK's esp32-s3 toolchain (my Getting Started with Zephyr on Linux Playground guide explains how to set this up)
- Adafruit QT Py ESP32-S3 dev board (8flash/nopsram) with Zephyr bootloader (or you can use the ESP32 BOOT+RESET procedure to flash the Zephyr bootloader for the first time)
- iPhone with the Adafruit Bluefruit Connect iOS app.
-
Getting Started with Zephyr on Linux This is for folks interested in learning about Zephyr. The first section shows, step by step, how to work through the Zephyr Getting Started Guide to install Zephyr on Linux, build the hello world sample, and run it on an Adafruit QT Py ESP32-S3. The second part has notes for tuning the default settings to use fewer resources for faster CI builds.
What are Zephyr and West?
The Zephyr Real Time Operating System (RTOS) provides an abstraction layer that helps make it easier to port applications like CircuitPython to boards from various manufacturers.
In theory, using an RTOS makes it easier to implement features using audio synthesis, graphic displays, HTTPS, MQTT, BLE, etc. By building on top of Zephyr APIs, rather than vendor-specific SDK APIs, application code can ignore some of the differences between microcontroller families. Zephyr helps with low-level hardware details and coordinating CPU time for concurrent tasks including application logic, hardware IO, network stacks, and number crunching.
Zephyr has a command line tool called
west
to manage and coordinate the many tasks involved in working on a Zephyr project. Once you install west, you can dowest help
to see documentation on the available sub-commands. -
Cedar Grove Weather Architecture v2.0 Overview
The first version of the weather system architecture (Display AIO Local Weather Conditions: MatrixWeather System) worked nicely, but reliability suffered when the multiple transmitter and receiver devices competed to access the Adafruit IO (AIO) feeds. To prevent access collisions using the first architecture, each independent device was designed to only transmit or receive at fixed rates well below the AIO+ subscription rate limit of 60 data point transactions per minute. However, since each device operated autonomously, there were occasions when two transactions would heterodyne and stress the limit and cause feed failures.
To remedy the reliability issue, the new architecture design was switched from using MQTT to the HTTP protocol. Even though MQTT makes it relatively easy to "subscribe" to AIO feeds, HTTP provides more control granularity that includes a relatively new feature for independent devices to monitor feed access activity. Collisions can be avoided by watching how many data point transactions remain and waiting until enough are available for the queued transaction event.
The primary change to the architecture was to incorporate throttling. A secondary goal was to reduce the number of devices in the system by combining the existing Corrosion Monitor sensor with the REPEATER device, creating the new Weather SOURCE device. The Weather SOURCE extracts local weather conditions from AIO+ Weather and combines it with the local sensor's temperature, humidity, dew point, and corrosion detection data. Weather SOURCE then publishes the information to a collection of standard AIO feeds.
The other devices in the system are displays that extract data stored in the AIO feeds. One display replaces the existing Workshop Corrosion LCARS Monitor (PyPortal M4) that lives in the workshop and now is named Workshop Corrosion Monitor Display. The second is our living room MatrixWeather Display (upgraded from a Matrix Portal M4 to the S3 version). Since AIO feed access rates are monitored, it will be possible to create additional task-customized displays, perhaps for the studio or kitchen.
An advantage of the new architecture is that some display devices will not require large PSRAM for retaining the huge JSON file that AIO+ Weather provides, with the exception of a Matrix Portal. The single Source device with a large PSRAM extracts only the essential information needed by the displays -- and stores the extraction into the AIO feeds.
Weather Source
The primary source of AIO+ Weather and the local workstation temperature/humidity sensor used for corrosion detection. Weather and the local workstation conditions are sent to AIO feeds in the client's account to be retrieved by display devices.
This version of the Weather Source will be replaced by the Nuevo Combined Weather Source device sometime in late March 2025.
CircuitPython code can be found in the
Weather_Source/bundle
folder of the CedarGrove Weather System repository. -
GFFA - Aurebesh! I really enjoy coming up with new ways to combine my appreciation for Science Fiction linguistics with Adafruit products (especially the neotrinkey!) and CircuitPython. For this project I combined a classic tool "FIGlet" with the Aurebesh, the alphabet from the Galaxy Far, Far Away... (GFFA).
I started with FIGlet, the computer program that generates text banners, in a variety of typefaces, composed of letters made up of conglomerations of smaller ASCII characters. I modified an existing font file (standard.flf), replacing the letters a-z with my handmade versions of the letters seen above (note: anyone know of a good editor for FIGlet fonts? I'd love to improve the above).
That file was rather big for the neotrinkey - so I just extracted the Aurebesh and made it into an array for aure.py, a module to convert alphabetic English into Aurebesh. Then I made a program, aurebesh.py which could call aure.py's function doAure() for displaying different sayings or the alphabet, character by character - a useful training tool to become familiar with the alphabet. That's an important skill if you come across warnings like this:
All of this work went into a Github repository "Aurebesh" - from the Readme file:
-
Using a modified Figlet font ("standard.flf") I created aurebesh.flf, replacing a-z in the font with Aurebesh symbols.
-
I extracted the text for the a-z from Aurebesh.flf and made them into an array of texts for aure.py
-
aure.py has a function doAure(text,delay,REPL) - text = the text to display in Aurebesh, delay is how long between each letter, and REPL indicates if the output is to go to the REPL or, via HID, out as keyboard input.
-
aurebesh.py is a CircuitPython program that uses prt.py and ncount.py. Touching pad#1 will deliver one-by-one the alphabet, touching #2 will choose a random saying from sayings[] and print the English version, then the Aurebesh letters, one-by-one.
Notes:
Edit the variable REPL in aurebesh.py to True for text to show up in the REPL; make it False for text to be delivered as if typed. Edit the variable "sayings" to the list of sayings you want to display in Aurebesh.
Files (copy these all to your neotrinkey)
- ncount.py
- aure.py
- prt.py
- aurebesh.py -- copy this to "code.py"
If output is going out as if typed, the program will pause when started, blinking red till you touch one of the pads - this gives you a chance to move the cursor to the window you wish to receive the output.
Info:
Figlet: https://en.wikipedia.org/wiki/FIGlet Aurebesh: https://starwars.fandom.com/wiki/Aurebesh
-
-
Build patterns: IR receiver variants Overview
This note presents a few different ways of building an microcontroller-based IR receiver. It is meant as a complement to the "PC media remote" note.
The idea is to somewhat parallel "Software design patterns" -- only for physical hardware builds. The note provides a variety of implementation examples for an IR receiver project. Juxtaposition is used to compare various different mechanical/mounting systems that provide structure, and also different practical connectivity solutions. Hopefully these options will make builds feel a bit more approachable, and possibly inspire new ideas.
Regarding the overall design philosophy: Attempts were made not to solder everything together in one monolithic block. Design often involves making mistakes, so having a way to easily re-configure your solution as it develops really helps. More specifically, I find that building "blocks" in a somewhat modular/generic fashion is preferable to building something that is completely "application-specific". As a bonus, if your blocks don't quite work out the way you want, they can more likely be re-purposed in later projects.
A good way to improve on the original "PC media remote" breadboard example is to use the IR receiver module (#5939). The build pictured above makes use of the STEMMA-QT port from a PiCowbell protoboard, and mounts all components to a 5x5 Adafruit swirly grid. Overall, this build should be a little more robust than what can be obtained with the breadboard solution, yet still be achievable without any soldering (if using Pico board with pre-soldered headers).
Some things to keep in mind:
- Need a custom 4-pin JST-SH to 3-pin JST-PH cable.
- Make sure the pin order is correct to avoid damaging the circuits (especially power/gnd).
Connecting the 2 boards in this fashion requires modifying a pre-built JST-SH cable (this one, for example). Crimping JST-SH connectors can be a bit difficult due to the small size, but removing the 4th (yellow) wire from a 4-pin connector is a bit more manageable. A hobby knife can be used to ⚠️carefully lift the plastic tab to release the pin/wire. Once that's done, JST-PH pins can be crimped to the other end of the cable, which in turn snap into the 3-pin JST-PH connector needed for the IR receiver terminal.
-
CircuitPython "Ring Oscillator" RNG with SN74AHCT14 I've long had an interest in random number generation. In fact, a very early PCB I designed and built was exactly for this purpose: Arduino Random Number Generator.
That project used a property of transistors called "avalanche noise". Inconveniently, it required a supply of +-10V to work properly. Avalanche noise is sometimes explained as being a "quantum effect" and thus is supposed to be a source of true randomness.
There are other types of physical randomness. One actually exists inside the RP2040 chip already: It has a Ring Oscillator peripheral built in. However, this project shows how to build a Ring Oscillator from a simple "78*14" chip and process it into an infinite unguessable string of bytes using CircuitPython.
I built this project with a QT Py RP2040. It's very simple; the only other required parts are the 74*14 chip, a breadboard, and some wire.
This is not a truly robust RNG and you shouldn't use it for anything serious. For example, someone could tamper with it and just remove the connection between the RP2040 and the ring oscillator; the code wouldn't notice, but its outputs would be exactly the same each time it was powered on. Real RNG products will have part of the software that verifies that the random source is behaving like a random source and is not fixed at a single value, or otherwise trivially predictable.
Ring Oscillator Theory
A Ring Oscillator is based on a ring of an odd number of Schmitt-trigger XOR gates. This project uses three gates in its ring.
The output of gate 1 is tied to the input of gate 2; the output of gate 2 is tied to the input of gate 3, and the output of gate 3 is tied to the input of gate 1.
Suppose you want to know the value that will appear at the output of each gate. Well, let's suppose the input to gate 1 is HIGH. Then we must have:
- Gate 1 input: HIGH output: LOW
- Gate 2 input: LOW output: HIGH
- Gate 3 input: HIGH output: LOW
Notice how we concluded that if the gate 1 input is HIGH, then the gate 1 input is LOW. In philosophy class, you'd call this a logical contradiction and just decide that such a thing cannot exist. But in a physical system, what happens is: Each gate takes some length of time to "drive" its output from HIGH to LOW or vice versa; and each gate has some specific input voltage to determine whether it wants to drive its output HIGH or LOW. And in fact these properties vary unpredictably from moment to moment.
The exact period of a ring oscillator like this varies from moment to moment, depending on many physical details. A lot of ink can be spilled by electronic engineers & physicists about exactly "how random" this is, but a screenshot from a scope shows clearly that over even a short period of time the crests and troughs of the output of the ring oscillator "smear out" across all possibilities: