#circuitpython-dev

1 messages · Page 93 of 1

manic glacierBOT
#

CircuitPython version and board name

tested various versions from
Adafruit CircuitPython 9.2.8 on 2025-05-28; Adafruit QT Py ESP32-S3 4MB Flash 2MB PSRAM with ESP32S3
through
Adafruit CircuitPython 10.1.0-beta.1 on 2025-11-06; Adafruit QT Py ESP32-S3 4MB Flash 2MB PSRAM with ESP32S3

Code/REPL

import time
import random
import os
import wifi
import socketpool
import asyncio


NUM_CLIENTS = 4
NUM_SERVERS = 2
BASE_PORT = 5000
MAXBUF = 64


class Socket:
    """ ...
runic loom
#

Here is a detailed writeup of what I did : https://ashishware.com/2026/01/10/cnn_circuitpython/
Here is link to repository containing required files: https://github.com/code2k13/neural_network_cp

GitHub

Contains information on porting tensorflow or pytorch models to circuitpython - code2k13/neural_network_cp

#

The model is tiny:
Total params: 3,116 (12.17 KB)

Here is link to Kaggle notebook used to train and export model to onnx:
https://www.kaggle.com/code/finalepoch/digit-classifier-to-onnx

It is the same model which I handcoded using ulab and CircuitPython in my below experiment:
https://ashishware.com/2024/06/29/pipico_digit_classification_cnn/

manic glacierBOT
#

Here are my kernel messages for a program that only mounts/umounts a SD-card (no further interaction). Although the kernel claims that it stops polling (line 6), it must be polling since it detects mount/umounts ("detected capacity change").

This would explain the slow down I can see, since the host keeps the device busy with polling the second device. I wonder if exposing the second device could be limited to the REPL-context. Or maybe it could be activated/deactivated by a parameter, e.g. ...

tulip sleet
manic glacierBOT
slender iron
#

I have zephyr setup to rotate through four smaller buffers. The filling thread will wait for the next free buffer once all four are full.

slender iron
#

the memory slab 4 buffer thing will be ok

#

as long as I can get nrfx to not try and free an old buffer

runic loom
runic loom
tulip sleet
runic loom
tulip sleet
#

you could load it from a file instead, then, so you could switch models?

#

load it into an array.array

runic loom
#

You mean the weights of model or the model itself. I mean there are two parts to this. The model structure, that dictates what operations have to be perfromed and the weights used for performing these operations. Weights can be loaded from a file, thats lot easier to achieve

tulip sleet
#

I assumed it was all data (weights), but you're saying there's custom compiled code for the model?

#

or is it pointers?

#

pointers could be converted to relative indices

runic loom
#

yes, the compiled code contains everything like a tar ball, the structure of model (like how many layers, what type of layers) and functions that support inference. A different model will have totally different compiled code.

#

Weights are also in the compiled code , like constants

tulip sleet
#

i see. If the compiled code (functions) are position-independent, then for any particular architecture (M0, M33, M4) they could be loaded at runtime. But that's a whole 'nother structural element to implement

runic loom
#

They could be made position-independent say if we were to use the same model (Structure). Like in my case the model say has 2 hidden convolution layers and input is 30x30 image and output is array of 10 probabilities. A different model will have different structure, hence computations will be totally different (not just the numbers). However, if let us say we decide to have a generic, well known model like yolo8 for example as part of CircuitPython, then I feel it would make sense to enable loading weights into a fixed model structure (computations and their sequence remains unchanged)

tulip sleet
#

got it, thank you, I thought it was more parameterized (at run-time) than it is.

runic loom
#

I wish it was, we could have add a module called neural network in CircuitPython and load the model and weights using some kind of JSON. This can be done to some extend for 'dense neural newtworks' because underlying computational pattern is repeatitive and easy. But for some more exotic types of models like CNN or RNN, this get's tricky. Not saying it cant be done, but quite a bit of work and the layer that does runtime parsing might actually be heavy.

#

Before I log off, you people are doing awesome work. Thank you for your work on CircuitPython

tulip sleet
#

you're welcome, and thanks for your more thorough knowledge than my casual surmises.

manic glacierBOT
manic glacierBOT
manic glacierBOT
tiny peak
#

@slender iron For the Zephyr port, where are things at with how you're implementing USB support? Are you still using TinyUSB, or has that changed? Based on your comments over on the baochip server's not-rust channel, I got the impression that when you mentioned implementing USB support, you meant for Zephyr APIs, not for TinyUSB.

#

Context for the question being, I could potentially start looking at that, but I'd want to make sure I wasn't implementing the wrong API.

slender iron
#

that way it just works

#

we only need usb going after getting the cpu and uart going though

#

usb can wait

tiny peak
#

Otherwise, it would be a matter of translating the drivers to C, I guess.

slender iron
#

I'd just do C

tiny peak
#

Are you assuming that Adafruit will end up attempting to upstream your work or probably just maintain your own fork? Wondering how important it would be to follow all their policies and such. That could be a bit burdensome.

slender iron
#

we want to upstream

#

plus folks will want to run bare zephyr on it

tiny peak
#

Ah, okay. That does complicate things a bit. They have a strict policy on commit signoffs with real names and live emails. among other things

#

I was thinking that with the way they have the build system set up, it might be pretty easy to just keep some board definitions in your own repo if you wanted, then do builds in a workspace with all the regular upstream drivers.

#

Then you'd only need to do the PR bureaucracy shepherding thing if you wanted to upstream driver patches. From reading the discussions in their PRs, getting code merged is typically a serious ordeal. I don't know how people would be willing to do that if they weren't getting a salary for it.

#

Worst case, I suppose I could just figure out techniques that work and somebody could redo it, or we could transfer copyright, if you wanted to upstream that stuff.

#

For the moment, I could probably start working on a stand-alone repo with a board def in the style of the board defs I made last year for some of the Feather S3 stuff. That would work with vanilla Zephyr, and it could probably also be used with your port.

slender iron
#

Yup, I agree that board defs may not be upstreamed

#

and we'll want to have extra

tiny peak
#

oh, that's good news then!

slender iron
#

not sure about peripheral drivers though

tiny peak
#

I think all of that is set up to work optionally out of tree if you want it to be

#

I can definitely look into that

slender iron
#

I plan to upstream what I can

#

but you can make a different choice

tiny peak
#

okay. sounds good. I just don't want to get going down a road that will end up making things more complicated for you rather than easier.

manic glacierBOT
#

Finally had some time to poke at this some more. I've come up with a new example that I apologize is not quite so minimal but it seems to consistently crash a freshly flashed device. Not instantiating tft_featherwing_35.TFTFeatherWing35V2() appears to prevent the crash.

I can't tell if it's a red herring or not but it seems like if I run this while connected to the serial port it crashes hard and no longer even shows up as a drive in Windows, but if I am not connected then it reboots into ...

manic glacierBOT
runic loom
# tulip sleet got it, thank you, I thought it was more parameterized (at run-time) than it is.

@tulip sleet your advice got me thinking. I am trying to write a reusable neural network library entirely in C. The idea is to support a tiny subset of operations needed by dense neural networks and Convolutional Neural Networks. People should be able to create tiny neural networks in Tessorflow/Pytorch, use a custom tool to convert them to *.bin format, and the library would load them. I will try to see how far I go with this idea. Will try this on Pi Pico and ESP S3 boards and come back . Thanks !

tulip sleet
# runic loom <@329766224093249548> your advice got me thinking. I am trying to write a reusa...

Interesting idea! I was wondering if there was an issue about the model not fitting into RAM but it could fit into flash. I think you would need it to be contiguous so you use the flash mapping into the address space and treat it as just read-only memory., as you are now.
MicroPython created a special kind of filesystem to allow loading things into contiguous regions of flash. The FAT filesystem we are using does not guarantee that, and because the microcontrollers do not have page tables to allow us to map file pages into memory regions at low granularity, we can't do that like regular OS's (mmap, etc.)

#

on Espressif or other boards with large PSRAM (some RP2350 boards) it could be copied into contiguous PSRAM from the filesystem.

lone sandalBOT
scarlet fjord
#

i know this is ancient, but im working again on a joystick project and wondering where the gamepad/joystick docs went? this link doesnt seem to work any more

#

or if theres anywhere else that has docs for joystick inputs

lone axle
#

<@&356864093652516868> The weekly meeting will be held here on Discord at the usual time, about 90 minutes from now at 2pm Eastern / 11am Pacific. Feel free to add hug reports and status updates to the notes doc ahead of time https://docs.google.com/document/d/1Kc6iC6-aOjE3SaAg9BfiK8xVNjm9YW0BBSvjk1jHqU8/edit?usp=sharing. We look forward to hearing from all that can attend.

slender iron
#

EPD and LSM6DS don't have semver version numbers. I tried rereleasing them but it doesn't look like the bundle picked up on it.

turbid radish
#

Thanks folks for the likes on my mini-IBM Fruit Jam project

slender iron
#

next week is on Tuesday

turbid radish
#

Lots in the newsletter due to the holiday break

tulip sleet
#

also group hug, checking mic

turbid radish
#

Cool work

slender iron
tidal kiln
#

👋

turbid radish
#

Great meeting @lone axle

lone axle
#

Thanks everyone, have a great week 👋

errant grail
#

Thanks for hosting, Tim!

lone axle
#

Here is the notes document for next Monday’s CircuitPython Weekly Meeting. It is at the normal time of 11am Pacific / 2pm US Eastern here on Discord. Add your hug reports and status updates to the document before the meeting. If you are unable to attend but would still like to contribute, feel free to add your notes and we’ll read them off during the meeting. Hope to see you there! <@&356864093652516868> https://docs.google.com/document/d/1knBYDjHI1NDehhhJfRufXqgP66RPJFA-LNYMTd1-dVA/edit?usp=sharing

candid sun
#

^^ meant to pr my fork, not main

slender iron
#

it has mmc working though

candid sun
slender iron
#

great! I'm thinking about how to get the display going

manic glacierBOT
manic glacierBOT
tender ginkgo
#

Out of curiosity, are there any plans to port Circuitpython to a TRMNL X (ESP32-S3 for 2.4Ghz, plus ESP32-C5 for 5Ghz, 10.3" e-ink display, high density, 1872x1404 resolution, with 16 grayscale. Full refresh <= 1.2s, partial refresh <=200ms) or TRMNL OG (ESP32-C3 based, smaller)

plucky tulip
stuck elbow
#

the drivers for the display may be the main problem

manic glacierBOT
#

CircuitPython version and board name

We made a custom .uf2 file for our board (https://circuitpython.org/board/studiolab_picoexpander/) but when we upload this .uf2 file to the board the MAC address in the boot_out.txt prints 00:00:00:00:00:00, when I upload the Pico 2W .uf2 file to the board, it does print the right MAC address.

Code/REPL

print("hello world")

Behavior

hello world

Description

No response

Additional information

_No res...

manic glacierBOT
manic glacierBOT
slender iron
#

we don't currently support external ESP-C5 afaik. that'd be trickier. the display is an unknown as well

manic glacierBOT
manic glacierBOT
#

I did ask Gemini, and it also suggested this fix, and for my it was so wild that I didn't even try it, i thought it was hallucinating.

Well, I did it without AI, but as something that varied between the working and non-working boards. That is my usual debugging strategy in cases like this: see what's different, and then try undoing the differences Did Gemini say why?

Thinking about this further: using the NeoPixel causes some delays, and it also uses PIO to send the data to the NeoPixel...

manic glacierBOT
#

Makes sense,
This was the response:

I will modify circuitpython/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h to comment out the MICROPY_HW_NEOPIXEL definition, as this is the most likely cause of the WiFi driver failure due to potential PIO resource conflicts. I will leave the SPI definitions untouched for now.

So it seems like a PIO problem. I guess there is no direct solution for this, we will have the students grab the MAC address from code.
Thanks anyways for the...

manic glacierBOT
#

I have a question here before I create a different ticket. I got the same results on a FeatherS3 with ESP32S3 and in testing, it's specifically with the host computer and the board.

In 10.0.3 when connected to my Windows 11 machine and I call:

storage.mount(vfs, "/sd")

The device shows up as a drive.

With the following test code:

import board
import sdcardio
import storage
import time

def test(sleep=False, flush=False):
  spi = board.SPI()
  cs = board.IO33
  sdcard ...
short tendon
#

Random question on preferences. I've been doing a lot of playing around with sensors, and noticed that sensors in a group (let's say pressure), don't always do things the same way, and there's a lot of duplicated code. If I were building these from scratch, I'd create base classes that did the common stuff and import from that. Obviously in CircuitPython that becomes another mpy file, but allows new features to be added globally (for example globally adding more accurate altitude when incorporating temperature).

Is this unified approach something Adafruit would be interested in?

slender iron
#

but it does depend on what is duplicated

short tendon
slender iron
#

meh, I don't really want to add a dep just to have it shared

short tendon
#

I've created a whole unified sensor lib, that takes in all the sensors I have and then can output all sorts of things.

manic glacierBOT
tidal kiln
#

lib bundle build seems broken

#

jan 16 zips both 9.x and 10.x have:

#

adafruit-circuitpython-bundle-10.x-mpy-20260116.zip

lone axle
tidal kiln
#

yep

lone axle
tidal kiln
#

wait. it's something local.

#

looking...

#

ok. the zip content issue is something going on locally. so its me. ignore.

#

@lone axle can you check something else though - what version of Adafruit_CircuitPython_Display_Shapes are you seeing in latest bundle?

tidal kiln
#

thanks. gonna reboot. im stuck in the weirdness multiverse. brb.

tidal kiln
#

@lone axle sry, wrong lib, what version do u see for adafruit_display_text

lone axle
tidal kiln
#

ah. ok. thanks. let me check for that.

#

ok, looks frozen for magtag

#

empty lib folder

#
Adafruit CircuitPython 10.0.3 on 2025-10-17; Adafruit MagTag with ESP32S2
>>> import adafruit_display_text
>>> adafruit_display_text.__version__
'3.3.3'
>>> 
#
>>> import sys
>>> sys.path
['', '/', '.frozen', '/lib']
#

frozen shadows lib

lone axle
#

that project was the impetus for some new functionality and ultimately some refactoring to make BitmapLabel more flexible and reduce the need for having so many different types of labels.

tidal kiln
#

thanks. im looking at guide too...

#

yah, and not seeing anything.

#

but ok, that generally explains things. i think/hope 🙂

lone axle
#

The version of display text downloaded by the project bundle button should be the latest, but it does need to be placed in the root instead of lib where it is in the bundle zip.

#

I'll add an alert to the guide shortly.

tidal kiln
#

thanks. yep. that's the general issue.

#

gotta work around the frozen version

#

the screen cap also shows it sitting in lib

lone axle
tidal kiln
#

cool. thanks! glad you were around for this 🙂

lone axle
#

okay, the screenshot is updated now too. I'll need to remember to swap that back to linking the one from github once the next release of cp core is made.

manic glacierBOT
manic glacierBOT
main furnace
#

I'm working on an MCP to allow Claude Desktop or any other agent with MCP support to read and write code on an attached CIRCUITPY drive. It also supports web workflow.

manic glacierBOT
lone sandalBOT
lone sandalBOT
lone sandalBOT
lone sandalBOT
lone sandalBOT
vague thicket
#

Hello, I´m trying to update the definition of my board (es3ink) as I want to use a different ESP32-S3 module (N4R2 instead of N16R8). I´m building CPY fw locally in my VM, and I have 2 issues with it.
I can build UF2 file, but when I put my board in bootloader mode, and I copy the fw file to the board, when it finishes uploading, it does not auto-restart as it should. Then, when I restart it manually, it jumps to the reboot loop, and the CPY drive does not show up.
I´m attaching the log file from this loop. I tried to upload the UF2 file with the latest fw from adafruit_feather_esp32s3_4mbflash_2mbpsram, which has the same module, and this fw is working fine. I tried to find a solution to my problem, but I did not find any here or online. Any help is really appreciated.

lone sandalBOT
lone sandalBOT
lone sandalBOT
tulip sleet
small cypress
# manic glacier

@slender iron Hey, hope you don't mind me asking here, but I was wondering if this being closed means the M5Stack Tab5 is fully supported in CP now?

manic glacierBOT
#

@muhammadawais92: one last thing to try: swap the order of initialization of RFM9x and of the SD card. There is some myth about needing to initialize the SD-card first (see https://github.com/adafruit/Adafruit_CircuitPython_SD#sharing-the-spi-bus-with-other-devices), which I never understood. But incidentally, my code does initialize the SD card first and then the LoRa device. So it might be worth a try.

manic glacierBOT
#

I'm seeing this again, on a Heltec V3.2. Google says: The Heltec V3.2 is a hardware revision of the V3, primarily fixing issues and improving the power/charging circuit with a new LDO voltage regulator (CE6260B33M), a better charging chip (LGS4056H), and updated layouts based on Espressif recommendations, plus a change to the Vext detection (requiring GPIO 37 pull-up) for better stability, while V3.1 used a [FET] switch and different components, making V3.2 generally more reliable for power...

manic glacierBOT
manic glacierBOT
manic glacierBOT
manic glacierBOT
#

I object to the changes in .devcontainer/. They are unrelated to this PR. They put temporary/build-environment files below the circuitpython/ directory, so running git status will detect new and non-commited files. Also, these changes do not improve anything.

Please revert these changes.

Thanks for spotting those!
I found the dev container doesn't have write access to /workspaces/ so the current scripts do not work for raspberry pi (+cortex-m). I'll drop from this PR and fi...

manic glacierBOT
tulip sleet
lone sandalBOT
thorny jay
tulip sleet
slender iron
#

@tulip sleet I'm home with Rynn. I'm going to try to make the meeting but if I don't respond then just read stuff off

thorny jay
lone axle
tidal kiln
#

plz read

#

thanks!

lone axle
#

cookiecutter I think.

slender iron
#

thanks all!

lone axle
#

Thanks for hosting Dan, have a great week everyone.

tulip sleet
#

Here is the notes document for next Monday’s CircuitPython Weekly Meeting. It is at the normal time of 11am Pacific / 2pm US Eastern here on Discord. Add your hug reports and status updates to the document before the meeting. If you are unable to attend but would still like to contribute, feel free to add your notes and we’ll read them off during the meeting. Hope to see you there! <@&356864093652516868> https://docs.google.com/document/d/1Db6h50frFZKWA3bCOdiDdZEkdtajotgL1SWobppy938/edit?usp=sharing

slender iron
slender iron
slender iron
#

@tulip sleet how are you capturing the additional socket requirements you are finding? could we add them as tests?

tulip sleet
#

I was planning to write some tests. Right now they are error conditions to be detected.

#

There is not necessarily consistency between what the POSIX socket API does and what CPython does, and it varies across OS's also.

#

I should see whether the POSIX socket spec describes this kind of thing

#

the Python doc does, to some extent (you can't bind() twice, for instance), but it's kind of vague in other ways. And since sockets cover a lot of protocols, it's not that specific

slender iron
#

It'd be nice to have it for CP anyway to make it consistent across impls

manic glacierBOT
vague thicket
# slender iron what bootloader are you using?

@tulip sleet @slender iron thank you for your help, but I did find out that I forget to make "make clean BOARD=" when I made changes, so my issue was that I was still using same config for the board from old config. This is solved.

tulip sleet
manic glacierBOT
#

I found the dev container doesn't have write access to /workspaces/ so the current scripts do not work for raspberry pi (+cortex-m).

This is strange because it worked in the past, but maybe Github has changed something. I haven't used this recently. I will check tomorrow and see how this can be fixed. Anyhow, this should be handled in a separate issue/PR.

Before you go wasting too much time testing, it was insanely slow to compile for me compared to WSL native folders, and I mig...

manic glacierBOT
#

I have a question here before I create a different ticket. I got the same results on a FeatherS3 with ESP32S3 and in testing, it's specifically with the host computer and the board.

In 10.0.3 when connected to my Windows 11 machine and I call:

storage.mount(vfs, "/sd")

The device shows up as a drive.

With the following test code:

import board
import sdcardio
import storage
import time

def test(sleep=False, flush=False):
  spi =...
manic glacierBOT
manic glacierBOT
#

Learned some new stuff about OS support for USB CDC-ECM, RNDIS, and CDC-NCM...

From what I read, prior to Windows 11, to get reliable cross-platform support, you had to implement a composite device with RNDIS for Windows and CDC-ECM for everything else. This is how BeagleBone Black was traditionally set up (recent firmware may be different).

As of Windows 11, Microsoft provides a CDC-NCM driver which is [recommended](https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/supporte...

manic glacierBOT
#

@tyeth I just tested it: /workspaces is writable and the exiting scripts just work. /workspaces is owned by user 'codespace' and that is the user that I am automatically login with.

So this might really be a problem caused by what you did. Or by something going on in the backgroud, it is a cloud platform after all and things are updated once in a while and if you use it at the wrong moment things might break.

manic glacierBOT
manic glacierBOT
#

CircuitPython version and board name

Adafruit CircuitPython 10.0.3 on 2025-10-17; FeatherS3 with ESP32S3

Code/REPL

import board
import sdcardio
import storage
import time

def test(sleep=False, flush=False):
  spi = board.SPI()
  cs = board.IO33
  sdcard = sdcardio.SDCard(spi, cs)
  vfs = storage.VfsFat(sdcard)
  storage.mount(vfs, "/sd")
  
  if sleep:
    time.sleep(5)
  
  with open("/sd/test.txt", "w") as f:
    for i in range(200):
      print(i)
      ...
manic glacierBOT
#

CircuitPython version and board name

Adafruit CircuitPython 10.0.3 on 2025-10-17; Adafruit Feather RP2040 with rp2040

Code/REPL

Contents of boot.py:

import usb_hid

GAMEPAD_REPORT_DESCRIPTOR = bytes((
    0x05, 0x01,  # Usage Page (Generic Desktop)
    0x09, 0x05,  # Usage (Gamepad)
    0xA1, 0x01,  # Collection (Application)
    0xA1, 0x00,  #   Collection (Physical)
    0x05, 0x09,  #     Usage Page (Button)
    0x19, 0x01,  #     Usage Minimum (Button 1)...
manic glacierBOT
#

There is no such argument name as custom_devices= for usb_hid.enable(). See https://docs.circuitpython.org/en/latest/shared-bindings/usb_hid/index.html#usb_hid.enable.

That call is failing. Look for errors in boot_out.py. That's why the tree default devices are showing up instead of just one.

My suspicion is that this was AI generated code. Please check such code for errors.

manic glacierBOT
manic glacierBOT
#

All the scripts in .devcontainer are targeted at (online) Github codespaces. At the time of writing them, dev containers weren't available locally. Even now, local devcontainers don't provide the full functionality. VSC expects a .devcontainer/devcontainer.json, but this does not exist for CircuitPython, since there are port-specific .devcontainer/<port>/devcontainer.json files which you can select at container creation from Github, but not locally from VSC.

Nevertheless, it might be...

manic glacierBOT
manic glacierBOT
manic glacierBOT
lone sandalBOT
manic glacierBOT
#

Dan, sincere thanks for your patient and helpful guidance. Some of the above example code was indeed AI-generated, not because I had asked Copilot (or some such) to gin up a solution, but because I had foolishly relied on Google's AI Overview in the search results. As you rightly point out, boot_out.txt is an excellent tool for troubleshooting. I reviewed all local code against the docs, supplemented by your Adafruit article with Jeff Epler, "Custom HID Devices in CircuitPython," and am hap...

manic glacierBOT
#

Happened to be looking at the docs, and noticed that the docstring and type annotation do not match. Looking at shared-bindings, it looks like it could be EITHER int or None depending on the input buffer (and whether it is actually a writable buffer):

import board
import audiobusio
mic = audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA)
buffer = bytearray(100)
print(mic.record(buffer, 10))  # prints 10
print(mic.record(123, 10))  # prints None

Is this inte...

manic glacierBOT
manic glacierBOT
manic glacierBOT
manic glacierBOT
#

The descriptor is set up in pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c, including fetching the unique id with pico_get_unique_board_id_string(), which is defined in pico-sdk/src/rp2_common/pico_unique_id/unique_id.c.

Changing this would require forking or at least modifying pico-sdk. The iManufacturer, etc. would also not match the device you're emulating, I think? But maybe you are redefining those already.

manic glacierBOT
#

There were a bunch of changes to enable the boards:

  • Add web workflow for sdioio cards. Adds the "native" access.
  • Introduce i2cioexpander for native I2C expander support.
    • Introduce DigitalInOut protocol so that IOPins can be used where DigitalInOut would be traditionally.
    • Add mp_errno_t for clarifying what APIs return errno.
    • DigitalInOut protocol uses it to pass through I2C issues.
    • Switch bitbangio and fourwire to DigitalInOutProtocol.
    • Support the Mini's ...
manic glacierBOT
manic glacierBOT
manic glacierBOT
#

The iManufacturer, etc. would also not match the device you're emulating, I think? But maybe you are redefining those already.

idVendor, idProduct, iManufacturer, iProduct can be changed using supervisor.set_usb_identification()
iInterface can be changed by using usb_hid.set_interface_name()
iSerial is only one left unloved

The descriptor is set up in pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c, including fetching the unique id with `pico_get_unique...

manic glacierBOT
#

According to their docs page, the sticker on the back of the unit (not seemingly the box) is the thing to look at:

Starting from October 14, 2025, the Tab5’s original independent display driver ILI9881C and touch driver GT911 will be replaced by the integrated display‑touch driver ST7123. Some early firmware builds may not run properly. The latest versions of M5Unified and M5GFX have already been adapted for compatibility with this new screen driver...

manic glacierBOT
manic glacierBOT
manic glacierBOT
candid sun
#

<@&356864093652516868> We'll have our weekly meeting in about 90 minutes from now in this text channel and in the circuitpython voice channel. Please take the time to add your notes in advance to the document: https://docs.google.com/document/d/1Db6h50frFZKWA3bCOdiDdZEkdtajotgL1SWobppy938/edit?tab=t.0 -- I look forward to everyone's updates!

manic glacierBOT
#

I was planning to order one from Mouser, though no idea which I'll get. Does the model with the old display driver chips work in CP?

The old display driver one will start up and have CIRCUITPY on the USB. Many of the internal chips like the audio haven't been added.

You may need to comment out the old display init to get it going on a new one. I can't remember how I left it. The USB should work just fine though. Once the display init sequence is tested, then it'll work too.

turbid radish
#

Folks, I'm looking for ways I can increase the number of subscribers for the Python on Microcontrollers Newsletter.

lone axle
tulip sleet
#

just read mine

wraith crow
#

Thanks all 👋

turbid radish
#

Thanks all

#

Thanks Liz

lone axle
#

Thanks for hosting Liz, have a great week everyone 👋

slender iron
#

Thanks Liz!

candid sun
#

thanks folks!

#

Here is the notes document for next Monday’s CircuitPython Weekly Meeting. It is at the normal time of 11am Pacific / 2pm US Eastern here on Discord. Add your hug reports and status updates to the document before the meeting. If you are unable to attend but would still like to contribute, feel free to add your notes and we’ll read them off during the meeting. Hope to see you there! <@&356864093652516868>

https://docs.google.com/document/d/1wMpXc_QzzngY0Nk-AnDDyDzIqjy_pXXW76yKbKys838/edit?tab=t.0

manic glacierBOT
manic glacierBOT
#

CircuitPython version and board name

Adafruit CircuitPython 10.0.3 on 2025-10-17; Adafruit QT Py ESP32-S3 no psram with ESP32S3

Code/REPL

# Running hello world but this is not a code issue but a BLE Workflow issue.

Behavior

BLE Workflow does not seem to accept any input or respond to the Chrome Browser. It does output REPL but no input is seen. Neither can the Open button dialog populate the files on the drive.

Output on serial window:

orchid basinBOT
manic glacierBOT
orchid basinBOT
serene token
#

In Framebuffer_RP2350.c, there is the following line variable declaration:

int8_t pins[8] = {
        clk_dp->number, clk_dn->number,
        red_dp->number, red_dn->number,
        green_dp->number, green_dn->number,
        blue_dp->number, blue_dn->number
    };

The various structs referenced here are passed into the function (common_hal_picodvi_framebuffer_construct()). I need to figure out what the actual pin numbers are (in Pico-SDK terms), not Arduino or CP).

#

Oh, I almost forgot: For the Fruit Jam specifically.

serene token
serene token
#

That's definitely closer! Now, is "pin_GPIO12" pin 12 in Pico SDK terms or in CP terms?

#

Wait, got it. Pins 12 through 19 are the pin numbers for HSTX in Pico SDK terms, so these must be in Pico SDK terms. Awesome. That should do it. Thanks!

stuck elbow
#

GPIO12 is the pin labeled "12" on the pi pico

serene token
#

Right. My problem was figuring out the order, because the HSTX peripheral uses a different pin order on some boards than others, and I couldn't find the Fruit Jam pin order. Thanks again!

inner orbit
#

I am compiling CP for Trinket M0, removing some built-in libs I don't need. What I want to do is include some CONST in the build to save RAM usage. Google AI says this and that, but not specifically where to add the definitions. Are there docs relating to this process anywhere on the 'net.

slender iron
manic glacierBOT
#

Implement wifi/socketpool/ssl for Airlift (NINA-FW) co-processors.

Starting this as a draft, for testing purposes. Tested with Adafruit NINA-FW 3.4.0.

  • Web workflow not yet implemented.
  • HTTP and HTTPS client work. UDP client and server work.
  • HTTP server gets an error after a minute or so of continuous polling, alternating GET_STATE_TCP_CMD and AVAIL_DATA_TCP_CMD. The failure is that the ready line from the AirLift is in the wrong state. This may be some failure or race conditi...
inner orbit
#

Which I guess could be a python lib. just not much going on in it except decarations.

#

I am trying to figure out where to put said declarations so they compile correctly.

manic glacierBOT
slender iron
inner orbit
#

Save RAM space. If I declare the variable in code.py, for example, it will push it into RAM. I would like to compile it into the firmware, as I have space there, to conserve the RAM. If it is not possible, I accept that. Kind of like how PROGMEM works in Arduino.

manic glacierBOT
inner orbit
#

Thanks for the help on my question. I think I found out how to integrate my own modules into my CP build.

manic glacierBOT
slender iron
slender iron
#

heh, I mistype codespell in my commit message

manic glacierBOT
manic glacierBOT
#

CircuitPython version and board name

Adafruit CircuitPython 10.0.3 on 2025-10-17; Adafruit Feather RP2040 Prop-Maker with rp2040

Code/REPL

storage.mount(vfs, "/sd", readonly=True)

Behavior

OSError: [Errno 2] No such file/directory:

Description

hey folks, I came across this bug while working on this project: https://learn.adafruit.com/color-sensing-music-player

The code uses storage.mount(vfs, "/sd", readonly=True) that allows writing files ...

manic glacierBOT
manic glacierBOT
#

CircuitPython version and board name

Adafruit CircuitPython 10.0.3 on 2025-10-17; Adafruit Feather ESP32S3 4MB Flash 2MB PSRAM with ESP32S3

Code/REPL

#
# i2c_power test
# 2026-01-27
#
# Test to see if i2c_power can be toggled before/after deep sleep and maintain setting through deep sleep
#

import board
import busio
import time
import digitalio
import adafruit_ens160
import alarm

print("\nESP32-S3 i2c_power test")

# Enable i2c_power pin to turn-on i2c pow...
manic glacierBOT
#

CircuitPython version and board name

Adafruit CircuitPython 10.1.0-beta.1-dirty on 2026-01-28; Adafruit QT Py RP2040 with rp2040

Code/REPL

# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import supervisor
import time

# Wait for USB serial to settle ; otherwise may lose initial console output
while not supervisor.runtime.serial_connected:
	time.sleep(0.001)
print("Start USB Serial")

import board
import displ...
tulip sleet
manic glacierBOT
#

@NateChurch TOML wants strings to have quotes: https://toml.io/en/

Good point. I wasn't thinking of it as a toml, I was thinking of it as an .env which of course is the problem you point out later in the thread. I realize that all of this was months ago, but wanted to chime in that I like #3 and #4 also. Those feel like the best logical solution to align with expectations and behaviors in big python. There could also be a toml library like in big py...

manic glacierBOT
#

CircuitPython version and board name

Adafruit CircuitPython 10.0.3 on 2025-10-17; Seeed Xiao ESP32-S3 Sense with ESP32S3

Code/REPL

import board
import audiocore
import audiobusio

audio = audiobusio.I2SOut(board.A2, board.A1, board.A0)

# An example of the samples. It's truncated (they're very long), but the same behaviour happened with anything I tried to play.
samples = array('h', [10390, 10470, 10410, 10230, 10020, 9890, 9920, 10150, 10390, 10440,...

raw...
tulip sleet
#

@slender iron in the zephyr port, in build_circuitpyhon.py, these are defined but are not defined as 1 or as the value of some variable. Is that intentional?
(trying to fix some build errors in my airlift PR)

    circuitpython_flags.append("-DINTERNAL_FLASH_FILESYSTEM")
    circuitpython_flags.append("-DLONGINT_IMPL_MPZ")
    circuitpython_flags.append("-DCIRCUITPY_SSL_MBEDTLS")
slender iron
#

Nope, you can change them

tulip sleet
#

where is the master list of the .toml variables? That is what I think I am looking for?

slender iron
#

I'm not sure what you mean by toml variables. Those are ones that would traditionally be in mpconfig.mk

tulip sleet
#

right, so like how do it create ``./boards/nordic/nrf7002dk/autogen_board_info.toml`? How does make know what to set those values to?

slender iron
#

that is created when you do a zephyr build

tulip sleet
#

is there a default .toml file? Where are the variations kept, in circuitpyt.toml?

slender iron
#

but there is an update script in cptools

tulip sleet
#

how does it know which ones to set to which values?

slender iron
#

zephyr2cp.py determines what modules to enable based on the zephyr device tree

#

the toml files are for the doc build so it doesn't need all of zephyr to determine it

tulip sleet
#

ok, I'll dive down on those, thanks

slender iron
#

what are you trying to fix?

tulip sleet
#

i added CIRCUITPY_SSL_NATIVE, which determines CIRCUITPY_SSL_MBEDTLS on some ports (e.g. espressif).

#

so on boards that used to say CIRCUITPY_SSL = 1, now they say CIRCUITPY_SSL_NATIVE = 1

#

(except for airlift-capable boards)

#

there's a CIRCUITPY_SSL_AIRLIFT

manic glacierBOT
#

Complete CircuitPython support for the Waveshare ESP32-S3 Touch AMOLED 2.41 board featuring:

  • Hardware-accelerated graphics (DMA, JPEG decoder)
  • Native Text - 7 built-in fonts (8×8 to 32×48)
  • Graphics - Lines, circles, rectangles, fills
  • Images - BMP and JPEG with hardware decoder
  • Double Buffering - Zero tearing animations
  • Performance - 60+ FPS capable

Documentation, technical details, examples, etc.:
https://github.com/ppsx/ws-esp32-s3-amoled-241

tulip sleet
#

so normally a native wifi board would set

CIRCUITPY_WIFI_NATIVE = 1
CIRCUITPY_SSL_NATIVE = 1
CIRCUITPY_SOCKETPOOL_NATIVE = 1
#

now (in my PR)

#

so need to do the same for zephyr

#

there is still a CIRCUITPY_SSL which gets set when any of CIRCUITPY_SSL_* gets set, etc.

slender iron
#

I think CIRCUITPY_SSL is set in build_circuitpython.py

#

but maybe it is in zephyr2cp

tulip sleet
#

there's a lot of logic in the .mk files to cascade these. circuitpython_flags.append("-DCIRCUITPY_SSL_MBEDTLS")

#

is the only mention of SSL in either file

slender iron
#

CIRCUITPY_<module name> is automatically added

tulip sleet
#

like now I have

ports/espressif/mpconfigport.mk
53:CIRCUITPY_SSL_MBEDTLS = $(CIRCUITPY_SSL_NATIVE)
slender iron
#

you want EXTRA_FLAGS in build circuitpython

#

did you remove CIRCUITPY_SSL?

tulip sleet
#

no, it's still there, but now it's cascaded off the others, and not set explicitly for a particular board or port

manic glacierBOT
#

Pull request overview

This pull request adds comprehensive CircuitPython support for the Waveshare ESP32-S3 Touch AMOLED 2.41 board, featuring a native RM690B0 AMOLED display driver with QSPI interface support, hardware-accelerated image conversion (BMP/JPEG), and ESP32-native SD card support.

Changes:

  • New rm690b0 module with native QSPI display driver supporting hardware DMA, built-in fonts (7 sizes), and drawing primitives
  • Image conversion utilities with BMP and JPEG support ...
#

Buffer overflow vulnerability: the code verifies data_offset < bmp_size at line 204, but then at line 216 it checks if data_offset + (row_stride * height) > bmp_size. However, the calculation row_stride * height can overflow if both values are large, causing the check to pass incorrectly. This could lead to reading beyond the buffer bounds. Consider checking for overflow in the multiplication before performing the bounds check.

#

Missing memory allocation check. The code allocates self->card with malloc on line 77, then immediately checks if it's NULL on line 78. However, if malloc fails, the code jumps to cleanup and calls spi_bus_free. But if the SPI bus was already initialized (ESP_ERR_INVALID_STATE case on line 60), the code marks self->spi_bus_initialized as false (implicitly by not setting it), so the cleanup won't free the bus. This is correct. However, the error message "No memory for SD card structure" at lin...

#

Inconsistent parameter naming between function signature and documentation. The parameter is named spi_or_cs in the function signature (line 40) but the documentation at lines 24-36 describes it as handling either "a busio.SPI object (Pattern 1) or CS pin (Pattern 2)". The name is clear, but ensure that all documentation examples use the correct parameter name.

#

Integer overflow in row stride calculation. The expression ((width * bytes_per_pixel + 3) & ~3) can overflow if width is very large. For example, if width is 0x40000000 and bytes_per_pixel is 4, the multiplication overflows before the padding is added. This could result in an incorrect row_stride value and subsequent buffer overread. Add overflow checking before the multiplication.

#

Resource leak: if IMAGE_MALLOC succeeds but jd_prepare fails, the work_buffer is freed correctly. However, if jd_prepare succeeds but the validation checks on lines 450-453 or 456-458 fail, the function returns without calling jd_decomp, but still frees the work_buffer. This is correct. But if jd_decomp itself is never called and ctx fields are left uninitialized in certain error paths, verify that all error paths properly free the work_buffer.

#

Incorrect bit manipulation for mirror_y. The code at line 308 logs an error saying "mirror_y is not supported by this panel" and returns ESP_ERR_NOT_SUPPORTED, but then continues to call tx_param at line 311, which will execute the MADCTL command with potentially incorrect values. The function should return immediately after setting the error, not continue execution. Change line 309 to return ESP_ERR_NOT_SUPPORTED; instead of just assigning to ret.

tulip sleet
#

because there are still plenty of conditional compilation guards for SSL in general

#

ok, I see EXTRA FLAGS

#

i see, this is fairly incomplete, because it's just what you needed to get those particular boards to build

slender iron
#

That's where you can add the other extra flags

#

yup, but all module flags are implicit rather than explicit like they are the mk

tulip sleet
#

so I will try this:

EXTRA_FLAGS = {
    "busio": ["BUSIO_SPI", "BUSIO_I2C"],
    "ssl": ["SSL_NATIVE", "SSL_MBEDTLS"],
}
#

and remove the other mention

slender iron
#

👍

tulip sleet
#

probably need similar for socketpool and wifi

manic glacierBOT
manic glacierBOT
#

The code is already correct - all error paths properly free work_buffer. The user's concern was valid to raise, but upon verification, there are no resource leaks in these functions.

However, I notice one potential issue: the ctx fields initialization is sufficient since the struct is fully initialized with designated initializers. But for robustness and to make the code's correctness more explicit, I can add a comment clarifying this.

Actually, looking more closely at the user's concer...

#

Given the size and style of this PR I suspect it was done via LLM agent. In principle that is ok but I'd like you to say so upfront. Please also state 1) What prompts you did and 2) how you tested it.

This PR has been mostly created with AI agents usage. Claude Opus + Claude Sonnet + Gemini Pro. Can't tell exact prompts because there were thousands of them.
I was working on that port for over 4 months (with some breaks).

Testing - mostly manual. Hundreds of flashed builds. Tens of te...

#

I can confirm this issue affects both the M5Stack CoreS3 and CoreS3 SE.

While working on a new board definition for the CoreS3 SE, I tested SD card functionality extensively:

  • Stock CoreS3 firmware (10.0.3 stable): sdcardio.SDCard(spi, board.SDCARD_CS) returns OSError: no SD card. The pure Python
    adafruit_sdcard driver also fails with the same error. Tested with multiple SD cards formatted as both FAT32 and exFAT.
  • Custom CoreS3 SE firmware: Same behavior. I also tried adding co...
#

There is a lot of of new device-specific code here, but underneath, there could be more generality that would add capabilities for more boards than this. It could be broken out into multiple PR's.

I am impressed by the amount of effort, but it has ended up being very specific.

  • espsdcard: instead of adding a new module, I think the implementation could have replaced sdcardio, with additional features that are not implemented on other ports.
  • JPEG support: can the ESP JPEG support repl...
manic glacierBOT
#

Agree that I've added some code specifically for this board.

#

Summary

  • Adds board definition for the M5Stack CoreS3 SE, a variant of the CoreS3 with camera/sensors removed, paired with the M5GO Battery Bottom3 (10x NeoPixels, IR transmitter, 500mAh battery)
  • Based on the existing m5stack_cores3 board with modifications for the SE hardware differences
  • SD card CS (GPIO4) is driven high before display init to mitigate shared SPI bus contention

Changes from CoreS3

File Changes
mpconfigboard.h Board name, NE...
tulip sleet
#

@slender iron further on mpconfig stuff and zephyr:
In py/circuitpy_mpconfig.mk we have:

CIRCUITPY_IPADDRESS ?= $(CIRCUITPY_WIFI)

In the zephyr nrf7002dk/autogen_board_info.toml we have:

ipaddress = false

because it's not turned on explicitly anywhere.
So should IPADDRESS be in EXTRA_FLAGS or as yet another

 circuitpython_flags.append(...)

? There is a lot of logic in circuitpy_mpconfig.mk that we have to put somewhere.

slender iron
#

it'd go in build_circuitpython.py

#

I think there is an if branch for wifi

tulip sleet
#
    if board_info["wifi"]:
        enabled_modules.add("wifi")
        module_reasons["wifi"] = "Zephyr board has wifi"
#

ok, I see

#

i will .add ipaddress

slender iron
#

module_reasons ends up as the comment in the toml

tulip sleet
#

do i have to do a clean build after modifying build_circuitpython.py?

slender iron
#

I don't think so

tulip sleet
#

i have one more issue where some routines in common-hal Socket.o are not being linked, despite being in the .o. They are referenced in a static routine in shared-bindings Socket.c. This is like not enough passes through the .a or .o files

#

years ago I saw something like this when files were in the wrong order in the linker line

slender iron
#

I thought we grouped them all together anyway

tulip sleet
#

that's what I thought, i have not seen something like this

#

there are other routines in the same .o that are linked just fine

#

and they are already declared in a .h that was included

#
/home/halbert/zephyr-sdk-0.17.4/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd: libcircuitpython.a(Socket.o): in function `socket_ioctl':
/home/halbert/repos/circuitpython/shared-bindings/socketpool/Socket.c:458: undefined reference to `common_hal_socketpool_socket_readable'
/home/halbert/zephyr-sdk-0.17.4/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd: /home/halbert/repos/circuitpython/shared-bindings/socketpool/Socket.c:461: undefined reference to `common_hal_socketpool_socket_writable'
#

since this USED to work, it's something that I have introduced in some way in the PR

slender iron
#

lemme look at your changes

tulip sleet
#

i pushed the latest

slender iron
#

you renamed the functions but didn't in the zephyr port

#

common_hal_socketpool_readable -> common_hal_socketpool_socket_readable

tulip sleet
#

i knew that -- i thought I had checked it 🙂

#

thanks for your eyes on that

#

now compiles 🙂

manic glacierBOT
manic glacierBOT
#

A potential workaround is to disable auto reload in boot.py
import supervisor
supervisor.runtime.autoreload = False
and configure a button in code.py (and note the trailing comma after 'BUTTON')
import keypad
button_restart = keypad.Keys((board.BUTTON,), value_when_pressed = False, pull = True)
while True:
p = button_restart.events.get()
if p is not None and p.pressed is True:
displayio.release_displays()
supervisor.reload()

manic glacierBOT
manic glacierBOT
manic glacierBOT
#

Summary

  • Adds board definition for the OHARARP ESP32-B, an ESP32-S3-WROOM-1-N16R8 based Feather-compatible board
  • 16MB QIO flash, 8MB OPI PSRAM, native USB-C
  • On-board peripherals: DS3231MZ+ RTC (coin cell backup), AT24CS32 I2C EEPROM, micro SD (SPI), NeoPixel, status LED, 2 user buttons, STEMMA/Qwiic I2C connector

Test plan

  • [ ] CI builds firmware successfully for ohararp_esp32b
  • [ ] Flash resulting firmware to hardware and verify USB CDC console
  • [ ] Verify board. pin names...
manic glacierBOT
orchid basinBOT
lone sandalBOT
manic glacierBOT
manic glacierBOT
lone sandalBOT
manic glacierBOT
#

Thanks again for your feedback, @dhalbert.

  • espsdcard: I removed this custom module entirely. After further testing, I found that the standard sdcardio module, when properly configured (20MHz baudrate and VFS optimization), achieves ~645 KB/s read speeds. This is parity with the native driver performance, so no custom C code or backend integration is needed for SD support anymore.

  • JPEG support: I have removed the custom esp_jpeg shim. I am now using the standard jpegio module...

manic glacierBOT
#

CircuitPython version and board name

Adafruit CircuitPython 10.0.3; micro:bit v2 with nRF52833

Code/REPL

import time
import digitalio
import board

led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
while True:
    led.value = True
    time.sleep(0.1)
    led.value = False
    time.sleep(0.1)

Behavior

Serial console setup

Auto-reload is off.
Running in safe mode! Not running saved code.

You are in safe mode bec...
orchid basinBOT
manic glacierBOT
tidal kiln
#

is there something happening with ⁨PDMin⁩? or something has changed? basic example is not working with latest but is working with older release.

#

⁨```py
import time
import array
import math
import board
import audiobusio

Remove DC bias before computing RMS.

def mean(values):
return sum(values) / len(values)

def normalized_rms(values):
minbuf = int(mean(values))
samples_sum = sum(
float(sample - minbuf) * (sample - minbuf)
for sample in values
)

return math.sqrt(samples_sum / len(values))

Main program

PDMIn(clock, data)

PDM_CLK = board.SCK
PDM_DAT = board.MISO
mic = audiobusio.PDMIn(PDM_CLK, PDM_DAT, sample_rate=16000, bit_depth=16)
samples = array.array('H', [0] * 160)

while True:
samples_recorded = mic.record(samples, len(samples))
magnitude = normalized_rms(samples)
print(samples_recorded, (magnitude,))
time.sleep(0.1)

#

⁨```py
Adafruit CircuitPython 10.0.3 on 2025-10-17; Adafruit QT Py RP2040 with rp2040

import pdm_test
160 (27868.4,)
160 (27800.1,)
160 (28557.6,)
160 (27592.9,)
160 (30034.0,)
160 (27794.3,)
160 (31051.4,)
160 (27718.9,)
160 (31760.0,)
160 (27820.6,)
160 (32098.1,)
160 (27696.6,)
160 (32036.7,)
160 (27840.9,)
160 (31387.6,)

#

⁨```py
Adafruit CircuitPython 6.2.0 on 2021-04-05; Adafruit QTPy RP2040 with rp2040

import pdm_test
160 (68.3422,)
160 (85.6272,)
160 (56.5817,)
160 (70.3068,)
160 (817.971,)
160 (914.963,)
160 (2242.5,)
160 (1457.44,)
160 (2299.47,)
160 (1060.62,)
160 (401.675,)
160 (66.1168,)
160 (49.2124,)
160 (57.3926,)

#

"not working" = the values do not change when making noise vs. silence

tulip sleet
#

@tidal kiln I'm assuming you found a bug; I don't see an existing issue, so please open one. Maybe it's RP2xxx-specific? also report when it started failing -- that's very helpful of cours

tidal kiln
#

i searched issues too and did not find anything. wanted a second look before i opened something. thanks!

manic glacierBOT
#

CircuitPython version and board name

Adafruit CircuitPython 7.2.0 on 2022-02-24; Adafruit QT Py RP2040 with rp2040

Code/REPL

import time
import array
import math
import board
import audiobusio


# Remove DC bias before computing RMS.
def mean(values):
    return sum(values) / len(values)


def normalized_rms(values):
    minbuf = int(mean(values))
    samples_sum = sum(
        float(sample - minbuf) * (sample - minbuf)
        for sample in values
    )

  ...
tidal kiln
#

@danh ^^ (and anyone else)

tulip sleet
slender iron
#

<@&356864093652516868> We'll have our weekly meeting in about an hour from now in this text channel and in the circuitpython voice channel. Please take the time to add your notes in advance to the document: https://docs.google.com/document/d/1wMpXc_QzzngY0Nk-AnDDyDzIqjy_pXXW76yKbKys838/edit?tab=t.0

manic glacierBOT
slender iron
#

@lone axle could you record for me please? my obs isn't starting up

lone axle
#
manic glacierBOT
#

Some test code I have been running on a PyPortal, which is basically like the typical WiFi test program you find in the guides.
Update the NINA-FW firmware on the AirLift co-processor to whatever is latest (currently 3.3.0).

import os
import board
from digitalio import DigitalInOut
import displayio
import ipaddress
import ssl
import wifi
import socketpool
import adafruit_requests
import sys
import time

displayio.release_displays()

# URLs to fetch from
HTTP_TEXT_URL =...
turbid radish
tidal kiln
#

👋

lone axle
#

Thanks for hosting Scott, have a great week everyone.

slender iron
#

@proven garnet I saw your note about using wokwi for memory testing and I think it'd be more worth while to try using the zephyr native_sim

lone axle
slender iron
#

Here is the notes document for next Monday’s CircuitPython Weekly Meeting. It is at the normal time of 11am Pacific / 2pm US Eastern here on Discord. Add your hug reports and status updates to the document before the meeting. If you are unable to attend but would still like to contribute, feel free to add your notes and we’ll read them off during the meeting. Hope to see you there! <@&356864093652516868> https://docs.google.com/document/d/1IsTbby5z8HJsNUdXBPoZI_zjVHO8dWR2t4TjUnRrmFc/edit?usp=sharing

manic glacierBOT
manic glacierBOT
#

I suggested some minor file changes.

I thought about Union[microcontroller.Pin, digitalio.DigitalInOutProtocol] a bit, but didn't come to any conclusions. In the long run we might remove passing a Pin, perhaps. A long time ago I proposed a Pin.Configuration type in #9845, and that is a bit related to this kind of change

I tried some smoke tests on boards with fourwire displays, since there were significant changes there. Some worked; most did not. So there's some debugging to do on t...

short tendon
#

@tulip sleet I think I have every airlift board (and multiple wings). Are there any you would like me to specifically test, or just test in general?

tulip sleet
short tendon
manic glacierBOT
#

I think you are going the right direction in using existing parts of CircuitPython. I'm glad you done a bunch of testing on this. Please come to us sooner to make sure you are taking the best high level approach.

Before adding sdcardio try sdioio in one bit mode. That is already implemented in espressif and I believe works for SPI sdcards. (That's why sdcardio isn't already implemented.)

I don't like the rm690b0 module because it is doing too much outside. Board specific stuff can be isolat...

manic glacierBOT
#

I've fixed FunHouse and I suspect montermask had the same issue. PyBadge was broken for the same reason but needed an additional fix due to https://github.com/adafruit/circuitpython/pull/10699 which removed the pin reset for the port reset. That's ok for after the vm runs but it is needed in port_init to get things into a good initial state. Feather S2 TFT may have the same issue but I'm out of time to test today and wanted to get these fixes out.

proven garnet
# slender iron <@135415127879974912> I saw your note about using wokwi for memory testing and I...

Caught up on the meeting this evening (thank you @lone axle for uploading) - that sounds good and makes a lot of sense. Don't know much about it, but will look into it over the next week (Wokwi was cool but I had some problems trying to bringing it back up to speed maybe 6-12 months ago anyway, so nothing lost).

From my brief look into it, am I correct in understanding that the Zephyr port is an RTOS that basically runs the CircuitPython runtime as the application?

manic glacierBOT
#

I either don't understand frozen modules or I built this wrong. I was assuming that all the libraries included in the frozen directory would be available without having to install an mpy version in the lib folder. I built the Makerfabs S3 TFT board but the connection_manager library isn't seen unless I put the file on the board.

When I did put the connection_manager and requests library on the board the SSL library wasn't available. I was able to fix this by adding `CIRCUITPY_SSL_NATIVE = ...

manic glacierBOT
slender iron
manic glacierBOT
manic glacierBOT
#

There are a number of boards available that have special features not well covered by existing modules. Or some attributes are transient during boot and must be captured very early during board initialization. Another example is updating large LUTs.

Instead of inflating the board module with very specific methods, it might be better to add a generic method that is modeled more like the ioctl system call on Linux (note: I wouldn't call it ioctl). The method could take an int and optional ...

manic glacierBOT
manic glacierBOT
#

Summary

On Seeed XIAO ESP32-C6 running CircuitPython 10.0.3 and 10.1.0-beta1, BLE central operations using _bleio show failures when connecting to a BLE peripheral that advertises 16-bit service UUIDs 0xAE30 / 0xAF30: service discovery either raises MemoryError: Nimble out of memory or returns zero services. Additionally, BLE connection state/teardown appears inconsistent across soft reloads (see “Disconnect behavior” below).

Environment

  • Board: Seeed XIAO ESP32-C6 (...
slender iron
#

yoto PR is ready for another look

#

and is basically a pre-req for the native sim one due to the codespell change

#

(which I should have done separately)

manic glacierBOT
#

Instead, an LLM will make quick work of adding board specific accessors

I don't understand that. In my understanding, to be accessible from Python a method has to be defined in shared-bindings/board/__init__.*. So these board specific accessors would bloat the board implementation. And how would an LLM make a difference here compared to classical coding?!

it is hard to document in the standard python way.

Another thing I don't understand. A generic method that takes an int and a byte-...

slender iron
#

@tulip sleet please look at the yoto PR before you are done for the day

tulip sleet
orchid basinBOT
#

Summary

Adds the M5Stack CoreS3 SE board to the CircuitPython downloads page.

  • Board markdown file: _board/m5stack_cores3_se.md
  • Large image: assets/images/boards/large/m5stack_cores3_se.jpg (800x600)
  • Small image: assets/images/boards/small/m5stack_cores3_se.jpg (300x225)

Related: CircuitPython core PR merged: https://github.com/adafruit/circuitpython/pull/10794

Notes in description:

  • Includes support for M5GO Battery Bottom 3 accessory
  • SD card is not yet functiona...
tulip sleet
manic glacierBOT
#

On MONSTERM4MSK, the display shows the REPL, but I am getting a safe mode Hard fault: memory access or instruction error., and when running a sample program, I get this error (works in previous versions):

Traceback (most recent call last):
  File "code.py", line 54, in 
  File "adafruit_monsterm4sk.py", line 129, in __init__
ValueError: RIGHT_TFT_SCK in use

code.py.zip

Other boards are working and code changes look f...

tulip sleet
#

i'm looking at the m4sk error in a little more detail

#

I get the RIGHT_TFT_SCK in use only sometimes. When I do it does NOT go into safe mode. When I go into safe mode there is no precursor error printed.

#

@slender iron offending line is

        right_spi = busio.SPI(board.RIGHT_TFT_SCK, MOSI=board.RIGHT_TFT_MOSI)
#

previous interesting lines:

        # Left screen spi bus
        left_spi = busio.SPI(board.LEFT_TFT_SCK, MOSI=board.LEFT_TFT_MOSI)
        left_tft_cs = board.LEFT_TFT_CS
        left_tft_dc = board.LEFT_TFT_DC

        left_display_bus = fourwire.FourWire(
            left_spi,
            command=left_tft_dc,
            chip_select=left_tft_cs,  # Reset on Seesaw
        )

        self.left_display = ST7789(left_display_bus, width=240, height=240, rowstart=80)

        # right backlight on board
        self.right_backlight = pwmio.PWMOut(board.RIGHT_TFT_LITE, frequency=5000, duty_cycle=0)
        # full brightness
        self.right_backlight.duty_cycle = 65535

        # right display spi bus
        right_spi = busio.SPI(board.RIGHT_TFT_SCK, MOSI=board.RIGHT_TFT_MOSI)
#

seems like maybe a static object is not being initialized and has some garbage somewhere

manic glacierBOT
#

I get the RIGHT_TFT_SCK in use only sometimes. When I do it does NOT go into safe mode. When I go into safe mode there is no precursor error printed.
offending line is

        right_spi = busio.SPI(board.RIGHT_TFT_SCK, MOSI=board.RIGHT_TFT_MOSI)

previous interesting lines:

        # Left screen spi bus
        left_spi = busio.SPI(board.LEFT_TFT_SCK, MOSI=board.LEFT_TFT_MOSI)
        left_tft_cs = board.LEFT_TFT_CS
        left_tft_dc = board.LEFT_TFT_DC

      ...
orchid basinBOT
slender iron
#

thanks @tulip sleet! I'll take a look now

#

(sorry I missed this earlier)

#

@tulip sleet what example are you testing with? you only shared the code.py and I'm missing a bmp running it

tulip sleet
#

I am not sure where this came from

#

some Guide example. It's not in the board guide that I saw

slender iron
#

I looked in the learn repo and didn't see it

tulip sleet
#

me neither

#

the eyes are from the Arduino code

#

it was just what was on the board from some previous forgotten debugging adventure

slender iron
#

it safe modes with main too

tulip sleet
#

if you press reset a few more times you may get the pin error. That's what happened with me

#

ok, i wrote Did work with 10.1.0-beta.1. I did not test it with main.

slender iron
#

I'll see if I can fix it anyway

#

suspect it is something with the dual screens

#

10.0.x works

manic glacierBOT
slender iron
#

nvm 10.0.x crashes too if you ctrl-c, enter the repl and then go back to code.py

manic glacierBOT
slender iron
#

ty

slender iron
#

I'm thinking about how we could test multiple displays

orchid basinBOT
manic glacierBOT
manic glacierBOT
#

Since Airlift isn't compatible with ethernet, does this imply that the Wiznet Eth-breakouts can't be used anymore?

I'll have to figure this out -- the problem is that two versions of ssl are needed. If the board doesn't provide AirLift support, then there's no conflict.

This is why this is a draft :) .

I could change the airlift support ssl to airlift_ssl, and one could do import airlift_ssl as ssl most of the time. I wonder if the other airlift modules should be similarly ...

manic glacierBOT
#

Or perhaps ssl can decide what to do at run time, based on the socketpool it is given. socketpool would also need to do run-time checking on the Radio it was given.

This sounds like core code taking on some of what connection_manager does, which is fine.

A small consideration: using two radio types on a project. I suspect wifi/airlift + ethernet would be more in demand than wifi + airlift. Or at least the ability to use airlift or ethernet on a native wifi board (that may have been ...

#

FWW there seem to be two PRs that changed PDMIn from 7.1.1 to 7.2.0:

  • #5984
  • #5993

neither is jumping out at me as a likely cause, though maybe something about the preexisting incorrect call order of #5984 was actually required?

If printing the received samples directly, does it show any interesting or obvious pattern? I am guessing that it includes both "very big" and "very small" values, so that the RMS value is around 32000 instead of 0 but I can't guess why.

manic glacierBOT
#

Between 7.1.1 and 7.2.0, a change was made to PDMIn that caused the passed-in sample rate to be used, instead of the fixed value 44100. When the sample rate 16000 was actually used, an underlying problem was exposed: The PIO clock was determined incorrectly.

Some problems in the same area were also resolved: The PIO frequency check was also wrong by a factor of two, and when a too-low sample rate led to the exception being thrown, the incomplete PDMIn object was not correctly deallocated, ...

manic glacierBOT
#

I investigated this from the standpoint of what output samples are being generated by audiomixer, within the "unix port" and I did not see anything unexpected in the output samples.

This example plays an unsigned 8 bit raw sine sample at several levels from 1.0 to 0.0:

import audiomixer
import audiocore
import ulab.numpy as np

fsine = np.sin(np.linspace(0, 2*np.pi, 200, endpoint=False))
sine8u = np.array(fsine * 127 + 127, dtype=np.uint8)
sine16s = np.array(fsine * 32700, dtype=np...
manic glacierBOT
manic glacierBOT
#

Just checking in to see if there has been any progress on this. I have contributed zero to this project so I am incredibly grateful for the hard work others have put into. Just want to make it clear I'm respectfully checking in, not making a demand :)

Not sure if it matters or offers any help, but it looks like MicroPython may provide support for this in their upcoming 1.28 release on March 9.

I work at a university, so if having ac...

slender iron
#

@tulip sleet native_sim PR is ready and fixes the new m5stack board

tulip sleet
slender iron
#

I don't think it does because we don't expose a transfer without a stop anymore

manic glacierBOT
#

Thank you for your thorough research, @jepler ! I'm going to put this issue to rest and chock it up to the limitations of 8-bit audio (ie: the stair-stepping mentioned above). The improvements by @samblenny to DAC clock configuration and their research into 8-bit µ-law encoded audio (https://github.com/samblenny/fruit-jam-au-file-player) have further improved the situation to make this problem an non-issue.

manic glacierBOT
#

In my understanding, to be accessible from Python a method has to be defined in shared-bindings/board/__init__.*. So these board specific accessors would bloat the board implementation.

The attributes on board module are set by the board in (misnamed) pins.c within the board directory. So, within that directory you can add special functions or objects.

The new yoto boards do this dynamically by setting values in board_init(): https://github.com/adafruit/circuitpython/blob/main/por...

manic glacierBOT
manic glacierBOT
manic glacierBOT
steady mulch
#

Regarding NVM "Each assignment causes an erase and write cycle", does it have to be written in one go, or could you write to single bytes which currently hold the empty value? (Or perhaps that depends on the microcontroller?)

manic glacierBOT
manic glacierBOT
#

The attributes on board module are set by the board in (misnamed) pins.c within the board directory. So, within that directory you can add special functions or objects.

I did not know about that. This sounds promising, although I did not find an example on how to add a function that takes arguments. Any pointers?! If the pins.c-method works, the generic IOCTL is indeed not necessary.

I disagree. A specific method ends up with a stub and doc string. The params can have names instea...

manic glacierBOT
#

@mlamparter @dhalbert This is correct. I'm just finalizing my PR and it is due in MPY 1.28. Please note it is ESP32 only at the moment (mostly a wrapper for the existing ESP-IDF 5.5 functions). The main commit is just an extension to wlan.connect() and should build cleanly on Circuitpython as well. Feel free to give it a test and let me know if something breaks. In this case I may be able to fix a thing or two before March 9.

manic glacierBOT
#

Nice! Seems to fix things re-running same test from issue thread:

Adafruit CircuitPython 10.1.0-beta.1-28-ge1bc5e2f40 on 2026-02-04; Adafruit QT Py RP2040 with rp2040
>>> import pdm_test
160 (96.1623,)
160 (63.4923,)
160 (73.8208,)
160 (81.238,)
160 (5275.07,)
160 (11503.3,)
160 (2226.01,)
160 (185.137,)
160 (55.1477,)
160 (59.0909,)
160 (59.9527,)
160 (52.0881,)
160 (61.6757,)
manic glacierBOT
#

Any pointers?!

Yup! Look in shared-bindings. The classes and modules there have similar tables that point to the objects. (Created by macros that take in a function pointer to a corresponding C function.)

This would save the state, which then could be read by a board-attribute.
👍

What about rtc.calibration? This is also generic and is documented as hardware-specific.

This still feels more specific to me than an IOCTL with magic numbers as args.

For boards with an integrated ...

manic glacierBOT
short tendon
#

@tulip sleet I'm not sure where to post this (possible) bug. When trying to update py Airlift (via m4 or pyportal), on my Windows 11 machine, I can't use Adafruit WebSerial ESPTool, I get the error:

Invalid head of packet (0x4): Possible serial noise or corruption.
using the python ESPTool, I need to downgrade to 4.7.0 otherwise I get timeout errors

tulip sleet
short tendon
#

I've made sure

tulip sleet
#

i also use esptool 5.x.x on Linux, but have not seen the timeout errors

#

use a slower speed like 115200 if you are not already doing so

short tendon
#

I'm doing that as well

#

I walked back the esptool every version until it worked (after jumping to a really old one to see if it would work)

tulip sleet
#

could you paste the command line you are using?

short tendon
#
esptool --port COM10 --before no_reset --baud 115200 write_flash 0 NINA_ADAFRUIT-esp32-3.3.0.bin
#

switching between 4.7.0 and 4.8.0 is works / doesn't work

tulip sleet
#

you could post this as a "Feedback? Corrections?" item on the AirLift update guide.

#

and you are using the passthrough UF2 from that guide, I assume

short tendon
#

I am, and can do

tulip sleet
#

this is also of interest to the wippersnapper people because they have an update guide

#

4.7.0 vs 4.8.0 is good -- we can see what changed

#

thanks for the detailed testing

manic glacierBOT
#

I loaded the matrix_portal_m4 artifact and it partially worked with my programs. I'm not sure, but I think connection manager may need to be updated as it looks like it decided to try and use the adafruit_esp32spi library in at least one case:

>> wifi_weather.wifi_weather()
Connecting to twilightzone
Connecting to AP...
Connected to twilightzone!
My IP address is 10.0.0.236
Fetching text from https://api.weather.gov/gridpoints/BOX/70,76/forecast
Traceback (most recent call last):
...
manic glacierBOT
#

Doing some random testing, noticed ntp doesn't work:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "adafruit_ntp.py", line 123, in datetime
  File "adafruit_ntp.py", line 91, in _update_time_sync
OSError: [Errno 9] EBADF

line 91 is:

sock.recv_into(self._packet)

I also noticed I needed to call pool.getaddrinfo multiple times. I got:

TimeoutError: timeout waiting for ready False

then

RuntimeError: Error response...
manic glacierBOT
#

After updating the airlift firmware, I'm no longer seeing the safe mode crashes and the DNS error I needed to try/except around in your test program no longer fails. The test program still ends at the same point but the message is slightly different:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "dantest.py", line 59, in <module>
ConnectionError: Failed
wraith crow
#

@tulip sleet should I have seen a MAC address change when updating the airlift firmware?

tulip sleet
wraith crow
#

After the firmware update your script says: MAC address: 94:e6:86:06:9a:88
but before (looking back at what I had posted on the PR) it said: MAC address: 88:9a:06:86:e6:94 Oh nevermind, the values are just reversed 😁

#

According to my router the new order is the correct one....

#

And the MAC address lookup website

manic glacierBOT
manic glacierBOT
#
upper radish
manic glacierBOT
#
  • Fixes #7544 (attn @fovea1959)
  • Fixes #8038
  • Fixes #8284 (attn @PythonAmateur742, @DavePutz)
  • Fixes #8364 (attn @PierreAboussouan)
  • Fixes #10665
  • Fixes #10711 (attn @davsrt)
  • Fixes #10717 (attn @hmaerki)
  • Fixes #10798 (attn @colinvail6)

Many issues were reported when using Thonny. If the code that Thonny sent to the REPL, while in raw paste mode, raised an exception, then there could be a hard crash causing safe mode, and causing the Thonny connection to fail. This problem w...

zinc walrus
#

Several months ago, when Win10 reached EOL, I switched to Arch Linux (CachyOS) after having prepared for a year by practicing my workflows in WSL. I'm now up and running again in KDE, with most of my needs met and configurations satisfactorily tweaked.

With the basics squared away, I'm beginning to rebuild my embedded development toolchain, but this time I want to avoid Microsoft as much as possible. I was very fond of VS Code and its ecosystem, but I just can't support that company any longer.

I've investigated VS Code's opensource builds (VSCodium and Code-OSS), and while these work well for some frameworks (eg. Zephyr), others are unsupported due to their dependency on MS plugins (eg. CircuitPython2 and PlatformIO).

One of my eventual goals is to play with the CircuitPython Zephyr port on the nRF5340 Audio DK, but that's still slightly beyond my reach. In the interim, I'd like to at least find a comfortable CircuitPython/Arduino coding environment with linting and completion.

KDE's Kate seems a promising candidate at the moment (with tio as serial monitor), but I'm soliciting advice and recommendations from those devs here with applicable experience. Suggestions and pointers to further resources appreciated.

manic glacierBOT
#

I'll have to figure this out -- the problem is that two versions of ssl are needed. If the board doesn't provide AirLift support, then there's no conflict.

Two additional options to investigate:

  • add a Python shim library for every implementation. The module __init__.py would basically just pull in the native implementations into the namespace. This would be future proof, e.g. if someone decides to implement esp-hosted
  • create an online CircuitPython generator. Other firmware-p...
serene token
# zinc walrus Several months ago, when Win10 reached EOL, I switched to Arch Linux (CachyOS) a...

If you are going to stick with KDE, Kate is pretty awesome. I used KDE up until KDE 4, which was buggy and way too much like Windows Vista. Sadly I had to let Kate go, as it is dependent on way too much of KDE. I use Vim now, but if I was still using KDE, I'd probably still be using Kate.

As far as Vim goes, it depends on what you need. You can get plugins for a lot of stuff, but I mostly debug from the command line, I have multiple terminal windows open and use separate terminals for editing and compiling. If you like that kind of workflow, and are willing to put in the effort to learn Vim (it's not easy), it's well worth it. If you prefer GUI with integrated stuff though, you won't like Vim.

I also used Bluefish for a bit after leaving KDE. It's not bad, and maybe it's better now (that was over 10 years ago). The last time I used it, it was way too web centric. It had syntax highlighting and other features for a ton of languages, but the toolbar was full of stuff designed for writing HTML, JS, and CSS, even when working in C, C++, Python, etc... Again though, that was a decade ago. Maybe it's better for more than just front end web now? It might have more familiar IDE features than Kate (though I haven't used that in a decade either, so maybe they've added those).

(I generally disable most IDE features in any coding editor I use. I learned to code when features like autoindent and autocomplete didn't exist, and when my editor tries to do them for me, it just ends up mangling my typing. So there may be pros and cons to some of these that I'm missing, if you use these features.)

zinc walrus
# serene token If you are going to stick with KDE, Kate is pretty awesome. I used KDE up until...

Thanks very much for the advice. I used vi all through college (in the university computer lab, where I had to teach others how to even close it), so I'm perfectly comfortable in both Vim and the terminal.

But I don't miss the days of having to constantly sift through the docs for unfamiliar function references, especially now that IDEs can provide a fingertip onscreen reference, and prevent misspelled variables that have already been declared with helpful autocomplete.

I still have lots of options to explore, but I'll give Vim another look to see what it's capable of these days. Kate is based on the same text editing library as Notepad++, so it was instantly familiar to me from my decades spent on Windows.

upper radish
# zinc walrus Several months ago, when Win10 reached EOL, I switched to Arch Linux (CachyOS) a...

Very cool! I've been working with WSL for a while now and would like to setup a Linux box at some point as well. Two of the options I'd consider are directly inspired by FoamyGuy and John Park. Tim (FoamyGuy) uses PyCharm - it features in his streams. There's also a setup overview video by Prof Gallaugher on YouTube I'll link. John Park uses Zed Editor, and you can see that during his CircuitPython Parsecs. Perhaps you might find one of those suitable?

https://youtu.be/5LoXTVGlNVU?si=f5GDyWtpzSOuS_od

serene token
# zinc walrus Thanks very much for the advice. I used `vi` all through college (in the univers...

I use Notepad++ for somethings when I'm working in Windows. I didn't know it was based on the same library as Kate, but it makes sense!

I'm pretty sure there are autocomplete plugins for Vim, but how far you want to go with that is up to you. There are a lot of plugins for Vim!

Anyhow, good luck. My typical strategy when looking for a good application for something in Linux is generally just to look up options and then go through the list trying them until I find one that feels really comfortable. That said, somehow I ended up on Vim for my coding editor, so it's obvious that I don't always stick to that strategy! (Vim is certainly comfortable now, but when I first started using it? Not so much.)

manic glacierBOT
wanton dirge
#

Hello friends! I'm back finishing up adding a couple more chips to the analog port; nearly ready to PR at this point. Before I do, I wanna check on an issue with USB connection. At the moment, when I connect via something like TeraTerm, it usually crashes on my first attempt to connect to the device. If I reset, then Teraterm is able to connect. I've seen similar issues with some other serial monitors like VS Code's serial monitor extension. My understanding is this could be due to a race between the serial monitor waiting for some specific packet from the target, and the target board already having delivered it by the time Teraterm tries to connect. Firstly, does that make sense? And secondly, is there a way I might work around that?

One of the quirks of our TinyUSB port is it doesn't support bidirectional endpoints (e.g. needs a unique ep for Tx/Rx), but I don't think that would cause what I'm seeing.

slender iron
#

@zinc walrus I use Zed or Sublime Text. I really like how fast Sublime Text opens. Honestly though, I'd recommend trying coding agents like Codex or Claude. I find myself often using them + Sublime Merge to see what they've changed. The editor matters much less to me now.

slender iron
#

(I'd love to move the existing ones there too.)

tulip sleet
#

The serial port might be going on and off and back on-line for some reason.

#

have you tried tio on Linux? That will reconnect automatically, and you will also see the disconnects.

#

might give more clues

wanton dirge
slender iron
#

I haven't tackled dynamic pin muxing yet but we'll get there. I switched to the Zephyr USB stack which makes it "just work" too

#

I'm working on BLE and networking now

wanton dirge
#

I liked how CP was doing pin aliases matching silkscreen...would I just add a .dtoverlay per board to give them aliases?

slender iron
#

right now it is based on the Zephyr gpio nexus

#

so if you have an "arduino pinout" it'll auto-add all of the names for that

#

that's how fixed busses like I2C work too

#

can I get dev boards for the new stuff?

#

(not sure what chip they are)

wanton dirge
#

It's the MAX32650 and MAX32666. In our HAL it's called the 32665, essentially the same underlying die

#

Boards are MAX32650FTHR / MAX32666FTHR

slender iron
#

you should try our zephyr port on them!

#

looks at what the analog port has already

wanton dirge
#

I shall!

slender iron
#

maybe my zephyr_bleio branch too

#

I have a pretty big fix for the heap

#

I think you'll definitely want to switch because the analog port doesn't have ble

wanton dirge
#

Yeah, I don't think we have BLE support mainlined in Zephyr for the time being as well. Some issues with licensing restrictions there.

slender iron
#

ah

#

do you have a downstream with it?

#

I'm not against figuring out how to use vendor zephyrs

#

looks at nordic too

wanton dirge
#

Not publicly afaik

slender iron
#

👍 count us as a +1 then

zinc walrus
#

I appreciate everyone who provided Linux code editor suggestions, but watching @slender iron's recent deep dive yesterday was so demoralizing and discouraging that I'm reconsidering even bothering anymore.

I'm not at all interested in paying a computer to write my code, but that's clearly the only future left. Why even attempt to learn something this complicated? Expertise is obsolete; just outsource it to the machines.

manic glacierBOT
manic glacierBOT
#

@tannewt
Thank you very much for the detailed feedback - it was extremely valuable and helped reshape the entire approach. I appreciate you pointing me in the right direction early.
Here's what has been done based on your guidance:

  1. Removed sdcardio - using sdioio instead
    The custom sdcardio implementation (~500 lines) has been removed entirely. The board now uses the existing sdioio module in 1-bit mode, as you suggested. Build config updated accordingly (CIRCUITPY_SDIOIO ...
manic glacierBOT
#

Pins GPIO38/GPIO39 are exposed as board.IO38/board.IO39 but this board’s sdkconfig assigns them to PSRAM (CONFIG_SPIRAM_CS_IO=38, CONFIG_SPIRAM_CLK_IO=39). Advertising them as free GPIOs is misleading and can lead to hard-to-debug crashes if a user reconfigures them. Please remove these aliases (or clearly mark them as reserved/not for general use).


#

spi_bus_config_t is initialized using .data0_io_num...data3_io_num, but the espressif port’s SPI code uses the standard field names (.mosi_io_num, .miso_io_num, .quadwp_io_num, .quadhd_io_num). Using data0_io_num etc is likely incompatible with the ESP-IDF headers used by this repo and can break builds on some IDF targets. Consider mapping QSPI pins via the standard fields (data0->mosi, data1->miso, data2->quadwp, data3->quadhd) and keep the struct initializer consistent with ...

manic glacierBOT
#

This QSPI-specific path increases the size of the stack-allocated VLA uint32_t buffer[buffer_size] from 128 words up to ~2048 words (~8KB) (plus the mask array). Since _refresh_area() runs on the main VM task stack, please confirm this cannot overflow the stack on all supported builds that enable CIRCUITPY_QSPIBUS; otherwise consider using a heap allocation (or a compile-time cap like CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE) to avoid large per-call stack usage.

#

Board SD configuration is internally inconsistent: pins.c labels the connector as "SD Card (SPI)" and exposes SD_SPI/SD_MISO/SD_MOSI/SD_CLK/SD_CS, but mpconfigboard.mk comments "SD card via SDMMC interface" and enables CIRCUITPY_SDIOIO = 1. Please reconcile whether the slot is wired for SPI or SDIO (and enable the appropriate module + expose the correct board.SDIO_* pins if SDIO).

# SD card via SPI interface
CIRCUITPY_SDCARDIO = 1
#

QSPIBus objects are allocated with mp_obj_malloc(), unlike other display buses (FourWire/ParallelBus/I2CDisplayBus) which allocate from displayio's global display_buses pool via allocate_display_bus_or_raise(). This likely breaks the "display buses persist across reload until displayio.release_displays()" behavior and can leave BusDisplay holding a pointer into the GC heap after a soft reload. Consider adding qspibus_qspibus_obj_t to primary_display_bus_t (shared-module/displayio/init.h) ...

manic glacierBOT
#

Setting CIRCUITPY_QSPIBUS ?= 1 at the port level enables and compiles the new qspibus module for all Espressif boards by default, including boards that explicitly disable display buses (many set CIRCUITPY_PARALLELDISPLAYBUS = 0). This can increase firmware size and may introduce build/link dependencies (esp_lcd) on targets/boards that don't need QSPI display support. Consider defaulting this to 0 in mpconfigport.mk and enabling CIRCUITPY_QSPIBUS = 1 only in the specific board(s)...

#

CIRCUITPY_QSPIBUS is configured with a hard default of 0, unlike other display bus helpers (e.g., CIRCUITPY_FOURWIRE and CIRCUITPY_I2CDISPLAYBUS) which default to $(CIRCUITPY_DISPLAYIO). Because qspibus relies on displayio symbols (e.g., display bus allocation/types), enabling it while CIRCUITPY_DISPLAYIO=0 is likely to break the build. Consider defaulting CIRCUITPY_QSPIBUS to $(CIRCUITPY_DISPLAYIO) (or otherwise enforcing the dependency).

CIRCUITPY_QSPIBUS ?...
#

Timeout error paths can leave the bus object in a partially-busy state. For example, if qspibus_wait_one_transfer_done() times out in qspibus_send_color_bytes(), an exception is raised but inflight_transfers/transfer_in_progress are not reset, and common_hal_qspibus_qspibus_bus_free() currently ignores transfer_in_progress. This can make the display core believe the bus is free even though DMA transfers may still be queued. Consider ensuring timeout paths put the object back into ...

#

The second QSPI-specific adjustment forces rows_per_buffer = 2, then recomputes buffer_size from the display width. When the display is wider than CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE * pixels_per_word, this can increase the VLA buffer[buffer_size] beyond the configured cap (and beyond the comment in mpconfig.h that suggests boards can control stack usage via that macro). Consider keeping buffer_size bounded (and only forcing 2 rows if it fits), or otherwise respecting `CIRCUIT...

#

CIRCUITPY_QSPIBUS defaults to 0 globally (in circuitpy_mpconfig.mk) and is explicitly enabled only in the Waveshare board's mpconfigboard.mk - changing the default to $(CIRCUITPY_DISPLAYIO) would needlessly compile QSPI bus support into every board that has displayio enabled, adding code size and esp_lcd dependencies to boards that will never use a QSPI display.
Won't fix

#

common_hal_qspibus_qspibus_bus_free() can return true even when has_pending_command is set (e.g., after DISPLAY_COMMAND bytes have been queued but not flushed due to an interrupted/aborted transaction). That can let displayio treat the bus as idle and start a new transaction while the previous command is still pending. Consider including !has_pending_command in the bus-free predicate (or flushing the pending command before reporting free).

    return self->bus_initialized &&
   ...
#

In qspibus_send_command_bytes(), the timeout path (when xSemaphoreTake fails) raises an exception but leaves inflight_transfers/transfer_in_progress unchanged. That can permanently wedge the bus in a “busy” state for subsequent calls (because inflight_transfers never returns to 0). Reset the transfer bookkeeping on timeout (similar to the color timeout paths) or otherwise ensure the bus can recover after a timeout.

#

common_hal_qspibus_qspibus_send() ignores the chip_select behavior argument entirely. displayio uses chip_select to request specific CS toggling semantics (e.g., CHIP_SELECT_TOGGLE_EVERY_BYTE), so silently ignoring it can produce incorrect behavior for some display drivers. If QSPIBus can’t support both behaviors, consider explicitly enforcing the supported mode(s) (and raising a clear error for unsupported chip_select values) to avoid subtle misbehavior.


    // QSPIBus does no...
#

CIRCUITPY_LCD_POWER (if defined) is claimed and driven without checking whether the pin is already in use. Since claim_pin() does not validate exclusivity, this can silently override an existing user pin claim (e.g. if the pin is exposed under another board name) and change its direction/level. Consider verifying common_hal_mcu_pin_is_free(power) before claiming/configuring it and raising a clear ValueError if it’s not free, or avoid auto-claiming/configuring the power pin here and requ...

#

GPIO16 is exported as board.BAT_CONTROL but is also used internally as CIRCUITPY_LCD_POWER (see mpconfigboard.h). That dual meaning is likely to confuse users and can lead to conflicting usage (battery control vs display power). Consider renaming BAT_CONTROL to a name that reflects its actual function on this board, or add an explicit LCD_POWER/DISPLAY_POWER alias and a comment noting it is shared with the battery control circuitry.

    // Boot/Control/Battery and Di...
crimson ferry
#

Is this a sign of things to come... Copilot PR comments flooding this channel?

manic glacierBOT
#

Board-level power pins defined in mpconfigboard.h are claimed without free-checking throughout CircuitPython - FourWire, DotClock, and other display bus drivers all follow the same pattern. The power pin is a hardware constant, not user-configurable, and QSPIBus is created early during display init before any user code runs, so no prior claim is possible in normal usage.
Won't fix

#

The common-hal layer raises a custom ValueError string ("QSPI bus deinitialized") instead of using the standard raise_deinited_error() path used across the codebase for deinitialized objects (see shared-bindings/util.c). Using raise_deinited_error() here would make the exception type/message consistent and avoid adding a new translatable string for the same condition.

#

QSPIBus.send() is documented as mirroring the FourWire convenience API, but it doesn't acquire the display-bus transaction (or wait for the bus to be free) before calling into common_hal_qspibus_qspibus_send_command_data(). This can raise "Bus in display transaction" during auto-refresh/background updates and makes the behavior differ from fourwire.FourWire.send() (which waits for begin_transaction). Consider either (a) doing a begin/end transaction (and waiting until the bus is free)...

manic glacierBOT
#

qspibus transfer completion waits use a blocking xSemaphoreTake() with a potentially long timeout. This can starve CircuitPython's background processing (USB/REPL, scheduling, etc.). Consider waiting in a loop with short time slices and calling RUN_BACKGROUND_TASKS (or MICROPY_EVENT_POLL_HOOK) between attempts, similar to other Espressif drivers.

#

On timeout, the code resets inflight_transfers/transfer_in_progress but does not drain/reset transfer_done_sem. If a late ISR completion gives the semaphore after the timeout, the next transfer wait can consume a stale token and incorrectly treat a new transfer as completed (risking DMA buffer reuse/corruption). When timing out, reset the semaphore state (e.g., xQueueReset / drain tokens) and consider forcing a bus deinit/reinit to restore a consistent state.

#

QSPI DMA transfers complete in microseconds — the semaphore wait is nearly instant in normal operation. The timeout is a safety net for hardware failures, not the expected path. Running RUN_BACKGROUND_TASKS inside the DMA wait loop would be unsafe: it triggers displayio_background(), which can attempt another display refresh, causing re-entrancy into the same bus code. Other CircuitPython display bus drivers (FourWire/SPI) also block during hardware transfers without running background task...

#

shared-module/displayio/__init__.h now includes shared-bindings/qspibus/QSPIBus.h, while this header includes shared-bindings/displayio/__init__.h, creating a circular include that can break builds depending on include order. Recommendation: remove the displayio/__init__.h include from this header and instead include a narrower header that only defines display_byte_type_t / display_chip_select_behavior_t (or forward-declare/relocate those enum definitions to a non-recursive header...

#

In reset_displays(), the QSPIBus branch intentionally does nothing, unlike other display buses that are set to None (and/or deinit’d) to make the bus slot reusable after a soft reload. This can leave the bus occupying a display_buses[] slot across reloads and prevent subsequent qspibus.QSPIBus() construction (or leave hardware/pins in a stale state). Recommendation: align behavior with other buses by deinitializing and/or setting display_buses[i].bus_base.type = &mp_type_NoneType he...

#

Setting .max_transfer_sz to SOC_SPI_MAXIMUM_BUFFER_SIZE can cause the SPI driver to allocate/prepare resources sized for a much larger transfer than this implementation actually uses (your DMA chunking caps transfers to self->dma_buffer_size, initially up to 16KB). Recommendation: set .max_transfer_sz to the real maximum transfer size you will submit (e.g., QSPI_DMA_BUFFER_SIZE or self->dma_buffer_size), to reduce driver-side memory overhead.

        .max_transfer_sz...
#
  • Fixes #10681 (attn @mrbbp)

#10277 added background task running during display refresh. However, it didn't guard against background refresh during an explicit foreground refresh. This cause display programs with an explicit .refresh() to run about twice as slow as before.

I was going to add some refresh_in_progress field to the display struct, but discovered it was already there, and that displayio_display_core_start_refresh() was already set up to check for recursive refresh. W...

#

There is no circular include. Copilot confuses shared-module/displayio/__init__.h with shared-bindings/displayio/__init__.h - these are different files. The include chain is:
shared-module/displayio/__init__.h -> shared-bindings/qspibus/QSPIBus.h -> shared-bindings/displayio/__init__.h (terminates here, no back-reference to shared-module/).
Won't fix.

crimson ferry
#

@zinc walrus I wouldn't let it get you down. You can choose how you want to develop for your own projects. I enjoy the process of writing software from scratch or adapting from examples, and I'm not a professional trying to compete on productivity or get certain skills on my resume. I do not want to use an LLM. I don't even use editors with code completion.

manic glacierBOT
#

qspibus_reset_transfer_state() drains the semaphore once, but it can’t prevent late ISR completions from posting additional tokens after the drain. If a timeout occurs and a transfer completes later, the semaphore can contain stale tokens that will be consumed by a subsequent qspibus_wait_one_transfer_done(), causing inflight_transfers to be decremented “early” and allowing new transfers to overlap with still-running ones. Consider redesigning the synchronization so stale completions can’t ...

#

qspibus_on_color_trans_done() unconditionally calls xSemaphoreGiveFromISR(self->transfer_done_sem, ...). If the semaphore has been deleted (or is temporarily NULL during init/deinit/error handling), this can become a use-after-free/NULL-deref from ISR context. Guard the ISR callback with a NULL check, and in deinit set transfer_done_sem to NULL before deleting the semaphore handle (so late callbacks safely no-op).

#

qspibus.QSPIBus.send() waits on common_hal_qspibus_qspibus_bus_free(), which returns false when has_pending_command is true. If a user previously called write_command() (without finishing with write_data()/end_transaction), send() can spin forever because the pending-command state is purely internal and will never clear in background tasks. Consider waiting only for “not in_transaction / not transfer_in_progress” (or flushing any pending command before the wait), rather than requiring bus_fre...

#

The current drain-on-timeout approach handles the practical case. A generation counter or "available slot" semaphore redesign would require significant refactoring of the entire transfer management architecture for an edge case that only occurs after a DMA hardware timeout — at which point the user typically reinitializes the bus. The incremental safety gain does not justify the complexity and risk of the refactor.
Won't fix.

lone axle
# crimson ferry Is this a sign of things to come... Copilot PR comments flooding this channel?

We are testing it on PR reviews and all comments auto forward to here from the bot. Maybe we could adjust it to filter out copilot ones if there is a preference for that.

Whether it's a sign of things to come I think depends on how good it's reviews end up being. If they end up being useful i.e. good reviews with helpful suggestions then I imagine they will keep getting used.

#

and to @zinc walrus I agree with anecdata. Scott's or anyone elses choice of development environment doesn't really have to dictate how you work. I don't agree that is the only future left. There is room for all kinds of different people to develop CircuitPython itself and projects built with it in any number of different ways.

I think the answer for "Why even attempt to learn something this complicated?" will differ from person to person. For me the answer is because I think its fun, I want to help make it easier for other people to play with, and there is a great community of folks involved. Personally, the existence or use of these tools by me or anyone else doesn't really change those motivations.

serene token
# crimson ferry <@834445433060589579> I wouldn't let it get you down. You can choose how you wan...

I do code professionally, and I don't like code completion or autotab. I also don't use LLMs (much). A large part of that is that my current work is research, and that means that LLMs have not been exposed to anything like what I'm writing, so they really can't do a very good job. Even for personal stuff, I'm mostly working on microcontrollers at the lowest level I can get away with, and LLMs aren't exactly great for that either. I've used basic search AI to generate example code, but even that I generally have to adapt to my specific use case.

A big part of it though, is that I want to know exactly what my code is doing (this saves an enormous amount of debugging time and makes maintenance much easier), and the time it would take me to go through code generated by an LLM to understand what it is doing is generally more than it would take me to write it myself.

That said, I have nothing against those who use LLMs. They can be really good for certain types of work. They just aren't as good for highly novel stuff and super low level stuff, which is both the space I work in and the space I prefer to develop in.

tiny peak
# lone axle We are testing it on PR reviews and all comments auto forward to here from the b...

FWIW, if it becomes common to have storms of copilot review comments and human responses, it's not gonna be practical for me to monitor this channel any more. I enjoy being able to follow the pulse of what's going on with CircuitPython PRs and issues. But, if today's volume of notifications becomes the norm, I don't think I'd be able to continue.

Specifically, I mean that posts here by the GitHub app previously had a very good signal to noise ratio and were one of the best available ways to track what's going on with CircuitPython. I would be sad to see the average noise floor on that go way up. I don't want to use Discord moderation tools to ignore the GitHub app because then I'd lose access to its feed of human activity on GitHub.

manic glacierBOT
manic glacierBOT
#

common_hal_qspibus_qspibus_write_data() returns early on len == 0 without clearing or flushing the staged pending_command. This leaves has_pending_command set, causing bus_free() to stay false and subsequent transactions/commands to behave incorrectly. Consider treating zero-length writes as a command-only transfer (send pending command with no data and clear the pending flag), or explicitly error and clear state to avoid wedging the bus.

    if (len == 0) {
        //...
#

The translation template entry uses msgid "data buffer is null", but the actual error text raised in QSPIBus.c is "Data buffer is null" (capital D). This mismatch prevents translations from being applied for that error message. Update the .pot entry to match the exact casing (or regenerate the pot file from the source strings).

msgid "Data buffer is null"
manic glacierBOT
manic glacierBOT
tulip sleet
manic glacierBOT
tulip sleet
manic glacierBOT
#

I am trying to reproduce this problem with a simple timing test and failing. I am testing on a PyPortal (SAMD51) on Ubuntu 24.04. Do you have a suggestion about how to reproduce the problem simply?

import board
import gc
import sdcardio
import storage
import time

spi = board.SPI()
cs = board.SD_CS

MOUNT = True

if MOUNT:
    print("mounting sd card...")
    sdcard = sdcardio.SDCard(spi, cs)
    vfs = storage.VfsFat(sdcard)
    storage.mount(vfs, "/sd")
else:
    print("skipping mount"...
tiny peak
#

We'll talk about how to manage this.

zinc walrus
#

Manually studying the Zephyr port of CircuitPython at this point feels like learning to handcraft wagon wheels while watching Karl Benz drive by in his horseless carriage.

I've spent 3 solid years in the bottomless pit of complexity that is Zephyr, and I still only barely qualify as a beginner. West, cmake, kconfig, devicetree, threads, workqueues, semaphores, mutexes, etc. It's nearly intractable, and why torture myself further when I will never hope to compete with an LLM?

Like @crimson ferry, @serene token, @lone axle, and @tiny peak, I enjoy writing code. I like understanding complicated systems and coaxing them to my will, but I can plainly see where programming is headed. I loved the accessibility and immediacy of CircuitPython for rapid prototyping, even with its performance limitations, but I'm beginning to doubt that it's where I should focus my efforts.

I had at one point hoped to participate in porting CircuitPython to the nRF5340 Audio DK, which is an amazing dev kit just begging for a simpler language than NCS (my kingdom for synthio), but I no longer believe it's within my grasp. Maybe instead I should abandon my attempts to program it at all and simply spec an agent to do it for me. Or maybe I should go do something else more satisfying.

tiny peak
#

I can definitely relate to the feeling of Zephyr being beyond my capacity as a human mortal to comprehend. Like, I've been able understand enough bits and pieces to use it to do some interesting stuff, but it's really complicated. Some things are easy, but if you want to go in a direction that's a bit off the beaten path... oh man... it gets intense fast.

zinc walrus
stuck elbow
manic glacierBOT
wanton dirge
#

Hey @slender iron , here's my Zephyr port update!

I was able to successfully enable the Zephyr port for all the boards I wanted, which is great. However, there seems to be a major issue causing USB enumeration for CDC / MSC to take ~2-3 minutes. At the moment this seems like a doozy to debug...but will continue looking into it. I might try and use SystemView to help me there. I also tried the zephyr_bleio branch from Scott's fork -- same behavior.

I tried to add a "digilent,pmod" connector for our SPI pmod on the APARD32690 board, but we have some small deviations in our devicetree (e.g. multiple CS pins available, plus an INT pin) which caused this to be challenging. I could refactor that node and the I2C one to be more compliant, but at the moment that's not done and I just deleted the node from our DT.

My board work is here:
https://github.com/Brandon-Hurst/circuitpython/tree/zephyr-add-max32

They depend on some driver fixes which I made a PR to mainline Zephyr for (marked as draft while I check on a couple small portability things I want to quickly sneak in):
https://github.com/zephyrproject-rtos/zephyr/pull/103720

I already am mostly finished with the baremetal port for MAX32666/MAX32650. I do want to keep working on the Zephyr port here as well, but in the meantime if I PR'd the work on our other port, would it be considered? We have some board development projects we're working on that could really use it 🙂

slender iron
#

We do have our own fork of Zephyr if you want to get it in CP on Zephyr quicker

manic glacierBOT
slender iron
# zinc walrus I appreciate everyone who provided Linux code editor suggestions, but watching <...

This makes me so sad. My intention of highlighting LLMs wasn't to deter people. I'm so excited to have a new powerful tool for making CircuitPython so much better. I'm excited to focus on what I care about: design, ease of use, and system architecture instead of typing and learning obscure code-isms (/me looks at Kconfig). It makes so much more possible sooner to me than before. For your example of the Audio DK. Not only do I see adding a board def happening but we could more easily get to BLE Audio in CP. To me, LLMs make that so much more possible.

I still feel like I need expertise even with LLMs. It's just at a higher systems and experience level instead of the weeds of C pointers and other language-isms. (Though there are lots of bugs I still have to help solve, like one with pulling in half float routines from libc.)

I get that the cost makes it hard to jump in. I'm lucky enough to be paid for my work which covers my LLM cost. My hope is that the open source models you can self run get good enough to use as a normal part of every future computer.

I also get that LLMs shift our future as software engineers. It is weird and uncomfortable to not know what software engineering will be tomorrow and in ten years. That weird, uncomfortable feeling is causing me to question the way I work and feel out a new normal. I hope that by showing my work I can help make what software engineering is becoming less unknown and more comfortable.

I really hope everyone sticks with Adafruit and CircuitPython during this shift. Please let me know how I can be better to not alienate folks.

lone axle
#

<@&356864093652516868> the weekly meeting will occur here on discord at the usual time 2pm Eastern / 11am pacific, about 1 hour 15 minutes from now. Add your hug reports and status updates to the notes doc if you'd like to participate: https://docs.google.com/document/d/1IsTbby5z8HJsNUdXBPoZI_zjVHO8dWR2t4TjUnRrmFc/edit?usp=sharing

tiny peak
#

@slender iron re your post above... One of the things that would be interesting to see Adafruit folks engage with is the impact that AI adoption is having on aspiring coders and junior devs. Various companies are firing huge numbers of people to free up funding for AI projects. It's very clear that companies who write software are trying to use increased AI adoption to avoid hiring. One of the things I read into Adafruit's recent LLM streaming stuff is that hiring of new CircuitPython devs is much less likely than increased LLM spend [edit: that might not be true, but to an outsider it looks very plausible in the current social context]. To somebody evaluating programming as a career path, it's easy to see very very strong signals that it's not looking like a great option. OTOH, AI can give superpowers to experienced devs with secure funding. It would be interesting to see some engagement with this dichotomy.

tulip sleet
#

AI spend

slender iron
#

Sure, if Zephyr is interesting to you. Testing the Zephyr port with any dev boards you have would be helpful and then see what isn't working yet. Coordinate with me if you work within Zephyr.

turbid radish
#

Hi all. I have been outputting VGA video from the Adafruit Feather RP2350. Using Claude Opus 4.5 in the second seat. After iteration, I have PIO generating the HSYNC and VSYNC and I can generate a PIO bitstream with the ⁨⁨set⁩⁩ operator. All efforts to output something like a file image require ⁨⁨out⁩⁩ and that seemed to not work in the same context.Has anyone run into similar issues or better at PIO?

slender iron
#

This works too!

wanton dirge
#

On the topic of LLMs, this RFD from Oxide was a pretty pivotal piece of writing for me to read on the subject and my guiding light in terms of how to think about when to use/not use them. I have found them pretty valuable in many use-cases, but as with many software silver bullets they can become detrimental if not wielded carefully.
https://rfd.shared.oxide.computer/rfd/0576

#

For instance...I don't know how much command-line gdb I really want to be doing with my life. As it turns out Claude can be decent at that, and can talk to my debug probe. Kinda nice especially for open-source work.

slender iron
#

They have a good podcast too

wanton dirge
#

Very aware 😛 I've probably heard over a hundred episodes at this point haha. Call me biased. But I thought it was a good piece of writing

slender iron
#

thanks for hosting foamyguy! Talk with you all next week (Tuesday!)

turbid radish
#

Thanks everyone

tidal kiln
#

👋

lone axle
#

Thanks everyone, have a great week 👋

errant grail
#

Thanks!

lone axle
#

Here is the notes document for next ***Tuesday’s ***CircuitPython Weekly Meeting. It is on Tuesday next week due to the US holiday on Monday. It is at the normal time of 11am Pacific / 2pm US Eastern here on Discord. Add your hug reports and status updates to the document before the meeting. If you are unable to attend but would still like to contribute, feel free to add your notes and we’ll read them off during the meeting. Hope to see you there! <@&356864093652516868> https://docs.google.com/document/d/1VZJGhjSXqRALVQQ6UR053aAV73KtAvlTx3KgfF531bM/edit?usp=sharing

manic glacierBOT
orchid basinBOT
manic glacierBOT
#

I retested with my test-program which I linked above (https://github.com/bablokb/circuitpython-examples/tree/master/perf). I can confirm that performance returns to normal, but for my test it took about 30s. And I don't mount from host side. Maybe the host gives up polling after a while.

Your timings are up by a factor of 2, my timings are up by a factor of 10. So the slow down also depends on what you do. My testprogram (see tests/perf_bench/bm_chaos.py) does fractals, which is probably c...

manic glacierBOT
manic glacierBOT
manic glacierBOT
#
[adafruit/circuitpython] New tag created: 10.1.0-rc.0
orchid basinBOT
manic glacierBOT
manic glacierBOT
orchid basinBOT
fiery ferry
#

Hello, everyone. 🙂 I was wondering if anyone could help me. A friend gifted me a Macropad RP2040 a while back, and I was wondering about programming in CircuitPython on it.

random junco
fiery ferry
#

Okay, thank you. 😊

orchid basinBOT
orchid basinBOT
tidal kiln
#

is anything special needed for adapting older code for newer magtag HW? or will it "just work" as long as using 10.x+ ?

#

trying to figure out what is creating this behavior

tulip sleet
tidal kiln
#

yep. and not my HW either. i also haven't gotten a new one yet.

tulip sleet
#

I looked over your code and I don't see anything tricky that might cause that

#

so he probably has one

tulip sleet
slender iron
#

because it doesn't update the right region of ram

tulip sleet
#

not sure if there was a further change to the displays after you added support

tidal kiln
#

^^ yep. that's the mystery at this point.

manic glacierBOT
#
[adafruit/circuitpython] New tag created: 10.1.0-rc.1
orchid basinBOT
manic glacierBOT
#
[adafruit/circuitpython] New branch created: 10.1.x
tulip sleet
#

Highlights of this release:

  • Fix long-standing Thonny disconnect issues.
  • Add hashlib.new("sha256").
  • Add bitmaptools.replace_color().
manic glacierBOT
#

CircuitPython version and board name

Adafruit CircuitPython 10.0.3 on 2025-10-17; FeatherS3 with ESP32S3

Code/REPL

import time
import supervisor

i=0
while True:
    i += 1
    print(f"[{time.monotonic_ns()}] [{supervisor.runtime.serial_connected}] {i}...")
    time.sleep(0.1)

Behavior

This code will run just fine on a fresh start. However, once a serial console has been connected (supervisor.runtime.serial_connected becomes True), _even after t...

manic glacierBOT
lone sandalBOT
manic glacierBOT
#

Could you describe in more detail how you provoke this? Are you shutting down the terminal program? Could you show some output that shows the printout including time values on disconnect and then after, on reconnect?

.serial_connected doesn't know that the terminal program has gone away. There is no USB indication on the CDC device that I know of. Instead, the host is going to buffer input on /dev/ttywhatever until someone reads it.But I think the serial output to the host will cause a ...

manic glacierBOT
#

Could you describe in more detail how you provoke this? Are you shutting down the terminal program? Could you show some output that shows the printout including time values on disconnect and then after, on reconnect?

  • screen: CTRL-A, k
  • minicom: CTRL-A, x or CTRL-A, q [same effect in both cases]
  • cat: SIGINT

Some sample output; I disconnected, waited a while, and then reconnected; you can see the jump caused by the stall at serial number 116:

[208679626477] [True] 1...
#

I don't want to discard when full because print() should be reliable when connected.

That's fair. The consequence of that is kind of unfortunate, though. Especially in a case where print() is called rarely, it results in a bit of a time-bomb; you set up a device, check its console to make sure it came up cleanly, walk away, and at some point—hours, days, or weeks later—it'll just quietly lock up forever. Worse, it'll look like a Heisenbug, because as soon as you connect to it to debug...

manic glacierBOT
#

Do we know if serial programs will set CDC line state when they exit? They might set the UART control flow lines.

I don't think the serial program would be the one doing it; even if it could, something like cat /dev/ttyACM0 wouldn't. Any disconnection-signalling seems like it'd need to originate in the kernel. The relevant driver is https://github.com/torvalds/linux/blob/-/drivers/usb/class/cdc-acm.c , but I confess that I'm unable to follow its logic clearly.

lone axle
#

How hard would it be to add something optional for devices with /saves/ that would save a history file of the last 5-10 REPL commands and then allow using up arrow to go through them again in a new REPL instance? Even if it can't handle more complex stuff like code blocks, this would be quite convenient for single line statements.

manic glacierBOT
#

usb_cdc.Serial has a .out_waiting attribute which says whether bytes are waiting to be written. I think you could use that to check whether usb_cdc.console (same as a default print() stream) is blocked, and not write in that case.

I cannot find a similar API in CPython for, say, sys.stdout, to whether there is output pending. I did some experiments in Linux desktop Python writing to to one of two serial ports connected to two USB-serial adapters. I saw blocking, but then saw it co...

stuck elbow
#

I'm testing the current main branch on an esp32-s3 device with a built-in busdisplay, and it seems to be horribly slow, like half a second per line of code or so. Is that a known problem?

manic glacierBOT
slender iron
manic glacierBOT
tulip sleet
#

a more sophisticated terminal program could provide this as well

lone axle
#

RAM would be good still I think, I'm generally not hard resetting. Hadn't considered flash wear.

fleet hollow
#

Thonny does this automatically with REPL

stuck elbow
lone axle
#

I'm not familiar with thonny, I'll have to try it out. In the REPL now accessed via tio there is history, but only until it resets with ctrl+d. I'm hoping to be able to go REPL -> commands -> ctrl+d & ctrl+c -> up arrow to get back to commands.

stuck elbow
manic glacierBOT
#

What I said above about .serial_connected not knowing the state of the USB connection is wrong. It can in fact return False if there's no terminal program connected. It calls tud_cdc_connected() which in turns tud_cdc_get_line_state(), which is 0 if both are unasserted and 3 if both are asserted. If the terminal program is closed then DTR/RTS are both unasserted.

However, .serial_connected is more complicated than the CDC state. It returns what serial_connected() in `superv...

tulip sleet
manic glacierBOT
#

Could you try the test program in this post on your FeatherS3 and see whether the LED goes out when the terminal program is disconnected?

Uploaded the program, (physically) reset the board, and it came up with light off. Connected with screen /dev/ttyACM0 115200 and shortly after I connected, the LED came on. The first output was:

11 supervisor.runtime.serial_connected=True
12 supervisor.runtime.serial_connected=True
13 supervisor.runtime.serial_connected=True
14 supervisor...
#

Using tio this time and my original repro code:

[77055328378] [True] 203...
[77156127941] [True] 204...
[77257141117] [True] 205...
[77357971199] [True] 206...
[77458770762] [True] 207...

[15:39:30.596] Disconnected
user@host:/path$ tio /dev/ttyACM0
[15:40:05.771] tio v2.7
[15:40:05.771] Press ctrl-t q to quit
[15:40:05.772] Connected
[112663604743] [True] 557...
[112764373789] [True] 558...
[112865142834] [True] 559...
[112965942384] [True] 560...
[113066772466] [True] 561...
...
manic glacierBOT
#

The GNU screen man page was unhelpful about DTR/RTS handling, and my websearching only turned up this ancient (2007) email thread: https://lists.gnu.org/archive/html/screen-devel/2007-10/msg00005.html.

So this seems to be an iodiosyncrasy of screen. We can put a warning about it in the "Welcome to CircuitPython" guide, but I don't think there's much we can do. If you are fine with that, we'll close this issue.

manic glacierBOT
fleet hollow
slender iron
#

Definitely interesting!

lone axle
candid sun
#

i tried approving but i don't think i have the right access unfortunately

lone axle
#

Thank you! It does show as approved but uses different icon color in some places which is odd. I think thats fine though.

manic glacierBOT
#

The GNU screen man page was unhelpful about DTR/RTS handling, and my websearching only turned up this ancient (2007) email thread: https://lists.gnu.org/archive/html/screen-devel/2007-10/msg00005.html.

So this seems to be an iodiosyncrasy of screen. We can put a warning about it in the "Welcome to CircuitPython" guide, but I don't think there's much we can do. If you are fine with that, we'll close this issue.

I concur. The issue also appears in minicom when using "quit with no r...

manic glacierBOT
manic glacierBOT
#

I am implementing 3 and 4 above:

os.getenv(key, default)

  • os.getenv(key, default) always returns a string, which is the value on the right side of the key =. Leading and trailing whitespace is removed. Surrounding double-quotes are removed. The value may be invalid in TOML, but no error is raised. If there is no settings.toml or the key is not found, the default value is returned.

supervisor.get_setting(key, default)

Tentatively, `supervisor.get_setting(key, default...

manic glacierBOT
#

This patch adds support for user-specific makefile-includes.

Currently, there are mainly

  • mpconfigboard.mk (board-specific)
  • mpconfigport.mk (port-specific)
  • circuitpy_mpconfig.mk (globals)

User-overrides are possible from the make commandline (except for a number of hardcoded settings), but this gets tedious. This patch allows power-users to put the changes in user-specific files with the added benefit that you can use makefile-logic to limit the changes to specif...

manic glacierBOT
#

CircuitPython version and board name

Adafruit CircuitPython 10.0.3 on 2025-10-17; Adafruit Feather ESP32S3 4MB Flash 2MB PSRAM with ESP32S3

Code/REPL

import board
import busio
import displayio
import fourwire
import time
import alarm


SLEEP=20

time.sleep(10) # Allow me time connect after reset via USB Serial
print("Initing SPI")
spi = busio.SPI(board.SCK, board.MOSI)  # Uses SCK and MOSI
print("Done initing SPI")

epd_cs = board.D9
epd_dc = board.D10
epd_r...
manic glacierBOT
#
  • Fixes #9113

See #9113 for the motivation for this PR.

  • os.getenv(key, default=None) now always returns a string. It never raises an error. It will return whatever is on the right hand side of key = in settings.toml after removing leading and trailing whitepsace. The value is returnedeven if that value is not valid TOML, such as an unquoted string. If the key cannot be found or there is a pathological problem (bad Unicode escape, etc.), it will return the default value.
  • A...
manic glacierBOT
manic glacierBOT
#

Summary

  • Adds board definition files for the NHB Systems L401-S3 datalogger board. (Not yet released)
  • Uses ESP32-S3-Mini-1 module (4MB Flash, 2MB PSRAM) with native USB-C
  • On-board peripherals include an AD7124-4 24 bit ADC, PCA9546A I2C mux, MCP7940N RTC, LSM6DSO IMU, and uSD slot

Testing

  • Firmware builds and runs successfully on board
  • All peripherals tested individually
  • Long running script that utilizes all peripherals, records to file, and publishes data via MQTT
manic glacierBOT
manic glacierBOT
#

CircuitPython version: 10.0.3
Board: Adafruit Metro RP2350 (RP2350B, A2 stepping)

Problem

PIO state machines run and consume FIFO data (sm.pending goes to 0), but GPIO pins are not driven. Pins stay at ~1.6V regardless of set pins, out pins, mov pins, or sideset instructions.

Works

  • digitalio drives pins correctly (0V/3.3V toggle)
  • picodvi (HSTX) works correctly
  • Same PIO code works on Feather RP2350 (RP2350A) with same CP version

Minimal reproduction

import board
imp...
thorny jay
manic glacierBOT
#
[adafruit/circuitpython] New tag created: 10.1.0
orchid basinBOT
iron finch
#

Friends, is it only me or has anyone else seen a performance reduction in rc.1 vs. the beta version on ESP32-S3?

tulip sleet
iron finch
#

I'm investigating, but this seems to be deeper and across the board on my build.

tulip sleet
#

are you using a display? which board is it?

iron finch
#

No display. ESP32-S3 - N4R2

#

It's strange as it seems to be across the board, not a single library operation.

tulip sleet
#

could you try some simple timing, like just a loop that adds to a count or similar?

iron finch
#

For sure.

tulip sleet
#

is this an Adafruit board?

#

10.1.0 rc.1 does include the BLE "no flash" PR you proposed and I modified

iron finch
#

I'm building it with those flags to speed up the startup process as I'm not using BLE workflow / serial. I had the fix in the beta version as well. It's probably something with the build, I will re-build it and also test with and without those flags set.

stuck elbow
#

I also noticed a big slowdown on esp32-s3 with a display

iron finch
iron finch
#

The size of the build is the same.. I thought I had set a JTAG/debug flag by mistake.

manic glacierBOT
iron finch
#

Can it have anything to do with commit 44f3816191 ("Fixes for native sim") in PR #10795?

The fix added port_yield() calls to the shared background callback code (background_callback.c, lines 64 and 91), so it affects all ports including ESP32 — not only Zephyr.

On ESP32, port_yield() calls vTaskDelay(4) (port.c, line 487), which with CONFIG_FREERTOS_HZ=1000 could mean a minimum 4ms sleep?

#

Potential fuzzy math that could be wrong:

background_callback_run_all() is called via the MICROPY_VM_HOOK_LOOP macro, which fires on every branch/jump opcode through DISPATCH_WITH_PEND_EXC_CHECK() — not just once per loop iteration.

A typical counter loop with an if check could hit 2–3 branch opcodes per iteration, so the actual cost could be 2–3 × ~4ms ≈ 8–12ms per iteration → ~83–125 counts/sec. At 3 branches × ~4ms = ~12ms per iteration, that gives ~83 counts/sec — matching my RC.1 log.

tulip sleet
manic glacierBOT
manic glacierBOT
#

#10795 added calls to port_yield() much more frequently, on every background_callback_run_all(). On most ports, port_yield() does nothing, but on Espressif, port_yield() delays for 4 msecs. This causes a 1400x (!) slowdown in a simple timing loop. Pico W boards will probably also have a big slowdown.

Thanks @daniel-alsen for catching this.

Test:

import time

while True:
    start = time.monotonic()
    count = 0
    while count < 10000:
        count += 1
    print(time.monoto...
orchid basinBOT
manic glacierBOT
manic glacierBOT
#

-- Fixes #10521

Update to ARM toolchain gcc 15.2Rel1.

Note that we use our own copy of libgcc for SAMD21 builds. The one that comes with the toolchain is compiled with -O2, but using a -Os version saves about 100 bytes. @tannewt extracted it from the Arch arm-none-eabi-gcc package. That package, as of this writing, has not yet been updated to gcc 15; see https://archlinux.org/packages/extra/x86_64/arm-none-eabi-gcc/.
https://github.com/adafruit/circuitpython/blob/8d17d0cff4ebcfb...

manic glacierBOT
#

@tannewt if you have a more in-depth fix that is fine. I was just trying to reverse the effects on the change on the non-zephyr builds.

The original port_yield() was for #6742, which maybe is a different use for port_yield(). I think it might be good to figure out if portYIELD() is good enough, instead of adding a delay. I think it could also be done only on msec ticks instead of on every HOOK (RUN_BACKGROUND_TASKS) call, which is a lot more often. We can discuss.

surreal perch
# manic glacier

I'm not sure how to classify this. My original bug code now works without the error but executing the code in REPL via importing the code still exhibits. I don't know whether it is significant or not.

>>> import code_sck_bug_as_filed.py
Initing SPI
Done initing SPI
>>> import code_sck_bug_as_filed.py
Initing SPI
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "code_sck_bug_as_filed.py", line 13, in <module>
ValueError: SCK in use

I'm almost leaning toward calling it an edge case and closing the issue. But perhaps I should wait and double check against 10.1.1.

manic glacierBOT
manic glacierBOT
stuck elbow
strange zinc
# manic glacier

Hello,

Is there anything I need to consider before I start implementing what I proposed? Is my proposed solution considered acceptable?

manic glacierBOT
tulip sleet
manic glacierBOT
orchid basinBOT
manic glacierBOT
#

I have a working implementation. Here are benchmarks on a Seeed Studio XIAO RP2350:

OLD:

os.urandom benchmark
-------------------------------------------------------
Size:    1B | 1000 calls | 0.039s | 25.04 KB/s
Size:    4B | 1000 calls | 0.040s | 97.65 KB/s
Size:   16B | 1000 calls | 0.041s | 381.09 KB/s
Size:   32B | 1000 calls | 0.042s | 744.05 KB/s
Size:   64B | 1000 calls | 0.074s | 844.54 KB/s
Size:  128B | 1000 calls | 0.140s | 892.86 KB/s
Size:  256B | 1000 calls | 0.275s | 909....
manic glacierBOT
#

There is the following note in section 8.3.8 of the datasheet that actually made me consider changing the RNG source:

When the system clocks are running from the XOSC, you can use the ROSC to generate random numbers. Enable the
ROSC and read the RANDOMBIT register to get a 1-bit random number; to get an n-bit value, read it n times. This does not
meet the requirements of randomness for security systems because it can be compromised, but it may be useful in less
critical applications. If th...

manic glacierBOT
manic glacierBOT
orchid basinBOT
manic glacierBOT
#

Why not just use what pico-sdk does?

pico_rand uses splitmix64/xoroshiro128** as its conditioner, while this implementation uses SHA-256, which is a cryptographically stronger conditioner. It also gives more control over the TRNG configuration (health tests, sampling rate).

This is consistent with what the RP2350 bootrom itself does. As documented in section 12.12.4.1 of the datasheet, the bootrom also uses SHA-256 for entropy conditioning:
https://datasheets.raspberrypi.com/rp2350/rp2350...

tulip sleet