aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/usb.rs158
-rw-r--r--embassy-usb/src/lib.rs1
-rw-r--r--examples/nrf/Cargo.toml2
-rw-r--r--examples/nrf/src/bin/usb/main.rs18
4 files changed, 116 insertions, 63 deletions
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index 163b2c794..874bfe841 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -1,7 +1,8 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::mem::MaybeUninit;
5use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
5use core::task::Poll; 6use core::task::Poll;
6use embassy::interrupt::InterruptExt; 7use embassy::interrupt::InterruptExt;
7use embassy::time::{with_timeout, Duration}; 8use embassy::time::{with_timeout, Duration};
@@ -23,6 +24,7 @@ const NEW_AW: AtomicWaker = AtomicWaker::new();
23static BUS_WAKER: AtomicWaker = NEW_AW; 24static BUS_WAKER: AtomicWaker = NEW_AW;
24static EP_IN_WAKERS: [AtomicWaker; 9] = [NEW_AW; 9]; 25static EP_IN_WAKERS: [AtomicWaker; 9] = [NEW_AW; 9];
25static EP_OUT_WAKERS: [AtomicWaker; 9] = [NEW_AW; 9]; 26static EP_OUT_WAKERS: [AtomicWaker; 9] = [NEW_AW; 9];
27static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
26 28
27pub struct Driver<'d, T: Instance> { 29pub struct Driver<'d, T: Instance> {
28 phantom: PhantomData<&'d mut T>, 30 phantom: PhantomData<&'d mut T>,
@@ -84,6 +86,8 @@ impl<'d, T: Instance> Driver<'d, T> {
84 regs.events_epdata.reset(); 86 regs.events_epdata.reset();
85 87
86 let r = regs.epdatastatus.read().bits(); 88 let r = regs.epdatastatus.read().bits();
89 regs.epdatastatus.write(|w| unsafe { w.bits(r) });
90 READY_ENDPOINTS.fetch_or(r, Ordering::AcqRel);
87 for i in 1..=7 { 91 for i in 1..=7 {
88 if r & (1 << i) != 0 { 92 if r & (1 << i) != 0 {
89 EP_IN_WAKERS[i].wake(); 93 EP_IN_WAKERS[i].wake();
@@ -143,15 +147,12 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
143 .alloc_in 147 .alloc_in
144 .allocate(ep_addr, ep_type, max_packet_size, interval)?; 148 .allocate(ep_addr, ep_type, max_packet_size, interval)?;
145 let ep_addr = EndpointAddress::from_parts(index, UsbDirection::In); 149 let ep_addr = EndpointAddress::from_parts(index, UsbDirection::In);
146 Ok(Endpoint { 150 Ok(Endpoint::new(EndpointInfo {
147 _phantom: PhantomData, 151 addr: ep_addr,
148 info: EndpointInfo { 152 ep_type,
149 addr: ep_addr, 153 max_packet_size,
150 ep_type, 154 interval,
151 max_packet_size, 155 }))
152 interval,
153 },
154 })
155 } 156 }
156 157
157 fn alloc_endpoint_out( 158 fn alloc_endpoint_out(
@@ -165,15 +166,12 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
165 .alloc_out 166 .alloc_out
166 .allocate(ep_addr, ep_type, max_packet_size, interval)?; 167 .allocate(ep_addr, ep_type, max_packet_size, interval)?;
167 let ep_addr = EndpointAddress::from_parts(index, UsbDirection::Out); 168 let ep_addr = EndpointAddress::from_parts(index, UsbDirection::Out);
168 Ok(Endpoint { 169 Ok(Endpoint::new(EndpointInfo {
169 _phantom: PhantomData, 170 addr: ep_addr,
170 info: EndpointInfo { 171 ep_type,
171 addr: ep_addr, 172 max_packet_size,
172 ep_type, 173 interval,
173 max_packet_size, 174 }))
174 interval,
175 },
176 })
177 } 175 }
178 176
179 fn enable(self) -> Self::Bus { 177 fn enable(self) -> Self::Bus {
@@ -284,7 +282,9 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
284 } 282 }
285 } 283 }
286 284
287 //self.busy_in_endpoints = 0; 285 // IN endpoints (low bits) default to ready.
286 // OUT endpoints (high bits) default to NOT ready, they become ready when data comes in.
287 READY_ENDPOINTS.store(0x0000FFFF, Ordering::Release);
288 } 288 }
289 289
290 #[inline] 290 #[inline]
@@ -324,6 +324,15 @@ pub struct Endpoint<'d, T: Instance, Dir> {
324 info: EndpointInfo, 324 info: EndpointInfo,
325} 325}
326 326
327impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> {
328 fn new(info: EndpointInfo) -> Self {
329 Self {
330 info,
331 _phantom: PhantomData,
332 }
333 }
334}
335
327impl<'d, T: Instance, Dir> driver::Endpoint for Endpoint<'d, T, Dir> { 336impl<'d, T: Instance, Dir> driver::Endpoint for Endpoint<'d, T, Dir> {
328 fn info(&self) -> &EndpointInfo { 337 fn info(&self) -> &EndpointInfo {
329 &self.info 338 &self.info
@@ -368,7 +377,6 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
368 } 377 }
369 }) 378 })
370 .await; 379 .await;
371 info!("got SETUP");
372 380
373 if buf.len() < 8 { 381 if buf.len() < 8 {
374 return Err(ReadError::BufferOverflow); 382 return Err(ReadError::BufferOverflow);
@@ -385,10 +393,10 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
385 393
386 Ok(8) 394 Ok(8)
387 } else { 395 } else {
396 // Wait until ready
388 poll_fn(|cx| { 397 poll_fn(|cx| {
389 EP_OUT_WAKERS[i].register(cx.waker()); 398 EP_OUT_WAKERS[i].register(cx.waker());
390 let regs = T::regs(); 399 let r = READY_ENDPOINTS.load(Ordering::Acquire);
391 let r = regs.epdatastatus.read().bits();
392 if r & (1 << (i + 16)) != 0 { 400 if r & (1 << (i + 16)) != 0 {
393 Poll::Ready(()) 401 Poll::Ready(())
394 } else { 402 } else {
@@ -397,9 +405,8 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
397 }) 405 })
398 .await; 406 .await;
399 407
400 // Clear status 408 // Mark as not ready
401 regs.epdatastatus 409 READY_ENDPOINTS.fetch_and(!(1 << (i + 16)), Ordering::AcqRel);
402 .write(|w| unsafe { w.bits(1 << (i + 16)) });
403 410
404 // Check that the packet fits into the buffer 411 // Check that the packet fits into the buffer
405 let size = regs.size.epout[i].read().bits(); 412 let size = regs.size.epout[i].read().bits();
@@ -448,48 +455,83 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
448 455
449 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { 456 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
450 async move { 457 async move {
451 info!("write: {:x}", buf);
452
453 let regs = T::regs(); 458 let regs = T::regs();
459 let i = self.info.addr.index();
454 460
455 let ptr = buf.as_ptr() as u32; 461 // Wait until ready.
456 let len = buf.len() as u32; 462 if i != 0 {
457 regs.epin0.ptr.write(|w| unsafe { w.bits(ptr) });
458 regs.epin0.maxcnt.write(|w| unsafe { w.bits(len) });
459
460 regs.events_ep0datadone.reset();
461 regs.events_endepin[0].reset();
462
463 dma_start();
464
465 regs.tasks_startepin[0].write(|w| unsafe { w.bits(1) });
466 info!("write: waiting for endepin...");
467 while regs.events_endepin[0].read().bits() == 0 {}
468
469 dma_end();
470
471 info!("write: waiting for ep0datadone...");
472 regs.intenset.write(|w| w.ep0datadone().set());
473 let res = with_timeout(
474 Duration::from_millis(10),
475 poll_fn(|cx| { 463 poll_fn(|cx| {
476 EP_IN_WAKERS[0].register(cx.waker()); 464 EP_IN_WAKERS[i].register(cx.waker());
477 let regs = T::regs(); 465 let r = READY_ENDPOINTS.load(Ordering::Acquire);
478 if regs.events_ep0datadone.read().bits() != 0 { 466 if r & (1 << i) != 0 {
479 Poll::Ready(()) 467 Poll::Ready(())
480 } else { 468 } else {
481 Poll::Pending 469 Poll::Pending
482 } 470 }
483 }), 471 })
484 ) 472 .await;
485 .await; 473
474 // Mark as not ready
475 READY_ENDPOINTS.fetch_and(!(1 << i), Ordering::AcqRel);
476 }
477
478 if i == 0 {
479 regs.events_ep0datadone.reset();
480 }
486 481
487 if res.is_err() { 482 assert!(buf.len() <= 64);
488 // todo wrong error 483
489 return Err(driver::WriteError::BufferOverflow); 484 // EasyDMA can't read FLASH, so we copy through RAM
485 let mut ram_buf: MaybeUninit<[u8; 64]> = MaybeUninit::uninit();
486 let ptr = ram_buf.as_mut_ptr() as *mut u8;
487 unsafe { core::ptr::copy_nonoverlapping(buf.as_ptr(), ptr, buf.len()) };
488
489 let epin = [
490 &regs.epin0,
491 &regs.epin1,
492 &regs.epin2,
493 &regs.epin3,
494 &regs.epin4,
495 &regs.epin5,
496 &regs.epin6,
497 &regs.epin7,
498 ];
499
500 // Set the buffer length so the right number of bytes are transmitted.
501 // Safety: `buf.len()` has been checked to be <= the max buffer length.
502 unsafe {
503 epin[i].ptr.write(|w| w.bits(ptr as u32));
504 epin[i].maxcnt.write(|w| w.maxcnt().bits(buf.len() as u8));
490 } 505 }
491 506
492 info!("write done"); 507 regs.events_endepin[i].reset();
508
509 dma_start();
510 regs.tasks_startepin[i].write(|w| unsafe { w.bits(1) });
511 while regs.events_endepin[i].read().bits() == 0 {}
512 dma_end();
513
514 if i == 0 {
515 regs.intenset.write(|w| w.ep0datadone().set());
516 let res = with_timeout(
517 Duration::from_millis(10),
518 poll_fn(|cx| {
519 EP_IN_WAKERS[0].register(cx.waker());
520 let regs = T::regs();
521 if regs.events_ep0datadone.read().bits() != 0 {
522 Poll::Ready(())
523 } else {
524 Poll::Pending
525 }
526 }),
527 )
528 .await;
529
530 if res.is_err() {
531 // todo wrong error
532 return Err(driver::WriteError::BufferOverflow);
533 }
534 }
493 535
494 Ok(()) 536 Ok(())
495 } 537 }
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index 33f3d4712..95f78804d 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -198,6 +198,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
198 } 198 }
199 199
200 fn control_reject(&mut self, req: Request) { 200 fn control_reject(&mut self, req: Request) {
201 info!("control reject");
201 self.control_out.set_stalled(true); 202 self.control_out.set_stalled(true);
202 } 203 }
203 204
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml
index fb846b3a9..59e5de026 100644
--- a/examples/nrf/Cargo.toml
+++ b/examples/nrf/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"] 2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018" 3edition = "2021"
4name = "embassy-nrf-examples" 4name = "embassy-nrf-examples"
5version = "0.1.0" 5version = "0.1.0"
6 6
diff --git a/examples/nrf/src/bin/usb/main.rs b/examples/nrf/src/bin/usb/main.rs
index d175766bb..014ad5c6e 100644
--- a/examples/nrf/src/bin/usb/main.rs
+++ b/examples/nrf/src/bin/usb/main.rs
@@ -10,13 +10,14 @@ mod cdc_acm;
10use core::mem; 10use core::mem;
11use defmt::*; 11use defmt::*;
12use embassy::executor::Spawner; 12use embassy::executor::Spawner;
13use embassy::time::{Duration, Timer};
13use embassy_nrf::interrupt; 14use embassy_nrf::interrupt;
14use embassy_nrf::pac; 15use embassy_nrf::pac;
15use embassy_nrf::usb::{self, Driver}; 16use embassy_nrf::usb::Driver;
16use embassy_nrf::Peripherals; 17use embassy_nrf::Peripherals;
17use embassy_usb::driver::EndpointOut; 18use embassy_usb::driver::{EndpointIn, EndpointOut};
18use embassy_usb::{Config, UsbDeviceBuilder}; 19use embassy_usb::{Config, UsbDeviceBuilder};
19use futures::future::{join, select}; 20use futures::future::join3;
20 21
21use crate::cdc_acm::CdcAcmClass; 22use crate::cdc_acm::CdcAcmClass;
22 23
@@ -61,6 +62,15 @@ async fn main(_spawner: Spawner, p: Peripherals) {
61 info!("data: {:x}", data); 62 info!("data: {:x}", data);
62 } 63 }
63 }; 64 };
65 let fut3 = async {
66 loop {
67 info!("writing...");
68 class.write_ep.write(b"Hello World!\r\n").await.unwrap();
69 info!("written");
70
71 Timer::after(Duration::from_secs(1)).await;
72 }
73 };
64 74
65 join(fut1, fut2).await; 75 join3(fut1, fut2, fut3).await;
66} 76}