RoadTest: Raspberry Pi Pico
Author: vmate
Creation date:
Evaluation Type: Development Boards & Tools
Did you receive all parts the manufacturer stated would be included in the package?: True
What other parts do you consider comparable to this product?: Various Arduino boards, Espressif ESP8266/ESP32, STM32
What were the biggest problems encountered?: Unlabeled pins on the board are a big annoyance
Detailed Review:
Introduction
The Pi Pico is a development board released by the Raspberry Pi Foundation. It uses the RP2040 MCU, which has 2 Cortex-M0+ cores running at 133MHz, 264kB of RAM, and 2MB of external QSPI flash.
There are 2 UARTs, 2 SPI controllers, 2 I2C controllers, 16 PWM channels, and 3 ADCs usable on this board. The RP2040 has one more ADC pin, however this is unexposed on the Pico.
There have been plenty of reviews and guides on using the Pi Pico, so instead of showing how to use it, I will be comparing it to two other common microcontrollers: the ESP32, and the ATSAMD series of MCUs.
The development board
Most of this review will be focusing on the RP2040 chip, however there are a few things to be said about the board itself.
A micro-USB connector is used to supply power and upload software to the microcontroller. I would have preferred a USB-C connector instead, as most things today have been using that instead of the older and inferior micro-USB connector. The Pi Foundation seems to agree with me on this, since they switched to it on the Pi 4.
A 2MB flash IC is used for the RP2040, which is usually plenty enough to work with.
There is an LED connected to GP25, and a button for selecting the boot mode.
26 of the RP2040’s GPIO pins are exposed, plus one for the LED mentioned above.
SWDIO and SWDCLK along with GND are also exposed as 3 separate pins.
The board is designed to be usable either as a standalone module, or as soldered to another board. All the GPIO pins have castellated holes, and USB lines have pads on the bottom that can be reflow soldered to another PCB.
The silkscreen text on the top of the board is minimal – it tells you which pin is the first and last, and that’s about it. Instead, all the pin numbers are shown on the bottom of the board, where most people cannot see it, unless you solder pin headers “upside down”, but then you lose access to the BOOTSEL button and probably won’t see the LED. There is plenty of space on the top of the board, it would have been nice if they laid out the components in a way so that pin names can fit where it is easy to see.
The other microcontrollers
I’ve chosen the NodeMCU ESP32S and Arduino MKR Zero to compare the Pi Pico to.
The MKR Zero is several times more expensive than the Pi Pico, however the MCU at the heart of it, the ATSAMD21G18 is roughly in the same class as the RP2040, and there are several development boards available using the exact same MCU, for a similar price to the Pi Pico.
Price
The Pi Pico costs 4 USD, it includes the RP2040 MCU, 2MB of flash, crystal for the clock, and some miscellaneous things like the BOOTSEL button, an LED, and the regulators. The RP2040 is available for 1 USD, making it one of the cheapest MCUs in its category.
The ESP32S costs roughly around 6 USD, it contains an ESP-WROOM-32 module, a USB to UART IC, a reset and boot button, and regulators. The ESP-WROOM-32 module costs around 3 USD, it includes the ESP32-D0WDQ6 MCU, 4MB of flash, a crystal for clock, and an antenna (or connector for an antenna with some versions) for Wi-Fi. The ESP32-D0WDQ6 MCU is available for 1.6 USD.
The MKR Zero costs 27 USD, however there are plenty of boards available that use the same MCU starting at 6 USD. They include a crystal for clock, and regulators. Flash is built into the MCU. The ATSAMD21G18 costs 3.4 USD.
Connectivity
The RP2040 has 30 GPIO pins, 2 UARTs, 2 SPI controllers, 2 I2C controllers, 16 PWM channels, 4 ADC channels(only 3 of which are usable on the Pico), a USB 1.1 controller, and 8 PIO state machines.
The ESP32 has 36 GPIO pins available on the development boards, some of these are used for the flash IC, and therefore unusable. The ESP32 includes 3 UARTs, 3 SPI controllers, 2 I2C controllers, 16 PWM channels, 18 ADC channels, 2 DACs, and 2 I2S controllers. There is also Wi-Fi b/g/n and Bluetooth 4.2 + BLE.
The ATSAMD21G18 has 38 GPIO pins, 6 SERCOM channels that can be configured as SPI/I2C/UART/USART, 14 ADC channels, 2 I2S channels, 1 DAC, and a USB 1.1 controller.
Memory
The RP2040 has 16kB of ROM, containing the bootloader and some miscellaneous functions, 264kB of RAM, and a QSPI interface for external flash. The Pi Pico includes a 2MB flash chip.
The ESP32 has 448kB of ROM containing a bootloader and miscellaneous functions, 520kB of RAM, a QSPI interface for external flash, and it can also use external SRAM. The ESP-WROOM-32 includes 4MB of flash.
The ATSAMD21G18 has 32kB of RAM, and 256kB of built-in flash.
CPU Core
The RP2040 consists of 2 Cortex-M0+ cores, running at up to 133MHz.
The ESP32 consists of 2 Xtensa-LX6 cores, running at up to 240Mhz.
The ATSAMD21G18 consists of a single Cortex-M0+ core, running at up to 48Mhz.
Coprocessors
The RP2040 has 8 PIO State Machines, which can be used to implement hardware communication protocols. They can be programmed in assembly.
The ESP32 has a ULP(Ultra Low Power) coprocessor, which is intended to handle basic functionality not requiring much processing power, so the main ESP32 cores can be put to sleep.
Programming
The RP2040 can be programmed in C/C++, MicroPython, and the Arduino Framework. C/C++ will definitely be the fastest and most efficient, however it takes some time to learn.
MicroPython was made to be simpler, targeting first time users of microcontrollers.
The Arduino Framework is somewhere in the middle, it uses C++, however a lot of things are simplified. The Arduino Framework also has a lot of libraries already, and most microcontrollers can be programmed using it, meaning there’s no need to re-learn everything when using a different microcontroller.
The ESP32 can be programmed in esp-idf which is a C framework, MicroPython, and the Arduino Framework.
The MKR Zero is designed to be programmed in the Arduino Framework, however you can also program it in lower-level languages like C and C++ in Microchip Studio. There’s also a port of MicroPython for it, but this MCU has a lot less memory, so you should probably stick to the previous options.
Debugging
The RP2040 and ATSAMD21G18 have an SWD port for debugging and flashing firmware, which is well documented and easy to use. It’s also possible to use a Raspberry Pi as an SWD debugger, which means no extra hardware is necessary.
The ESP32 does not support SWD, it needs a JTAG debugger, which is usually more expensive.
First impressions, ease of setup
The MKR Zero easily wins in this category. Install the Arduino IDE, plug in the board, select it in a dropdown menu, done. There are also plenty of examples available.
The ESP32 and RP2040 can be used in Arduino IDE as well, however you need to install some extra stuff inside the Arduino IDE to make them work.
Using the Pi Pico with MicroPython involves a few more steps, but it’s not compilated. Plug in the board while holding the BOOTSEL button, copy the MicroPython UF2 file to the Pi Pico, which appears as a flash drive, and then use something like PuTTY to access the Python interpreter, or get an IDE like Thonny where you can easily write and upload code to the board.
Using Microchip Studio to develop for the ATSAMD21G18 is straight forward as well, but setting up Microchip Studio takes a bit of time, however that is justified for me: Microchip Studio contains every tool you will ever need when programming the ATSAMD21G18, compared to the barebones Arduino IDE and Thonny.
The Pi Pico C/C++ SDK is a bit more complicated to set up than the previous tools, however it’s not made for beginners. Still, the Pi Foundation managed to make the process relatively simple and hard to mess up, thanks to the great guides.
Out of these options, setting up an ESP-IDF development environment is definitely the hardest – however, it’s intended for people familiar with the ESP, and definitely not beginners.
MicroPython vs C/C++ SDK vs Arduino Framework
MicroPython is the intended way to program the Pico for beginners, however the Arduino Framework is another great option. The C/C++ SDK is for more experienced developers, providing more performance and lower level access to hardware.
Blinking an LED
MicroPython
from machine import Pin led = Pin(25, Pin.OUT) while(True): led.toggle() sleep(1)
Arduino Framework
void setup() { pinMode(LED_BUILTIN, OUTPUT); } void loop() { digitalWrite(LED_BUILTIN, HIGH); delay(1000); digitalWrite(LED_BUILTIN, LOW); delay(1000); }
C/C++ SDK
#include "pico/stdlib.h" int main() { gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); while (true) { gpio_put(PICO_DEFAULT_LED_PIN, 1); sleep_ms(1000); gpio_put(PICO_DEFAULT_LED_PIN, 0); sleep_ms(1000); } }
Fading an LED
MicroPython
from machine import Pin, PWM from time import sleep pwm = PWM(Pin(25)) pwm.freq(1000) while True: for i in range(0, 65025, 32): pwm.duty_u16(i) sleep(0.001) for i in range(65025, 0, -32): pwm.duty_u16(i) sleep(0.001)
Arduino Framework
void setup() { pinMode(LED_BUILTIN, OUTPUT); } void loop() { for(byte i = 0; i < 256; i++) { analogWrite(LED_BUILTIN, i); delay(5); } for(byte i = 255; i >= 0; i--) { analogWrite(LED_BUILTIN, i); delay(5); } }
C/C++ SDK
#include "pico/stdlib.h" #include <stdio.h> #include "pico/time.h" #include "hardware/pwm.h" int main() { gpio_set_function(PICO_DEFAULT_LED_PIN, GPIO_FUNC_PWM); uint slice = pwm_gpio_to_slice_num(PICO_DEFAULT_LED_PIN); pwm_config config = pwm_get_default_config(); pwm_init(slice, &config, true); while(true) { for(uint16_t i = 0; i < 65536; i += 32) { pwm_set_gpio_level(PICO_DEFAULT_LED_PIN, i); sleep_ms(1); } for(uint16_t i = 65535; i >= 0; i -= 32) { pwm_set_gpio_level(PICO_DEFAULT_LED_PIN, i); sleep_ms(1); } } }
Hello, World!
MicroPython
print("Hello, world!")
Arduino Framework
void setup() { Serial.begin(9600); } void loop() { Serial.println("Hello, world!") }
C/C++ SDK
#include <stdio.h> #include "pico/stdlib.h" int main() { stdio_init_all(); printf("Hello, world!"); return 0; }
Using multiple cores
MicroPython
import time, _thread, machine def thread(): while(True): #Do something on thread 1 here _thread.start_new_thread(task, ()) while(True): #Do something on thread 0 here
C/C++ SDK
#include <stdio.h> #include "pico/stdlib.h" #include "pico/multicore.h" void core1_entry() { while(true) { //Do something here on core 1 } } int main() { stdio_init_all(); multicore_launch_core1(core1_entry); while(true) { //Do something here on core 2 } }
UART
MicroPython
from machine import UART, Pin uart0 = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1)) uart0.write("Hello, UART!")
Arduino Framework
void setup() { Serial.begin(9600); } void loop() { Serial.println("Hello, UART!") }
C/C++ SDK
#include <stdio.h> #include "pico/stdlib.h" #include "hardware/uart.h" int main() { uart_init(uart0, 115200); gpio_set_function(0, GPIO_FUNC_UART); gpio_set_function(1, GPIO_FUNC_UART); uart_puts(UART_ID, "Hello, UART!\n"); }
Conclusion
The Pi Pico is a great budget development board, offering MicroPython support, easily beating most microcontrollers in its price range, however the ESP32 offers more memory, performance, and it has built-in WiFi and Bluetooth for just a tiny bit higher price. For projects not requiring wireless communications or every single bit of performance possible, the Pi Pico is a great choice, with superb documentation and guides both from the Pi Foundation and the community.
Top Comments
I tried using it with a handful of modules and other things I found laying around, but I am working on a larger project using it. I didn't write about that in the RoadTest, mostly because I don't have…