Skip to main content

embassy_usb_synopsys_otg/
lib.rs

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