Skip to content

nina-fw CircuitPython installer #68

@mikeysklar

Description

@mikeysklar

Currently the nina-fw install process involves pasthrough code written in Arduino. @b-blake proposed a CircuitPython installer and came up with some code that gets pretty close, but is not quite usable to push up a stub.

This is a request for enhancement. Making this functional as a convenient way for the CircuitPython crowd to manage ESP32 Airlift updates. It is a an elegant approach leaving the CircuitPython installation and libraries intact. Rather than the sledgehammer UF2 pass through image which wipes everything.

We have been testing with a mix of Feather RP2040 + Airlift (breakout or FeatherWing).

import time
import board
import busio
import digitalio
import usb_cdc
import supervisor
# 3 seconds to get here from fresh load
time.sleep(10)

# Define your pins (example for Feather RP2040)
TX = board.TX
RX = board.RX
ESP32_CS    = digitalio.DigitalInOut(board.D13)  # B Chip Select pin, LED
ESP32_RST   = digitalio.DigitalInOut(board.D12)  # G Reset pin
ESP32_GPIO0 = digitalio.DigitalInOut(board.D10)  # W GPIO0 pin (force bootloader mode)

ESP32_CS.direction    = digitalio.Direction.OUTPUT
ESP32_RST.direction   = digitalio.Direction.OUTPUT
ESP32_GPIO0.direction = digitalio.Direction.OUTPUT

# Create UART for ESP32 communication
uart = busio.UART(TX, RX, baudrate=115_200, timeout=0)

# Wait for USB connection (if needed)
while not supervisor.runtime.usb_connected:
    time.sleep(0.1)

# --- Reset ESP32 Sequence ---
# Force ESP32 into bootloader mode
time.sleep(0.1)           # Short delay
ESP32_GPIO0.value = False # Pull GPIO0 low
time.sleep(0.1)           # Short delay
ESP32_RST.value   = False # Assert reset
time.sleep(0.1)           # Short delay
ESP32_RST.value   = True  # Release reset
# Minimal delay to let bootloader initialize but not too long so we don't miss its handshake
time.sleep(0.1)

# --- Main Passthrough Loop ---
while True:
    # Forward data from ESP32 (UART) to USB console
    data = uart.read(32)  # Read up to 32 bytes
    if data:
        try:
            usb_cdc.console.write(data)
        except Exception as e:
            # In case of a transient error, you could log it here
            pass

    # Forward data from USB console to ESP32 (UART)
    if usb_cdc.console.in_waiting:
        incoming = usb_cdc.console.read(usb_cdc.console.in_waiting)
        if incoming:
            uart.write(incoming)

    # A short sleep to prevent hogging the CPU; adjust as needed
    time.sleep(0.001)

This is how far the code gets:

% esptool.py --port /dev/cu.usbmodem142101 --before no_reset --baud 115200 write_flash 0 NINA_W102-1.7.7.bin
esptool.py v4.8.1
Serial port /dev/cu.usbmodem142101
WARNING: Pre-connection option "no_reset" was selected. Connection may fail if the chip is not in bootloader or flasher stub mode.
Connecting....
Detecting chip type... Unsupported detection protocol, switching and trying again...
Connecting...
Detecting chip type... ESP32
Chip is ESP32-U4WDH (revision v3.1)
Features: WiFi, BT, Dual Core, 240MHz, Embedded Flash, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: 30:c9:22:7b:41:a4
Uploading stub...

A fatal error occurred: Invalid head of packet (0x54): Possible serial noise or corruption.

Longer forum thread for reference.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions