From 0050d1a07b549565c8c9d37be3cbe1a821e9fa11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aaro=20Per=C3=A4maa?= Date: Thu, 24 Apr 2025 22:35:03 +0300 Subject: [PATCH] usbd: Remove debug prints and add an example for the V203 The driver works for the most part, except you must for some reason use the arch-spin executor to make it work. Perhaps something is wrong in the interrupts? Do not merge in the current form! --- README.md | 1 + examples/ch32v203/Cargo.toml | 8 ++- examples/ch32v203/src/bin/usbd.rs | 107 ++++++++++++++++++++++++++++++ src/usbd.rs | 89 +++++++++++++------------ 4 files changed, 162 insertions(+), 43 deletions(-) create mode 100644 examples/ch32v203/src/bin/usbd.rs diff --git a/README.md b/README.md index 88963a0..eada600 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ For a full list of chip capabilities and peripherals, check the [ch32-data](http | I2C | ✅ | ✅ | ✅ | ❓ | ❓ | ❓ | | | ADC | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | Timer(PWM) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | +| USBD | ✅* | N/A | N/A | N/A | N/A | N/A | | | USB/OTG FS | ✅* | N/A | N/A | N/A | N/A | N/A | | | USB HS | ✅* | N/A | N/A | N/A | N/A | N/A | | diff --git a/examples/ch32v203/Cargo.toml b/examples/ch32v203/Cargo.toml index e79a39b..e5142ec 100644 --- a/examples/ch32v203/Cargo.toml +++ b/examples/ch32v203/Cargo.toml @@ -3,6 +3,11 @@ name = "ch32v203-examples" version = "0.1.0" edition = "2021" +[[bin]] +name = "usbd" +path = "src/bin/usbd.rs" +required-features = ["embassy-executor/arch-spin"] + [dependencies] ch32-hal = { path = "../../", features = [ "ch32v203g6u6", @@ -14,7 +19,8 @@ ch32-hal = { path = "../../", features = [ embassy-executor = { version = "0.6.0", features = [ "integrated-timers", - "arch-riscv32", + # "arch-riscv32", + "arch-spin", # TODO: Required for USBD to connect properly "executor-thread", ] } diff --git a/examples/ch32v203/src/bin/usbd.rs b/examples/ch32v203/src/bin/usbd.rs new file mode 100644 index 0000000..9a5e17e --- /dev/null +++ b/examples/ch32v203/src/bin/usbd.rs @@ -0,0 +1,107 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; +use embassy_usb::driver::EndpointError; +use embassy_usb::Builder; +use hal::time::Hertz; +use hal::usbd::{Driver, Instance}; +use hal::{bind_interrupts, peripherals, println, usb, Config}; +use {ch32_hal as hal, panic_halt as _}; + +bind_interrupts!(struct Irqs { + USB_LP_CAN1_RX0 => hal::usbd::InterruptHandler; +}); + +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. +#[embassy_executor::main(entry = "qingke_rt::entry")] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::Config { + rcc: hal::rcc::Config::SYSCLK_FREQ_144MHZ_HSI, + ..Default::default() + }); + + let driver = Driver::new(p.USBD, Irqs, p.PA12, p.PA11); + + // Create embassy-usb Config + let mut config = embassy_usb::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; + + // Windows compatibility requires these; CDC-ACM + config.device_class = 0x02; + config.device_sub_class = 0x02; + config.device_protocol = 0x00; + config.composite_with_iads = false; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut msos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], // no msos descriptors + &mut control_buf, + ); + + // Create classes on the builder. + let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Do stuff with the class! + let echo_fut = async { + loop { + class.wait_connection().await; + println!("Connected"); + let _ = echo(&mut class).await; + println!("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; +} + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { + let mut buf = [0; 64]; + loop { + let n = class.read_packet(&mut buf).await?; + let data = &buf[..n]; + println!("Data: {data:X?}"); + class.write_packet(data).await?; + } +} diff --git a/src/usbd.rs b/src/usbd.rs index 55cdf97..74c5423 100644 --- a/src/usbd.rs +++ b/src/usbd.rs @@ -16,6 +16,7 @@ use embassy_usb_driver::{ }; use crate::gpio::Speed; +use crate::interrupt::typelevel::Interrupt; use crate::pac::usbd::regs; use crate::pac::usbd::vals::{EpType, Stat}; use crate::pac::{EXTEND, USBRAM}; @@ -30,8 +31,8 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { let regs = T::regs(); - let x = regs.istr().read().0; - crate::println!("USB IRQ: {:08x}", x); + // let x = regs.istr().read().0; + // crate::println!("USB IRQ: {:08x}", x); let istr = regs.istr().read(); @@ -53,7 +54,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } if istr.wkup() { - crate::println!("USB IRQ: wkup"); + // crate::println!("USB IRQ: wkup"); IRQ_RESUME.store(true, Ordering::Relaxed); regs.cntr().modify(|w| { w.set_fsusp(false); @@ -70,7 +71,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } if istr.reset() { - crate::println!("USB IRQ: reset"); + // crate::println!("USB IRQ: reset"); IRQ_RESET.store(true, Ordering::Relaxed); // Write 0 to clear. @@ -89,7 +90,7 @@ impl interrupt::typelevel::Handler for InterruptHandl if index == 0 && epr.setup() { EP0_SETUP.store(true, Ordering::Relaxed); } - crate::println!("EP {} RX, setup={}", index, epr.setup()); + // crate::println!("EP {} RX, setup={}", index, epr.setup()); EP_OUT_WAKERS[index].wake(); } if epr.ctr_tx() { @@ -295,13 +296,13 @@ impl<'d, T: Instance> Driver<'d, T> { max_packet_size: u16, interval_ms: u8, ) -> Result, driver::EndpointAllocError> { - crate::println!( - "allocating type={:?} mps={:?} interval_ms={}, dir={:?}", - ep_type, - max_packet_size, - interval_ms, - D::dir() - ); + // crate::println!( + // "allocating type={:?} mps={:?} interval_ms={}, dir={:?}", + // ep_type, + // max_packet_size, + // interval_ms, + // D::dir() + // ); let index = self.alloc.iter_mut().enumerate().find(|(i, ep)| { if *i == 0 && ep_type != EndpointType::Control { @@ -330,7 +331,7 @@ impl<'d, T: Instance> Driver<'d, T> { let (len, len_bits) = calc_out_len(max_packet_size); let addr = self.alloc_ep_mem(len); - crate::println!(" len_bits = {:04x}", len_bits); + // crate::println!(" len_bits = {:04x}", len_bits); btable::write_out::(index, addr, len_bits); EndpointBuffer { @@ -357,7 +358,7 @@ impl<'d, T: Instance> Driver<'d, T> { } }; - crate::println!(" index={} addr={} len={}", index, buf.addr, buf.len); + // crate::println!(" index={} addr={} len={}", index, buf.addr, buf.len); Ok(Endpoint { _phantom: PhantomData, @@ -417,7 +418,11 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { w.set_ctrm(true); }); - crate::println!("enabled"); + // crate::println!("enabled"); + unsafe { + T::Interrupt::unpend(); + T::Interrupt::enable(); + } let mut ep_types = [EpType::BULK; EP_COUNT - 1]; for i in 1..EP_COUNT { @@ -468,7 +473,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { if IRQ_RESET.load(Ordering::Acquire) { IRQ_RESET.store(false, Ordering::Relaxed); - crate::println!("RESET"); + // crate::println!("RESET"); regs.daddr().write(|w| { w.set_ef(true); w.set_add(0); @@ -562,10 +567,10 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { } fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) { - crate::println!("set_enabled {:x?} {}", ep_addr, enabled); + // crate::println!("set_enabled {:x?} {}", ep_addr, enabled); // This can race, so do a retry loop. let reg = T::regs().epr(ep_addr.index() as _); - crate::println!("EPR before: {:04x}", reg.read().0); + // crate::println!("EPR before: {:04x}", reg.read().0); match ep_addr.direction() { Direction::In => { loop { @@ -600,7 +605,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { EP_OUT_WAKERS[ep_addr.index()].wake(); } } - crate::println!("EPR after: {:04x}", reg.read().0); + // crate::println!("EPR after: {:04x}", reg.read().0); } async fn enable(&mut self) {} @@ -648,7 +653,7 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> { fn read_data(&mut self, buf: &mut [u8]) -> Result { let index = self.info.addr.index(); let rx_len = btable::read_out_len::(index) as usize & 0x3FF; - crate::println!("READ DONE, rx_len = {}", rx_len); + // crate::println!("READ DONE, rx_len = {}", rx_len); if rx_len > buf.len() { return Err(EndpointError::BufferOverflow); } @@ -663,7 +668,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { } async fn wait_enabled(&mut self) { - crate::println!("wait_enabled IN WAITING"); + // crate::println!("wait_enabled IN WAITING"); let index = self.info.addr.index(); poll_fn(|cx| { EP_IN_WAKERS[index].register(cx.waker()); @@ -675,7 +680,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { } }) .await; - crate::println!("wait_enabled IN OK"); + // crate::println!("wait_enabled IN OK"); } } @@ -685,7 +690,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> { } async fn wait_enabled(&mut self) { - crate::println!("wait_enabled OUT WAITING"); + // crate::println!("wait_enabled OUT WAITING"); let index = self.info.addr.index(); poll_fn(|cx| { EP_OUT_WAKERS[index].register(cx.waker()); @@ -697,13 +702,13 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> { } }) .await; - crate::println!("wait_enabled OUT OK"); + // crate::println!("wait_enabled OUT OK"); } } impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { async fn read(&mut self, buf: &mut [u8]) -> Result { - crate::println!("READ WAITING, buf.len() = {}", buf.len()); + // crate::println!("READ WAITING, buf.len() = {}", buf.len()); let index = self.info.addr.index(); let stat = poll_fn(|cx| { EP_OUT_WAKERS[index].register(cx.waker()); @@ -732,7 +737,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear }); - crate::println!("READ OK, rx_len = {}", rx_len); + // crate::println!("READ OK, rx_len = {}", rx_len); Ok(rx_len) } @@ -746,7 +751,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { let index = self.info.addr.index(); - crate::println!("WRITE WAITING"); + // crate::println!("WRITE WAITING"); let stat = poll_fn(|cx| { EP_IN_WAKERS[index].register(cx.waker()); let regs = T::regs(); @@ -775,7 +780,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { w.set_ctr_tx(true); // don't clear }); - crate::println!("WRITE OK"); + // crate::println!("WRITE OK"); Ok(()) } @@ -796,7 +801,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { async fn setup(&mut self) -> [u8; 8] { loop { - crate::println!("SETUP read waiting"); + // crate::println!("SETUP read waiting"); poll_fn(|cx| { EP_OUT_WAKERS[0].register(cx.waker()); if EP0_SETUP.load(Ordering::Relaxed) { @@ -810,13 +815,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { let mut buf = [0; 8]; let rx_len = self.ep_out.read_data(&mut buf); if rx_len != Ok(8) { - crate::println!("SETUP read failed: {:?}", rx_len); + // crate::println!("SETUP read failed: {:?}", rx_len); continue; } EP0_SETUP.store(false, Ordering::Relaxed); - crate::println!("SETUP read ok"); + // crate::println!("SETUP read ok"); return buf; } } @@ -852,7 +857,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { }); } - crate::println!("data_out WAITING, buf.len() = {}", buf.len()); + // crate::println!("data_out WAITING, buf.len() = {}", buf.len()); poll_fn(|cx| { EP_OUT_WAKERS[0].register(cx.waker()); let regs = T::regs(); @@ -865,7 +870,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { .await; if EP0_SETUP.load(Ordering::Relaxed) { - crate::println!("received another SETUP, aborting data_out."); + // crate::println!("received another SETUP, aborting data_out."); return Err(EndpointError::Disabled); } @@ -887,7 +892,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { } async fn data_in(&mut self, data: &[u8], first: bool, last: bool) -> Result<(), EndpointError> { - crate::println!("control: data_in"); + // crate::println!("control: data_in"); if data.len() > self.ep_in.info.max_packet_size as usize { return Err(EndpointError::BufferOverflow); @@ -919,7 +924,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { }); } - crate::println!("WRITE WAITING"); + // crate::println!("WRITE WAITING"); poll_fn(|cx| { EP_IN_WAKERS[0].register(cx.waker()); EP_OUT_WAKERS[0].register(cx.waker()); @@ -933,7 +938,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { .await; if EP0_SETUP.load(Ordering::Relaxed) { - crate::println!("received another SETUP, aborting data_in."); + // crate::println!("received another SETUP, aborting data_in."); return Err(EndpointError::Disabled); } @@ -948,14 +953,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { w.set_ctr_tx(true); // don't clear }); - crate::println!("WRITE OK"); + // crate::println!("WRITE OK"); Ok(()) } async fn accept(&mut self) { let regs = T::regs(); - crate::println!("control: accept"); + // crate::println!("control: accept"); self.ep_in.write_data(&[]); @@ -968,7 +973,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear }); - crate::println!("control: accept WAITING"); + // crate::println!("control: accept WAITING"); // Wait is needed, so that we don't set the address too soon, breaking the status stage. // (embassy-usb sets the address after accept() returns) @@ -983,12 +988,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { }) .await; - crate::println!("control: accept OK"); + // crate::println!("control: accept OK"); } async fn reject(&mut self) { let regs = T::regs(); - crate::println!("control: reject"); + // crate::println!("control: reject"); // Set IN+OUT to stall let epr = regs.epr(0).read(); @@ -1005,7 +1010,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { self.accept().await; let regs = T::regs(); - crate::println!("setting addr: {}", addr); + // crate::println!("setting addr: {}", addr); regs.daddr().write(|w| { w.set_ef(true); w.set_add(addr);