The PicoBoy
The PicoBoy is a powerful mini handheld measuring just 3×5 ㎝. It is suitable for learning programming, developing your own games or simply playing with it. All you need is a PC, the PicoBoy and a USB-C cable. As the PicoBoy based on the RP2040 SoC [26] by Raspberry Pi Ltd. and is compatible with the Raspberry Pi Pico programming model and process, there are countless other tutorials, examples and libraries on the internet to make programming easier.
Board Overview
Hardware
The PicoBoy [8] [1] is a special mini sized RP2040 development board.
Features and Resources |
Printed Circuit Board |
5V/125~250㎃ 3.0~3.3V/180~200㎃ 133㎒ 2㎆ 264㎅ USB-C CR2032 UF2 RST BOOT UP|DOWN|LEFT|RIGHT|ENTER RED YELLOW GREEN OLED PASSIVE 9 4 4 1 1
Design Data
|
![]() |
Positions
Data Sheets
Pinouts
The peripherals of the RP2040 SoC [26] can be routed to various pins on the board. The configuration of these routes can be modified through DTS. Please refer to the datasheet to see the possible routings for each peripheral. The default assignments for the PicoBoy on-board wiring is defined below. There are no edge connectors, headers or solder pads with additional signals routed to outside of the board.
Pin Mapping |
Default Zephyr On-Board Mapping
Buttons
LEDs
Display and Speaker
Sensors and ADCs
|
Supported Features
Similar to the Raspberry Pi Pico the PicoBoy board configuration supports the following hardware features:
Peripheral |
Kconfig option |
Devicetree compatible |
Zephyr API |
---|---|---|---|
PINCTRL |
|||
GPIO |
|||
USB Device |
|||
I2C |
|||
SPI |
|||
PWM |
|||
ADC |
|||
Temperature (Sensor) |
|||
Timer (Counter) |
|||
Watchdog Timer (WDT) |
|||
Flash |
|||
PIO |
N/A |
||
SPI (PIO) |
|||
DMA |
|||
CLOCK |
|||
RESET |
|||
VREG |
|||
NVIC |
N/A |
Nested Vector Interrupts Controller |
|
HWINFO |
N/A |
- (!) Designware I2C driver has issues:
The Raspberry Pi Pico I2C driver is using the Designware I2C driver automatically. According to our observation, this driver has some shortcomings in interrupt handling and leads to a dead-lock of the entire runtime system. Also known is the lack of support for 0 byte transfers, which prevents a proper I2C device scan. Thus, the PicoBoy board will be configured to use the simple GPIO-I2C bit-bang driver as long as this driver is not applicable as expected.
See also: https://github.com/zephyrproject-rtos/zephyr/pull/60427
- (!!) Die-Temperature Sensor driver has issues:
It seems the RP2040 Die-Temperature sensor driver has also race conditions and leads to a dead-lock of the entire runtime system. Thus, all PicoBoy board will be configured to disable this sensor node in DTS explicitly. As a workaround the ADC channel 4 can be used, but that result have to convert manually to the corresponding chip temperature following the formula that can be found in the RP2040 Datasheet [27], section with title “Temperature Sensor”.
Other hardware features are not currently supported by Zephyr. The default configuration can be found in the following Kconfig file:
Board Configurations
The PicoBoy board can be configured only for the following single use cases.
west build -b picoboy
Use the native USB device port with CDC-ACM as Zephyr console and for the shell.
Connections and IOs
The PicoBoy [1] website has detailed information about board connections. Download the different datasheets there or as linked above on the positions for more details.
System Clock
The RP2040 [26] MCU is configured to use the 12㎒ external crystal with the on-chip PLL generating the 125㎒ system clock. The internal AHB and APB units are set up in the same way as the upstream Raspberry Pi Pico C/C++ SDK [3] libraries.
GPIO (PWM) Ports
The RP2040 [26] MCU has 1 GPIO cell which covers all I/O pads and 8 PWM function unit each with 2 channels beside a dedicated Timer unit. On the PicoBoy, only 4 PWM channels are available on the three user LEDs and the passive magnetic speaker.
ADC/TS Ports
The RP2040 [26] MCU has 1 ADC with 4 channels and an additional fifth channel for the on-chip temperature sensor (TS). The ADC channels 0-3 are no available for any on-board function and may be completely unusable, but they ar all configured.
Also it is completely unclear if the external voltage reference ADC_VREF is connected to any voltage level, e.g. to the 3.3V power supply.
SPI Port
The RP2040 [26] MCU has 2 SPIs. The serial bus SPI0 is connect to the on-board OLED display over GP19 (MOSI), GP16 (MISO), GP18 (SCK), and GP17 (CSn), but only MOSI and SCK is really used for the OLED. The display chip-select signal will driven as simple GPIO by GP10 and the display itself does not provide any data out signal (MISO). SPI1 is not available in any default setup.
I2C Port
The RP2040 [26] MCU has 2 I2Cs. The serial bus I2C0 is connect to the on-board acceleration sensor over GP20 (I2C0_SDA), GP21 (I2C0_SCL). I2C1 is not available in any default setup.
Serial Port
The RP2040 [26] MCU has 2 UARTs. Neither UART0 nor UART1 are available in any of the default setups. Then ever a Zephyr serial console will be needed, the USB port have to be used.
USB Device Port
The RP2040 [26] MCU has a (native) USB device port that can be used to communicate with a host PC. See the USB device support samples sample applications for more, such as the USB CDC-ACM sample which sets up a virtual serial port that echos characters back to the host PC. The PicoBoy provides the Zephyr console per default on the USB port as CDC ACM:
USB device idVendor=2e8a, idProduct=000a, bcdDevice= 3.06
USB device strings: Mfr=1, Product=2, SerialNumber=3
Product: PicoBoy (CDC ACM)
Manufacturer: JSED (Raspberry Pi)
SerialNumber: BD774B2618DAAA7D
Programmable I/O (PIO)
The RP2040 SoC [26] comes with two PIO periherals. These are two simple co-processors that are designed for I/O operations. The PIOs run a custom instruction set, generated from a custom assembly language. PIO programs are assembled using pioasm, a tool provided by Raspberry Pi. Further informations can be found in the Raspberry Pi Pico C/C++ SDK [3] document, section with title “Using PIOASM, the PIO Assembler”.
Zephyr does not (currently) assemble PIO programs. Rather, they should be manually assembled and embedded in source code. An example of how this is done can be found at drivers/serial/uart_rpi_pico_pio.c or drivers/spi/spi_rpi_pico_pio.c.
Programming and Debugging
Flashing
The PicoBoy can only be flashed with a UF2 file. There is no SWD connector.
Using UF2
By default, building an app for the PicoBoy board will generate a
build/zephyr/zephyr.uf2
file. If the board is powered on with the
BOOTSEL button pressed, it will appear on the host as a mass
storage device:
USB device idVendor=2e8a, idProduct=0003, bcdDevice= 1.00
USB device strings: Mfr=1, Product=2, SerialNumber=3
Product: RP2 Boot
Manufacturer: Raspberry Pi
SerialNumber: E0C9125B0D9B
The UF2 file should be drag-and-dropped or copied on command line to the device, which will then flash the PicoBoy board.
Each RP2040 SoC [26] ships the UF2 compatible [2] bootloader pico-bootrom [5], a native support in silicon. The full source for the RP2040 bootrom at pico-bootrom [5] includes versions 1, 2 and 3 of the bootrom, which correspond to the B0, B1 and B2 silicon revisions, respectively.
Note that every time you build a program for the RP2040, the Pico SDK selects
an appropriate second stage bootloader based on what kind of external QSPI
Flash type the board configuration you are building for was giving. There
are several versions of boot2
[4] for different flash chips, and each one is
exactly 256 bytes of code which is put right at the start of the eventual
program binary. On Zephyr the boot2
versions are part of the
Raspberry Pi Pico HAL [7] module. Possible selections:
CONFIG_RP2_FLASH_AT25SF128A
:boot2_at25sf128a.S
CONFIG_RP2_FLASH_GENERIC_03H
:boot2_generic_03h.S
CONFIG_RP2_FLASH_IS25LP080
:boot2_is25lp080.S
CONFIG_RP2_FLASH_W25Q080
:boot2_w25q080.S
CONFIG_RP2_FLASH_W25X10CL
:boot2_w25x10cl.S
The PicoBoy board set this option to CONFIG_RP2_FLASH_W25Q080
. Further
informations can be found in the RP2040 Datasheet [27], sections with title
“Bootrom” and “Processor Controlled Boot Sequence”
or Brian Starkey’s Blog article Pico serial bootloader [6]
Debugging
The PicoBoy does not provide any SWD connector, thus debugging software is not possible.
More Samples
LED Blinky and Fade
Red User LED Blinky by GPIO
See also Zephyr sample: Blinky
west build -b picoboy -p -d build/picoboy zephyr/samples/basic/blinky
west flash -d build/picoboy
Red User LED Blinky by PWM
See also Zephyr sample: PWM Blinky
west build -b picoboy -p -d build/picoboy zephyr/samples/basic/blinky_pwm
west flash -d build/picoboy
Red User LED Fade by PWM
See also Zephyr sample: Fade LED
west build -b picoboy -p -d build/picoboy zephyr/samples/basic/fade_led
west flash -d build/picoboy
Red User LED On/Off by GPIO Button (Joystick ENTER)
See also Zephyr sample: Button
west build -b picoboy -p -d build/picoboy zephyr/samples/basic/button
west flash -d build/picoboy
Hello Shell on the USB-CDC/ACM Console
Hello Shell
west build -b picoboy -p -d build/picoboy bridle/samples/helloshell
west flash -d build/picoboy
Simple test execution on target
(text in bold is a command input)
uart:~$ hello -h hello - say hello uart:~$ hello Hello from shell. uart:~$ hwinfo devid Length: 8 ID: 0xbd774b2618daaa7d uart:~$ kernel version Zephyr version 3.6.0 uart:~$ bridle version Bridle version 3.6.1 uart:~$ bridle version long Bridle version 3.6.1.0 uart:~$ bridle info Zephyr: 3.6.0 Bridle: 3.6.1 uart:~$ device list devices: - clock-controller@40008000 (READY) - reset-controller@4000c000 (READY) - cdc_acm_console_uart (READY) - timer@40054000 (READY) - gpio@40014000 (READY) - adc@4004c000 (READY) - flash-controller@18000000 (READY) - i2c@40044000 (READY) - pwm@40050000 (READY) - vreg@40064000 (READY) - pwm_leds (READY) uart:~$ history [ 0] history [ 1] device list [ 2] bridle info [ 3] bridle version long [ 4] bridle version [ 5] kernel version [ 6] hwinfo devid [ 7] hello [ 8] hello -h
Operate with the on-chip voltage regulator unit:
uart:~$ regulator vlist vreg@40064000
0.800 V
0.850 V
0.900 V
0.950 V
1.000 V
1.050 V
1.100 V
1.150 V
1.200 V
1.250 V
1.300 V
Trigger a power-of/on sequence:
uart:~$ hwinfo reset_cause reset caused by: - pin uart:~$ regulator disable vreg@40064000 *** Booting Zephyr OS … … …*** Hello World! I'm THE SHELL from picoboy uart:~$ hwinfo reset_cause reset caused by: - power-on reset
Note
PWM LED conflicts with GPIO!
Operations with the red user LED in PWM mode will fail when ever the corresponding GPIO line 5 was configured as digital output. This condition is irreversible at runtime within the shell and requires a system reset.
Operate with the red user LED PWM_LED at GP5 / PWM5 (PWM2CHA):
uart:~$ led on pwm_leds 0 pwm_leds: turning on LED 0 uart:~$ led set_brightness pwm_leds 0 10 pwm_leds: setting LED 0 brightness to 10 uart:~$ led set_brightness pwm_leds 0 50 pwm_leds: setting LED 0 brightness to 50 uart:~$ led set_brightness pwm_leds 0 100 pwm_leds: setting LED 0 brightness to 100 uart:~$ led off pwm_leds 0 pwm_leds: turning off LED 0
Note
PWM conflicts with GPIO!
Operations with the red user LED in PWM mode will fail when ever the corresponding GPIO line 5 was configured as digital output. This condition is irreversible at runtime within the shell and requires a system reset.
Operate with the red user LED PWM_LED at GP5 / PWM5 (PWM2CHA):
uart:~$ pwm usec pwm@40050000 5 20000 20000 uart:~$ pwm usec pwm@40050000 5 20000 19000 uart:~$ pwm usec pwm@40050000 5 20000 18000 uart:~$ pwm usec pwm@40050000 5 20000 17000 uart:~$ pwm usec pwm@40050000 5 20000 16000 uart:~$ pwm usec pwm@40050000 5 20000 15000 uart:~$ pwm usec pwm@40050000 5 20000 10000 uart:~$ pwm usec pwm@40050000 5 20000 5000 uart:~$ pwm usec pwm@40050000 5 20000 2500 uart:~$ pwm usec pwm@40050000 5 20000 500 uart:~$ pwm usec pwm@40050000 5 20000 0
Operate with the PASSIVE magnetic speaker at GP15 / PWM15 (PWM7CHB):
concert pitch: 440 ㎐
Piezo middle frequency: 1,000 ㎑
Piezo resonance: 4,000 ㎑
Piezo high frequency: 10,000 ㎑
uart:~$ pwm usec pwm@40050000 15 2273 1136 uart:~$ pwm usec pwm@40050000 15 2000 1000 uart:~$ pwm usec pwm@40050000 15 250 125 uart:~$ pwm usec pwm@40050000 15 100 50
Operate with the red user LED LED at GP5:
uart:~$ gpio get gpio@40014000 5 0 uart:~$ gpio conf gpio@40014000 5 oh0 uart:~$ gpio set gpio@40014000 5 1 uart:~$ gpio set gpio@40014000 5 0 uart:~$ gpio blink gpio@40014000 5 Hit any key to exit
Operate with the user joystick center button ENTER at GP0:
uart:~$ gpio get gpio@40014000 0 0 uart:~$ gpio conf gpio@40014000 0 iul uart:~$ gpio get gpio@40014000 0 0 uart:~$ gpio get gpio@40014000 0 1 uart:~$ gpio get gpio@40014000 0 0
Operate with the channels:
ADC0, pulled to unknown voltage level
ADC1, pulled to unknown voltage level
ADC2, pulled to unknown voltage level
ADC3, pulled to unknown voltage level
on-chip temperature sensor on channel ADC4
uart:~$ adc adc@4004c000 resolution 12 uart:~$ adc adc@4004c000 channel id 0 uart:~$ adc adc@4004c000 channel id 1 uart:~$ adc adc@4004c000 channel id 2 uart:~$ adc adc@4004c000 channel id 3 uart:~$ adc adc@4004c000 channel id 4 uart:~$ adc adc@4004c000 read 0 read: 681 uart:~$ adc adc@4004c000 read 1 read: 617 uart:~$ adc adc@4004c000 read 2 read: 745 uart:~$ adc adc@4004c000 read 3 read: 692 uart:~$ adc adc@4004c000 read 4 read: 749
Operate with the on-chip timer unit:
uart:~$ timer oneshot timer@40054000 0 1000000 timer@40054000: Alarm triggered
uart:~$ flash read flash-controller@18000000 17af0 40 00017AF0: 70 69 63 6f 62 6f 79 00 48 65 6c 6c 6f 20 57 6f |picoboy. Hello Wo| 00017B00: 72 6c 64 21 20 49 27 6d 20 54 48 45 20 53 48 45 |rld! I'm THE SHE| 00017B10: 4c 4c 20 66 72 6f 6d 20 25 73 0a 00 69 6c 6c 65 |LL from %s..ille| 00017B20: 67 61 6c 20 6f 70 74 69 6f 6e 20 2d 2d 20 25 63 |gal opti on -- %c| uart:~$ flash read flash-controller@18000000 e0000 40 000E0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |........ ........| 000E0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |........ ........| 000E0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |........ ........| 000E0030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |........ ........| uart:~$ flash test flash-controller@18000000 e0000 1000 2 Erase OK. Write OK. Verified OK. Erase OK. Write OK. Verified OK. Erase-Write-Verify test done. uart:~$ flash read flash-controller@18000000 e0000 40 000E0000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |........ ........| 000E0010: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |........ ........| 000E0020: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f | !"#$%&' ()*+,-./| 000E0030: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f |01234567 89:;<=>?| uart:~$ flash page_info e0000 Page for address 0xe0000: start offset: 0xe0000 size: 4096 index: 224 uart:~$ flash erase flash-controller@18000000 e0000 1000 Erase success. uart:~$ flash read flash-controller@18000000 e0000 40 000E0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |........ ........| 000E0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |........ ........| 000E0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |........ ........| 000E0030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |........ ........|
The PicoBoy has the on-board acceleration sensor connected on I2C0.
uart:~$ i2c scan i2c@40044000
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- 18 -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
1 devices found on i2c@40044000
The I2C address 0x18
is a Sensortek STK8BA58 [16] 3D Acceleration Sensor
and their Chip-ID can read from register 0x0
. The Chip-ID must be
0x87
:
uart:~$ i2c read_byte i2c@40044000 18 0
Output: 0x87
Input dump on the USB-CDC/ACM Console
Print the input events related to the five on-board joystick keys using the Input subsystem API. That are:
zephyr,code = <INPUT_KEY_UP>;
zephyr,code = <INPUT_KEY_DOWN>;
zephyr,code = <INPUT_KEY_LEFT>;
zephyr,code = <INPUT_KEY_RIGHT>;
zephyr,code = <INPUT_KEY_ENTER>;
See also Zephyr sample: Input dump.
Joystick Test
west build -b picoboy -p -d build/picoboy zephyr/samples/subsys/input/input_dump
west flash -d build/picoboy
Simple logging output on target
***** delaying boot 4000ms (per build configuration) ***** W: BUS RESET W: BUS RESET *** Booting Zephyr OS … … … (delayed boot 4000ms) *** Input sample started I: input event: dev=gpio_keys SYN type= 1 code=103 value=1 I: input event: dev=gpio_keys SYN type= 1 code=103 value=0 I: input event: dev=gpio_keys SYN type= 1 code=108 value=1 I: input event: dev=gpio_keys SYN type= 1 code=108 value=0 I: input event: dev=gpio_keys SYN type= 1 code=105 value=1 I: input event: dev=gpio_keys SYN type= 1 code=105 value=0 I: input event: dev=gpio_keys SYN type= 1 code=106 value=1 I: input event: dev=gpio_keys SYN type= 1 code=106 value=0 I: input event: dev=gpio_keys SYN type= 1 code= 28 value=1 I: input event: dev=gpio_keys SYN type= 1 code= 28 value=0
Sounds from the speaker on the USB-CDC/ACM Console
Speaker Test

The sample is prepared for the on-board PWM_SPEAKER connected to the PWM channel at GP15 / PWM15 (PWM7CHB).
The PWM period is 880 ㎐, twice the concert pitch frequency of 440 ㎐.
1/ {
2 aliases {
3 pwm-buzzer0 = &pwm_speaker0;
4 };
5
6 pwm_buzzers {
7 compatible = "pwm-buzzers";
8 status = "okay";
9
10 pwm_speaker0: pwm_speaker0 {
11 pwms = <&pwm 15 PWM_HZ(880) PWM_POLARITY_NORMAL>;
12 label = "User PWM_SPEAKER";
13 };
14 };
15};
16
17&pwm {
18 divider-int-7 = <255>;
19};
Invoke west build and west flash:
west build -b picoboy -p -d build/picoboy bridle/samples/buzzer
west flash -d build/picoboy
Simple test execution on target
play a beep
play a folk song
play a chrismas song
uart:~$ buzzer beep uart:~$ buzzer play folksong uart:~$ buzzer play xmastime
Display Test and Demonstration
The following samples work with the chosen display. That is:
chosen { zephyr,display = &oled_panel; };
oled_panel: &sh1106_128x64 {};
Devicetree compatible
zephyr,lvgl-keypad-input
with devicetree relationlvgl_keypad: lvgl-keypad { input = <&gpio_keys>; };
UP :input-codes = <INPUT_KEY_UP>;
:lvgl-codes = <LV_KEY_UP>;
DOWN :input-codes = <INPUT_KEY_DOWN>;
:lvgl-codes = <LV_KEY_DOWN>;
LEFT :input-codes = <INPUT_KEY_LEFT>;
:lvgl-codes = <LV_KEY_LEFT>;
RIGHT :input-codes = <INPUT_KEY_RIGHT>;
:lvgl-codes = <LV_KEY_RIGHT>;
ENTER :input-codes = <INPUT_KEY_ENTER>;
:lvgl-codes = <LV_KEY_ENTER>;
LCD Orientation and Bit Order Test

Draw some basic rectangles onto the display using the Display driver API. See also Zephyr sample: Display.
west build -b picoboy -p -d build/picoboy zephyr/samples/drivers/display
west flash -d build/picoboy
LVGL Basic Sample
Displays “Hello World!” in the center of the screen and a counter at the bottom which increments every second using the LVGL module on top of the Display driver API. See also Zephyr sample: LVGL basic sample.
west build -b picoboy -p -d build/picoboy zephyr/samples/subsys/display/lvgl
west flash -d build/picoboy
This sample comes with a Shell command line access to the LVGL backend on the console, here configured for a USB console:
Simple test execution on target
uart:~$ lvgl lvgl - LVGL shell commands Subcommands: stats :Show LVGL statistics monkey :LVGL monkey testing uart:~$ lvgl stats stats - Show LVGL statistics Subcommands: memory :Show LVGL memory statistics Usage: lvgl stats memory [-c] -c dump chunk information uart:~$ lvgl stats memory Heap at 0x20001270 contains 2047 units in 11 buckets bucket# min units total largest largest threshold chunks (units) (bytes) ----------------------------------------------------------- 0 1 1 1 4 1 2 1 2 12 10 1024 1 1824 14588 14604 free bytes, 1544 allocated bytes, overhead = 232 bytes (1.4%)