aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJomer.Dev <[email protected]>2024-01-08 00:21:02 +0100
committerJomer.Dev <[email protected]>2024-01-08 00:21:02 +0100
commit6f505feeb1640c3d76c47aa21160a5a802fb6b93 (patch)
treea66fc8caf49218f84efb6b4a5aae7d2f23742109
parent1f57692d042de781f884d50f0cbd9eea0c71626d (diff)
Add example
-rw-r--r--examples/rp/src/bin/usb_serial_with_logger.rs117
1 files changed, 117 insertions, 0 deletions
diff --git a/examples/rp/src/bin/usb_serial_with_logger.rs b/examples/rp/src/bin/usb_serial_with_logger.rs
new file mode 100644
index 000000000..4ba4fc25c
--- /dev/null
+++ b/examples/rp/src/bin/usb_serial_with_logger.rs
@@ -0,0 +1,117 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip as well as how to create multiple usb classes for one device
2//!
3//! This creates a USB serial port that echos. It will also print out logging information on a separate serial device
4
5#![no_std]
6#![no_main]
7
8use defmt::{info, panic};
9use embassy_executor::Spawner;
10use embassy_futures::join::join;
11use embassy_rp::bind_interrupts;
12use embassy_rp::peripherals::USB;
13use embassy_rp::usb::{Driver, Instance, InterruptHandler};
14use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
15use embassy_usb::driver::EndpointError;
16use embassy_usb::{Builder, Config};
17use {defmt_rtt as _, panic_probe as _};
18
19bind_interrupts!(struct Irqs {
20 USBCTRL_IRQ => InterruptHandler<USB>;
21});
22
23#[embassy_executor::main]
24async fn main(_spawner: Spawner) {
25 info!("Hello there!");
26
27 let p = embassy_rp::init(Default::default());
28
29 // Create the driver, from the HAL.
30 let driver = Driver::new(p.USB, Irqs);
31
32 // Create embassy-usb Config
33 let mut config = Config::new(0xc0de, 0xcafe);
34 config.manufacturer = Some("Embassy");
35 config.product = Some("USB-serial example");
36 config.serial_number = Some("12345678");
37 config.max_power = 100;
38 config.max_packet_size_0 = 64;
39
40 // Required for windows compatibility.
41 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
42 config.device_class = 0xEF;
43 config.device_sub_class = 0x02;
44 config.device_protocol = 0x01;
45 config.composite_with_iads = true;
46
47 // Create embassy-usb DeviceBuilder using the driver and config.
48 // It needs some buffers for building the descriptors.
49 let mut device_descriptor = [0; 256];
50 let mut config_descriptor = [0; 256];
51 let mut bos_descriptor = [0; 256];
52 let mut control_buf = [0; 64];
53
54 let mut state = State::new();
55 let mut logger_state = State::new();
56
57 let mut builder = Builder::new(
58 driver,
59 config,
60 &mut device_descriptor,
61 &mut config_descriptor,
62 &mut bos_descriptor,
63 &mut [], // no msos descriptors
64 &mut control_buf,
65 );
66
67 // Create classes on the builder.
68 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
69
70 // Create a class for the logger
71 let logger_class = CdcAcmClass::new(&mut builder, &mut logger_state, 64);
72
73 // Creates the logger and returns the logger future
74 // Note: You'll need to use log::info! afterwards instead of info! for this to work (this also applies to all the other log::* macros)
75 let log_fut = embassy_usb_logger::with_class!(1024, log::LevelFilter::Info, logger_class);
76
77 // Build the builder.
78 let mut usb = builder.build();
79
80 // Run the USB device.
81 let usb_fut = usb.run();
82
83 // Do stuff with the class!
84 let echo_fut = async {
85 loop {
86 class.wait_connection().await;
87 log::info!("Connected");
88 let _ = echo(&mut class).await;
89 log::info!("Disconnected");
90 }
91 };
92
93 // Run everything concurrently.
94 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
95 join(usb_fut, join(echo_fut, log_fut)).await;
96}
97
98struct Disconnected {}
99
100impl From<EndpointError> for Disconnected {
101 fn from(val: EndpointError) -> Self {
102 match val {
103 EndpointError::BufferOverflow => panic!("Buffer overflow"),
104 EndpointError::Disabled => Disconnected {},
105 }
106 }
107}
108
109async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
110 let mut buf = [0; 64];
111 loop {
112 let n = class.read_packet(&mut buf).await?;
113 let data = &buf[..n];
114 info!("data: {:x}", data);
115 class.write_packet(data).await?;
116 }
117}