aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/Cargo.toml8
-rw-r--r--embassy-rp/src/gpio.rs4
-rw-r--r--embassy-rp/src/lib.rs37
-rw-r--r--embassy-rp/src/usb.rs846
-rw-r--r--examples/rp/Cargo.toml6
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs264
-rw-r--r--examples/rp/src/bin/usb_serial.rs103
7 files changed, 1263 insertions, 5 deletions
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index cfd95b7b4..f76e439ab 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -12,6 +12,7 @@ flavors = [
12] 12]
13 13
14[features] 14[features]
15defmt = ["dep:defmt", "embassy-usb?/defmt"]
15 16
16# Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. 17# Reexport the PAC for the currently enabled chip at `embassy_rp::pac`.
17# This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version. 18# This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version.
@@ -20,7 +21,7 @@ flavors = [
20unstable-pac = [] 21unstable-pac = []
21 22
22# Enable nightly-only features 23# Enable nightly-only features
23nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly"] 24nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb"]
24 25
25# Implement embedded-hal 1.0 alpha traits. 26# Implement embedded-hal 1.0 alpha traits.
26# Implement embedded-hal-async traits if `nightly` is set as well. 27# Implement embedded-hal-async traits if `nightly` is set as well.
@@ -33,6 +34,7 @@ embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick
33embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]} 34embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]}
34embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } 35embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
35embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 36embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
37embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional = true }
36atomic-polyfill = "1.0.1" 38atomic-polyfill = "1.0.1"
37defmt = { version = "0.3", optional = true } 39defmt = { version = "0.3", optional = true }
38log = { version = "0.4.14", optional = true } 40log = { version = "0.4.14", optional = true }
@@ -43,8 +45,8 @@ cortex-m = "0.7.6"
43critical-section = "1.1" 45critical-section = "1.1"
44futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 46futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
45 47
46rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="9ad7223a48a065e612bc7dc7be5bf5bd0b41cfc4", features = ["rt"] } 48rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] }
47#rp2040-pac2 = { path = "../../rp/rp2040-pac2", features = ["rt"] } 49#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] }
48 50
49embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 51embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
50embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true} 52embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true}
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index 428855c7f..a0328302a 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -433,7 +433,7 @@ impl<'d, T: Pin> Flex<'d, T> {
433 }); 433 });
434 434
435 pin.io().ctrl().write(|w| { 435 pin.io().ctrl().write(|w| {
436 w.set_funcsel(pac::io::vals::Gpio0CtrlFuncsel::SIO_0.0); 436 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0);
437 }); 437 });
438 } 438 }
439 439
@@ -586,7 +586,7 @@ impl<'d, T: Pin> Drop for Flex<'d, T> {
586 unsafe { 586 unsafe {
587 self.pin.pad_ctrl().write(|_| {}); 587 self.pin.pad_ctrl().write(|_| {});
588 self.pin.io().ctrl().write(|w| { 588 self.pin.io().ctrl().write(|w| {
589 w.set_funcsel(pac::io::vals::Gpio0CtrlFuncsel::NULL.0); 589 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0);
590 }); 590 });
591 } 591 }
592 } 592 }
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 6db77b8cd..aebbbf567 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -10,6 +10,8 @@ pub mod interrupt;
10pub mod spi; 10pub mod spi;
11pub mod timer; 11pub mod timer;
12pub mod uart; 12pub mod uart;
13#[cfg(feature = "nightly")]
14pub mod usb;
13 15
14mod clocks; 16mod clocks;
15mod reset; 17mod reset;
@@ -80,6 +82,8 @@ embassy_hal_common::peripherals! {
80 DMA_CH9, 82 DMA_CH9,
81 DMA_CH10, 83 DMA_CH10,
82 DMA_CH11, 84 DMA_CH11,
85
86 USB,
83} 87}
84 88
85#[link_section = ".boot2"] 89#[link_section = ".boot2"]
@@ -110,3 +114,36 @@ pub fn init(_config: config::Config) -> Peripherals {
110 114
111 peripherals 115 peripherals
112} 116}
117
118/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes.
119trait RegExt<T: Copy> {
120 unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
121 unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
122 unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
123}
124
125impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> {
126 unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
127 let mut val = Default::default();
128 let res = f(&mut val);
129 let ptr = (self.ptr() as *mut u8).add(0x1000) as *mut T;
130 ptr.write_volatile(val);
131 res
132 }
133
134 unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
135 let mut val = Default::default();
136 let res = f(&mut val);
137 let ptr = (self.ptr() as *mut u8).add(0x2000) as *mut T;
138 ptr.write_volatile(val);
139 res
140 }
141
142 unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
143 let mut val = Default::default();
144 let res = f(&mut val);
145 let ptr = (self.ptr() as *mut u8).add(0x3000) as *mut T;
146 ptr.write_volatile(val);
147 res
148 }
149}
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
new file mode 100644
index 000000000..82eafdefd
--- /dev/null
+++ b/embassy-rp/src/usb.rs
@@ -0,0 +1,846 @@
1use core::marker::PhantomData;
2use core::slice;
3use core::sync::atomic::Ordering;
4use core::task::Poll;
5
6use atomic_polyfill::compiler_fence;
7use embassy_hal_common::into_ref;
8use embassy_sync::waitqueue::AtomicWaker;
9use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported};
10use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
11use futures::future::poll_fn;
12use futures::Future;
13
14use crate::interrupt::{Interrupt, InterruptExt};
15use crate::{pac, peripherals, Peripheral, RegExt};
16
17pub(crate) mod sealed {
18 pub trait Instance {
19 fn regs() -> crate::pac::usb::Usb;
20 fn dpram() -> crate::pac::usb_dpram::UsbDpram;
21 }
22}
23
24pub trait Instance: sealed::Instance + 'static {
25 type Interrupt: Interrupt;
26}
27
28impl crate::usb::sealed::Instance for peripherals::USB {
29 fn regs() -> pac::usb::Usb {
30 pac::USBCTRL_REGS
31 }
32 fn dpram() -> crate::pac::usb_dpram::UsbDpram {
33 pac::USBCTRL_DPRAM
34 }
35}
36
37impl crate::usb::Instance for peripherals::USB {
38 type Interrupt = crate::interrupt::USBCTRL_IRQ;
39}
40
41const EP_COUNT: usize = 16;
42const EP_MEMORY_SIZE: usize = 4096;
43const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.0;
44
45const NEW_AW: AtomicWaker = AtomicWaker::new();
46static BUS_WAKER: AtomicWaker = NEW_AW;
47static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
48static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
49
50struct EndpointBuffer<T: Instance> {
51 addr: u16,
52 len: u16,
53 _phantom: PhantomData<T>,
54}
55
56impl<T: Instance> EndpointBuffer<T> {
57 const fn new(addr: u16, len: u16) -> Self {
58 Self {
59 addr,
60 len,
61 _phantom: PhantomData,
62 }
63 }
64
65 fn read(&mut self, buf: &mut [u8]) {
66 assert!(buf.len() <= self.len as usize);
67 compiler_fence(Ordering::SeqCst);
68 let mem = unsafe { slice::from_raw_parts(EP_MEMORY.add(self.addr as _), buf.len()) };
69 buf.copy_from_slice(mem);
70 compiler_fence(Ordering::SeqCst);
71 }
72
73 fn write(&mut self, buf: &[u8]) {
74 assert!(buf.len() <= self.len as usize);
75 compiler_fence(Ordering::SeqCst);
76 let mem = unsafe { slice::from_raw_parts_mut(EP_MEMORY.add(self.addr as _), buf.len()) };
77 mem.copy_from_slice(buf);
78 compiler_fence(Ordering::SeqCst);
79 }
80}
81
82#[derive(Debug, Clone, Copy)]
83#[cfg_attr(feature = "defmt", derive(defmt::Format))]
84struct EndpointData {
85 ep_type: EndpointType, // only valid if used
86 max_packet_size: u16,
87 used: bool,
88}
89
90impl EndpointData {
91 const fn new() -> Self {
92 Self {
93 ep_type: EndpointType::Bulk,
94 max_packet_size: 0,
95 used: false,
96 }
97 }
98}
99
100pub struct Driver<'d, T: Instance> {
101 phantom: PhantomData<&'d mut T>,
102 ep_in: [EndpointData; EP_COUNT],
103 ep_out: [EndpointData; EP_COUNT],
104 ep_mem_free: u16, // first free address in EP mem, in bytes.
105}
106
107impl<'d, T: Instance> Driver<'d, T> {
108 pub fn new(_usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd) -> Self {
109 into_ref!(irq);
110 irq.set_handler(Self::on_interrupt);
111 irq.unpend();
112 irq.enable();
113
114 let regs = T::regs();
115 unsafe {
116 // zero fill regs
117 let p = regs.0 as *mut u32;
118 for i in 0..0x9c / 4 {
119 p.add(i).write_volatile(0)
120 }
121
122 // zero fill epmem
123 let p = EP_MEMORY as *mut u32;
124 for i in 0..0x100 / 4 {
125 p.add(i).write_volatile(0)
126 }
127
128 regs.usb_muxing().write(|w| {
129 w.set_to_phy(true);
130 w.set_softcon(true);
131 });
132 regs.usb_pwr().write(|w| {
133 w.set_vbus_detect(true);
134 w.set_vbus_detect_override_en(true);
135 });
136 regs.main_ctrl().write(|w| {
137 w.set_controller_en(true);
138 });
139 }
140
141 // Initialize the bus so that it signals that power is available
142 BUS_WAKER.wake();
143
144 Self {
145 phantom: PhantomData,
146 ep_in: [EndpointData::new(); EP_COUNT],
147 ep_out: [EndpointData::new(); EP_COUNT],
148 ep_mem_free: 0x180, // data buffer region
149 }
150 }
151
152 fn on_interrupt(_: *mut ()) {
153 unsafe {
154 let regs = T::regs();
155 //let x = regs.istr().read().0;
156 //trace!("USB IRQ: {:08x}", x);
157
158 let ints = regs.ints().read();
159
160 if ints.bus_reset() {
161 regs.inte().write_clear(|w| w.set_bus_reset(true));
162 BUS_WAKER.wake();
163 }
164 if ints.dev_resume_from_host() {
165 regs.inte().write_clear(|w| w.set_dev_resume_from_host(true));
166 BUS_WAKER.wake();
167 }
168 if ints.dev_suspend() {
169 regs.inte().write_clear(|w| w.set_dev_suspend(true));
170 BUS_WAKER.wake();
171 }
172 if ints.setup_req() {
173 regs.inte().write_clear(|w| w.set_setup_req(true));
174 EP_OUT_WAKERS[0].wake();
175 }
176
177 if ints.buff_status() {
178 let s = regs.buff_status().read();
179 regs.buff_status().write_value(s);
180
181 for i in 0..EP_COUNT {
182 if s.ep_in(i) {
183 EP_IN_WAKERS[i].wake();
184 }
185 if s.ep_out(i) {
186 EP_OUT_WAKERS[i].wake();
187 }
188 }
189 }
190 }
191 }
192
193 fn alloc_endpoint<D: Dir>(
194 &mut self,
195 ep_type: EndpointType,
196 max_packet_size: u16,
197 interval: u8,
198 ) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> {
199 trace!(
200 "allocating type={:?} mps={:?} interval={}, dir={:?}",
201 ep_type,
202 max_packet_size,
203 interval,
204 D::dir()
205 );
206
207 let alloc = match D::dir() {
208 UsbDirection::Out => &mut self.ep_out,
209 UsbDirection::In => &mut self.ep_in,
210 };
211
212 let index = alloc.iter_mut().enumerate().find(|(i, ep)| {
213 if *i == 0 {
214 return false; // reserved for control pipe
215 }
216 !ep.used
217 });
218
219 let (index, ep) = index.ok_or(EndpointAllocError)?;
220 assert!(!ep.used);
221
222 if max_packet_size > 64 {
223 warn!("max_packet_size too high: {}", max_packet_size);
224 return Err(EndpointAllocError);
225 }
226
227 // ep mem addrs must be 64-byte aligned, so there's no point in trying
228 // to allocate smaller chunks to save memory.
229 let len = 64;
230
231 let addr = self.ep_mem_free;
232 if addr + len > EP_MEMORY_SIZE as _ {
233 warn!("Endpoint memory full");
234 return Err(EndpointAllocError);
235 }
236 self.ep_mem_free += len;
237
238 let buf = EndpointBuffer {
239 addr,
240 len,
241 _phantom: PhantomData,
242 };
243
244 trace!(" index={} addr={} len={}", index, buf.addr, buf.len);
245
246 ep.ep_type = ep_type;
247 ep.used = true;
248 ep.max_packet_size = max_packet_size;
249
250 let ep_type_reg = match ep_type {
251 EndpointType::Bulk => pac::usb_dpram::vals::EpControlEndpointType::BULK,
252 EndpointType::Control => pac::usb_dpram::vals::EpControlEndpointType::CONTROL,
253 EndpointType::Interrupt => pac::usb_dpram::vals::EpControlEndpointType::INTERRUPT,
254 EndpointType::Isochronous => pac::usb_dpram::vals::EpControlEndpointType::ISOCHRONOUS,
255 };
256
257 match D::dir() {
258 UsbDirection::Out => unsafe {
259 T::dpram().ep_out_control(index - 1).write(|w| {
260 w.set_enable(false);
261 w.set_buffer_address(addr);
262 w.set_interrupt_per_buff(true);
263 w.set_endpoint_type(ep_type_reg);
264 })
265 },
266 UsbDirection::In => unsafe {
267 T::dpram().ep_in_control(index - 1).write(|w| {
268 w.set_enable(false);
269 w.set_buffer_address(addr);
270 w.set_interrupt_per_buff(true);
271 w.set_endpoint_type(ep_type_reg);
272 })
273 },
274 }
275
276 Ok(Endpoint {
277 _phantom: PhantomData,
278 info: EndpointInfo {
279 addr: EndpointAddress::from_parts(index, D::dir()),
280 ep_type,
281 max_packet_size,
282 interval,
283 },
284 buf,
285 })
286 }
287}
288
289impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
290 type EndpointOut = Endpoint<'d, T, Out>;
291 type EndpointIn = Endpoint<'d, T, In>;
292 type ControlPipe = ControlPipe<'d, T>;
293 type Bus = Bus<'d, T>;
294
295 fn alloc_endpoint_in(
296 &mut self,
297 ep_type: EndpointType,
298 max_packet_size: u16,
299 interval: u8,
300 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
301 self.alloc_endpoint(ep_type, max_packet_size, interval)
302 }
303
304 fn alloc_endpoint_out(
305 &mut self,
306 ep_type: EndpointType,
307 max_packet_size: u16,
308 interval: u8,
309 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
310 self.alloc_endpoint(ep_type, max_packet_size, interval)
311 }
312
313 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
314 let regs = T::regs();
315 unsafe {
316 regs.inte().write(|w| {
317 w.set_bus_reset(true);
318 w.set_buff_status(true);
319 w.set_dev_resume_from_host(true);
320 w.set_dev_suspend(true);
321 w.set_setup_req(true);
322 });
323 regs.int_ep_ctrl().write(|w| {
324 w.set_int_ep_active(0xFFFE); // all EPs
325 });
326 regs.sie_ctrl().write(|w| {
327 w.set_ep0_int_1buf(true);
328 w.set_pullup_en(true);
329 })
330 }
331 trace!("enabled");
332
333 (
334 Bus {
335 phantom: PhantomData,
336 inited: false,
337 ep_out: self.ep_out,
338 },
339 ControlPipe {
340 _phantom: PhantomData,
341 max_packet_size: control_max_packet_size,
342 },
343 )
344 }
345}
346
347pub struct Bus<'d, T: Instance> {
348 phantom: PhantomData<&'d mut T>,
349 ep_out: [EndpointData; EP_COUNT],
350 inited: bool,
351}
352
353impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
354 type PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a;
355
356 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> {
357 poll_fn(move |cx| unsafe {
358 BUS_WAKER.register(cx.waker());
359
360 if !self.inited {
361 self.inited = true;
362 return Poll::Ready(Event::PowerDetected);
363 }
364
365 let regs = T::regs();
366 let siestatus = regs.sie_status().read();
367
368 if siestatus.resume() {
369 regs.sie_status().write(|w| w.set_resume(true));
370 return Poll::Ready(Event::Resume);
371 }
372
373 if siestatus.bus_reset() {
374 regs.sie_status().write(|w| {
375 w.set_bus_reset(true);
376 w.set_setup_rec(true);
377 });
378 regs.buff_status().write(|w| w.0 = 0xFFFF_FFFF);
379 regs.addr_endp().write(|w| w.set_address(0));
380
381 for i in 1..EP_COUNT {
382 T::dpram().ep_in_control(i - 1).modify(|w| w.set_enable(false));
383 T::dpram().ep_out_control(i - 1).modify(|w| w.set_enable(false));
384 }
385
386 for w in &EP_IN_WAKERS {
387 w.wake()
388 }
389 for w in &EP_OUT_WAKERS {
390 w.wake()
391 }
392 return Poll::Ready(Event::Reset);
393 }
394
395 if siestatus.suspended() {
396 regs.sie_status().write(|w| w.set_suspended(true));
397 return Poll::Ready(Event::Suspend);
398 }
399
400 // no pending event. Reenable all irqs.
401 regs.inte().write_set(|w| {
402 w.set_bus_reset(true);
403 w.set_dev_resume_from_host(true);
404 w.set_dev_suspend(true);
405 });
406 Poll::Pending
407 })
408 }
409
410 #[inline]
411 fn set_address(&mut self, addr: u8) {
412 let regs = T::regs();
413 trace!("setting addr: {}", addr);
414 unsafe { regs.addr_endp().write(|w| w.set_address(addr)) }
415 }
416
417 fn endpoint_set_stalled(&mut self, _ep_addr: EndpointAddress, _stalled: bool) {
418 todo!();
419 }
420
421 fn endpoint_is_stalled(&mut self, _ep_addr: EndpointAddress) -> bool {
422 todo!();
423 }
424
425 fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
426 trace!("set_enabled {:?} {}", ep_addr, enabled);
427 if ep_addr.index() == 0 {
428 return;
429 }
430
431 let n = ep_addr.index();
432 match ep_addr.direction() {
433 UsbDirection::In => unsafe {
434 T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled));
435 T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| {
436 w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
437 });
438 EP_IN_WAKERS[n].wake();
439 },
440 UsbDirection::Out => unsafe {
441 T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled));
442
443 T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
444 w.set_pid(0, false);
445 w.set_length(0, self.ep_out[n].max_packet_size);
446 });
447 cortex_m::asm::delay(12);
448 T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
449 w.set_pid(0, false);
450 w.set_length(0, self.ep_out[n].max_packet_size);
451 w.set_available(0, true);
452 });
453 EP_OUT_WAKERS[n].wake();
454 },
455 }
456 }
457
458 type EnableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
459
460 fn enable(&mut self) -> Self::EnableFuture<'_> {
461 async move {}
462 }
463
464 type DisableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
465
466 fn disable(&mut self) -> Self::DisableFuture<'_> {
467 async move {}
468 }
469
470 type RemoteWakeupFuture<'a> = impl Future<Output = Result<(), Unsupported>> + 'a where Self: 'a;
471
472 fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_> {
473 async move { Err(Unsupported) }
474 }
475}
476
477trait Dir {
478 fn dir() -> UsbDirection;
479 fn waker(i: usize) -> &'static AtomicWaker;
480}
481
482pub enum In {}
483impl Dir for In {
484 fn dir() -> UsbDirection {
485 UsbDirection::In
486 }
487
488 #[inline]
489 fn waker(i: usize) -> &'static AtomicWaker {
490 &EP_IN_WAKERS[i]
491 }
492}
493
494pub enum Out {}
495impl Dir for Out {
496 fn dir() -> UsbDirection {
497 UsbDirection::Out
498 }
499
500 #[inline]
501 fn waker(i: usize) -> &'static AtomicWaker {
502 &EP_OUT_WAKERS[i]
503 }
504}
505
506pub struct Endpoint<'d, T: Instance, D> {
507 _phantom: PhantomData<(&'d mut T, D)>,
508 info: EndpointInfo,
509 buf: EndpointBuffer<T>,
510}
511
512impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
513 fn info(&self) -> &EndpointInfo {
514 &self.info
515 }
516
517 type WaitEnabledFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
518
519 fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_> {
520 async move {
521 trace!("wait_enabled IN WAITING");
522 let index = self.info.addr.index();
523 poll_fn(|cx| {
524 EP_OUT_WAKERS[index].register(cx.waker());
525 let val = unsafe { T::dpram().ep_in_control(self.info.addr.index() - 1).read() };
526 if val.enable() {
527 Poll::Ready(())
528 } else {
529 Poll::Pending
530 }
531 })
532 .await;
533 trace!("wait_enabled IN OK");
534 }
535 }
536}
537
538impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
539 fn info(&self) -> &EndpointInfo {
540 &self.info
541 }
542
543 type WaitEnabledFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
544
545 fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_> {
546 async move {
547 trace!("wait_enabled OUT WAITING");
548 let index = self.info.addr.index();
549 poll_fn(|cx| {
550 EP_OUT_WAKERS[index].register(cx.waker());
551 let val = unsafe { T::dpram().ep_out_control(self.info.addr.index() - 1).read() };
552 if val.enable() {
553 Poll::Ready(())
554 } else {
555 Poll::Pending
556 }
557 })
558 .await;
559 trace!("wait_enabled OUT OK");
560 }
561 }
562}
563
564impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
565 type ReadFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a;
566
567 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
568 async move {
569 trace!("READ WAITING, buf.len() = {}", buf.len());
570 let index = self.info.addr.index();
571 let val = poll_fn(|cx| unsafe {
572 EP_OUT_WAKERS[index].register(cx.waker());
573 let val = T::dpram().ep_out_buffer_control(index).read();
574 if val.available(0) {
575 Poll::Pending
576 } else {
577 Poll::Ready(val)
578 }
579 })
580 .await;
581
582 let rx_len = val.length(0) as usize;
583 if rx_len > buf.len() {
584 return Err(EndpointError::BufferOverflow);
585 }
586 self.buf.read(&mut buf[..rx_len]);
587
588 trace!("READ OK, rx_len = {}", rx_len);
589
590 unsafe {
591 let pid = !val.pid(0);
592 T::dpram().ep_out_buffer_control(index).write(|w| {
593 w.set_pid(0, pid);
594 w.set_length(0, self.info.max_packet_size);
595 });
596 cortex_m::asm::delay(12);
597 T::dpram().ep_out_buffer_control(index).write(|w| {
598 w.set_pid(0, pid);
599 w.set_length(0, self.info.max_packet_size);
600 w.set_available(0, true);
601 });
602 }
603
604 Ok(rx_len)
605 }
606 }
607}
608
609impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
610 type WriteFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a;
611
612 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
613 async move {
614 if buf.len() > self.info.max_packet_size as usize {
615 return Err(EndpointError::BufferOverflow);
616 }
617
618 trace!("WRITE WAITING");
619
620 let index = self.info.addr.index();
621 let val = poll_fn(|cx| unsafe {
622 EP_IN_WAKERS[index].register(cx.waker());
623 let val = T::dpram().ep_in_buffer_control(index).read();
624 if val.available(0) {
625 Poll::Pending
626 } else {
627 Poll::Ready(val)
628 }
629 })
630 .await;
631
632 self.buf.write(buf);
633
634 unsafe {
635 let pid = !val.pid(0);
636 T::dpram().ep_in_buffer_control(index).write(|w| {
637 w.set_pid(0, pid);
638 w.set_length(0, buf.len() as _);
639 w.set_full(0, true);
640 });
641 cortex_m::asm::delay(12);
642 T::dpram().ep_in_buffer_control(index).write(|w| {
643 w.set_pid(0, pid);
644 w.set_length(0, buf.len() as _);
645 w.set_full(0, true);
646 w.set_available(0, true);
647 });
648 }
649
650 trace!("WRITE OK");
651
652 Ok(())
653 }
654 }
655}
656
657pub struct ControlPipe<'d, T: Instance> {
658 _phantom: PhantomData<&'d mut T>,
659 max_packet_size: u16,
660}
661
662impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
663 type SetupFuture<'a> = impl Future<Output = [u8;8]> + 'a where Self: 'a;
664 type DataOutFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a;
665 type DataInFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a;
666 type AcceptFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
667 type RejectFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
668
669 fn max_packet_size(&self) -> usize {
670 64
671 }
672
673 fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a> {
674 async move {
675 loop {
676 trace!("SETUP read waiting");
677 let regs = T::regs();
678 unsafe { regs.inte().write_set(|w| w.set_setup_req(true)) };
679
680 poll_fn(|cx| unsafe {
681 EP_OUT_WAKERS[0].register(cx.waker());
682 let regs = T::regs();
683 if regs.sie_status().read().setup_rec() {
684 Poll::Ready(())
685 } else {
686 Poll::Pending
687 }
688 })
689 .await;
690
691 let mut buf = [0; 8];
692 EndpointBuffer::<T>::new(0, 8).read(&mut buf);
693
694 let regs = T::regs();
695 unsafe {
696 regs.sie_status().write(|w| w.set_setup_rec(true));
697
698 // set PID to 0, so (after toggling) first DATA is PID 1
699 T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false));
700 T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false));
701 }
702
703 trace!("SETUP read ok");
704 return buf;
705 }
706 }
707 }
708
709 fn data_out<'a>(&'a mut self, buf: &'a mut [u8], _first: bool, _last: bool) -> Self::DataOutFuture<'a> {
710 async move {
711 unsafe {
712 let bufcontrol = T::dpram().ep_out_buffer_control(0);
713 let pid = !bufcontrol.read().pid(0);
714 bufcontrol.write(|w| {
715 w.set_length(0, self.max_packet_size);
716 w.set_pid(0, pid);
717 });
718 cortex_m::asm::delay(12);
719 bufcontrol.write(|w| {
720 w.set_length(0, self.max_packet_size);
721 w.set_pid(0, pid);
722 w.set_available(0, true);
723 });
724 }
725
726 trace!("control: data_out len={} first={} last={}", buf.len(), _first, _last);
727 let val = poll_fn(|cx| unsafe {
728 EP_OUT_WAKERS[0].register(cx.waker());
729 let val = T::dpram().ep_out_buffer_control(0).read();
730 if val.available(0) {
731 Poll::Pending
732 } else {
733 Poll::Ready(val)
734 }
735 })
736 .await;
737
738 let rx_len = val.length(0) as _;
739 trace!("control data_out DONE, rx_len = {}", rx_len);
740
741 if rx_len > buf.len() {
742 return Err(EndpointError::BufferOverflow);
743 }
744 EndpointBuffer::<T>::new(0x100, 64).read(&mut buf[..rx_len]);
745
746 Ok(rx_len)
747 }
748 }
749
750 fn data_in<'a>(&'a mut self, buf: &'a [u8], _first: bool, _last: bool) -> Self::DataInFuture<'a> {
751 async move {
752 trace!("control: data_in len={} first={} last={}", buf.len(), _first, _last);
753
754 if buf.len() > 64 {
755 return Err(EndpointError::BufferOverflow);
756 }
757 EndpointBuffer::<T>::new(0x100, 64).write(buf);
758
759 unsafe {
760 let bufcontrol = T::dpram().ep_in_buffer_control(0);
761 let pid = !bufcontrol.read().pid(0);
762 bufcontrol.write(|w| {
763 w.set_length(0, buf.len() as _);
764 w.set_pid(0, pid);
765 w.set_full(0, true);
766 });
767 cortex_m::asm::delay(12);
768 bufcontrol.write(|w| {
769 w.set_length(0, buf.len() as _);
770 w.set_pid(0, pid);
771 w.set_full(0, true);
772 w.set_available(0, true);
773 });
774 }
775
776 poll_fn(|cx| unsafe {
777 EP_IN_WAKERS[0].register(cx.waker());
778 let bufcontrol = T::dpram().ep_in_buffer_control(0);
779 if bufcontrol.read().available(0) {
780 Poll::Pending
781 } else {
782 Poll::Ready(())
783 }
784 })
785 .await;
786 trace!("control: data_in DONE");
787
788 if _last {
789 // prepare status phase right away.
790 unsafe {
791 let bufcontrol = T::dpram().ep_out_buffer_control(0);
792 bufcontrol.write(|w| {
793 w.set_length(0, 0);
794 w.set_pid(0, true);
795 });
796 cortex_m::asm::delay(12);
797 bufcontrol.write(|w| {
798 w.set_length(0, 0);
799 w.set_pid(0, true);
800 w.set_available(0, true);
801 });
802 }
803 }
804
805 Ok(())
806 }
807 }
808
809 fn accept<'a>(&'a mut self) -> Self::AcceptFuture<'a> {
810 async move {
811 trace!("control: accept");
812
813 unsafe {
814 let bufcontrol = T::dpram().ep_in_buffer_control(0);
815 bufcontrol.write(|w| {
816 w.set_length(0, 0);
817 w.set_pid(0, true);
818 w.set_full(0, true);
819 });
820 cortex_m::asm::delay(12);
821 bufcontrol.write(|w| {
822 w.set_length(0, 0);
823 w.set_pid(0, true);
824 w.set_full(0, true);
825 w.set_available(0, true);
826 });
827 }
828 }
829 }
830
831 fn reject<'a>(&'a mut self) -> Self::RejectFuture<'a> {
832 async move {
833 trace!("control: reject");
834
835 let regs = T::regs();
836 unsafe {
837 regs.ep_stall_arm().write_set(|w| {
838 w.set_ep0_in(true);
839 w.set_ep0_out(true);
840 });
841 T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true));
842 T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true));
843 }
844 }
845 }
846}
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index d804a660b..72a3a057d 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -9,6 +9,10 @@ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["de
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
11embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac"] } 11embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
13embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] }
14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
15embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"] }
12 16
13defmt = "0.3" 17defmt = "0.3"
14defmt-rtt = "0.3" 18defmt-rtt = "0.3"
@@ -25,3 +29,5 @@ byte-slice-cast = { version = "1.2.0", default-features = false }
25 29
26embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } 30embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" }
27embedded-hal-async = { version = "0.1.0-alpha.1" } 31embedded-hal-async = { version = "0.1.0-alpha.1" }
32embedded-io = { version = "0.3.0", features = ["async", "defmt"] }
33static_cell = "1.0.0"
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
new file mode 100644
index 000000000..2cb0010f1
--- /dev/null
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -0,0 +1,264 @@
1#![no_std]
2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)]
5
6use core::sync::atomic::{AtomicBool, Ordering};
7use core::task::Waker;
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_net::tcp::TcpSocket;
12use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources};
13use embassy_rp::usb::Driver;
14use embassy_rp::{interrupt, peripherals};
15use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
16use embassy_sync::channel::Channel;
17use embassy_usb::{Builder, Config, UsbDevice};
18use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
19use embedded_io::asynch::{Read, Write};
20use static_cell::StaticCell;
21use {defmt_rtt as _, panic_probe as _};
22
23type MyDriver = Driver<'static, peripherals::USB>;
24
25macro_rules! singleton {
26 ($val:expr) => {{
27 type T = impl Sized;
28 static STATIC_CELL: StaticCell<T> = StaticCell::new();
29 STATIC_CELL.init_with(move || $val)
30 }};
31}
32
33#[embassy_executor::task]
34async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
35 device.run().await
36}
37
38#[embassy_executor::task]
39async fn usb_ncm_rx_task(mut class: Receiver<'static, MyDriver>) {
40 loop {
41 warn!("WAITING for connection");
42 LINK_UP.store(false, Ordering::Relaxed);
43
44 class.wait_connection().await.unwrap();
45
46 warn!("Connected");
47 LINK_UP.store(true, Ordering::Relaxed);
48
49 loop {
50 let mut p = unwrap!(PacketBox::new(embassy_net::Packet::new()));
51 let n = match class.read_packet(&mut p[..]).await {
52 Ok(n) => n,
53 Err(e) => {
54 warn!("error reading packet: {:?}", e);
55 break;
56 }
57 };
58
59 let buf = p.slice(0..n);
60 if RX_CHANNEL.try_send(buf).is_err() {
61 warn!("Failed pushing rx'd packet to channel.");
62 }
63 }
64 }
65}
66
67#[embassy_executor::task]
68async fn usb_ncm_tx_task(mut class: Sender<'static, MyDriver>) {
69 loop {
70 let pkt = TX_CHANNEL.recv().await;
71 if let Err(e) = class.write_packet(&pkt[..]).await {
72 warn!("Failed to TX packet: {:?}", e);
73 }
74 }
75}
76
77#[embassy_executor::task]
78async fn net_task(stack: &'static Stack<Device>) -> ! {
79 stack.run().await
80}
81
82#[embassy_executor::main]
83async fn main(spawner: Spawner) {
84 let p = embassy_rp::init(Default::default());
85
86 // Create the driver, from the HAL.
87 let irq = interrupt::take!(USBCTRL_IRQ);
88 let driver = Driver::new(p.USB, irq);
89
90 // Create embassy-usb Config
91 let mut config = Config::new(0xc0de, 0xcafe);
92 config.manufacturer = Some("Embassy");
93 config.product = Some("USB-Ethernet example");
94 config.serial_number = Some("12345678");
95 config.max_power = 100;
96 config.max_packet_size_0 = 64;
97
98 // Required for Windows support.
99 config.composite_with_iads = true;
100 config.device_class = 0xEF;
101 config.device_sub_class = 0x02;
102 config.device_protocol = 0x01;
103
104 struct Resources {
105 device_descriptor: [u8; 256],
106 config_descriptor: [u8; 256],
107 bos_descriptor: [u8; 256],
108 control_buf: [u8; 128],
109 serial_state: State<'static>,
110 }
111 let res: &mut Resources = singleton!(Resources {
112 device_descriptor: [0; 256],
113 config_descriptor: [0; 256],
114 bos_descriptor: [0; 256],
115 control_buf: [0; 128],
116 serial_state: State::new(),
117 });
118
119 // Create embassy-usb DeviceBuilder using the driver and config.
120 let mut builder = Builder::new(
121 driver,
122 config,
123 &mut res.device_descriptor,
124 &mut res.config_descriptor,
125 &mut res.bos_descriptor,
126 &mut res.control_buf,
127 None,
128 );
129
130 // WARNINGS for Android ethernet tethering:
131 // - On Pixel 4a, it refused to work on Android 11, worked on Android 12.
132 // - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte),
133 // it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled.
134 // This is due to regex spaghetti: https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r84/core/res/res/values/config.xml#417
135 // and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757
136
137 // Our MAC addr.
138 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
139 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
140 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
141
142 // Create classes on the builder.
143 let class = CdcNcmClass::new(&mut builder, &mut res.serial_state, host_mac_addr, 64);
144
145 // Build the builder.
146 let usb = builder.build();
147
148 unwrap!(spawner.spawn(usb_task(usb)));
149
150 let (tx, rx) = class.split();
151 unwrap!(spawner.spawn(usb_ncm_rx_task(rx)));
152 unwrap!(spawner.spawn(usb_ncm_tx_task(tx)));
153
154 let config = embassy_net::ConfigStrategy::Dhcp;
155 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
156 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
157 // dns_servers: Vec::new(),
158 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
159 //});
160
161 // Generate random seed
162 let seed = 1234; // guaranteed random, chosen by a fair dice roll
163
164 // Init network stack
165 let device = Device { mac_addr: our_mac_addr };
166 let stack = &*singleton!(Stack::new(
167 device,
168 config,
169 singleton!(StackResources::<1, 2, 8>::new()),
170 seed
171 ));
172
173 unwrap!(spawner.spawn(net_task(stack)));
174
175 // And now we can use it!
176
177 let mut rx_buffer = [0; 4096];
178 let mut tx_buffer = [0; 4096];
179 let mut buf = [0; 4096];
180
181 loop {
182 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
183 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
184
185 info!("Listening on TCP:1234...");
186 if let Err(e) = socket.accept(1234).await {
187 warn!("accept error: {:?}", e);
188 continue;
189 }
190
191 info!("Received connection from {:?}", socket.remote_endpoint());
192
193 loop {
194 let n = match socket.read(&mut buf).await {
195 Ok(0) => {
196 warn!("read EOF");
197 break;
198 }
199 Ok(n) => n,
200 Err(e) => {
201 warn!("read error: {:?}", e);
202 break;
203 }
204 };
205
206 info!("rxd {:02x}", &buf[..n]);
207
208 match socket.write_all(&buf[..n]).await {
209 Ok(()) => {}
210 Err(e) => {
211 warn!("write error: {:?}", e);
212 break;
213 }
214 };
215 }
216 }
217}
218
219static TX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
220static RX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
221static LINK_UP: AtomicBool = AtomicBool::new(false);
222
223struct Device {
224 mac_addr: [u8; 6],
225}
226
227impl embassy_net::Device for Device {
228 fn register_waker(&mut self, waker: &Waker) {
229 // loopy loopy wakey wakey
230 waker.wake_by_ref()
231 }
232
233 fn link_state(&mut self) -> embassy_net::LinkState {
234 match LINK_UP.load(Ordering::Relaxed) {
235 true => embassy_net::LinkState::Up,
236 false => embassy_net::LinkState::Down,
237 }
238 }
239
240 fn capabilities(&self) -> embassy_net::DeviceCapabilities {
241 let mut caps = embassy_net::DeviceCapabilities::default();
242 caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header
243 caps.medium = embassy_net::Medium::Ethernet;
244 caps
245 }
246
247 fn is_transmit_ready(&mut self) -> bool {
248 true
249 }
250
251 fn transmit(&mut self, pkt: PacketBuf) {
252 if TX_CHANNEL.try_send(pkt).is_err() {
253 warn!("TX failed")
254 }
255 }
256
257 fn receive<'a>(&mut self) -> Option<PacketBuf> {
258 RX_CHANNEL.try_recv().ok()
259 }
260
261 fn ethernet_address(&self) -> [u8; 6] {
262 self.mac_addr
263 }
264}
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
new file mode 100644
index 000000000..74be1f598
--- /dev/null
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -0,0 +1,103 @@
1#![no_std]
2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)]
5
6use defmt::{info, panic};
7use embassy_executor::Spawner;
8use embassy_rp::interrupt;
9use embassy_rp::usb::{Driver, Instance};
10use embassy_usb::driver::EndpointError;
11use embassy_usb::{Builder, Config};
12use embassy_usb_serial::{CdcAcmClass, State};
13use futures::future::join;
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 info!("Hello there!");
19
20 let p = embassy_rp::init(Default::default());
21
22 // Create the driver, from the HAL.
23 let irq = interrupt::take!(USBCTRL_IRQ);
24 let driver = Driver::new(p.USB, irq);
25
26 // Create embassy-usb Config
27 let mut config = Config::new(0xc0de, 0xcafe);
28 config.manufacturer = Some("Embassy");
29 config.product = Some("USB-serial example");
30 config.serial_number = Some("12345678");
31 config.max_power = 100;
32 config.max_packet_size_0 = 64;
33
34 // Required for windows compatiblity.
35 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
36 config.device_class = 0xEF;
37 config.device_sub_class = 0x02;
38 config.device_protocol = 0x01;
39 config.composite_with_iads = true;
40
41 // Create embassy-usb DeviceBuilder using the driver and config.
42 // It needs some buffers for building the descriptors.
43 let mut device_descriptor = [0; 256];
44 let mut config_descriptor = [0; 256];
45 let mut bos_descriptor = [0; 256];
46 let mut control_buf = [0; 64];
47
48 let mut state = State::new();
49
50 let mut builder = Builder::new(
51 driver,
52 config,
53 &mut device_descriptor,
54 &mut config_descriptor,
55 &mut bos_descriptor,
56 &mut control_buf,
57 None,
58 );
59
60 // Create classes on the builder.
61 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
62
63 // Build the builder.
64 let mut usb = builder.build();
65
66 // Run the USB device.
67 let usb_fut = usb.run();
68
69 // Do stuff with the class!
70 let echo_fut = async {
71 loop {
72 class.wait_connection().await;
73 info!("Connected");
74 let _ = echo(&mut class).await;
75 info!("Disconnected");
76 }
77 };
78
79 // Run everything concurrently.
80 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
81 join(usb_fut, echo_fut).await;
82}
83
84struct Disconnected {}
85
86impl From<EndpointError> for Disconnected {
87 fn from(val: EndpointError) -> Self {
88 match val {
89 EndpointError::BufferOverflow => panic!("Buffer overflow"),
90 EndpointError::Disabled => Disconnected {},
91 }
92 }
93}
94
95async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
96 let mut buf = [0; 64];
97 loop {
98 let n = class.read_packet(&mut buf).await?;
99 let data = &buf[..n];
100 info!("data: {:x}", data);
101 class.write_packet(data).await?;
102 }
103}