USB Serial Communication

In this section, we'll explore how to establish communication between the Pico 2 W and a computer. We'll demonstrate how to send strings from the device to the computer and receive input from the computer to control the Pico.

CDC ACM Overview

The Communication Device Class (CDC) is a standard USB device class defined by the USB Implementers Forum. The Abstract Control Model (ACM) in CDC allows a device to act like a traditional serial port (like old COM ports). When you flash USB serial code, the Pico appears as /dev/ttyACM0 on Linux.

Required Crates

toml
[dependencies]
usb-device = "0.3.2"
usbd-serial = "0.2.2"

These crates provide a USB stack for embedded devices and implement the USB CDC-ACM serial port class respectively.

Basic USB Serial Setup

rust
use usb_device::{class_prelude::*, prelude::*};
use usbd_serial::SerialPort;

// Set up USB driver
let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new(
    pac.USB,
    pac.USB_DPRAM,
    clocks.usb_clock,
    true,
    &mut pac.RESETS,
));

// Create serial port
let mut serial = SerialPort::new(&usb_bus);

// Create USB device
let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
    .strings(&[StringDescriptors::default()
        .manufacturer("implRust")
        .product("Pico 2 W")
        .serial_number("TEST")])
    .unwrap()
    .device_class(2) // CDC class
    .build();

Sending Data to PC

rust
if !said_hello && timer.get_counter().ticks() >= 2_000_000 {
    said_hello = true;
    let _ = serial.write(b"Hello, Rust!\r\n");
}

Receiving Data from PC

rust
if usb_dev.poll(&mut [&mut serial]) {
    let mut buf = [0u8; 64];
    if let Ok(count) = serial.read(&mut buf) {
        for &byte in &buf[..count] {
            // Process received byte
            if byte == b'r' {
                led.set_high().unwrap();
            } else {
                led.set_low().unwrap();
            }
        }
    }
}

Pico 2 W Considerations

Tip

LED Control on Pico 2 W

The onboard LED on Pico 2 W is controlled by the wireless chip (CYW43), not directly via GPIO25. For simple LED control examples with USB serial, use an external LED on a free GPIO pin, or use the cyw43 driver for onboard LED.

Using on Linux

Connect to the Pico using tio or minicom:

bash
# Install tio
sudo apt install tio

# Connect to Pico
tio /dev/ttyACM0

Then flash your code in another terminal with cargo run. You'll see output from the Pico in the tio terminal, and you can type to send data to the Pico.