1#![cfg_attr(not(test), no_std)]
2#![allow(async_fn_in_trait)]
3#![doc = include_str!("../README.md")]
4#![warn(missing_docs)]
5
6// This must go FIRST so that all the other modules see its macros.
7mod fmt;
8
9use core::cell::UnsafeCell;
10use core::future::poll_fn;
11use core::marker::PhantomData;
12use core::sync::atomic::{AtomicBool, AtomicU16, AtomicU32, Ordering};
13use core::task::Poll;
14
15use embassy_sync::waitqueue::AtomicWaker;
16use embassy_usb_driver::{
17 Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut,
18 EndpointType, Event, Unsupported,
19};
20
21use crate::fmt::Bytes;
22
23pub mod otg_v1;
24
25use otg_v1::{regs, vals, Otg};
26
27/// Handle interrupts.
28pub unsafe fn on_interrupt<const MAX_EP_COUNT: usize>(r: Otg, state: &State<MAX_EP_COUNT>, ep_count: usize) {
29 trace!("irq");
30
31 let ints = r.gintsts().read();
32 if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() {
33 // Mask interrupts and notify `Bus` to process them
34 r.gintmsk().write(|w| {
35 w.set_iepint(true);
36 w.set_oepint(true);
37 w.set_rxflvlm(true);
38 });
39 state.bus_waker.wake();
40 }
41
42 // Handle RX
43 while r.gintsts().read().rxflvl() {
44 let status = r.grxstsp().read();
45 trace!("=== status {:08x}", status.0);
46 let ep_num = status.epnum() as usize;
47 let len = status.bcnt() as usize;
48
49 assert!(ep_num < ep_count);
50
51 match status.pktstsd() {
52 vals::Pktstsd::SETUP_DATA_RX => {
53 trace!("SETUP_DATA_RX");
54 assert!(len == 8, "invalid SETUP packet length={}", len);
55 assert!(ep_num == 0, "invalid SETUP packet endpoint={}", ep_num);
56
57 // flushing TX if something stuck in control endpoint
58 if r.dieptsiz(ep_num).read().pktcnt() != 0 {
59 r.grstctl().modify(|w| {
60 w.set_txfnum(ep_num as _);
61 w.set_txfflsh(true);
62 });
63 while r.grstctl().read().txfflsh() {}
64 }
65
66 let data = &state.cp_state.setup_data;
67 data[0].store(r.fifo(0).read().data(), Ordering::Relaxed);
68 data[1].store(r.fifo(0).read().data(), Ordering::Relaxed);
69 }
70 vals::Pktstsd::OUT_DATA_RX => {
71 trace!("OUT_DATA_RX ep={} len={}", ep_num, len);
72
73 if state.ep_states[ep_num].out_size.load(Ordering::Acquire) == EP_OUT_BUFFER_EMPTY {
74 // SAFETY: Buffer size is allocated to be equal to endpoint's maximum packet size
75 // We trust the peripheral to not exceed its configured MPSIZ
76 let buf =
77 unsafe { core::slice::from_raw_parts_mut(*state.ep_states[ep_num].out_buffer.get(), len) };
78
79 for chunk in buf.chunks_mut(4) {
80 // RX FIFO is shared so always read from fifo(0)
81 let data = r.fifo(0).read().0;
82 chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]);
83 }
84
85 state.ep_states[ep_num].out_size.store(len as u16, Ordering::Release);
86 state.ep_states[ep_num].out_waker.wake();
87 } else {
88 error!("ep_out buffer overflow index={}", ep_num);
89
90 // discard FIFO data
91 let len_words = (len + 3) / 4;
92 for _ in 0..len_words {
93 r.fifo(0).read().data();
94 }
95 }
96 }
97 vals::Pktstsd::OUT_DATA_DONE => {
98 trace!("OUT_DATA_DONE ep={}", ep_num);
99 }
100 vals::Pktstsd::SETUP_DATA_DONE => {
101 trace!("SETUP_DATA_DONE ep={}", ep_num);
102 }
103 x => trace!("unknown PKTSTS: {}", x.to_bits()),
104 }
105 }
106
107 // IN endpoint interrupt
108 if ints.iepint() {
109 let mut ep_mask = r.daint().read().iepint();
110 let mut ep_num = 0;
111
112 // Iterate over endpoints while there are non-zero bits in the mask
113 while ep_mask != 0 {
114 if ep_mask & 1 != 0 {
115 let ep_ints = r.diepint(ep_num).read();
116
117 // clear all
118 r.diepint(ep_num).write_value(ep_ints);
119
120 // TXFE is cleared in DIEPEMPMSK
121 if ep_ints.txfe() {
122 critical_section::with(|_| {
123 r.diepempmsk().modify(|w| {
124 w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num));
125 });
126 });
127 }
128
129 state.ep_states[ep_num].in_waker.wake();
130 trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0);
131 }
132
133 ep_mask >>= 1;
134 ep_num += 1;
135 }
136 }
137
138 // out endpoint interrupt
139 if ints.oepint() {
140 trace!("oepint");
141 let mut ep_mask = r.daint().read().oepint();
142 let mut ep_num = 0;
143
144 // Iterate over endpoints while there are non-zero bits in the mask
145 while ep_mask != 0 {
146 if ep_mask & 1 != 0 {
147 let ep_ints = r.doepint(ep_num).read();
148 // clear all
149 r.doepint(ep_num).write_value(ep_ints);
150
151 if ep_ints.stup() {
152 state.cp_state.setup_ready.store(true, Ordering::Release);
153 }
154 state.ep_states[ep_num].out_waker.wake();
155 trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0);
156 }
157
158 ep_mask >>= 1;
159 ep_num += 1;
160 }
161 }
162}
163
164/// USB PHY type
165#[derive(Copy, Clone, Debug, Eq, PartialEq)]
166pub enum PhyType {
167 /// Internal Full-Speed PHY
168 ///
169 /// Available on most High-Speed peripherals.
170 InternalFullSpeed,
171 /// Internal High-Speed PHY
172 ///
173 /// Available on a few STM32 chips.
174 InternalHighSpeed,
175 /// External ULPI Full-Speed PHY (or High-Speed PHY in Full-Speed mode)
176 ExternalFullSpeed,
177 /// External ULPI High-Speed PHY
178 ExternalHighSpeed,
179}
180
181impl PhyType {
182 /// Get whether this PHY is any of the internal types.
183 pub fn internal(&self) -> bool {
184 match self {
185 PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true,
186 PhyType::ExternalHighSpeed | PhyType::ExternalFullSpeed => false,
187 }
188 }
189
190 /// Get whether this PHY is any of the high-speed types.
191 pub fn high_speed(&self) -> bool {
192 match self {
193 PhyType::InternalFullSpeed | PhyType::ExternalFullSpeed => false,
194 PhyType::ExternalHighSpeed | PhyType::InternalHighSpeed => true,
195 }
196 }
197
198 fn to_dspd(&self) -> vals::Dspd {
199 match self {
200 PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL,
201 PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED,
202 PhyType::ExternalFullSpeed => vals::Dspd::FULL_SPEED_EXTERNAL,
203 PhyType::ExternalHighSpeed => vals::Dspd::HIGH_SPEED,
204 }
205 }
206}
207
208/// Indicates that [State::ep_out_buffers] is empty.
209const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX;
210
211struct EpState {
212 in_waker: AtomicWaker,
213 out_waker: AtomicWaker,
214 /// RX FIFO is shared so extra buffers are needed to dequeue all data without waiting on each endpoint.
215 /// Buffers are ready when associated [State::ep_out_size] != [EP_OUT_BUFFER_EMPTY].
216 out_buffer: UnsafeCell<*mut u8>,
217 out_size: AtomicU16,
218}
219
220// SAFETY: The EndpointAllocator ensures that the buffer points to valid memory exclusive for each endpoint and is
221// large enough to hold the maximum packet size. Access to the buffer is synchronized between the USB interrupt and the
222// EndpointOut impl using the out_size atomic variable.
223unsafe impl Send for EpState {}
224unsafe impl Sync for EpState {}
225
226struct ControlPipeSetupState {
227 /// Holds received SETUP packets. Available if [Ep0State::setup_ready] is true.
228 setup_data: [AtomicU32; 2],
229 setup_ready: AtomicBool,
230}
231
232/// USB OTG driver state.
233pub struct State<const EP_COUNT: usize> {
234 cp_state: ControlPipeSetupState,
235 ep_states: [EpState; EP_COUNT],
236 bus_waker: AtomicWaker,
237}
238
239unsafe impl<const EP_COUNT: usize> Send for State<EP_COUNT> {}
240unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {}
241
242impl<const EP_COUNT: usize> State<EP_COUNT> {
243 /// Create a new State.
244 pub const fn new() -> Self {
245 Self {
246 cp_state: ControlPipeSetupState {
247 setup_data: [const { AtomicU32::new(0) }; 2],
248 setup_ready: AtomicBool::new(false),
249 },
250 ep_states: [const {
251 EpState {
252 in_waker: AtomicWaker::new(),
253 out_waker: AtomicWaker::new(),
254 out_buffer: UnsafeCell::new(0 as _),
255 out_size: AtomicU16::new(EP_OUT_BUFFER_EMPTY),
256 }
257 }; EP_COUNT],
258 bus_waker: AtomicWaker::new(),
259 }
260 }
261}
262
263#[derive(Debug, Clone, Copy)]
264struct EndpointData {
265 ep_type: EndpointType,
266 max_packet_size: u16,
267 fifo_size_words: u16,
268}
269
270/// USB driver config.
271#[non_exhaustive]
272#[derive(Clone, Copy, PartialEq, Eq, Debug)]
273pub struct Config {
274 /// Enable VBUS detection.
275 ///
276 /// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly.
277 /// This is done by checking whether there is 5V on the VBUS pin or not.
278 ///
279 /// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional.
280 /// (If there's no power in VBUS your device would be off anyway, so it's fine to always assume
281 /// there's power in VBUS, i.e. the USB cable is always plugged in.)
282 ///
283 /// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and
284 /// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true.
285 ///
286 /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a
287 /// voltage divider. See ST application note AN4879 and the reference manual for more details.
288 pub vbus_detection: bool,
289
290 /// Enable transceiver delay.
291 ///
292 /// Some ULPI PHYs like the Microchip USB334x series require a delay between the ULPI register write that initiates
293 /// the HS Chirp and the subsequent transmit command, otherwise the HS Chirp does not get executed and the deivce
294 /// enumerates in FS mode. Some USB Link IP like those in the STM32H7 series support adding this delay to work with
295 /// the affected PHYs.
296 pub xcvrdly: bool,
297}
298
299impl Default for Config {
300 fn default() -> Self {
301 Self {
302 vbus_detection: false,
303 xcvrdly: false,
304 }
305 }
306}
307
308/// USB OTG driver.
309pub struct Driver<'d, const MAX_EP_COUNT: usize> {
310 config: Config,
311 ep_in: [Option<EndpointData>; MAX_EP_COUNT],
312 ep_out: [Option<EndpointData>; MAX_EP_COUNT],
313 ep_out_buffer: &'d mut [u8],
314 ep_out_buffer_offset: usize,
315 instance: OtgInstance<'d, MAX_EP_COUNT>,
316}
317
318impl<'d, const MAX_EP_COUNT: usize> Driver<'d, MAX_EP_COUNT> {
319 /// Initializes the USB OTG peripheral.
320 ///
321 /// # Arguments
322 ///
323 /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
324 /// Must be large enough to fit all OUT endpoint max packet sizes.
325 /// Endpoint allocation will fail if it is too small.
326 /// * `instance` - The USB OTG peripheral instance and its configuration.
327 /// * `config` - The USB driver configuration.
328 pub fn new(ep_out_buffer: &'d mut [u8], instance: OtgInstance<'d, MAX_EP_COUNT>, config: Config) -> Self {
329 Self {
330 config,
331 ep_in: [None; MAX_EP_COUNT],
332 ep_out: [None; MAX_EP_COUNT],
333 ep_out_buffer,
334 ep_out_buffer_offset: 0,
335 instance,
336 }
337 }
338
339 /// Returns the total amount of words (u32) allocated in dedicated FIFO.
340 fn allocated_fifo_words(&self) -> u16 {
341 self.instance.extra_rx_fifo_words + ep_fifo_size(&self.ep_out) + ep_fifo_size(&self.ep_in)
342 }
343
344 /// Creates an [`Endpoint`] with the given parameters.
345 fn alloc_endpoint<D: Dir>(
346 &mut self,
347 ep_type: EndpointType,
348 max_packet_size: u16,
349 interval_ms: u8,
350 ) -> Result<Endpoint<'d, D>, EndpointAllocError> {
351 trace!(
352 "allocating type={:?} mps={:?} interval_ms={}, dir={:?}",
353 ep_type,
354 max_packet_size,
355 interval_ms,
356 D::dir()
357 );
358
359 if D::dir() == Direction::Out {
360 if self.ep_out_buffer_offset + max_packet_size as usize >= self.ep_out_buffer.len() {
361 error!("Not enough endpoint out buffer capacity");
362 return Err(EndpointAllocError);
363 }
364 };
365
366 let fifo_size_words = match D::dir() {
367 Direction::Out => (max_packet_size + 3) / 4,
368 // INEPTXFD requires minimum size of 16 words
369 Direction::In => u16::max((max_packet_size + 3) / 4, 16),
370 };
371
372 if fifo_size_words + self.allocated_fifo_words() > self.instance.fifo_depth_words {
373 error!("Not enough FIFO capacity");
374 return Err(EndpointAllocError);
375 }
376
377 let eps = match D::dir() {
378 Direction::Out => &mut self.ep_out[..self.instance.endpoint_count],
379 Direction::In => &mut self.ep_in[..self.instance.endpoint_count],
380 };
381
382 // Find free endpoint slot
383 let slot = eps.iter_mut().enumerate().find(|(i, ep)| {
384 if *i == 0 && ep_type != EndpointType::Control {
385 // reserved for control pipe
386 false
387 } else {
388 ep.is_none()
389 }
390 });
391
392 let index = match slot {
393 Some((index, ep)) => {
394 *ep = Some(EndpointData {
395 ep_type,
396 max_packet_size,
397 fifo_size_words,
398 });
399 index
400 }
401 None => {
402 error!("No free endpoints available");
403 return Err(EndpointAllocError);
404 }
405 };
406
407 trace!(" index={}", index);
408
409 let state = &self.instance.state.ep_states[index];
410 if D::dir() == Direction::Out {
411 // Buffer capacity check was done above, now allocation cannot fail
412 unsafe {
413 *state.out_buffer.get() = self.ep_out_buffer.as_mut_ptr().offset(self.ep_out_buffer_offset as _);
414 }
415 self.ep_out_buffer_offset += max_packet_size as usize;
416 }
417
418 Ok(Endpoint {
419 _phantom: PhantomData,
420 regs: self.instance.regs,
421 state,
422 info: EndpointInfo {
423 addr: EndpointAddress::from_parts(index, D::dir()),
424 ep_type,
425 max_packet_size,
426 interval_ms,
427 },
428 })
429 }
430}
431
432impl<'d, const MAX_EP_COUNT: usize> embassy_usb_driver::Driver<'d> for Driver<'d, MAX_EP_COUNT> {
433 type EndpointOut = Endpoint<'d, Out>;
434 type EndpointIn = Endpoint<'d, In>;
435 type ControlPipe = ControlPipe<'d>;
436 type Bus = Bus<'d, MAX_EP_COUNT>;
437
438 fn alloc_endpoint_in(
439 &mut self,
440 ep_type: EndpointType,
441 max_packet_size: u16,
442 interval_ms: u8,
443 ) -> Result<Self::EndpointIn, EndpointAllocError> {
444 self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
445 }
446
447 fn alloc_endpoint_out(
448 &mut self,
449 ep_type: EndpointType,
450 max_packet_size: u16,
451 interval_ms: u8,
452 ) -> Result<Self::EndpointOut, EndpointAllocError> {
453 self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
454 }
455
456 fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
457 let ep_out = self
458 .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0)
459 .unwrap();
460 let ep_in = self
461 .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0)
462 .unwrap();
463 assert_eq!(ep_out.info.addr.index(), 0);
464 assert_eq!(ep_in.info.addr.index(), 0);
465
466 trace!("start");
467
468 let regs = self.instance.regs;
469 let cp_setup_state = &self.instance.state.cp_state;
470 (
471 Bus {
472 config: self.config,
473 ep_in: self.ep_in,
474 ep_out: self.ep_out,
475 inited: false,
476 instance: self.instance,
477 },
478 ControlPipe {
479 max_packet_size: control_max_packet_size,
480 setup_state: cp_setup_state,
481 ep_out,
482 ep_in,
483 regs,
484 },
485 )
486 }
487}
488
489/// USB bus.
490pub struct Bus<'d, const MAX_EP_COUNT: usize> {
491 config: Config,
492 ep_in: [Option<EndpointData>; MAX_EP_COUNT],
493 ep_out: [Option<EndpointData>; MAX_EP_COUNT],
494 instance: OtgInstance<'d, MAX_EP_COUNT>,
495 inited: bool,
496}
497
498impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> {
499 fn restore_irqs(&mut self) {
500 self.instance.regs.gintmsk().write(|w| {
501 w.set_usbrst(true);
502 w.set_enumdnem(true);
503 w.set_usbsuspm(true);
504 w.set_wuim(true);
505 w.set_iepint(true);
506 w.set_oepint(true);
507 w.set_rxflvlm(true);
508 w.set_srqim(true);
509 w.set_otgint(true);
510 });
511 }
512
513 /// Returns the PHY type.
514 pub fn phy_type(&self) -> PhyType {
515 self.instance.phy_type
516 }
517
518 /// Configures the PHY as a device.
519 pub fn configure_as_device(&mut self) {
520 let r = self.instance.regs;
521 let phy_type = self.instance.phy_type;
522 r.gusbcfg().write(|w| {
523 // Force device mode
524 w.set_fdmod(true);
525 // Enable internal full-speed PHY
526 w.set_physel(phy_type.internal() && !phy_type.high_speed());
527 });
528 }
529
530 /// Applies configuration specific to
531 /// Core ID 0x0000_1100 and 0x0000_1200
532 pub fn config_v1(&mut self) {
533 let r = self.instance.regs;
534 let phy_type = self.instance.phy_type;
535 assert!(phy_type != PhyType::InternalHighSpeed);
536
537 r.gccfg_v1().modify(|w| {
538 // Enable internal full-speed PHY, logic is inverted
539 w.set_pwrdwn(phy_type.internal());
540 });
541
542 // F429-like chips have the GCCFG.NOVBUSSENS bit
543 r.gccfg_v1().modify(|w| {
544 w.set_novbussens(!self.config.vbus_detection);
545 w.set_vbusasen(false);
546 w.set_vbusbsen(self.config.vbus_detection);
547 w.set_sofouten(false);
548 });
549 }
550
551 /// Applies configuration specific to
552 /// Core ID 0x0000_2000, 0x0000_2100, 0x0000_2300, 0x0000_3000 and 0x0000_3100
553 pub fn config_v2v3(&mut self) {
554 let r = self.instance.regs;
555 let phy_type = self.instance.phy_type;
556
557 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
558 r.gccfg_v2().modify(|w| {
559 // Enable internal full-speed PHY, logic is inverted
560 w.set_pwrdwn(phy_type.internal() && !phy_type.high_speed());
561 w.set_phyhsen(phy_type.internal() && phy_type.high_speed());
562 });
563
564 r.gccfg_v2().modify(|w| {
565 w.set_vbden(self.config.vbus_detection);
566 });
567
568 // Force B-peripheral session
569 r.gotgctl().modify(|w| {
570 w.set_bvaloen(!self.config.vbus_detection);
571 w.set_bvaloval(true);
572 });
573 }
574
575 /// Applies configuration specific to
576 /// Core ID 0x0000_5000
577 pub fn config_v5(&mut self) {
578 let r = self.instance.regs;
579 let phy_type = self.instance.phy_type;
580
581 if phy_type == PhyType::InternalHighSpeed {
582 r.gccfg_v3().modify(|w| {
583 w.set_vbvaloven(!self.config.vbus_detection);
584 w.set_vbvaloval(!self.config.vbus_detection);
585 w.set_vbden(self.config.vbus_detection);
586 });
587 } else {
588 r.gotgctl().modify(|w| {
589 w.set_bvaloen(!self.config.vbus_detection);
590 w.set_bvaloval(!self.config.vbus_detection);
591 });
592 r.gccfg_v3().modify(|w| {
593 w.set_vbden(self.config.vbus_detection);
594 });
595 }
596 }
597
598 fn init(&mut self) {
599 let r = self.instance.regs;
600 let phy_type = self.instance.phy_type;
601
602 // Soft disconnect.
603 r.dctl().write(|w| w.set_sdis(true));
604
605 // Set speed.
606 r.dcfg().write(|w| {
607 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
608 w.set_dspd(phy_type.to_dspd());
609 if self.config.xcvrdly {
610 w.set_xcvrdly(true);
611 }
612 });
613
614 // Unmask transfer complete EP interrupt
615 r.diepmsk().write(|w| {
616 w.set_xfrcm(true);
617 });
618
619 // Unmask SETUP received EP interrupt
620 r.doepmsk().write(|w| {
621 w.set_stupm(true);
622 });
623
624 // Unmask and clear core interrupts
625 self.restore_irqs();
626 r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
627
628 // Unmask global interrupt
629 r.gahbcfg().write(|w| {
630 w.set_gint(true); // unmask global interrupt
631 });
632
633 // Connect
634 r.dctl().write(|w| w.set_sdis(false));
635 }
636
637 fn init_fifo(&mut self) {
638 trace!("init_fifo");
639
640 let regs = self.instance.regs;
641 // ERRATA NOTE: Don't interrupt FIFOs being written to. The interrupt
642 // handler COULD interrupt us here and do FIFO operations, so ensure
643 // the interrupt does not occur.
644 critical_section::with(|_| {
645 // Configure RX fifo size. All endpoints share the same FIFO area.
646 let rx_fifo_size_words = self.instance.extra_rx_fifo_words + ep_fifo_size(&self.ep_out);
647 trace!("configuring rx fifo size={}", rx_fifo_size_words);
648
649 regs.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
650
651 // Configure TX (USB in direction) fifo size for each endpoint
652 let mut fifo_top = rx_fifo_size_words;
653 for i in 0..self.instance.endpoint_count {
654 if let Some(ep) = self.ep_in[i] {
655 trace!(
656 "configuring tx fifo ep={}, offset={}, size={}",
657 i,
658 fifo_top,
659 ep.fifo_size_words
660 );
661
662 let dieptxf = if i == 0 { regs.dieptxf0() } else { regs.dieptxf(i - 1) };
663
664 dieptxf.write(|w| {
665 w.set_fd(ep.fifo_size_words);
666 w.set_sa(fifo_top);
667 });
668
669 fifo_top += ep.fifo_size_words;
670 }
671 }
672
673 assert!(
674 fifo_top <= self.instance.fifo_depth_words,
675 "FIFO allocations exceeded maximum capacity"
676 );
677
678 // Flush fifos
679 regs.grstctl().write(|w| {
680 w.set_rxfflsh(true);
681 w.set_txfflsh(true);
682 w.set_txfnum(0x10);
683 });
684 });
685
686 loop {
687 let x = regs.grstctl().read();
688 if !x.rxfflsh() && !x.txfflsh() {
689 break;
690 }
691 }
692 }
693
694 fn configure_endpoints(&mut self) {
695 trace!("configure_endpoints");
696
697 let regs = self.instance.regs;
698
699 // Configure IN endpoints
700 for (index, ep) in self.ep_in.iter().enumerate() {
701 if let Some(ep) = ep {
702 critical_section::with(|_| {
703 regs.diepctl(index).write(|w| {
704 if index == 0 {
705 w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
706 } else {
707 w.set_mpsiz(ep.max_packet_size);
708 w.set_eptyp(to_eptyp(ep.ep_type));
709 w.set_sd0pid_sevnfrm(true);
710 w.set_txfnum(index as _);
711 w.set_snak(true);
712 }
713 });
714 });
715 }
716 }
717
718 // Configure OUT endpoints
719 for (index, ep) in self.ep_out.iter().enumerate() {
720 if let Some(ep) = ep {
721 critical_section::with(|_| {
722 regs.doepctl(index).write(|w| {
723 if index == 0 {
724 w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
725 } else {
726 w.set_mpsiz(ep.max_packet_size);
727 w.set_eptyp(to_eptyp(ep.ep_type));
728 w.set_sd0pid_sevnfrm(true);
729 }
730 });
731
732 regs.doeptsiz(index).modify(|w| {
733 w.set_xfrsiz(ep.max_packet_size as _);
734 if index == 0 {
735 w.set_rxdpid_stupcnt(3);
736 } else {
737 w.set_pktcnt(1);
738 }
739 });
740 });
741 }
742 }
743
744 // Enable IRQs for allocated endpoints
745 regs.daintmsk().modify(|w| {
746 w.set_iepm(ep_irq_mask(&self.ep_in));
747 w.set_oepm(ep_irq_mask(&self.ep_out));
748 });
749 }
750
751 fn disable_all_endpoints(&mut self) {
752 for i in 0..self.instance.endpoint_count {
753 self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false);
754 self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false);
755 }
756 }
757}
758
759impl<'d, const MAX_EP_COUNT: usize> embassy_usb_driver::Bus for Bus<'d, MAX_EP_COUNT> {
760 async fn poll(&mut self) -> Event {
761 poll_fn(move |cx| {
762 if !self.inited {
763 self.init();
764 self.inited = true;
765
766 // If no vbus detection, just return a single PowerDetected event at startup.
767 if !self.config.vbus_detection {
768 return Poll::Ready(Event::PowerDetected);
769 }
770 }
771
772 let regs = self.instance.regs;
773 self.instance.state.bus_waker.register(cx.waker());
774
775 let ints = regs.gintsts().read();
776
777 if ints.srqint() {
778 trace!("vbus detected");
779
780 regs.gintsts().write(|w| w.set_srqint(true)); // clear
781 self.restore_irqs();
782
783 if self.config.vbus_detection {
784 return Poll::Ready(Event::PowerDetected);
785 }
786 }
787
788 if ints.otgint() {
789 let otgints = regs.gotgint().read();
790 regs.gotgint().write_value(otgints); // clear all
791 self.restore_irqs();
792
793 if otgints.sedet() {
794 trace!("vbus removed");
795 if self.config.vbus_detection {
796 self.disable_all_endpoints();
797 return Poll::Ready(Event::PowerRemoved);
798 }
799 }
800 }
801
802 if ints.usbrst() {
803 trace!("reset");
804
805 self.init_fifo();
806 self.configure_endpoints();
807
808 // Reset address
809 critical_section::with(|_| {
810 regs.dcfg().modify(|w| {
811 w.set_dad(0);
812 });
813 });
814
815 regs.gintsts().write(|w| w.set_usbrst(true)); // clear
816 self.restore_irqs();
817 }
818
819 if ints.enumdne() {
820 trace!("enumdne");
821
822 let speed = regs.dsts().read().enumspd();
823 let trdt = (self.instance.calculate_trdt_fn)(speed);
824 trace!(" speed={} trdt={}", speed.to_bits(), trdt);
825 regs.gusbcfg().modify(|w| w.set_trdt(trdt));
826
827 regs.gintsts().write(|w| w.set_enumdne(true)); // clear
828 self.restore_irqs();
829
830 return Poll::Ready(Event::Reset);
831 }
832
833 if ints.usbsusp() {
834 trace!("suspend");
835 regs.gintsts().write(|w| w.set_usbsusp(true)); // clear
836 self.restore_irqs();
837 return Poll::Ready(Event::Suspend);
838 }
839
840 if ints.wkupint() {
841 trace!("resume");
842 regs.gintsts().write(|w| w.set_wkupint(true)); // clear
843 self.restore_irqs();
844 return Poll::Ready(Event::Resume);
845 }
846
847 Poll::Pending
848 })
849 .await
850 }
851
852 fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
853 trace!("endpoint_set_stalled ep={:?} en={}", ep_addr, stalled);
854
855 assert!(
856 ep_addr.index() < self.instance.endpoint_count,
857 "endpoint_set_stalled index {} out of range",
858 ep_addr.index()
859 );
860
861 let regs = self.instance.regs;
862 let state = self.instance.state;
863 match ep_addr.direction() {
864 Direction::Out => {
865 critical_section::with(|_| {
866 regs.doepctl(ep_addr.index()).modify(|w| {
867 w.set_stall(stalled);
868 });
869 });
870
871 state.ep_states[ep_addr.index()].out_waker.wake();
872 }
873 Direction::In => {
874 critical_section::with(|_| {
875 regs.diepctl(ep_addr.index()).modify(|w| {
876 w.set_stall(stalled);
877 });
878 });
879
880 state.ep_states[ep_addr.index()].in_waker.wake();
881 }
882 }
883 }
884
885 fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
886 assert!(
887 ep_addr.index() < self.instance.endpoint_count,
888 "endpoint_is_stalled index {} out of range",
889 ep_addr.index()
890 );
891
892 let regs = self.instance.regs;
893 match ep_addr.direction() {
894 Direction::Out => regs.doepctl(ep_addr.index()).read().stall(),
895 Direction::In => regs.diepctl(ep_addr.index()).read().stall(),
896 }
897 }
898
899 fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
900 trace!("endpoint_set_enabled ep={:?} en={}", ep_addr, enabled);
901
902 assert!(
903 ep_addr.index() < self.instance.endpoint_count,
904 "endpoint_set_enabled index {} out of range",
905 ep_addr.index()
906 );
907
908 let regs = self.instance.regs;
909 let state = self.instance.state;
910 match ep_addr.direction() {
911 Direction::Out => {
912 critical_section::with(|_| {
913 // cancel transfer if active
914 if !enabled && regs.doepctl(ep_addr.index()).read().epena() {
915 regs.doepctl(ep_addr.index()).modify(|w| {
916 w.set_snak(true);
917 w.set_epdis(true);
918 })
919 }
920
921 regs.doepctl(ep_addr.index()).modify(|w| {
922 w.set_usbaep(enabled);
923 });
924
925 // Flush tx fifo
926 regs.grstctl().write(|w| {
927 w.set_txfflsh(true);
928 w.set_txfnum(ep_addr.index() as _);
929 });
930 loop {
931 let x = regs.grstctl().read();
932 if !x.txfflsh() {
933 break;
934 }
935 }
936 });
937
938 // Wake `Endpoint::wait_enabled()`
939 state.ep_states[ep_addr.index()].out_waker.wake();
940 }
941 Direction::In => {
942 critical_section::with(|_| {
943 // cancel transfer if active
944 if !enabled && regs.diepctl(ep_addr.index()).read().epena() {
945 regs.diepctl(ep_addr.index()).modify(|w| {
946 w.set_snak(true); // set NAK
947 w.set_epdis(true);
948 })
949 }
950
951 regs.diepctl(ep_addr.index()).modify(|w| {
952 w.set_usbaep(enabled);
953 w.set_cnak(enabled); // clear NAK that might've been set by SNAK above.
954 })
955 });
956
957 // Wake `Endpoint::wait_enabled()`
958 state.ep_states[ep_addr.index()].in_waker.wake();
959 }
960 }
961 }
962
963 async fn enable(&mut self) {
964 trace!("enable");
965 // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb
966 }
967
968 async fn disable(&mut self) {
969 trace!("disable");
970
971 // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb
972 //Bus::disable(self);
973 }
974
975 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
976 Err(Unsupported)
977 }
978}
979
980/// USB endpoint direction.
981trait Dir {
982 /// Returns the direction value.
983 fn dir() -> Direction;
984}
985
986/// Marker type for the "IN" direction.
987pub enum In {}
988impl Dir for In {
989 fn dir() -> Direction {
990 Direction::In
991 }
992}
993
994/// Marker type for the "OUT" direction.
995pub enum Out {}
996impl Dir for Out {
997 fn dir() -> Direction {
998 Direction::Out
999 }
1000}
1001
1002/// USB endpoint.
1003pub struct Endpoint<'d, D> {
1004 _phantom: PhantomData<D>,
1005 regs: Otg,
1006 info: EndpointInfo,
1007 state: &'d EpState,
1008}
1009
1010impl<'d> embassy_usb_driver::Endpoint for Endpoint<'d, In> {
1011 fn info(&self) -> &EndpointInfo {
1012 &self.info
1013 }
1014
1015 async fn wait_enabled(&mut self) {
1016 poll_fnPollFn) -> …>(|cx: &mut Context<'_>| {
1017 let ep_index: usize = self.info.addr.index();
1018
1019 self.state.in_waker.register(cx.waker());
1020
1021 if self.regs.diepctl(ep_index).read().usbaep() {
1022 Poll::Ready(())
1023 } else {
1024 Poll::Pending
1025 }
1026 })
1027 .await
1028 }
1029}
1030
1031impl<'d> embassy_usb_driver::Endpoint for Endpoint<'d, Out> {
1032 fn info(&self) -> &EndpointInfo {
1033 &self.info
1034 }
1035
1036 async fn wait_enabled(&mut self) {
1037 poll_fnPollFn) -> …>(|cx: &mut Context<'_>| {
1038 let ep_index: usize = self.info.addr.index();
1039
1040 self.state.out_waker.register(cx.waker());
1041
1042 if self.regs.doepctl(ep_index).read().usbaep() {
1043 Poll::Ready(())
1044 } else {
1045 Poll::Pending
1046 }
1047 })
1048 .await
1049 }
1050}
1051
1052impl<'d> embassy_usb_driver::EndpointOut for Endpoint<'d, Out> {
1053 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
1054 trace!("read start len={}", buf.len());
1055
1056 poll_fn(|cx| {
1057 let index = self.info.addr.index();
1058 self.state.out_waker.register(cx.waker());
1059
1060 let doepctl = self.regs.doepctl(index).read();
1061 trace!("read ep={:?}: doepctl {:08x}", self.info.addr, doepctl.0,);
1062 if !doepctl.usbaep() {
1063 trace!("read ep={:?} error disabled", self.info.addr);
1064 return Poll::Ready(Err(EndpointError::Disabled));
1065 }
1066
1067 let len = self.state.out_size.load(Ordering::Relaxed);
1068 if len != EP_OUT_BUFFER_EMPTY {
1069 trace!("read ep={:?} done len={}", self.info.addr, len);
1070
1071 if len as usize > buf.len() {
1072 return Poll::Ready(Err(EndpointError::BufferOverflow));
1073 }
1074
1075 // SAFETY: exclusive access ensured by `out_size` atomic variable
1076 let data = unsafe { core::slice::from_raw_parts(*self.state.out_buffer.get(), len as usize) };
1077 buf[..len as usize].copy_from_slice(data);
1078
1079 // Release buffer
1080 self.state.out_size.store(EP_OUT_BUFFER_EMPTY, Ordering::Release);
1081
1082 critical_section::with(|_| {
1083 // Receive 1 packet
1084 self.regs.doeptsiz(index).modify(|w| {
1085 w.set_xfrsiz(self.info.max_packet_size as _);
1086 w.set_pktcnt(1);
1087 });
1088
1089 if self.info.ep_type == EndpointType::Isochronous {
1090 // Isochronous endpoints must set the correct even/odd frame bit to
1091 // correspond with the next frame's number.
1092 let frame_number = self.regs.dsts().read().fnsof();
1093 let frame_is_odd = frame_number & 0x01 == 1;
1094
1095 self.regs.doepctl(index).modify(|r| {
1096 if frame_is_odd {
1097 r.set_sd0pid_sevnfrm(true);
1098 } else {
1099 r.set_sd1pid_soddfrm(true);
1100 }
1101 });
1102 }
1103
1104 // Clear NAK to indicate we are ready to receive more data
1105 self.regs.doepctl(index).modify(|w| {
1106 w.set_cnak(true);
1107 });
1108 });
1109
1110 Poll::Ready(Ok(len as usize))
1111 } else {
1112 Poll::Pending
1113 }
1114 })
1115 .await
1116 }
1117}
1118
1119impl<'d> embassy_usb_driver::EndpointIn for Endpoint<'d, In> {
1120 async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> {
1121 trace!("write ep={:?} data={:?}", self.info.addr, Bytes(buf));
1122
1123 if buf.len() > self.info.max_packet_size as usize {
1124 return Err(EndpointError::BufferOverflow);
1125 }
1126
1127 let index = self.info.addr.index();
1128 // Wait for previous transfer to complete and check if endpoint is disabled
1129 poll_fn(|cx| {
1130 self.state.in_waker.register(cx.waker());
1131
1132 let diepctl = self.regs.diepctl(index).read();
1133 let dtxfsts = self.regs.dtxfsts(index).read();
1134 trace!(
1135 "write ep={:?}: diepctl {:08x} ftxfsts {:08x}",
1136 self.info.addr,
1137 diepctl.0,
1138 dtxfsts.0
1139 );
1140 if !diepctl.usbaep() {
1141 trace!("write ep={:?} wait for prev: error disabled", self.info.addr);
1142 Poll::Ready(Err(EndpointError::Disabled))
1143 } else if !diepctl.epena() {
1144 trace!("write ep={:?} wait for prev: ready", self.info.addr);
1145 Poll::Ready(Ok(()))
1146 } else {
1147 trace!("write ep={:?} wait for prev: pending", self.info.addr);
1148 Poll::Pending
1149 }
1150 })
1151 .await?;
1152
1153 if buf.len() > 0 {
1154 poll_fn(|cx| {
1155 self.state.in_waker.register(cx.waker());
1156
1157 let size_words = (buf.len() + 3) / 4;
1158
1159 let fifo_space = self.regs.dtxfsts(index).read().ineptfsav() as usize;
1160 if size_words > fifo_space {
1161 // Not enough space in fifo, enable tx fifo empty interrupt
1162 critical_section::with(|_| {
1163 self.regs.diepempmsk().modify(|w| {
1164 w.set_ineptxfem(w.ineptxfem() | (1 << index));
1165 });
1166 });
1167
1168 trace!("tx fifo for ep={} full, waiting for txfe", index);
1169
1170 Poll::Pending
1171 } else {
1172 trace!("write ep={:?} wait for fifo: ready", self.info.addr);
1173 Poll::Ready(())
1174 }
1175 })
1176 .await
1177 }
1178
1179 // ERRATA: Transmit data FIFO is corrupted when a write sequence to the FIFO is interrupted with
1180 // accesses to certain OTG_FS registers.
1181 //
1182 // Prevent the interrupt (which might poke FIFOs) from executing while copying data to FIFOs.
1183 critical_section::with(|_| {
1184 // Setup transfer size
1185 self.regs.dieptsiz(index).write(|w| {
1186 w.set_mcnt(1);
1187 w.set_pktcnt(1);
1188 w.set_xfrsiz(buf.len() as _);
1189 });
1190
1191 if self.info.ep_type == EndpointType::Isochronous {
1192 // Isochronous endpoints must set the correct even/odd frame bit to
1193 // correspond with the next frame's number.
1194 let frame_number = self.regs.dsts().read().fnsof();
1195 let frame_is_odd = frame_number & 0x01 == 1;
1196
1197 self.regs.diepctl(index).modify(|r| {
1198 if frame_is_odd {
1199 r.set_sd0pid_sevnfrm(true);
1200 } else {
1201 r.set_sd1pid_soddfrm(true);
1202 }
1203 });
1204 }
1205
1206 // Enable endpoint
1207 self.regs.diepctl(index).modify(|w| {
1208 w.set_cnak(true);
1209 w.set_epena(true);
1210 });
1211
1212 // Write data to FIFO
1213 for chunk in buf.chunks(4) {
1214 let mut tmp = [0u8; 4];
1215 tmp[0..chunk.len()].copy_from_slice(chunk);
1216 self.regs.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp)));
1217 }
1218 });
1219
1220 trace!("write done ep={:?}", self.info.addr);
1221
1222 Ok(())
1223 }
1224}
1225
1226/// USB control pipe.
1227pub struct ControlPipe<'d> {
1228 max_packet_size: u16,
1229 regs: Otg,
1230 setup_state: &'d ControlPipeSetupState,
1231 ep_in: Endpoint<'d, In>,
1232 ep_out: Endpoint<'d, Out>,
1233}
1234
1235impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> {
1236 fn max_packet_size(&self) -> usize {
1237 usize::from(self.max_packet_size)
1238 }
1239
1240 async fn setup(&mut self) -> [u8; 8] {
1241 poll_fn(|cx| {
1242 self.ep_out.state.out_waker.register(cx.waker());
1243
1244 if self.setup_state.setup_ready.load(Ordering::Relaxed) {
1245 let mut data = [0; 8];
1246 data[0..4].copy_from_slice(&self.setup_state.setup_data[0].load(Ordering::Relaxed).to_ne_bytes());
1247 data[4..8].copy_from_slice(&self.setup_state.setup_data[1].load(Ordering::Relaxed).to_ne_bytes());
1248 self.setup_state.setup_ready.store(false, Ordering::Release);
1249
1250 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
1251 self.regs.doeptsiz(self.ep_out.info.addr.index()).modify(|w| {
1252 w.set_rxdpid_stupcnt(3);
1253 });
1254
1255 // Clear NAK to indicate we are ready to receive more data
1256 self.regs
1257 .doepctl(self.ep_out.info.addr.index())
1258 .modify(|w| w.set_cnak(true));
1259
1260 trace!("SETUP received: {:?}", Bytes(&data));
1261 Poll::Ready(data)
1262 } else {
1263 trace!("SETUP waiting");
1264 Poll::Pending
1265 }
1266 })
1267 .await
1268 }
1269
1270 async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result<usize, EndpointError> {
1271 trace!("control: data_out");
1272 let len = self.ep_out.read(buf).await?;
1273 trace!("control: data_out read: {:?}", Bytes(&buf[..len]));
1274 Ok(len)
1275 }
1276
1277 async fn data_in(&mut self, data: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> {
1278 trace!("control: data_in write: {:?}", Bytes(data));
1279 self.ep_in.write(data).await?;
1280
1281 // wait for status response from host after sending the last packet
1282 if last {
1283 trace!("control: data_in waiting for status");
1284 self.ep_out.read(&mut []).await?;
1285 trace!("control: complete");
1286 }
1287
1288 Ok(())
1289 }
1290
1291 async fn accept(&mut self) {
1292 trace!("control: accept");
1293
1294 self.ep_in.write(&[]).await.ok();
1295
1296 trace!("control: accept OK");
1297 }
1298
1299 async fn reject(&mut self) {
1300 trace!("control: reject");
1301
1302 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
1303 self.regs.diepctl(self.ep_in.info.addr.index()).modify(|w| {
1304 w.set_stall(true);
1305 });
1306 self.regs.doepctl(self.ep_out.info.addr.index()).modify(|w| {
1307 w.set_stall(true);
1308 });
1309 }
1310
1311 async fn accept_set_address(&mut self, addr: u8) {
1312 trace!("setting addr: {}", addr);
1313 critical_section::with(|_| {
1314 self.regs.dcfg().modify(|w| {
1315 w.set_dad(addr);
1316 });
1317 });
1318
1319 // synopsys driver requires accept to be sent after changing address
1320 self.accept().await
1321 }
1322}
1323
1324/// Translates HAL [EndpointType] into PAC [vals::Eptyp]
1325fn to_eptyp(ep_type: EndpointType) -> vals::Eptyp {
1326 match ep_type {
1327 EndpointType::Control => vals::Eptyp::CONTROL,
1328 EndpointType::Isochronous => vals::Eptyp::ISOCHRONOUS,
1329 EndpointType::Bulk => vals::Eptyp::BULK,
1330 EndpointType::Interrupt => vals::Eptyp::INTERRUPT,
1331 }
1332}
1333
1334/// Calculates total allocated FIFO size in words
1335fn ep_fifo_size(eps: &[Option<EndpointData>]) -> u16 {
1336 eps.iter().map(|ep: &Option| ep.map(|ep| ep.fifo_size_words).unwrap_or(default:0)).sum()
1337}
1338
1339/// Generates IRQ mask for enabled endpoints
1340fn ep_irq_mask(eps: &[Option<EndpointData>]) -> u16 {
1341 eps.iter().enumerate().fold(
1342 init:0,
1343 |mask: u16, (index: usize, ep: &Option)| {
1344 if ep.is_some() {
1345 mask | (1 << index)
1346 } else {
1347 mask
1348 }
1349 },
1350 )
1351}
1352
1353/// Calculates MPSIZ value for EP0, which uses special values.
1354fn ep0_mpsiz(max_packet_size: u16) -> u16 {
1355 match max_packet_size {
1356 8 => 0b11,
1357 16 => 0b10,
1358 32 => 0b01,
1359 64 => 0b00,
1360 other: u16 => panic!("Unsupported EP0 size: {}", other),
1361 }
1362}
1363
1364/// Hardware-dependent USB IP configuration.
1365pub struct OtgInstance<'d, const MAX_EP_COUNT: usize> {
1366 /// The USB peripheral.
1367 pub regs: Otg,
1368 /// The USB state.
1369 pub state: &'d State<MAX_EP_COUNT>,
1370 /// FIFO depth in words.
1371 pub fifo_depth_words: u16,
1372 /// Number of used endpoints.
1373 pub endpoint_count: usize,
1374 /// The PHY type.
1375 pub phy_type: PhyType,
1376 /// Extra RX FIFO words needed by some implementations.
1377 pub extra_rx_fifo_words: u16,
1378 /// Function to calculate TRDT value based on some internal clock speed.
1379 pub calculate_trdt_fn: fn(speed: vals::Dspd) -> u8,
1380}
1381