diff --git a/boards/pico/examples/pico_usb_serial.rs b/boards/pico/examples/pico_usb_serial.rs index a6c2b1f..8a69aed 100644 --- a/boards/pico/examples/pico_usb_serial.rs +++ b/boards/pico/examples/pico_usb_serial.rs @@ -1,30 +1,64 @@ -//! Creates a USB Serial device on a Pico board. +//! # Pico USB Serial Example //! -//! This will create a USB Serial device echoing anything it receives converting to caps the ASCII -//! alphabetical caracters. +//! Creates a USB Serial device on a Pico board, with the USB driver running in +//! the main thread. +//! +//! This will create a USB Serial device echoing anything it receives. Incoming +//! ASCII characters are converted to upercase, so you can tell it is working +//! and not just local-echo! +//! +//! See the `Cargo.toml` file for Copyright and licence details. + #![no_std] #![no_main] +// The macro for our start-up function use cortex_m_rt::entry; + +// Ensure we halt the program on panic (if we don't mention this crate it won't +// be linked) use panic_halt as _; -use pico::{ - hal::{clocks::init_clocks_and_plls, pac, timer::Timer, usb::UsbBus, watchdog::Watchdog}, - XOSC_CRYSTAL_FREQ, -}; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use pico::hal::pac; + +// A shorter alias for the Hardware Abstraction Layer, which provides +// higher-level drivers. +use pico::hal; + +// USB Device support use usb_device::{class_prelude::*, prelude::*}; + +// USB Communications Class Device support use usbd_serial::SerialPort; +/// The linker will place this boot block at the start of our program image. We +/// need this to help the ROM bootloader get our code up and running. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; +/// Entry point to our bare-metal application. +/// +/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function +/// as soon as all global variables are initialised. +/// +/// The function configures the RP2040 peripherals, then echoes any characters +/// received over USB Serial. #[entry] fn main() -> ! { + // Grab our singleton objects let mut pac = pac::Peripherals::take().unwrap(); - let mut watchdog = Watchdog::new(pac.WATCHDOG); - let clocks = init_clocks_and_plls( - XOSC_CRYSTAL_FREQ, + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + // + // Our default is 12 MHz crystal input, 125 MHz system clock + let clocks = hal::clocks::init_clocks_and_plls( + pico::XOSC_CRYSTAL_FREQ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, @@ -35,15 +69,19 @@ fn main() -> ! { .ok() .unwrap(); - let timer = Timer::new(pac.TIMER); - let usb_bus = UsbBusAllocator::new(UsbBus::new( + // Set up the USB driver + let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new( pac.USBCTRL_REGS, pac.USBCTRL_DPRAM, clocks.usb_clock, true, &mut pac.RESETS, )); + + // Set up the USB Communications Class Device driver let mut serial = SerialPort::new(&usb_bus); + + // Create a USB device with a fake VID and PID let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) .manufacturer("Fake company") .product("Serial port") @@ -51,36 +89,41 @@ fn main() -> ! { .device_class(2) // from: https://www.usb.org/defined-class-codes .build(); + let timer = hal::timer::Timer::new(pac.TIMER); let mut said_hello = false; loop { + // A welcome message at the beginning if !said_hello && timer.get_counter() >= 2_000_000 { said_hello = true; - let _ = serial.write(b"HelloWorld!\r\n"); + let _ = serial.write(b"Hello, World!\r\n"); } - if !usb_dev.poll(&mut [&mut serial]) { - continue; - } - - let mut buf = [0u8; 64]; - let _ = serial.read(&mut buf).map(|count| { - if count == 0 { - return; - } - - // Echo back in upper case - buf.iter_mut().take(count).for_each(|c| { - if let 0x61..=0x7a = *c { - *c &= !0x20; + // Check for new data + if usb_dev.poll(&mut [&mut serial]) { + let mut buf = [0u8; 64]; + match serial.read(&mut buf) { + Err(_e) => { + // Do nothing + } + Ok(0) => { + // Do nothing + } + Ok(count) => { + // Convert to upper case + buf.iter_mut().take(count).for_each(|b| { + b.make_ascii_uppercase(); + }); + // Send back to the host + let mut wr_ptr = &buf[..count]; + while !wr_ptr.is_empty() { + let _ = serial.write(wr_ptr).map(|len| { + wr_ptr = &wr_ptr[len..]; + }); + } } - }); - - let mut wr_ptr = &buf[..count]; - while !wr_ptr.is_empty() { - let _ = serial.write(wr_ptr).map(|len| { - wr_ptr = &wr_ptr[len..]; - }); } - }); + } } } + +// End of file diff --git a/boards/pico/examples/pico_usb_serial_interrupt.rs b/boards/pico/examples/pico_usb_serial_interrupt.rs index 5801e25..cc67de8 100644 --- a/boards/pico/examples/pico_usb_serial_interrupt.rs +++ b/boards/pico/examples/pico_usb_serial_interrupt.rs @@ -91,6 +91,7 @@ fn main() -> ! { .ok() .unwrap(); + // Set up the USB driver let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new( pac.USBCTRL_REGS, pac.USBCTRL_DPRAM, @@ -103,11 +104,13 @@ fn main() -> ! { USB_BUS = Some(usb_bus); } + // Set up the USB Communications Class Device driver let serial = SerialPort::new(unsafe { USB_BUS.as_ref().unwrap() }); unsafe { USB_SERIAL = Some(serial); } + // Create a USB device with a fake VID and PID let usb_dev = UsbDeviceBuilder::new( // Note (safety): This is safe as interrupts haven't been started yet unsafe { USB_BUS.as_ref().unwrap() },