diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-03-09 23:06:27 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-04-06 05:38:11 +0200 |
| commit | 77ceced036d574c7d67259b85e1d61b96e82d0d3 (patch) | |
| tree | 4f1a250f92d59922ae7ceda0779aae16cfa767bb /embassy-nrf/src | |
| parent | 37598a5b3792ec1b763b5c16fe422c9e1347d7d6 (diff) | |
Working CDC-ACM host->device
Diffstat (limited to 'embassy-nrf/src')
| -rw-r--r-- | embassy-nrf/src/usb.rs | 209 |
1 files changed, 176 insertions, 33 deletions
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs index 0f7d68d8c..163b2c794 100644 --- a/embassy-nrf/src/usb.rs +++ b/embassy-nrf/src/usb.rs | |||
| @@ -8,7 +8,7 @@ use embassy::time::{with_timeout, Duration}; | |||
| 8 | use embassy::util::Unborrow; | 8 | use embassy::util::Unborrow; |
| 9 | use embassy::waitqueue::AtomicWaker; | 9 | use embassy::waitqueue::AtomicWaker; |
| 10 | use embassy_hal_common::unborrow; | 10 | use embassy_hal_common::unborrow; |
| 11 | use embassy_usb::driver::{self, ReadError, WriteError}; | 11 | use embassy_usb::driver::{self, Event, ReadError, WriteError}; |
| 12 | use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; | 12 | use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; |
| 13 | use futures::future::poll_fn; | 13 | use futures::future::poll_fn; |
| 14 | use futures::Future; | 14 | use futures::Future; |
| @@ -19,7 +19,10 @@ pub use embassy_usb; | |||
| 19 | use crate::interrupt::Interrupt; | 19 | use crate::interrupt::Interrupt; |
| 20 | use crate::pac; | 20 | use crate::pac; |
| 21 | 21 | ||
| 22 | static EP0_WAKER: AtomicWaker = AtomicWaker::new(); | 22 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 23 | static BUS_WAKER: AtomicWaker = NEW_AW; | ||
| 24 | static EP_IN_WAKERS: [AtomicWaker; 9] = [NEW_AW; 9]; | ||
| 25 | static EP_OUT_WAKERS: [AtomicWaker; 9] = [NEW_AW; 9]; | ||
| 23 | 26 | ||
| 24 | pub struct Driver<'d, T: Instance> { | 27 | pub struct Driver<'d, T: Instance> { |
| 25 | phantom: PhantomData<&'d mut T>, | 28 | phantom: PhantomData<&'d mut T>, |
| @@ -47,13 +50,48 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 47 | fn on_interrupt(_: *mut ()) { | 50 | fn on_interrupt(_: *mut ()) { |
| 48 | let regs = T::regs(); | 51 | let regs = T::regs(); |
| 49 | 52 | ||
| 53 | if regs.events_usbreset.read().bits() != 0 { | ||
| 54 | regs.intenclr.write(|w| w.usbreset().clear()); | ||
| 55 | BUS_WAKER.wake(); | ||
| 56 | } | ||
| 57 | |||
| 50 | if regs.events_ep0setup.read().bits() != 0 { | 58 | if regs.events_ep0setup.read().bits() != 0 { |
| 51 | regs.intenclr.write(|w| w.ep0setup().clear()); | 59 | regs.intenclr.write(|w| w.ep0setup().clear()); |
| 52 | EP0_WAKER.wake(); | 60 | EP_OUT_WAKERS[0].wake(); |
| 53 | } | 61 | } |
| 62 | |||
| 54 | if regs.events_ep0datadone.read().bits() != 0 { | 63 | if regs.events_ep0datadone.read().bits() != 0 { |
| 55 | regs.intenclr.write(|w| w.ep0datadone().clear()); | 64 | regs.intenclr.write(|w| w.ep0datadone().clear()); |
| 56 | EP0_WAKER.wake(); | 65 | EP_IN_WAKERS[0].wake(); |
| 66 | } | ||
| 67 | |||
| 68 | // USBEVENT and EPDATA events are weird. They're the "aggregate" | ||
| 69 | // of individual bits in EVENTCAUSE and EPDATASTATUS. We handle them | ||
| 70 | // differently than events normally. | ||
| 71 | // | ||
| 72 | // They seem to be edge-triggered, not level-triggered: when an | ||
| 73 | // individual bit goes 0->1, the event fires *just once*. | ||
| 74 | // Therefore, it's fine to clear just the event, and let main thread | ||
| 75 | // check the individual bits in EVENTCAUSE and EPDATASTATUS. It | ||
| 76 | // doesn't cause an infinite irq loop. | ||
| 77 | if regs.events_usbevent.read().bits() != 0 { | ||
| 78 | regs.events_usbevent.reset(); | ||
| 79 | //regs.intenclr.write(|w| w.usbevent().clear()); | ||
| 80 | BUS_WAKER.wake(); | ||
| 81 | } | ||
| 82 | |||
| 83 | if regs.events_epdata.read().bits() != 0 { | ||
| 84 | regs.events_epdata.reset(); | ||
| 85 | |||
| 86 | let r = regs.epdatastatus.read().bits(); | ||
| 87 | for i in 1..=7 { | ||
| 88 | if r & (1 << i) != 0 { | ||
| 89 | EP_IN_WAKERS[i].wake(); | ||
| 90 | } | ||
| 91 | if r & (1 << (i + 16)) != 0 { | ||
| 92 | EP_OUT_WAKERS[i].wake(); | ||
| 93 | } | ||
| 94 | } | ||
| 57 | } | 95 | } |
| 58 | } | 96 | } |
| 59 | 97 | ||
| @@ -153,6 +191,12 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | |||
| 153 | 191 | ||
| 154 | unsafe { NVIC::unmask(pac::Interrupt::USBD) }; | 192 | unsafe { NVIC::unmask(pac::Interrupt::USBD) }; |
| 155 | 193 | ||
| 194 | regs.intenset.write(|w| { | ||
| 195 | w.usbreset().set_bit(); | ||
| 196 | w.usbevent().set_bit(); | ||
| 197 | w.epdata().set_bit(); | ||
| 198 | w | ||
| 199 | }); | ||
| 156 | // Enable the USB pullup, allowing enumeration. | 200 | // Enable the USB pullup, allowing enumeration. |
| 157 | regs.usbpullup.write(|w| w.connect().enabled()); | 201 | regs.usbpullup.write(|w| w.connect().enabled()); |
| 158 | info!("enabled"); | 202 | info!("enabled"); |
| @@ -172,6 +216,49 @@ pub struct Bus<'d, T: Instance> { | |||
| 172 | } | 216 | } |
| 173 | 217 | ||
| 174 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | 218 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { |
| 219 | type PollFuture<'a> | ||
| 220 | where | ||
| 221 | Self: 'a, | ||
| 222 | = impl Future<Output = Event> + 'a; | ||
| 223 | |||
| 224 | fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> { | ||
| 225 | poll_fn(|cx| { | ||
| 226 | BUS_WAKER.register(cx.waker()); | ||
| 227 | let regs = T::regs(); | ||
| 228 | |||
| 229 | if regs.events_usbreset.read().bits() != 0 { | ||
| 230 | regs.events_usbreset.reset(); | ||
| 231 | regs.intenset.write(|w| w.usbreset().set()); | ||
| 232 | return Poll::Ready(Event::Reset); | ||
| 233 | } | ||
| 234 | |||
| 235 | let r = regs.eventcause.read(); | ||
| 236 | |||
| 237 | if r.isooutcrc().bit() { | ||
| 238 | regs.eventcause.write(|w| w.isooutcrc().set_bit()); | ||
| 239 | info!("USB event: isooutcrc"); | ||
| 240 | } | ||
| 241 | if r.usbwuallowed().bit() { | ||
| 242 | regs.eventcause.write(|w| w.usbwuallowed().set_bit()); | ||
| 243 | info!("USB event: usbwuallowed"); | ||
| 244 | } | ||
| 245 | if r.suspend().bit() { | ||
| 246 | regs.eventcause.write(|w| w.suspend().set_bit()); | ||
| 247 | info!("USB event: suspend"); | ||
| 248 | } | ||
| 249 | if r.resume().bit() { | ||
| 250 | regs.eventcause.write(|w| w.resume().set_bit()); | ||
| 251 | info!("USB event: resume"); | ||
| 252 | } | ||
| 253 | if r.ready().bit() { | ||
| 254 | regs.eventcause.write(|w| w.ready().set_bit()); | ||
| 255 | info!("USB event: ready"); | ||
| 256 | } | ||
| 257 | |||
| 258 | Poll::Pending | ||
| 259 | }) | ||
| 260 | } | ||
| 261 | |||
| 175 | #[inline] | 262 | #[inline] |
| 176 | fn reset(&mut self) { | 263 | fn reset(&mut self) { |
| 177 | let regs = T::regs(); | 264 | let regs = T::regs(); |
| @@ -260,40 +347,95 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 260 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | 347 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { |
| 261 | async move { | 348 | async move { |
| 262 | let regs = T::regs(); | 349 | let regs = T::regs(); |
| 350 | let i = self.info.addr.index(); | ||
| 263 | 351 | ||
| 264 | if buf.len() == 0 { | 352 | if i == 0 { |
| 265 | regs.tasks_ep0status.write(|w| unsafe { w.bits(1) }); | 353 | if buf.len() == 0 { |
| 266 | return Ok(0); | 354 | regs.tasks_ep0status.write(|w| unsafe { w.bits(1) }); |
| 267 | } | 355 | return Ok(0); |
| 356 | } | ||
| 357 | |||
| 358 | // Wait for SETUP packet | ||
| 359 | regs.events_ep0setup.reset(); | ||
| 360 | regs.intenset.write(|w| w.ep0setup().set()); | ||
| 361 | poll_fn(|cx| { | ||
| 362 | EP_OUT_WAKERS[0].register(cx.waker()); | ||
| 363 | let regs = T::regs(); | ||
| 364 | if regs.events_ep0setup.read().bits() != 0 { | ||
| 365 | Poll::Ready(()) | ||
| 366 | } else { | ||
| 367 | Poll::Pending | ||
| 368 | } | ||
| 369 | }) | ||
| 370 | .await; | ||
| 371 | info!("got SETUP"); | ||
| 268 | 372 | ||
| 269 | // Wait for SETUP packet | 373 | if buf.len() < 8 { |
| 270 | regs.events_ep0setup.reset(); | 374 | return Err(ReadError::BufferOverflow); |
| 271 | regs.intenset.write(|w| w.ep0setup().set()); | ||
| 272 | poll_fn(|cx| { | ||
| 273 | EP0_WAKER.register(cx.waker()); | ||
| 274 | if regs.events_ep0setup.read().bits() != 0 { | ||
| 275 | Poll::Ready(()) | ||
| 276 | } else { | ||
| 277 | Poll::Pending | ||
| 278 | } | 375 | } |
| 279 | }) | ||
| 280 | .await; | ||
| 281 | info!("got SETUP"); | ||
| 282 | 376 | ||
| 283 | if buf.len() < 8 { | 377 | buf[0] = regs.bmrequesttype.read().bits() as u8; |
| 284 | return Err(ReadError::BufferOverflow); | 378 | buf[1] = regs.brequest.read().brequest().bits(); |
| 285 | } | 379 | buf[2] = regs.wvaluel.read().wvaluel().bits(); |
| 380 | buf[3] = regs.wvalueh.read().wvalueh().bits(); | ||
| 381 | buf[4] = regs.windexl.read().windexl().bits(); | ||
| 382 | buf[5] = regs.windexh.read().windexh().bits(); | ||
| 383 | buf[6] = regs.wlengthl.read().wlengthl().bits(); | ||
| 384 | buf[7] = regs.wlengthh.read().wlengthh().bits(); | ||
| 385 | |||
| 386 | Ok(8) | ||
| 387 | } else { | ||
| 388 | poll_fn(|cx| { | ||
| 389 | EP_OUT_WAKERS[i].register(cx.waker()); | ||
| 390 | let regs = T::regs(); | ||
| 391 | let r = regs.epdatastatus.read().bits(); | ||
| 392 | if r & (1 << (i + 16)) != 0 { | ||
| 393 | Poll::Ready(()) | ||
| 394 | } else { | ||
| 395 | Poll::Pending | ||
| 396 | } | ||
| 397 | }) | ||
| 398 | .await; | ||
| 286 | 399 | ||
| 287 | buf[0] = regs.bmrequesttype.read().bits() as u8; | 400 | // Clear status |
| 288 | buf[1] = regs.brequest.read().brequest().bits(); | 401 | regs.epdatastatus |
| 289 | buf[2] = regs.wvaluel.read().wvaluel().bits(); | 402 | .write(|w| unsafe { w.bits(1 << (i + 16)) }); |
| 290 | buf[3] = regs.wvalueh.read().wvalueh().bits(); | ||
| 291 | buf[4] = regs.windexl.read().windexl().bits(); | ||
| 292 | buf[5] = regs.windexh.read().windexh().bits(); | ||
| 293 | buf[6] = regs.wlengthl.read().wlengthl().bits(); | ||
| 294 | buf[7] = regs.wlengthh.read().wlengthh().bits(); | ||
| 295 | 403 | ||
| 296 | Ok(8) | 404 | // Check that the packet fits into the buffer |
| 405 | let size = regs.size.epout[i].read().bits(); | ||
| 406 | if size as usize > buf.len() { | ||
| 407 | return Err(ReadError::BufferOverflow); | ||
| 408 | } | ||
| 409 | |||
| 410 | let epout = [ | ||
| 411 | ®s.epout0, | ||
| 412 | ®s.epout1, | ||
| 413 | ®s.epout2, | ||
| 414 | ®s.epout3, | ||
| 415 | ®s.epout4, | ||
| 416 | ®s.epout5, | ||
| 417 | ®s.epout6, | ||
| 418 | ®s.epout7, | ||
| 419 | ]; | ||
| 420 | epout[i] | ||
| 421 | .ptr | ||
| 422 | .write(|w| unsafe { w.bits(buf.as_ptr() as u32) }); | ||
| 423 | // MAXCNT must match SIZE | ||
| 424 | epout[i].maxcnt.write(|w| unsafe { w.bits(size) }); | ||
| 425 | |||
| 426 | dma_start(); | ||
| 427 | regs.events_endepout[i].reset(); | ||
| 428 | regs.tasks_startepout[i].write(|w| w.tasks_startepout().set_bit()); | ||
| 429 | while regs.events_endepout[i] | ||
| 430 | .read() | ||
| 431 | .events_endepout() | ||
| 432 | .bit_is_clear() | ||
| 433 | {} | ||
| 434 | regs.events_endepout[i].reset(); | ||
| 435 | dma_end(); | ||
| 436 | |||
| 437 | Ok(size as usize) | ||
| 438 | } | ||
| 297 | } | 439 | } |
| 298 | } | 440 | } |
| 299 | } | 441 | } |
| @@ -331,7 +473,8 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 331 | let res = with_timeout( | 473 | let res = with_timeout( |
| 332 | Duration::from_millis(10), | 474 | Duration::from_millis(10), |
| 333 | poll_fn(|cx| { | 475 | poll_fn(|cx| { |
| 334 | EP0_WAKER.register(cx.waker()); | 476 | EP_IN_WAKERS[0].register(cx.waker()); |
| 477 | let regs = T::regs(); | ||
| 335 | if regs.events_ep0datadone.read().bits() != 0 { | 478 | if regs.events_ep0datadone.read().bits() != 0 { |
| 336 | Poll::Ready(()) | 479 | Poll::Ready(()) |
| 337 | } else { | 480 | } else { |
