CircuitPython on the Pico

Run code.py on a Pico with the official CircuitPython firmware: the Firmware panel, the CIRCUITPY drive, libraries, the REPL and Wokwi imports.

Which boards

The plain Raspberry Pi Pico runs CircuitPython, and so does the Arduino Nano RP2040 Connect, with CircuitPython's own build for it: the same RP2040, with board.LED on D13 (GPIO 6) and board.I2C() on A4 and A5. See the Nano RP2040 Connect. The Raspberry Pi Pico W runs its own build, with its CYW43439 radio chip modeled, so board.LED lights and WiFi works on Mokxi's simulated network (see WiFi on the Pico W). The ESP32-S3-DevKitC-1 runs CircuitPython too, with its own build and its REPL and drive on the S3's native USB; WiFi is not simulated under CircuitPython there. The Pico runs MicroPython too; see the Pico.

What runs is CircuitPython 10.3.1 for the Raspberry Pi Pico, the official Adafruit firmware, byte for byte as circuitpython.org publishes it, on Mokxi's simulated RP2040. Nothing in the page interprets your Python.

Choosing it in the Firmware panel

  1. Put a Raspberry Pi Pico, a Pico W, an Arduino Nano RP2040 Connect or an ESP32-S3-DevKitC-1 on the canvas.
  2. Open its Firmware panel and pick CircuitPython (code.py).
  3. The board's files become a code.py. If they hold work of your own, you are asked first. Write your program there and press Run.

A board whose files have a code.py and no .ino runs CircuitPython. An Arduino sketch or a MicroPython project on the same board runs as before, and nothing of CircuitPython is loaded for it.

The first Run of a CircuitPython project downloads the firmware, and the browser keeps it for every later Run. An Arduino sketch never downloads it.

The CIRCUITPY drive and code.py

CircuitPython keeps its files on a drive called CIRCUITPY, in the board's flash. At Run, Mokxi writes that drive before the board powers on: the firmware's own boot_out.txt, the Adafruit libraries your program imports under lib/, and every .py, .txt, .json, .csv and .toml tab but code.py.

Then the computer on the end of the Pico's simulated USB cable opens the board's serial port and saves code.py onto the drive over USB, the way your own computer does when you save it from your editor. CircuitPython sees the save and reloads, as it does on a desk, and runs code.py with the Serial Monitor connected, so every line it prints is shown.

code.py prints about two seconds after Run. Most of that is CircuitPython's own: the one-second safe-mode window at boot, while the LED on GP25 blinks, and the wait after a save before it reloads.

microcontroller.reset() and the watchdog keep the drive, so code.py runs again; what it prints before the serial port opens again is lost, as on a desk. Run again starts from a freshly written drive.

Libraries

Mokxi reads your import lines and puts the Adafruit libraries it finds into the drive's lib/ folder by itself, with what they import in turn, as circup would. They are Adafruit's own compiled .mpy files from their CircuitPython 10.x bundle, unchanged:

  • adafruit_bme280
  • adafruit_display_text (with adafruit_ticks)
  • adafruit_displayio_ssd1306
  • adafruit_framebuf (with its font5x8.bin at the top of the drive)
  • adafruit_hcsr04
  • adafruit_requests (with adafruit_connection_manager)
  • adafruit_ssd1306
  • neopixel

Each one is downloaded only when a program imports it. A tab named after a library, such as neopixel.py, is your own and is used instead. Modules built into the firmware (board, digitalio, analogio, pwmio, busio, time, displayio, terminalio, i2cdisplaybus and the rest) need nothing.

The Serial Monitor and the REPL

The Serial Monitor is the board's USB serial port, both ways: what code.py prints, its tracebacks, and Code done running. when it ends.

  • Ctrl-C stops code.py with a KeyboardInterrupt.
  • Any key then enters the REPL, and >>> answers there.
  • Ctrl-D reloads and runs code.py again.

When a program stops with an error, CircuitPython prints a traceback. Mokxi reads it, marks the line in your file, and says what the error usually means in CircuitPython's words: a MicroPython module in a CircuitPython program, a missing pull-up, a pin already in use, or board.I2C(), which the Pico does not have (use busio.I2C(board.GP5, board.GP4)).

What works, and what does not

digitalio, analogio, pwmio, busio.I2C and busio.UART work, so adafruit_bme280, adafruit_ssd1306 and displayio with adafruit_display_text talk to the parts on the canvas.

The PIO runs too, so neopixel_write and the neopixel library light a WS2812 strip, and pulseio.PulseIn reads the echo that adafruit_hcsr04 times an HC-SR04 with.

Not simulated: the second core; audiobusio, audiopwmio and picodvi; and reading the drive from the computer, which only saves to it.

WiFi on the Pico W

wifi.radio.connect() joins Mokxi's simulated access point. Its name and password are the board's WiFi properties, which start as Mokxi-Lab and breadboard. socketpool and adafruit_requests (which the editor puts in lib/ with the adafruit_connection_manager it needs) reach the made-up .mokxi sites, such as http://weather.mokxi/:

import wifi, socketpool, adafruit_requests

wifi.radio.connect("Mokxi-Lab", "breadboard")
print("Connected, IP address", wifi.radio.ipv4_address)
requests = adafruit_requests.Session(socketpool.SocketPool(wifi.radio))
print(requests.get("http://weather.mokxi/").json())

Any other name is not found, and https:// has nowhere to go. Not simulated: Bluetooth, the access point mode's clients and power save. wifi.radio.ap_info raises NotImplementedError, because CircuitPython's Pico W port does not implement it.

Importing from Wokwi

A Wokwi project for the Pico, the Pico W, the Nano RP2040 Connect or the ESP32-S3-DevKitC-1 with a code.py imports with its board set to CircuitPython, and runs. On another board its code.py is kept as text, and the import says why. Wokwi may have used another CircuitPython version; the import report says which one runs here. See Coming from Wokwi.

On a real board

A CircuitPython board needs no build. Put CircuitPython on the Pico (hold BOOTSEL while you plug it in, then drag the .uf2 from circuitpython.org/board/raspberry_pi_pico onto the RPI-RP2 drive), then save code.py onto the CIRCUITPY drive that appears, and copy any libraries it imports into CIRCUITPY/lib (circup install does it for you).

On a Pico W, drag the .uf2 from circuitpython.org/board/raspberry_pi_pico_w instead, and put your own network's name and password in code.py. On a Nano RP2040 Connect, jumper REC to GND while you plug it in instead, and drag the .uf2 from circuitpython.org/board/arduino_nano_rp2040_connect. On the ESP32-S3-DevKitC-1, plug in its USB port (the one marked USB, not UART) and use the installer at circuitpython.org/board/espressif_esp32s3_devkitc_1_n8.

Starters

Starters on a Pico, each on its own page: blink, a button, a NeoPixel rainbow, a BME280 and text on an SSD1306 OLED. The CircuitPython simulator walks through them.

Elsewhere