November 1, 2023

Raspberry Pi Pico - hello USB example

This is a recommended first example to build for USB, so let's give it a go.
cd pico-examples
export PICO_SDK_PATH=../../pico-sdk/
cd build
cmake ..
make hello_usb
This seems to work, yielding the following output:
[  0%] Performing build step for 'ELF2UF2Build'
-- The C compiler identification is GNU 13.2.1
-- The CXX compiler identification is GNU 13.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (0.5s)
-- Generating done (0.0s)
-- Build files have been written to: /u1/Projects/rp2040/pico-examples/build/elf2uf2
[ 50%] Building CXX object CMakeFiles/elf2uf2.dir/main.cpp.o
[100%] Linking CXX executable elf2uf2
[100%] Built target elf2uf2
[  0%] No install step for 'ELF2UF2Build'
[  0%] Completed 'ELF2UF2Build'
[  0%] Built target ELF2UF2Build
[  0%] Built target bs2_default
[  0%] Built target bs2_default_padded_checksummed_asm
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/hello_usb.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_stdlib/stdlib.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_gpio/gpio.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_platform/platform.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_claim/claim.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_sync/sync.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_irq/irq.c.obj
[  0%] Building ASM object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_irq/irq_handler_chain.S.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/common/pico_sync/sem.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/common/pico_sync/lock_core.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/common/pico_sync/mutex.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/common/pico_sync/critical_section.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/common/pico_time/time.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/common/pico_time/timeout_helper.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_timer/timer.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/common/pico_util/datetime.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/common/pico_util/pheap.c.obj
[  0%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/common/pico_util/queue.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_uart/uart.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_clocks/clocks.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_pll/pll.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_vreg/vreg.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_watchdog/watchdog.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_xosc/xosc.c.obj
[100%] Building ASM object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_divider/divider.S.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_runtime/runtime.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_printf/printf.c.obj
[100%] Building ASM object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_bootrom/bootrom.c.obj
[100%] Building ASM object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_divider/divider.S.obj
[100%] Building ASM object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_double/double_aeabi.S.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_double/double_init_rom.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_double/double_math.c.obj
[100%] Building ASM object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_double/double_v1_rom_shim.S.obj
[100%] Building ASM object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S.obj
[100%] Building ASM object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_float/float_aeabi.S.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_float/float_init_rom.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_float/float_math.c.obj
[100%] Building ASM object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_float/float_v1_rom_shim.S.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_malloc/pico_malloc.c.obj
[100%] Building ASM object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S.obj
[100%] Building ASM object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_standard_link/crt0.S.obj
[100%] Building CXX object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_standard_link/new_delete.cpp.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_standard_link/binary_info.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_stdio/stdio.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_stdio_usb/reset_interface.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_unique_id/unique_id.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/hardware_flash/flash.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/portable/raspberrypi/rp2040/dcd_rp2040.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/portable/raspberrypi/rp2040/rp2040_usb.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/device/usbd.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/device/usbd_control.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/audio/audio_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/cdc/cdc_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/dfu/dfu_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/dfu/dfu_rt_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/hid/hid_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/midi/midi_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/msc/msc_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/net/ecm_rndis_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/net/ncm_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/usbtmc/usbtmc_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/vendor/vendor_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/class/video/video_device.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/tusb.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/lib/tinyusb/src/common/tusb_fifo.c.obj
[100%] Building C object hello_world/usb/CMakeFiles/hello_usb.dir/u1/Projects/rp2040/pico-sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c.obj
[100%] Linking CXX executable hello_usb.elf
[100%] Built target hello_usb
Note the hated CXX thing. It is actually doing something with C++, but it looks like the only C++ source file is rp2_common/pico_standard_link/new_delete.cpp

Where is the generated executable?

Now we get to play hide and seek. It seems to be in pico-examples/build/hello_world/usb, where I see "hello_usb.uf2" with the current date and time (i.e. built just a minute or two ago).

There is a 1820 line Makefile in the same directory. The source code is in pico-examples/hello_world/usb.

The Pico SDK philosophy seems to be to let the source directory areas be read only and only write files in directories under the build directory. Don't ask me why. It suppose it fulfils someone's idea of organization and neatness.

The source is the following. Note that there is nothing about USB here at all. In fact the soure in hello_world/serial is exactly identical.

#include 
#include "pico/stdlib.h"

int main() {
    stdio_init_all();
    while (true) {
        printf("Hello, world!\n");
        sleep_ms(1000);
    }
}

Let's run the code

I find my Pico and a USB cable, plug it in holding the button, and once the RPI-RP2 icon appears on my desktop, I do:
cp hello_usb.uf2 /run/media/tom/RPI-RP2/
It appears as /dev/ttyACM0 and when I use picocom, it is sending "Hello, world!" over and over at 9600 baud. When I close the picocom connection, the ttyACM0 device vanishes and the game is over. And, strangely enough, when I unplug and replug I can never get ttyACM0 again! I cannot even get it to show up as a mass storage device! This was through a USB hub built into my monitor. This is clearly something wrong either with the hub inside the monitor or the way linux deals with the hub. I try using that cable for other purposes and it is useless now. I power cycle the monitor, and I still have trouble! So this is some kind of linux bug.

When I try it on a USB port on the front of my computer, I get ttyACM0 again! Now I try this:

picocom -b 115200 /dev/ttyACM0
So, it works at any baud rate, which sort of makes sense. USB doesn't know anything about baud rates and we aren't dealing with a USB to serial dongle like I usually am.

The USB port on the front of my computer (xhci_hcd) seems to let me disconnect and reconnect without any bugs or trouble. I can press the reset button on the Pico and it renegotiates ttyACM0 every time. And when I hold down the boot button and reset I get the mass storage device as I should


Have any comments? Questions? Drop me a line!

Tom's electronics pages / tom@mmto.org