Why Doesn’t this Upload? A Debugging Tale

This is a story of doing some debugging, and how various possibilities were eliminated.

Last week an SSL certificate that is needed for access to Adafruit IO expired. The older certificate was embedded in CircuitPython and also in the NINA-FW firmware. The NINA-FW firmware runs on an ESP32, which is meant to be used as a WiFi co-processor. NINA-FW was originally written byArduino, was forked by us, and is used for Adafruit’s AirLift series of boards and breakouts.

CircuitPython 8.2.2 was released to include the new certificate. We also rebuilt the NINA-FW firmware to include this new certificate, in version v1.7.5. On boards like the PyPortal or MatrixPortal M4, NINA-FW is updated by loading a simple serial-“passthrough” program, written with Arduino, on the board’s main microcontroller. The passthrough passes bytes in both directions between the board’s USB serial port and the UART port on the ESP32.

However, the new NINA-FW would not load properly using the passthrough. We tried rebuilding the release in a couple of different ways, but the upload would always fail partway through the upload.

I was wondering what was wrong with the passthrough. It’s a very simple program, just reading bytes and writing them to the other side. I tried a number of small tweaks on the basic loop, to no avail.

Over the weekend, I attacked the problem in a divide-and-conquer way. When there are multiple possible causes, you try to eliminate a cause to narrow down what the problem could be.

First I made a testbed with a Feather M4 (SAMD51) and an ESP32 breakout board that was wired the same way the chips were connected on a MatrixPortal or PyPortal. I reproduced the upload failure. Then I made passthrough programs for other Feather boards: SAMD21 (M0), nRF52840, and RP2040. The upload failure also occurred with SAMD21, but there was no problem with the nRF52840 and RP2040 Feathers.

That told me that the problem was something with the passthrough only on SAMD boards. The next question was whether the problem was related to the UART implementation, or to the USB serial implementation for SAMD boards. I  made another testbed, connecting a standard USB-serial adapter to a UART port on a SAMD Feather, and then connecting a second UART port on the SAMD to the ESP32. I modified the passthrough program to be UART-to-UART, instead of UART-to-USB-serial. That worked with SAMD boards, which told me the problem was with the USB code “stack”.

While investigating the USB code, I discovered that we had provided an Arduino compile option to use the TinyUSB stack instead of the native SAMD USB stack. I recompiled the original passthrough with TinyUSB, and it worked! I tested a little more, and then rebuilt all the passthroughs with TinyUSB. The problem was solved. What’s wrong with the USB stack is still unknown, but that is a problem for another day.


Adafruit publishes a wide range of writing and video content, including interviews and reporting on the maker market and the wider technology world. Our standards page is intended as a guide to best practices that Adafruit uses, as well as an outline of the ethical standards Adafruit aspires to. While Adafruit is not an independent journalistic institution, Adafruit strives to be a fair, informative, and positive voice within the community – check it out here: adafruit.com/editorialstandards

Join Adafruit on Mastodon

Adafruit is on Mastodon, join in! adafruit.com/mastodon

Stop breadboarding and soldering – start making immediately! Adafruit’s Circuit Playground is jam-packed with LEDs, sensors, buttons, alligator clip pads and more. Build projects with Circuit Playground in a few minutes with the drag-and-drop MakeCode programming site, learn computer science using the CS Discoveries class on code.org, jump into CircuitPython to learn Python and hardware together, TinyGO, or even use the Arduino IDE. Circuit Playground Express is the newest and best Circuit Playground board, with support for CircuitPython, MakeCode, and Arduino. It has a powerful processor, 10 NeoPixels, mini speaker, InfraRed receive and transmit, two buttons, a switch, 14 alligator clip pads, and lots of sensors: capacitive touch, IR proximity, temperature, light, motion and sound. A whole wide world of electronics and coding is waiting for you, and it fits in the palm of your hand.

Have an amazing project to share? The Electronics Show and Tell is every Wednesday at 7pm ET! To join, head over to YouTube and check out the show’s live chat – we’ll post the link there.

Join us every Wednesday night at 8pm ET for Ask an Engineer!

Join over 36,000+ makers on Adafruit’s Discord channels and be part of the community! http://adafru.it/discord

CircuitPython – The easiest way to program microcontrollers – CircuitPython.org


Maker Business — “Packaging” chips in the US

Wearables — Enclosures help fight body humidity in costumes

Electronics — Transformers: More than meets the eye!

Python for Microcontrollers — Python on Microcontrollers Newsletter: Silicon Labs introduces CircuitPython support, and more! #CircuitPython #Python #micropython @ThePSF @Raspberry_Pi

Adafruit IoT Monthly — Guardian Robot, Weather-wise Umbrella Stand, and more!

Microsoft MakeCode — MakeCode Thank You!

EYE on NPI — Maxim’s Himalaya uSLIC Step-Down Power Module #EyeOnNPI @maximintegrated @digikey

New Products – Adafruit Industries – Makers, hackers, artists, designers and engineers! — #NewProds 7/19/23 Feat. Adafruit Matrix Portal S3 CircuitPython Powered Internet Display!

Get the only spam-free daily newsletter about wearables, running a "maker business", electronic tips and more! Subscribe at AdafruitDaily.com !



1 Comment

  1. Please check to see if you have chunks of FF data in your build.
    USB cannot send lots of 1’s in a row and needs to insert an extra transition in there.
    This will mess up timings as it is done at a low level after a number of 1’s (6 if memory serves me well)

    I had this issue once with a self made camera system which approached max USB bandwidth.
    Trick I used was to let the FPGA on that board XOR the data with 0xA5 and then convert it back at the receiver end.

Sorry, the comment form is closed at this time.