A first look at a MicroPython marvel: the Raspberry Pi Pico, in partnership with a Mac

On Thursday morning I awoke to the news that the Raspberry Pi people have entered the microcontroller board market with a new product, the Raspberry Pi Pico. Before I’d even got out of bed, I ordered a couple. Well, at £3.60 a pop, why not? I’ve now had a chance for a quick play, and here are my findings.

The Raspberry Pi Pico
“Yeah, I know it — it’s on Pico…”

The Pico doesn’t ship with header pins, so you’ll need to buy some and solder them on yourself. The Pico is about the same size as an Adafruit Feather board, but is narrower so it gives you back one line of breadboard pins. Some of the components are very close to the header pins, so you should take care when soldering not to jab them with the tip of your iron. Maybe the Feather’s extra width is useful after all: not only are you less likely to damage components with your soldering iron but also there’s room on the PCB silkscreen to add pin designations, which are missing from the upper side of the Pico.

Raspberry Pi Pico and Adafruit Feather
The Pico is a breadboard pin row narrower than the Adafruit Feather (top)

The only thing I don’t like about the Pico is its micro USB connector. I’d much rather have USB-C, which makes repeatedly connecting and disconnecting the device way smoother than micro USB does, especially the one here. Given that the Foundation favours USB-C for the latest generation of full-size Pis, why not use it here too? Price, I presume, but other suppliers of microcontroller boards have adopted USB-C. It’s a shame the Foundation isn’t leading the way here too.

Assembled and hooked up to a Mac, the Pico immediately boots into USB mode ready for you to install MicroPython. This is a good choice and the best one for most people, but the Foundation also support C/C++ for folk who are more demanding. I plan to look at this option next, but I wanted to start out with MicroPython because I’m familiar with it from other boards.

So, one quick .uf2 file download later, I’ve copied MicroPython over to the mounted USB drive, which auto-dismounts and reboots ready for programming.

I have this function set in my .zshrc file:

dlist() {
    local list=$(/bin/ls /dev/cu.*)
    local ignores=(Bluetooth TSAirPods debug)
    while IFS= read -r device; do
        local do_show=1
        for ignorable in "${ignores[@]}"; do
            local ignore=$(grep "$ignorable" < <(echo -e "$device"))
            if [[ -n "$ignore" ]]; then
                do_show=0
                break
            fi
        done
        if [[ $do_show -eq 1 ]]; then
            echo $device
        fi
    done <<< "$list"
}

It prints out the filename of connected devices and yields /dev/cu.usbmodem0000000000001 for the Pico. Like other MicroPython devices — but not those using CircuitPython — the application Flash storage doesn’t mount so you have to enter programs at the MicroPython command line, or use serial software to squirt code over.

The Foundation’s instructions are Pi-centric, naturally, but they also include guidance for Mac and Windows users. I don’t really want to install extra tools that do the same job as tools I already have, so I’ve gone my own way. To access the MicroPython REPL, I use screen:

/Users/smitty > screen $(dlist) 115200

To send over code, I tried the recommended rshell but had no joy — it couldn’t talk to the board. So I used ampy, the tool I use for my ESP8266-based feather boards running MicroPython. It worked. You use put to send a file over and ls to list files:

/Users/smitty > ampy -p $(dlist) put main.py
/Users/smitty > ampy -p $(dlist) ls
/ht16k33.py
/ht16k33matrix.py
/main.py

As you can see from the list of files, I wanted to try my HT16K33 display library first. I chose an 8×8 LED matrix first and adapted my test code for the Pico’s primary I²C pins. Ah, but which pins?

If you read the official pinout diagram, you’ll see dozens of I²C-capable pins listed, but these are not all made accessible through MicroPython it seems. Instead you use the “default” ones, which are not indicated on the pinout. The Foundation’s guide to MicroPython on the Pico says you want pins 8 and 9; pins 6 and 7 are also available. It actually means GPIO pins 8 and 9, not pins 8 and 9 as labelled on the pinout.

I finally connected my matrix to GPIO 8 and 9 (pins 11 and 12) not pin numbers 8 and 9, or one of the other listed I²C buses. I have a working LED matrix. Hello, World!

“It lives!”

The Pico is a powerful microcontroller package that is incredibly good value — one advantage of no USB-C port. I looked at the Serpente R2 a little while ago. It’s more than three times the price of the Pico but slower (48MHz to 133MHz), has less memory (32KB to 264KB) and way fewer GPIO (26 to 5) and peripherals (two UARTs, two SPI and two I2C, to two, one and one, respectively). The R2 has more Flash storage (4MB to 2MB) and is physically smaller — those are its only advantages.

The Pico has an ideal specification for low-power or space-constrained projects, and its price is such that you’d really need to reject it because it’s not capable enough for your needs before you’d turn to any other microcontroller board. It’s not ready for Internet of Things projects because it has no networking, but expect that shortcoming to be addressed in licensed boards based on the Pico’s 2040 MCU. But I think I may have just found my new standard for non-networked MCU projects.

Now to go and try the C implementation…

More on the Raspberry Pi Pico