You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As far as I can tell, we don't get any kind of interrupts when a ZLP is sent from host to nrf. This occurs when we transfer messages with a multiple of the 64-byte bulk packet size, and need to terminate them.
Using the following nrf52840 code:
#![no_std]#![no_main]use defmt::{info, panic};use embassy_executor::Spawner;use embassy_futures::join::join;use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;use embassy_nrf::usb::Driver;use embassy_nrf::{bind_interrupts, pac, peripherals, usb};use embassy_usb::driver::EndpointError;use embassy_usb::driver::Endpoint;use embassy_usb::driver::EndpointOut;use embassy_usb::driver::EndpointIn;use embassy_usb::msos::{self, windows_version};use embassy_usb::{Builder,Config};use{defmt_rtt as _, panic_probe as _};bind_interrupts!(structIrqs{USBD => usb::InterruptHandler<peripherals::USBD>;CLOCK_POWER => usb::vbus_detect::InterruptHandler;});constDEVICE_INTERFACE_GUIDS:&[&str] = &["{AFB9A6FB-30BA-44BC-9232-806CFC875321}"];#[embassy_executor::main]asyncfnmain(_spawner:Spawner){let p = embassy_nrf::init(Default::default());info!("Enabling ext hfosc...");
pac::CLOCK.tasks_hfclkstart().write_value(1);while pac::CLOCK.events_hfclkstarted().read() != 1{}// Create the driver, from the HAL.let driver = Driver::new(p.USBD,Irqs,HardwareVbusDetect::new(Irqs));// Create embassy-usb Configletmut config = Config::new(0xc0de,0xcafe);
config.manufacturer = Some("Embassy");
config.product = Some("USB-serial example");
config.serial_number = Some("12345678");
config.max_power = 100;
config.max_packet_size_0 = 64;// Create embassy-usb DeviceBuilder using the driver and config.// It needs some buffers for building the descriptors.letmut config_descriptor = [0;256];letmut bos_descriptor = [0;256];letmut msos_descriptor = [0;256];letmut control_buf = [0;64];letmut builder = Builder::new(
driver,
config,&mut config_descriptor,&mut bos_descriptor,&mut msos_descriptor,&mut control_buf,);// Add the Microsoft OS Descriptor (MSOS/MOD) descriptor.// We tell Windows that this entire device is compatible with the "WINUSB" feature,// which causes it to use the built-in WinUSB driver automatically, which in turn// can be used by libusb/rusb software without needing a custom driver or INF file.// In principle you might want to call msos_feature() just on a specific function,// if your device also has other functions that still use standard class drivers.
builder.msos_descriptor(windows_version::WIN8_1,0);
builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB",""));
builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new("DeviceInterfaceGUIDs",
msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),));// Add a vendor-specific function (class 0xFF), and corresponding interface,// that uses our custom handler.letmut function = builder.function(0xFF,0,0);letmut interface = function.interface();letmut alt = interface.alt_setting(0xFF,0,0,None);letmut read_ep = alt.endpoint_bulk_out(64);letmut write_ep = alt.endpoint_bulk_in(64);drop(function);// Build the builder.letmut usb = builder.build();// Run the USB device.let usb_fut = usb.run();// Do stuff with the class!let echo_fut = async{loop{
read_ep.wait_enabled().await;info!("Connected");loop{letmut data = [0;64];match read_ep.read(&mut data).await{Ok(n) => {info!("Got bulk ({=usize}): {:a}", n, data[..n]);if n == 64{info!("More to come...");}else{info!("End of chunk");}
write_ep.write(&data[..n]).await.ok();info!("Wrote back. {=usize}", n);}Err(_) => break,}}info!("Disconnected");}};// Run everything concurrently.// If we had made everything `'static` above instead, we could do this using separate tasks instead.join(usb_fut, echo_fut).await;}structDisconnected{}implFrom<EndpointError>forDisconnected{fnfrom(val:EndpointError) -> Self{match val {EndpointError::BufferOverflow => panic!("Buffer overflow"),EndpointError::Disabled => Disconnected{},}}}
And the following host side code:
use nusb::transfer::RequestBuffer;constBULK_OUT_EP:u8 = 0x01;constBULK_IN_EP:u8 = 0x81;#[tokio::main]asyncfnmain(){let di = nusb::list_devices().unwrap().find(|d| d.vendor_id() == 0xc0de && d.product_id() == 0xcafe).expect("no device found");let device = di.open().expect("error opening device");let interface = device.claim_interface(0).expect("error claiming interface");// This workslet result = interface.bulk_out(BULK_OUT_EP,b"hello world".into()).await;println!("{result:?}");let result = interface.bulk_in(BULK_IN_EP,RequestBuffer::new(512)).await;println!("{result:?}");// This worksletmut data65 = vec![];for _x in0..4{
data65.extend_from_slice(b"hello world12345");}
data65.push(b'!');let result = interface.bulk_out(BULK_OUT_EP, data65).await;println!("tx1 {result:?}");let result = interface.bulk_in(BULK_IN_EP,RequestBuffer::new(512)).await;println!("rx1 {result:?}");// This doesn'tletmut data64 = vec![];for _x in0..4{
data64.extend_from_slice(b"hello world12345");}assert_eq!(data64.len(),64);let result = interface.bulk_out(BULK_OUT_EP, data64).await;println!("tx2 {result:?}");let result = interface.bulk_in(BULK_IN_EP,RequestBuffer::new(512)).await;println!("rx2 {result:?}");}
The text was updated successfully, but these errors were encountered:
As far as I can tell, we don't get any kind of interrupts when a ZLP is sent from host to nrf. This occurs when we transfer messages with a multiple of the 64-byte bulk packet size, and need to terminate them.
Using the following nrf52840 code:
And the following host side code:
The text was updated successfully, but these errors were encountered: