Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 | |

Expand Down
8 changes: 7 additions & 1 deletion examples/ch32v203/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
] }

Expand Down
107 changes: 107 additions & 0 deletions examples/ch32v203/src/bin/usbd.rs
Original file line number Diff line number Diff line change
@@ -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<hal::peripherals::USBD>;
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment that the println! lines should be commented to work properly without a probe connected.

// 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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the default value, this line can be omitted.

config.max_packet_size_0 = 64;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the default value, this line can be omitted.


// 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];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If no msos descriptor is used, this buffer should be [0; 0]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variable is not used, this line can be omitted.

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<EndpointError> 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?;
}
}
Loading