defmt-embassy-usbserial

Crates.iodefmt-embassy-usbserial
lib.rsdefmt-embassy-usbserial
version0.2.1
created_at2025-10-27 16:44:56.273706+00
updated_at2025-10-27 16:57:44.07244+00
descriptionTransmit defmt log messages over USB serial
homepage
repositoryhttps://github.com/robjwells/defmt-embassy-usbserial
max_upload_size
id1903255
size87,925
Rob Wells (robjwells)

documentation

README

defmtusb

defmtusb lets you read your Embassy firmware's defmt log messages over USB serial.

Quickstart

This is the easiest method, for when you are not otherwise using the USB peripheral in your firmware (to, for example, act as a keyboard).

Add defmtusb to your dependencies in your Cargo.toml file. In your firmware, create an Embassy task that constructs your HAL-specific USB driver and an approriate USB configuration. For example, using embassy-rp and with general firmware setup elided:

use embassy_rp::{bind_interrupts, Peri};

bind_interrupts!(struct Irqs {
    USBCTRL_IRQ => embassy_rp::usb::InterruptHandler<embassy_rp::peripherals::USB>;
});

#[embassy_executor::task]
async fn defmtusb_wrapper(usb: Peri<'static, embassy_rp::peripherals::USB>) {
    let driver = embassy_rp::usb::Driver::new(usb, Irqs);
    let usb_config = {
        let mut c = embassy_usb::Config::new(0x1234, 0x5678);
        c.serial_number = Some("defmt");
        c.max_packet_size_0 = 64;
        c.composite_with_iads = true;
        c.device_class = 0xEF;
        c.device_sub_class = 0x02;
        c.device_protocol = 0x01;
        c
    };
    defmt_embassy_usbserial::run(driver, usb_config).await;
}

In your main function, pass in the USB peripheral and spawn the task:

spawner.must_spawn(defmtusb_wrapper(peripherals.USB));

Now you can use the defmt logging macros as you'd expect.

loop {
    defmt::info!("Hello! {=u64:ts}", Instant::now().as_secs());
    delay.delay_ms(1000).await;
}

On the host side, use defmt-print to decode and print the messages.

Complex USB setups

(Note: This section has not yet been updated since the fork from micro-rust/defmtusb.)

If you intend to create a variety of endpoints in the USB and use them, you can create them and then simply pass a CDC ACM Sender to the logger task in defmtusb. This method also requires the maximum packet size of the hardware USB implementation.

#[task]
async fn logger_wrapper(usb: USB) {
    // Create the USB driver.
    let driver = Driver::new(usb, Irqs);

    // Create the different interfaces and endpoints.
    ...

    // Create the CDC ACM class.
    let cdc = CdcAcmClass::new(&mut builder, &mut state, <max_packet_size>);

    // Split to get the sender only.
    let sender = class.split();

    // Run only the logging function.
    defmtusb::logger(sender, <max_packet_size>).await;
}

Contributing

Any contribution intentionally submitted for inclusion in the work by you shall be licensed under either the MIT License or the Mozilla Public License Version 2.0, without any additional terms and conditions.

License

This work is licensed, at your option, under the

Commit count: 0

cargo fmt