From 91c42e0b9e118d88a51fecf07dc3f41b61c0762c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 26 Apr 2024 17:35:28 +0200 Subject: [PATCH] Extract synopsys otg driver --- embassy-stm32/Cargo.toml | 1 + embassy-stm32/src/usb/otg.rs | 1316 +------ embassy-usb-synopsys-otg/Cargo.toml | 13 + embassy-usb-synopsys-otg/README.md | 1 + embassy-usb-synopsys-otg/src/fmt.rs | 257 ++ embassy-usb-synopsys-otg/src/lib.rs | 1300 +++++++ embassy-usb-synopsys-otg/src/otg_v1.rs | 4482 ++++++++++++++++++++++++ 7 files changed, 6164 insertions(+), 1206 deletions(-) create mode 100644 embassy-usb-synopsys-otg/Cargo.toml create mode 100644 embassy-usb-synopsys-otg/README.md create mode 100644 embassy-usb-synopsys-otg/src/fmt.rs create mode 100644 embassy-usb-synopsys-otg/src/lib.rs create mode 100644 embassy-usb-synopsys-otg/src/otg_v1.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 095427171..da8978599 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -50,6 +50,7 @@ embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", fea embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } +embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" } embassy-executor = { version = "0.5.0", path = "../embassy-executor", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 29572d3c6..c59aae87f 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -1,22 +1,19 @@ -use core::cell::UnsafeCell; use core::marker::PhantomData; -use core::sync::atomic::{AtomicBool, AtomicU16, Ordering}; -use core::task::Poll; use embassy_hal_internal::{into_ref, Peripheral}; -use embassy_sync::waitqueue::AtomicWaker; -use embassy_usb_driver::{ - Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut, - EndpointType, Event, Unsupported, +use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported}; +use embassy_usb_synopsys_otg::otg_v1::vals::Dspd; +use embassy_usb_synopsys_otg::otg_v1::Otg; +pub use embassy_usb_synopsys_otg::Config; +use embassy_usb_synopsys_otg::{ + on_interrupt as on_interrupt_impl, Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out, + PhyType, State, MAX_EP_COUNT, }; -use futures::future::poll_fn; use crate::gpio::AFType; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; -use crate::pac::otg::{regs, vals}; use crate::rcc::{RccPeripheral, SealedRccPeripheral}; -use crate::time::Hertz; /// Interrupt handler. pub struct InterruptHandler { @@ -29,142 +26,9 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let state = T::state(); - let ints = r.gintsts().read(); - if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() { - // Mask interrupts and notify `Bus` to process them - r.gintmsk().write(|_| {}); - T::state().bus_waker.wake(); - } + let setup_late_cnak = quirk_setup_late_cnak(r); - // Handle RX - while r.gintsts().read().rxflvl() { - let status = r.grxstsp().read(); - trace!("=== status {:08x}", status.0); - let ep_num = status.epnum() as usize; - let len = status.bcnt() as usize; - - assert!(ep_num < T::ENDPOINT_COUNT); - - match status.pktstsd() { - vals::Pktstsd::SETUP_DATA_RX => { - trace!("SETUP_DATA_RX"); - assert!(len == 8, "invalid SETUP packet length={}", len); - assert!(ep_num == 0, "invalid SETUP packet endpoint={}", ep_num); - - // flushing TX if something stuck in control endpoint - if r.dieptsiz(ep_num).read().pktcnt() != 0 { - r.grstctl().modify(|w| { - w.set_txfnum(ep_num as _); - w.set_txfflsh(true); - }); - while r.grstctl().read().txfflsh() {} - } - - if state.ep0_setup_ready.load(Ordering::Relaxed) == false { - // SAFETY: exclusive access ensured by atomic bool - let data = unsafe { &mut *state.ep0_setup_data.get() }; - data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); - data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); - state.ep0_setup_ready.store(true, Ordering::Release); - state.ep_out_wakers[0].wake(); - } else { - error!("received SETUP before previous finished processing"); - // discard FIFO - r.fifo(0).read(); - r.fifo(0).read(); - } - } - vals::Pktstsd::OUT_DATA_RX => { - trace!("OUT_DATA_RX ep={} len={}", ep_num, len); - - if state.ep_out_size[ep_num].load(Ordering::Acquire) == EP_OUT_BUFFER_EMPTY { - // SAFETY: Buffer size is allocated to be equal to endpoint's maximum packet size - // We trust the peripheral to not exceed its configured MPSIZ - let buf = unsafe { core::slice::from_raw_parts_mut(*state.ep_out_buffers[ep_num].get(), len) }; - - for chunk in buf.chunks_mut(4) { - // RX FIFO is shared so always read from fifo(0) - let data = r.fifo(0).read().0; - chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]); - } - - state.ep_out_size[ep_num].store(len as u16, Ordering::Release); - state.ep_out_wakers[ep_num].wake(); - } else { - error!("ep_out buffer overflow index={}", ep_num); - - // discard FIFO data - let len_words = (len + 3) / 4; - for _ in 0..len_words { - r.fifo(0).read().data(); - } - } - } - vals::Pktstsd::OUT_DATA_DONE => { - trace!("OUT_DATA_DONE ep={}", ep_num); - } - vals::Pktstsd::SETUP_DATA_DONE => { - trace!("SETUP_DATA_DONE ep={}", ep_num); - - if quirk_setup_late_cnak(r) { - // Clear NAK to indicate we are ready to receive more data - r.doepctl(ep_num).modify(|w| w.set_cnak(true)); - } - } - x => trace!("unknown PKTSTS: {}", x.to_bits()), - } - } - - // IN endpoint interrupt - if ints.iepint() { - let mut ep_mask = r.daint().read().iepint(); - let mut ep_num = 0; - - // Iterate over endpoints while there are non-zero bits in the mask - while ep_mask != 0 { - if ep_mask & 1 != 0 { - let ep_ints = r.diepint(ep_num).read(); - - // clear all - r.diepint(ep_num).write_value(ep_ints); - - // TXFE is cleared in DIEPEMPMSK - if ep_ints.txfe() { - critical_section::with(|_| { - r.diepempmsk().modify(|w| { - w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num)); - }); - }); - } - - state.ep_in_wakers[ep_num].wake(); - trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0); - } - - ep_mask >>= 1; - ep_num += 1; - } - } - - // not needed? reception handled in rxflvl - // OUT endpoint interrupt - // if ints.oepint() { - // let mut ep_mask = r.daint().read().oepint(); - // let mut ep_num = 0; - - // while ep_mask != 0 { - // if ep_mask & 1 != 0 { - // let ep_ints = r.doepint(ep_num).read(); - // // clear all - // r.doepint(ep_num).write_value(ep_ints); - // state.ep_out_wakers[ep_num].wake(); - // trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0); - // } - - // ep_mask >>= 1; - // ep_num += 1; - // } - // } + on_interrupt_impl(r, state, T::ENDPOINT_COUNT, setup_late_cnak); } } @@ -187,129 +51,10 @@ macro_rules! config_ulpi_pins { // The following numbers are pessimistic and were figured out empirically. const RX_FIFO_EXTRA_SIZE_WORDS: u16 = 30; -/// USB PHY type -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum PhyType { - /// Internal Full-Speed PHY - /// - /// Available on most High-Speed peripherals. - InternalFullSpeed, - /// Internal High-Speed PHY - /// - /// Available on a few STM32 chips. - InternalHighSpeed, - /// External ULPI High-Speed PHY - ExternalHighSpeed, -} - -impl PhyType { - /// Get whether this PHY is any of the internal types. - pub fn internal(&self) -> bool { - match self { - PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, - PhyType::ExternalHighSpeed => false, - } - } - - /// Get whether this PHY is any of the high-speed types. - pub fn high_speed(&self) -> bool { - match self { - PhyType::InternalFullSpeed => false, - PhyType::ExternalHighSpeed | PhyType::InternalHighSpeed => true, - } - } - - fn to_dspd(&self) -> vals::Dspd { - match self { - PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, - PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, - PhyType::ExternalHighSpeed => vals::Dspd::HIGH_SPEED, - } - } -} - -/// Indicates that [State::ep_out_buffers] is empty. -const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; - -/// USB OTG driver state. -pub struct State { - /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. - ep0_setup_data: UnsafeCell<[u8; 8]>, - ep0_setup_ready: AtomicBool, - ep_in_wakers: [AtomicWaker; EP_COUNT], - ep_out_wakers: [AtomicWaker; EP_COUNT], - /// RX FIFO is shared so extra buffers are needed to dequeue all data without waiting on each endpoint. - /// Buffers are ready when associated [State::ep_out_size] != [EP_OUT_BUFFER_EMPTY]. - ep_out_buffers: [UnsafeCell<*mut u8>; EP_COUNT], - ep_out_size: [AtomicU16; EP_COUNT], - bus_waker: AtomicWaker, -} - -unsafe impl Send for State {} -unsafe impl Sync for State {} - -impl State { - /// Create a new State. - pub const fn new() -> Self { - const NEW_AW: AtomicWaker = AtomicWaker::new(); - const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); - const NEW_SIZE: AtomicU16 = AtomicU16::new(EP_OUT_BUFFER_EMPTY); - - Self { - ep0_setup_data: UnsafeCell::new([0u8; 8]), - ep0_setup_ready: AtomicBool::new(false), - ep_in_wakers: [NEW_AW; EP_COUNT], - ep_out_wakers: [NEW_AW; EP_COUNT], - ep_out_buffers: [NEW_BUF; EP_COUNT], - ep_out_size: [NEW_SIZE; EP_COUNT], - bus_waker: NEW_AW, - } - } -} - -#[derive(Debug, Clone, Copy)] -struct EndpointData { - ep_type: EndpointType, - max_packet_size: u16, - fifo_size_words: u16, -} - -/// USB driver config. -#[non_exhaustive] -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct Config { - /// Enable VBUS detection. - /// - /// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly. - /// This is done by checking whether there is 5V on the VBUS pin or not. - /// - /// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional. - /// (If there's no power in VBUS your device would be off anyway, so it's fine to always assume - /// there's power in VBUS, i.e. the USB cable is always plugged in.) - /// - /// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and - /// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true. - /// - /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a - /// voltage divider. See ST application note AN4879 and the reference manual for more details. - pub vbus_detection: bool, -} - -impl Default for Config { - fn default() -> Self { - Self { vbus_detection: true } - } -} - /// USB driver. pub struct Driver<'d, T: Instance> { - config: Config, phantom: PhantomData<&'d mut T>, - ep_in: [Option; MAX_EP_COUNT], - ep_out: [Option; MAX_EP_COUNT], - ep_out_buffer: &'d mut [u8], - ep_out_buffer_offset: usize, - phy_type: PhyType, + inner: OtgDriver<'d>, } impl<'d, T: Instance> Driver<'d, T> { @@ -333,14 +78,22 @@ impl<'d, T: Instance> Driver<'d, T> { dp.set_as_af(dp.af_num(), AFType::OutputPushPull); dm.set_as_af(dm.af_num(), AFType::OutputPushPull); - Self { - config, - phantom: PhantomData, - ep_in: [None; MAX_EP_COUNT], - ep_out: [None; MAX_EP_COUNT], - ep_out_buffer, - ep_out_buffer_offset: 0, + let regs = T::regs(); + + let instance = OtgInstance { + regs, + state: T::state(), + fifo_depth_words: T::FIFO_DEPTH_WORDS, + extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS, + endpoint_count: T::ENDPOINT_COUNT, phy_type: PhyType::InternalFullSpeed, + quirk_setup_late_cnak: quirk_setup_late_cnak(regs), + calculate_trdt_fn: calculate_trdt::, + }; + + Self { + inner: OtgDriver::new(ep_out_buffer, instance, config), + phantom: PhantomData, } } @@ -376,111 +129,30 @@ impl<'d, T: Instance> Driver<'d, T> { ulpi_d7 ); - Self { - config, - phantom: PhantomData, - ep_in: [None; MAX_EP_COUNT], - ep_out: [None; MAX_EP_COUNT], - ep_out_buffer, - ep_out_buffer_offset: 0, + let regs = T::regs(); + + let instance = OtgInstance { + regs: T::regs(), + state: T::state(), + fifo_depth_words: T::FIFO_DEPTH_WORDS, + extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS, + endpoint_count: T::ENDPOINT_COUNT, phy_type: PhyType::ExternalHighSpeed, + quirk_setup_late_cnak: quirk_setup_late_cnak(regs), + calculate_trdt_fn: calculate_trdt::, + }; + + Self { + inner: OtgDriver::new(ep_out_buffer, instance, config), + phantom: PhantomData, } } - - // Returns total amount of words (u32) allocated in dedicated FIFO - fn allocated_fifo_words(&self) -> u16 { - RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out) + ep_fifo_size(&self.ep_in) - } - - fn alloc_endpoint( - &mut self, - ep_type: EndpointType, - max_packet_size: u16, - interval_ms: u8, - ) -> Result, EndpointAllocError> { - trace!( - "allocating type={:?} mps={:?} interval_ms={}, dir={:?}", - ep_type, - max_packet_size, - interval_ms, - D::dir() - ); - - if D::dir() == Direction::Out { - if self.ep_out_buffer_offset + max_packet_size as usize >= self.ep_out_buffer.len() { - error!("Not enough endpoint out buffer capacity"); - return Err(EndpointAllocError); - } - }; - - let fifo_size_words = match D::dir() { - Direction::Out => (max_packet_size + 3) / 4, - // INEPTXFD requires minimum size of 16 words - Direction::In => u16::max((max_packet_size + 3) / 4, 16), - }; - - if fifo_size_words + self.allocated_fifo_words() > T::FIFO_DEPTH_WORDS { - error!("Not enough FIFO capacity"); - return Err(EndpointAllocError); - } - - let eps = match D::dir() { - Direction::Out => &mut self.ep_out, - Direction::In => &mut self.ep_in, - }; - - // Find free endpoint slot - let slot = eps.iter_mut().enumerate().find(|(i, ep)| { - if *i == 0 && ep_type != EndpointType::Control { - // reserved for control pipe - false - } else { - ep.is_none() - } - }); - - let index = match slot { - Some((index, ep)) => { - *ep = Some(EndpointData { - ep_type, - max_packet_size, - fifo_size_words, - }); - index - } - None => { - error!("No free endpoints available"); - return Err(EndpointAllocError); - } - }; - - trace!(" index={}", index); - - if D::dir() == Direction::Out { - // Buffer capacity check was done above, now allocation cannot fail - unsafe { - *T::state().ep_out_buffers[index].get() = - self.ep_out_buffer.as_mut_ptr().offset(self.ep_out_buffer_offset as _); - } - self.ep_out_buffer_offset += max_packet_size as usize; - } - - Ok(Endpoint { - _phantom: PhantomData, - info: EndpointInfo { - addr: EndpointAddress::from_parts(index, D::dir()), - ep_type, - max_packet_size, - interval_ms, - }, - }) - } } impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { - type EndpointOut = Endpoint<'d, T, Out>; - type EndpointIn = Endpoint<'d, T, In>; - type ControlPipe = ControlPipe<'d, T>; + type EndpointOut = Endpoint<'d, Out>; + type EndpointIn = Endpoint<'d, In>; + type ControlPipe = ControlPipe<'d>; type Bus = Bus<'d, T>; fn alloc_endpoint_in( @@ -489,7 +161,7 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { max_packet_size: u16, interval_ms: u8, ) -> Result { - self.alloc_endpoint(ep_type, max_packet_size, interval_ms) + self.inner.alloc_endpoint(ep_type, max_packet_size, interval_ms) } fn alloc_endpoint_out( @@ -498,72 +170,37 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { max_packet_size: u16, interval_ms: u8, ) -> Result { - self.alloc_endpoint(ep_type, max_packet_size, interval_ms) + self.inner.alloc_endpoint(ep_type, max_packet_size, interval_ms) } - fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { - let ep_out = self - .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) - .unwrap(); - let ep_in = self - .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) - .unwrap(); - assert_eq!(ep_out.info.addr.index(), 0); - assert_eq!(ep_in.info.addr.index(), 0); - - trace!("start"); + fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { + let (bus, cp) = self.inner.start(control_max_packet_size); ( Bus { - config: self.config, phantom: PhantomData, - ep_in: self.ep_in, - ep_out: self.ep_out, - phy_type: self.phy_type, + inner: bus, inited: false, }, - ControlPipe { - _phantom: PhantomData, - max_packet_size: control_max_packet_size, - ep_out, - ep_in, - }, + cp, ) } } /// USB bus. pub struct Bus<'d, T: Instance> { - config: Config, phantom: PhantomData<&'d mut T>, - ep_in: [Option; MAX_EP_COUNT], - ep_out: [Option; MAX_EP_COUNT], - phy_type: PhyType, + inner: OtgBus<'d>, inited: bool, } -impl<'d, T: Instance> Bus<'d, T> { - fn restore_irqs() { - T::regs().gintmsk().write(|w| { - w.set_usbrst(true); - w.set_enumdnem(true); - w.set_usbsuspm(true); - w.set_wuim(true); - w.set_iepint(true); - w.set_oepint(true); - w.set_rxflvlm(true); - w.set_srqim(true); - w.set_otgint(true); - }); - } -} - impl<'d, T: Instance> Bus<'d, T> { fn init(&mut self) { super::common_init::(); // Enable ULPI clock if external PHY is used - let _ulpien = !self.phy_type.internal(); + let phy_type = self.inner.phy_type(); + let _ulpien = !phy_type.internal(); #[cfg(any(stm32f2, stm32f4, stm32f7))] if T::HIGH_SPEED { @@ -594,200 +231,14 @@ impl<'d, T: Instance> Bus<'d, T> { while !r.grstctl().read().ahbidl() {} // Configure as device. - r.gusbcfg().write(|w| { - // Force device mode - w.set_fdmod(true); - // Enable internal full-speed PHY - w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed()); - }); + self.inner.configure_as_device(); // Configuring Vbus sense and SOF output match core_id { - 0x0000_1200 | 0x0000_1100 => { - assert!(self.phy_type != PhyType::InternalHighSpeed); - - r.gccfg_v1().modify(|w| { - // Enable internal full-speed PHY, logic is inverted - w.set_pwrdwn(self.phy_type.internal()); - }); - - // F429-like chips have the GCCFG.NOVBUSSENS bit - r.gccfg_v1().modify(|w| { - w.set_novbussens(!self.config.vbus_detection); - w.set_vbusasen(false); - w.set_vbusbsen(self.config.vbus_detection); - w.set_sofouten(false); - }); - } - 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => { - // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning - r.gccfg_v2().modify(|w| { - // Enable internal full-speed PHY, logic is inverted - w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed()); - w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed()); - }); - - r.gccfg_v2().modify(|w| { - w.set_vbden(self.config.vbus_detection); - }); - - // Force B-peripheral session - r.gotgctl().modify(|w| { - w.set_bvaloen(!self.config.vbus_detection); - w.set_bvaloval(true); - }); - } + 0x0000_1200 | 0x0000_1100 => self.inner.config_v1(), + 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(), _ => unimplemented!("Unknown USB core id {:X}", core_id), } - - // Soft disconnect. - r.dctl().write(|w| w.set_sdis(true)); - - // Set speed. - r.dcfg().write(|w| { - w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); - w.set_dspd(self.phy_type.to_dspd()); - }); - - // Unmask transfer complete EP interrupt - r.diepmsk().write(|w| { - w.set_xfrcm(true); - }); - - // Unmask and clear core interrupts - Bus::::restore_irqs(); - r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); - - // Unmask global interrupt - r.gahbcfg().write(|w| { - w.set_gint(true); // unmask global interrupt - }); - - // Connect - r.dctl().write(|w| w.set_sdis(false)); - } - - fn init_fifo(&mut self) { - trace!("init_fifo"); - - let r = T::regs(); - - // ERRATA NOTE: Don't interrupt FIFOs being written to. The interrupt - // handler COULD interrupt us here and do FIFO operations, so ensure - // the interrupt does not occur. - critical_section::with(|_| { - // Configure RX fifo size. All endpoints share the same FIFO area. - let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); - trace!("configuring rx fifo size={}", rx_fifo_size_words); - - r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)); - - // Configure TX (USB in direction) fifo size for each endpoint - let mut fifo_top = rx_fifo_size_words; - for i in 0..T::ENDPOINT_COUNT { - if let Some(ep) = self.ep_in[i] { - trace!( - "configuring tx fifo ep={}, offset={}, size={}", - i, - fifo_top, - ep.fifo_size_words - ); - - let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; - - dieptxf.write(|w| { - w.set_fd(ep.fifo_size_words); - w.set_sa(fifo_top); - }); - - fifo_top += ep.fifo_size_words; - } - } - - assert!( - fifo_top <= T::FIFO_DEPTH_WORDS, - "FIFO allocations exceeded maximum capacity" - ); - - // Flush fifos - r.grstctl().write(|w| { - w.set_rxfflsh(true); - w.set_txfflsh(true); - w.set_txfnum(0x10); - }); - }); - - loop { - let x = r.grstctl().read(); - if !x.rxfflsh() && !x.txfflsh() { - break; - } - } - } - - fn configure_endpoints(&mut self) { - trace!("configure_endpoints"); - - let r = T::regs(); - - // Configure IN endpoints - for (index, ep) in self.ep_in.iter().enumerate() { - if let Some(ep) = ep { - critical_section::with(|_| { - r.diepctl(index).write(|w| { - if index == 0 { - w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); - } else { - w.set_mpsiz(ep.max_packet_size); - w.set_eptyp(to_eptyp(ep.ep_type)); - w.set_sd0pid_sevnfrm(true); - w.set_txfnum(index as _); - w.set_snak(true); - } - }); - }); - } - } - - // Configure OUT endpoints - for (index, ep) in self.ep_out.iter().enumerate() { - if let Some(ep) = ep { - critical_section::with(|_| { - r.doepctl(index).write(|w| { - if index == 0 { - w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); - } else { - w.set_mpsiz(ep.max_packet_size); - w.set_eptyp(to_eptyp(ep.ep_type)); - w.set_sd0pid_sevnfrm(true); - } - }); - - r.doeptsiz(index).modify(|w| { - w.set_xfrsiz(ep.max_packet_size as _); - if index == 0 { - w.set_rxdpid_stupcnt(1); - } else { - w.set_pktcnt(1); - } - }); - }); - } - } - - // Enable IRQs for allocated endpoints - r.daintmsk().modify(|w| { - w.set_iepm(ep_irq_mask(&self.ep_in)); - // OUT interrupts not used, handled in RXFLVL - // w.set_oepm(ep_irq_mask(&self.ep_out)); - }); - } - - fn disable_all_endpoints(&mut self) { - for i in 0..T::ENDPOINT_COUNT { - self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false); - self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false); - } } fn disable(&mut self) { @@ -803,634 +254,52 @@ impl<'d, T: Instance> Bus<'d, T> { impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { async fn poll(&mut self) -> Event { - poll_fn(move |cx| { - if !self.inited { - self.init(); - self.inited = true; + if !self.inited { + self.init(); + self.inited = true; + } - // If no vbus detection, just return a single PowerDetected event at startup. - if !self.config.vbus_detection { - return Poll::Ready(Event::PowerDetected); - } - } - - let r = T::regs(); - - T::state().bus_waker.register(cx.waker()); - - let ints = r.gintsts().read(); - - if ints.srqint() { - trace!("vbus detected"); - - r.gintsts().write(|w| w.set_srqint(true)); // clear - Self::restore_irqs(); - - if self.config.vbus_detection { - return Poll::Ready(Event::PowerDetected); - } - } - - if ints.otgint() { - let otgints = r.gotgint().read(); - r.gotgint().write_value(otgints); // clear all - Self::restore_irqs(); - - if otgints.sedet() { - trace!("vbus removed"); - if self.config.vbus_detection { - self.disable_all_endpoints(); - return Poll::Ready(Event::PowerRemoved); - } - } - } - - if ints.usbrst() { - trace!("reset"); - - self.init_fifo(); - self.configure_endpoints(); - - // Reset address - critical_section::with(|_| { - r.dcfg().modify(|w| { - w.set_dad(0); - }); - }); - - r.gintsts().write(|w| w.set_usbrst(true)); // clear - Self::restore_irqs(); - } - - if ints.enumdne() { - trace!("enumdne"); - - let speed = r.dsts().read().enumspd(); - let trdt = calculate_trdt(speed, T::frequency()); - trace!(" speed={} trdt={}", speed.to_bits(), trdt); - r.gusbcfg().modify(|w| w.set_trdt(trdt)); - - r.gintsts().write(|w| w.set_enumdne(true)); // clear - Self::restore_irqs(); - - return Poll::Ready(Event::Reset); - } - - if ints.usbsusp() { - trace!("suspend"); - r.gintsts().write(|w| w.set_usbsusp(true)); // clear - Self::restore_irqs(); - return Poll::Ready(Event::Suspend); - } - - if ints.wkupint() { - trace!("resume"); - r.gintsts().write(|w| w.set_wkupint(true)); // clear - Self::restore_irqs(); - return Poll::Ready(Event::Resume); - } - - Poll::Pending - }) - .await + self.inner.poll().await } fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) { - trace!("endpoint_set_stalled ep={:?} en={}", ep_addr, stalled); - - assert!( - ep_addr.index() < T::ENDPOINT_COUNT, - "endpoint_set_stalled index {} out of range", - ep_addr.index() - ); - - let regs = T::regs(); - match ep_addr.direction() { - Direction::Out => { - critical_section::with(|_| { - regs.doepctl(ep_addr.index()).modify(|w| { - w.set_stall(stalled); - }); - }); - - T::state().ep_out_wakers[ep_addr.index()].wake(); - } - Direction::In => { - critical_section::with(|_| { - regs.diepctl(ep_addr.index()).modify(|w| { - w.set_stall(stalled); - }); - }); - - T::state().ep_in_wakers[ep_addr.index()].wake(); - } - } + self.inner.endpoint_set_stalled(ep_addr, stalled) } fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool { - assert!( - ep_addr.index() < T::ENDPOINT_COUNT, - "endpoint_is_stalled index {} out of range", - ep_addr.index() - ); - - let regs = T::regs(); - - match ep_addr.direction() { - Direction::Out => regs.doepctl(ep_addr.index()).read().stall(), - Direction::In => regs.diepctl(ep_addr.index()).read().stall(), - } + self.inner.endpoint_is_stalled(ep_addr) } fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) { - trace!("endpoint_set_enabled ep={:?} en={}", ep_addr, enabled); - - assert!( - ep_addr.index() < T::ENDPOINT_COUNT, - "endpoint_set_enabled index {} out of range", - ep_addr.index() - ); - - let r = T::regs(); - match ep_addr.direction() { - Direction::Out => { - critical_section::with(|_| { - // cancel transfer if active - if !enabled && r.doepctl(ep_addr.index()).read().epena() { - r.doepctl(ep_addr.index()).modify(|w| { - w.set_snak(true); - w.set_epdis(true); - }) - } - - r.doepctl(ep_addr.index()).modify(|w| { - w.set_usbaep(enabled); - }); - - // Flush tx fifo - r.grstctl().write(|w| { - w.set_txfflsh(true); - w.set_txfnum(ep_addr.index() as _); - }); - loop { - let x = r.grstctl().read(); - if !x.txfflsh() { - break; - } - } - }); - - // Wake `Endpoint::wait_enabled()` - T::state().ep_out_wakers[ep_addr.index()].wake(); - } - Direction::In => { - critical_section::with(|_| { - // cancel transfer if active - if !enabled && r.diepctl(ep_addr.index()).read().epena() { - r.diepctl(ep_addr.index()).modify(|w| { - w.set_snak(true); // set NAK - w.set_epdis(true); - }) - } - - r.diepctl(ep_addr.index()).modify(|w| { - w.set_usbaep(enabled); - w.set_cnak(enabled); // clear NAK that might've been set by SNAK above. - }) - }); - - // Wake `Endpoint::wait_enabled()` - T::state().ep_in_wakers[ep_addr.index()].wake(); - } - } + self.inner.endpoint_set_enabled(ep_addr, enabled) } async fn enable(&mut self) { - trace!("enable"); - // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb + self.inner.enable().await } async fn disable(&mut self) { - trace!("disable"); - - // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb - //Bus::disable(self); + Bus::disable(self); + // NOTE: inner call is a no-op + self.inner.disable().await } async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { - Err(Unsupported) + self.inner.remote_wakeup().await } } impl<'d, T: Instance> Drop for Bus<'d, T> { - fn drop(&mut self) { - Bus::disable(self); - } + fn drop(&mut self) {} } -trait Dir { - fn dir() -> Direction; -} - -/// Marker type for the "IN" direction. -pub enum In {} -impl Dir for In { - fn dir() -> Direction { - Direction::In - } -} - -/// Marker type for the "OUT" direction. -pub enum Out {} -impl Dir for Out { - fn dir() -> Direction { - Direction::Out - } -} - -/// USB endpoint. -pub struct Endpoint<'d, T: Instance, D> { - _phantom: PhantomData<(&'d mut T, D)>, - info: EndpointInfo, -} - -impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, In> { - fn info(&self) -> &EndpointInfo { - &self.info - } - - async fn wait_enabled(&mut self) { - poll_fn(|cx| { - let ep_index = self.info.addr.index(); - - T::state().ep_in_wakers[ep_index].register(cx.waker()); - - if T::regs().diepctl(ep_index).read().usbaep() { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await - } -} - -impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, Out> { - fn info(&self) -> &EndpointInfo { - &self.info - } - - async fn wait_enabled(&mut self) { - poll_fn(|cx| { - let ep_index = self.info.addr.index(); - - T::state().ep_out_wakers[ep_index].register(cx.waker()); - - if T::regs().doepctl(ep_index).read().usbaep() { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await - } -} - -impl<'d, T: Instance> embassy_usb_driver::EndpointOut for Endpoint<'d, T, Out> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - trace!("read start len={}", buf.len()); - - poll_fn(|cx| { - let r = T::regs(); - let index = self.info.addr.index(); - let state = T::state(); - - state.ep_out_wakers[index].register(cx.waker()); - - let doepctl = r.doepctl(index).read(); - trace!("read ep={:?}: doepctl {:08x}", self.info.addr, doepctl.0,); - if !doepctl.usbaep() { - trace!("read ep={:?} error disabled", self.info.addr); - return Poll::Ready(Err(EndpointError::Disabled)); - } - - let len = state.ep_out_size[index].load(Ordering::Relaxed); - if len != EP_OUT_BUFFER_EMPTY { - trace!("read ep={:?} done len={}", self.info.addr, len); - - if len as usize > buf.len() { - return Poll::Ready(Err(EndpointError::BufferOverflow)); - } - - // SAFETY: exclusive access ensured by `ep_out_size` atomic variable - let data = unsafe { core::slice::from_raw_parts(*state.ep_out_buffers[index].get(), len as usize) }; - buf[..len as usize].copy_from_slice(data); - - // Release buffer - state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release); - - critical_section::with(|_| { - // Receive 1 packet - T::regs().doeptsiz(index).modify(|w| { - w.set_xfrsiz(self.info.max_packet_size as _); - w.set_pktcnt(1); - }); - - // Clear NAK to indicate we are ready to receive more data - T::regs().doepctl(index).modify(|w| { - w.set_cnak(true); - }); - }); - - Poll::Ready(Ok(len as usize)) - } else { - Poll::Pending - } - }) - .await - } -} - -impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { - async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> { - trace!("write ep={:?} data={:?}", self.info.addr, buf); - - if buf.len() > self.info.max_packet_size as usize { - return Err(EndpointError::BufferOverflow); - } - - let r = T::regs(); - let index = self.info.addr.index(); - let state = T::state(); - - // Wait for previous transfer to complete and check if endpoint is disabled - poll_fn(|cx| { - state.ep_in_wakers[index].register(cx.waker()); - - let diepctl = r.diepctl(index).read(); - let dtxfsts = r.dtxfsts(index).read(); - trace!( - "write ep={:?}: diepctl {:08x} ftxfsts {:08x}", - self.info.addr, - diepctl.0, - dtxfsts.0 - ); - if !diepctl.usbaep() { - trace!("write ep={:?} wait for prev: error disabled", self.info.addr); - Poll::Ready(Err(EndpointError::Disabled)) - } else if !diepctl.epena() { - trace!("write ep={:?} wait for prev: ready", self.info.addr); - Poll::Ready(Ok(())) - } else { - trace!("write ep={:?} wait for prev: pending", self.info.addr); - Poll::Pending - } - }) - .await?; - - if buf.len() > 0 { - poll_fn(|cx| { - state.ep_in_wakers[index].register(cx.waker()); - - let size_words = (buf.len() + 3) / 4; - - let fifo_space = r.dtxfsts(index).read().ineptfsav() as usize; - if size_words > fifo_space { - // Not enough space in fifo, enable tx fifo empty interrupt - critical_section::with(|_| { - r.diepempmsk().modify(|w| { - w.set_ineptxfem(w.ineptxfem() | (1 << index)); - }); - }); - - trace!("tx fifo for ep={} full, waiting for txfe", index); - - Poll::Pending - } else { - trace!("write ep={:?} wait for fifo: ready", self.info.addr); - Poll::Ready(()) - } - }) - .await - } - - // ERRATA: Transmit data FIFO is corrupted when a write sequence to the FIFO is interrupted with - // accesses to certain OTG_FS registers. - // - // Prevent the interrupt (which might poke FIFOs) from executing while copying data to FIFOs. - critical_section::with(|_| { - // Setup transfer size - r.dieptsiz(index).write(|w| { - w.set_mcnt(1); - w.set_pktcnt(1); - w.set_xfrsiz(buf.len() as _); - }); - - // Enable endpoint - r.diepctl(index).modify(|w| { - w.set_cnak(true); - w.set_epena(true); - }); - - // Write data to FIFO - for chunk in buf.chunks(4) { - let mut tmp = [0u8; 4]; - tmp[0..chunk.len()].copy_from_slice(chunk); - r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))); - } - }); - - trace!("write done ep={:?}", self.info.addr); - - Ok(()) - } -} - -/// USB control pipe. -pub struct ControlPipe<'d, T: Instance> { - _phantom: PhantomData<&'d mut T>, - max_packet_size: u16, - ep_in: Endpoint<'d, T, In>, - ep_out: Endpoint<'d, T, Out>, -} - -impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> { - fn max_packet_size(&self) -> usize { - usize::from(self.max_packet_size) - } - - async fn setup(&mut self) -> [u8; 8] { - poll_fn(|cx| { - let state = T::state(); - - state.ep_out_wakers[0].register(cx.waker()); - - let r = T::regs(); - - if state.ep0_setup_ready.load(Ordering::Relaxed) { - let data = unsafe { *state.ep0_setup_data.get() }; - state.ep0_setup_ready.store(false, Ordering::Release); - - // EP0 should not be controlled by `Bus` so this RMW does not need a critical section - // Receive 1 SETUP packet - r.doeptsiz(self.ep_out.info.addr.index()).modify(|w| { - w.set_rxdpid_stupcnt(1); - }); - - // Clear NAK to indicate we are ready to receive more data - if !quirk_setup_late_cnak(r) { - r.doepctl(self.ep_out.info.addr.index()).modify(|w| w.set_cnak(true)); - } - - trace!("SETUP received: {:?}", data); - Poll::Ready(data) - } else { - trace!("SETUP waiting"); - Poll::Pending - } - }) - .await - } - - async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result { - trace!("control: data_out"); - let len = self.ep_out.read(buf).await?; - trace!("control: data_out read: {:?}", &buf[..len]); - Ok(len) - } - - async fn data_in(&mut self, data: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> { - trace!("control: data_in write: {:?}", data); - self.ep_in.write(data).await?; - - // wait for status response from host after sending the last packet - if last { - trace!("control: data_in waiting for status"); - self.ep_out.read(&mut []).await?; - trace!("control: complete"); - } - - Ok(()) - } - - async fn accept(&mut self) { - trace!("control: accept"); - - self.ep_in.write(&[]).await.ok(); - - trace!("control: accept OK"); - } - - async fn reject(&mut self) { - trace!("control: reject"); - - // EP0 should not be controlled by `Bus` so this RMW does not need a critical section - let regs = T::regs(); - regs.diepctl(self.ep_in.info.addr.index()).modify(|w| { - w.set_stall(true); - }); - regs.doepctl(self.ep_out.info.addr.index()).modify(|w| { - w.set_stall(true); - }); - } - - async fn accept_set_address(&mut self, addr: u8) { - trace!("setting addr: {}", addr); - critical_section::with(|_| { - T::regs().dcfg().modify(|w| { - w.set_dad(addr); - }); - }); - - // synopsys driver requires accept to be sent after changing address - self.accept().await - } -} - -/// Translates HAL [EndpointType] into PAC [vals::Eptyp] -fn to_eptyp(ep_type: EndpointType) -> vals::Eptyp { - match ep_type { - EndpointType::Control => vals::Eptyp::CONTROL, - EndpointType::Isochronous => vals::Eptyp::ISOCHRONOUS, - EndpointType::Bulk => vals::Eptyp::BULK, - EndpointType::Interrupt => vals::Eptyp::INTERRUPT, - } -} - -/// Calculates total allocated FIFO size in words -fn ep_fifo_size(eps: &[Option]) -> u16 { - eps.iter().map(|ep| ep.map(|ep| ep.fifo_size_words).unwrap_or(0)).sum() -} - -/// Generates IRQ mask for enabled endpoints -fn ep_irq_mask(eps: &[Option]) -> u16 { - eps.iter().enumerate().fold( - 0, - |mask, (index, ep)| { - if ep.is_some() { - mask | (1 << index) - } else { - mask - } - }, - ) -} - -/// Calculates MPSIZ value for EP0, which uses special values. -fn ep0_mpsiz(max_packet_size: u16) -> u16 { - match max_packet_size { - 8 => 0b11, - 16 => 0b10, - 32 => 0b01, - 64 => 0b00, - other => panic!("Unsupported EP0 size: {}", other), - } -} - -fn calculate_trdt(speed: vals::Dspd, ahb_freq: Hertz) -> u8 { - match speed { - vals::Dspd::HIGH_SPEED => { - // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446) - if ahb_freq.0 >= 30_000_000 { - 0x9 - } else { - panic!("AHB frequency is too low") - } - } - vals::Dspd::FULL_SPEED_EXTERNAL | vals::Dspd::FULL_SPEED_INTERNAL => { - // From RM0431 (F72xx), RM0090 (F429) - match ahb_freq.0 { - 0..=14_199_999 => panic!("AHB frequency is too low"), - 14_200_000..=14_999_999 => 0xF, - 15_000_000..=15_999_999 => 0xE, - 16_000_000..=17_199_999 => 0xD, - 17_200_000..=18_499_999 => 0xC, - 18_500_000..=19_999_999 => 0xB, - 20_000_000..=21_799_999 => 0xA, - 21_800_000..=23_999_999 => 0x9, - 24_000_000..=27_499_999 => 0x8, - 27_500_000..=31_999_999 => 0x7, // 27.7..32 in code from CubeIDE - 32_000_000..=u32::MAX => 0x6, - } - } - _ => unimplemented!(), - } -} - -fn quirk_setup_late_cnak(r: crate::pac::otg::Otg) -> bool { - r.cid().read().0 & 0xf000 == 0x1000 -} - -// Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps -const MAX_EP_COUNT: usize = 9; - trait SealedInstance { const HIGH_SPEED: bool; const FIFO_DEPTH_WORDS: u16; const ENDPOINT_COUNT: usize; - fn regs() -> crate::pac::otg::Otg; - fn state() -> &'static super::State<{ MAX_EP_COUNT }>; + fn regs() -> Otg; + fn state() -> &'static State<{ MAX_EP_COUNT }>; } /// USB instance trait. @@ -1509,8 +378,8 @@ foreach_interrupt!( } } - fn regs() -> crate::pac::otg::Otg { - crate::pac::USB_OTG_FS + fn regs() -> Otg { + unsafe { Otg::from_ptr(crate::pac::USB_OTG_FS.as_ptr()) } } fn state() -> &'static State { @@ -1559,9 +428,9 @@ foreach_interrupt!( } } - fn regs() -> crate::pac::otg::Otg { + fn regs() -> Otg { // OTG HS registers are a superset of FS registers - unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) } + unsafe { Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) } } fn state() -> &'static State { @@ -1575,3 +444,38 @@ foreach_interrupt!( } }; ); + +fn calculate_trdt(speed: Dspd) -> u8 { + let ahb_freq = T::frequency().0; + match speed { + Dspd::HIGH_SPEED => { + // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446) + if ahb_freq >= 30_000_000 { + 0x9 + } else { + panic!("AHB frequency is too low") + } + } + Dspd::FULL_SPEED_EXTERNAL | Dspd::FULL_SPEED_INTERNAL => { + // From RM0431 (F72xx), RM0090 (F429) + match ahb_freq { + 0..=14_199_999 => panic!("AHB frequency is too low"), + 14_200_000..=14_999_999 => 0xF, + 15_000_000..=15_999_999 => 0xE, + 16_000_000..=17_199_999 => 0xD, + 17_200_000..=18_499_999 => 0xC, + 18_500_000..=19_999_999 => 0xB, + 20_000_000..=21_799_999 => 0xA, + 21_800_000..=23_999_999 => 0x9, + 24_000_000..=27_499_999 => 0x8, + 27_500_000..=31_999_999 => 0x7, // 27.7..32 in code from CubeIDE + 32_000_000..=u32::MAX => 0x6, + } + } + _ => unimplemented!(), + } +} + +fn quirk_setup_late_cnak(r: Otg) -> bool { + r.cid().read().0 & 0xf000 == 0x1000 +} diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml new file mode 100644 index 000000000..5693acc38 --- /dev/null +++ b/embassy-usb-synopsys-otg/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "embassy-usb-synopsys-otg" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +critical-section = "1.1" +futures = { version = "0.3.17", default-features = false } + +embassy-sync = { version = "0.5.0", path = "../embassy-sync" } +embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } diff --git a/embassy-usb-synopsys-otg/README.md b/embassy-usb-synopsys-otg/README.md new file mode 100644 index 000000000..c3f914896 --- /dev/null +++ b/embassy-usb-synopsys-otg/README.md @@ -0,0 +1 @@ +# Embassy USB driver for the Synopsys OTG core diff --git a/embassy-usb-synopsys-otg/src/fmt.rs b/embassy-usb-synopsys-otg/src/fmt.rs new file mode 100644 index 000000000..2ac42c557 --- /dev/null +++ b/embassy-usb-synopsys-otg/src/fmt.rs @@ -0,0 +1,257 @@ +#![macro_use] +#![allow(unused)] + +use core::fmt::{Debug, Display, LowerHex}; + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unreachable { + ($($x:tt)*) => { + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) + }; +} + +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::trace!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::debug!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::info!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::warn!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::error!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} + +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs new file mode 100644 index 000000000..6d6cc9b0f --- /dev/null +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -0,0 +1,1300 @@ +#![cfg_attr(not(test), no_std)] +#![allow(async_fn_in_trait)] +#![doc = include_str!("../README.md")] +#![warn(missing_docs)] + +// This must go FIRST so that all the other modules see its macros. +mod fmt; + +use core::cell::UnsafeCell; +use core::marker::PhantomData; +use core::sync::atomic::{AtomicBool, AtomicU16, Ordering}; +use core::task::Poll; + +use embassy_sync::waitqueue::AtomicWaker; +use embassy_usb_driver::{ + Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut, + EndpointType, Event, Unsupported, +}; +use futures::future::poll_fn; + +pub mod otg_v1; + +use otg_v1::{regs, vals, Otg}; + +/// Handle interrupts. +pub unsafe fn on_interrupt(r: Otg, state: &State<{ MAX_EP_COUNT }>, ep_count: usize, quirk_setup_late_cnak: bool) { + let ints = r.gintsts().read(); + if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() { + // Mask interrupts and notify `Bus` to process them + r.gintmsk().write(|_| {}); + state.bus_waker.wake(); + } + + // Handle RX + while r.gintsts().read().rxflvl() { + let status = r.grxstsp().read(); + trace!("=== status {:08x}", status.0); + let ep_num = status.epnum() as usize; + let len = status.bcnt() as usize; + + assert!(ep_num < ep_count); + + match status.pktstsd() { + vals::Pktstsd::SETUP_DATA_RX => { + trace!("SETUP_DATA_RX"); + assert!(len == 8, "invalid SETUP packet length={}", len); + assert!(ep_num == 0, "invalid SETUP packet endpoint={}", ep_num); + + // flushing TX if something stuck in control endpoint + if r.dieptsiz(ep_num).read().pktcnt() != 0 { + r.grstctl().modify(|w| { + w.set_txfnum(ep_num as _); + w.set_txfflsh(true); + }); + while r.grstctl().read().txfflsh() {} + } + + if state.ep0_setup_ready.load(Ordering::Relaxed) == false { + // SAFETY: exclusive access ensured by atomic bool + let data = unsafe { &mut *state.ep0_setup_data.get() }; + data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); + data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); + state.ep0_setup_ready.store(true, Ordering::Release); + state.ep_out_wakers[0].wake(); + } else { + error!("received SETUP before previous finished processing"); + // discard FIFO + r.fifo(0).read(); + r.fifo(0).read(); + } + } + vals::Pktstsd::OUT_DATA_RX => { + trace!("OUT_DATA_RX ep={} len={}", ep_num, len); + + if state.ep_out_size[ep_num].load(Ordering::Acquire) == EP_OUT_BUFFER_EMPTY { + // SAFETY: Buffer size is allocated to be equal to endpoint's maximum packet size + // We trust the peripheral to not exceed its configured MPSIZ + let buf = unsafe { core::slice::from_raw_parts_mut(*state.ep_out_buffers[ep_num].get(), len) }; + + for chunk in buf.chunks_mut(4) { + // RX FIFO is shared so always read from fifo(0) + let data = r.fifo(0).read().0; + chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]); + } + + state.ep_out_size[ep_num].store(len as u16, Ordering::Release); + state.ep_out_wakers[ep_num].wake(); + } else { + error!("ep_out buffer overflow index={}", ep_num); + + // discard FIFO data + let len_words = (len + 3) / 4; + for _ in 0..len_words { + r.fifo(0).read().data(); + } + } + } + vals::Pktstsd::OUT_DATA_DONE => { + trace!("OUT_DATA_DONE ep={}", ep_num); + } + vals::Pktstsd::SETUP_DATA_DONE => { + trace!("SETUP_DATA_DONE ep={}", ep_num); + + if quirk_setup_late_cnak { + // Clear NAK to indicate we are ready to receive more data + r.doepctl(ep_num).modify(|w| w.set_cnak(true)); + } + } + x => trace!("unknown PKTSTS: {}", x.to_bits()), + } + } + + // IN endpoint interrupt + if ints.iepint() { + let mut ep_mask = r.daint().read().iepint(); + let mut ep_num = 0; + + // Iterate over endpoints while there are non-zero bits in the mask + while ep_mask != 0 { + if ep_mask & 1 != 0 { + let ep_ints = r.diepint(ep_num).read(); + + // clear all + r.diepint(ep_num).write_value(ep_ints); + + // TXFE is cleared in DIEPEMPMSK + if ep_ints.txfe() { + critical_section::with(|_| { + r.diepempmsk().modify(|w| { + w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num)); + }); + }); + } + + state.ep_in_wakers[ep_num].wake(); + trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0); + } + + ep_mask >>= 1; + ep_num += 1; + } + } + + // not needed? reception handled in rxflvl + // OUT endpoint interrupt + // if ints.oepint() { + // let mut ep_mask = r.daint().read().oepint(); + // let mut ep_num = 0; + + // while ep_mask != 0 { + // if ep_mask & 1 != 0 { + // let ep_ints = r.doepint(ep_num).read(); + // // clear all + // r.doepint(ep_num).write_value(ep_ints); + // state.ep_out_wakers[ep_num].wake(); + // trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0); + // } + + // ep_mask >>= 1; + // ep_num += 1; + // } + // } +} + +/// USB PHY type +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum PhyType { + /// Internal Full-Speed PHY + /// + /// Available on most High-Speed peripherals. + InternalFullSpeed, + /// Internal High-Speed PHY + /// + /// Available on a few STM32 chips. + InternalHighSpeed, + /// External ULPI High-Speed PHY + ExternalHighSpeed, +} + +impl PhyType { + /// Get whether this PHY is any of the internal types. + pub fn internal(&self) -> bool { + match self { + PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, + PhyType::ExternalHighSpeed => false, + } + } + + /// Get whether this PHY is any of the high-speed types. + pub fn high_speed(&self) -> bool { + match self { + PhyType::InternalFullSpeed => false, + PhyType::ExternalHighSpeed | PhyType::InternalHighSpeed => true, + } + } + + fn to_dspd(&self) -> vals::Dspd { + match self { + PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, + PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, + PhyType::ExternalHighSpeed => vals::Dspd::HIGH_SPEED, + } + } +} + +/// Indicates that [State::ep_out_buffers] is empty. +const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; + +/// USB OTG driver state. +pub struct State { + /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. + ep0_setup_data: UnsafeCell<[u8; 8]>, + ep0_setup_ready: AtomicBool, + ep_in_wakers: [AtomicWaker; EP_COUNT], + ep_out_wakers: [AtomicWaker; EP_COUNT], + /// RX FIFO is shared so extra buffers are needed to dequeue all data without waiting on each endpoint. + /// Buffers are ready when associated [State::ep_out_size] != [EP_OUT_BUFFER_EMPTY]. + ep_out_buffers: [UnsafeCell<*mut u8>; EP_COUNT], + ep_out_size: [AtomicU16; EP_COUNT], + bus_waker: AtomicWaker, +} + +unsafe impl Send for State {} +unsafe impl Sync for State {} + +impl State { + /// Create a new State. + pub const fn new() -> Self { + const NEW_AW: AtomicWaker = AtomicWaker::new(); + const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); + const NEW_SIZE: AtomicU16 = AtomicU16::new(EP_OUT_BUFFER_EMPTY); + + Self { + ep0_setup_data: UnsafeCell::new([0u8; 8]), + ep0_setup_ready: AtomicBool::new(false), + ep_in_wakers: [NEW_AW; EP_COUNT], + ep_out_wakers: [NEW_AW; EP_COUNT], + ep_out_buffers: [NEW_BUF; EP_COUNT], + ep_out_size: [NEW_SIZE; EP_COUNT], + bus_waker: NEW_AW, + } + } +} + +#[derive(Debug, Clone, Copy)] +struct EndpointData { + ep_type: EndpointType, + max_packet_size: u16, + fifo_size_words: u16, +} + +/// USB driver config. +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct Config { + /// Enable VBUS detection. + /// + /// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly. + /// This is done by checking whether there is 5V on the VBUS pin or not. + /// + /// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional. + /// (If there's no power in VBUS your device would be off anyway, so it's fine to always assume + /// there's power in VBUS, i.e. the USB cable is always plugged in.) + /// + /// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and + /// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true. + /// + /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a + /// voltage divider. See ST application note AN4879 and the reference manual for more details. + pub vbus_detection: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { vbus_detection: true } + } +} + +/// USB driver. +pub struct Driver<'d> { + config: Config, + ep_in: [Option; MAX_EP_COUNT], + ep_out: [Option; MAX_EP_COUNT], + ep_out_buffer: &'d mut [u8], + ep_out_buffer_offset: usize, + instance: OtgInstance<'d>, +} + +impl<'d> Driver<'d> { + /// Initializes USB OTG peripheral. + /// + /// # Arguments + /// + /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets. + /// Must be large enough to fit all OUT endpoint max packet sizes. + /// Endpoint allocation will fail if it is too small. + pub fn new(ep_out_buffer: &'d mut [u8], instance: OtgInstance<'d>, config: Config) -> Self { + Self { + config, + ep_in: [None; MAX_EP_COUNT], + ep_out: [None; MAX_EP_COUNT], + ep_out_buffer, + ep_out_buffer_offset: 0, + instance, + } + } + + // Returns total amount of words (u32) allocated in dedicated FIFO + fn allocated_fifo_words(&self) -> u16 { + self.instance.extra_rx_fifo_words + ep_fifo_size(&self.ep_out) + ep_fifo_size(&self.ep_in) + } + + /// Creates an [`Endpoint`] with the given parameters. + pub fn alloc_endpoint( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + ) -> Result, EndpointAllocError> { + trace!( + "allocating type={:?} mps={:?} interval_ms={}, dir={:?}", + ep_type, + max_packet_size, + interval_ms, + D::dir() + ); + + if D::dir() == Direction::Out { + if self.ep_out_buffer_offset + max_packet_size as usize >= self.ep_out_buffer.len() { + error!("Not enough endpoint out buffer capacity"); + return Err(EndpointAllocError); + } + }; + + let fifo_size_words = match D::dir() { + Direction::Out => (max_packet_size + 3) / 4, + // INEPTXFD requires minimum size of 16 words + Direction::In => u16::max((max_packet_size + 3) / 4, 16), + }; + + if fifo_size_words + self.allocated_fifo_words() > self.instance.fifo_depth_words { + error!("Not enough FIFO capacity"); + return Err(EndpointAllocError); + } + + let eps = match D::dir() { + Direction::Out => &mut self.ep_out, + Direction::In => &mut self.ep_in, + }; + + // Find free endpoint slot + let slot = eps.iter_mut().enumerate().find(|(i, ep)| { + if *i == 0 && ep_type != EndpointType::Control { + // reserved for control pipe + false + } else { + ep.is_none() + } + }); + + let index = match slot { + Some((index, ep)) => { + *ep = Some(EndpointData { + ep_type, + max_packet_size, + fifo_size_words, + }); + index + } + None => { + error!("No free endpoints available"); + return Err(EndpointAllocError); + } + }; + + trace!(" index={}", index); + + if D::dir() == Direction::Out { + // Buffer capacity check was done above, now allocation cannot fail + unsafe { + *self.instance.state.ep_out_buffers[index].get() = + self.ep_out_buffer.as_mut_ptr().offset(self.ep_out_buffer_offset as _); + } + self.ep_out_buffer_offset += max_packet_size as usize; + } + + Ok(Endpoint { + _phantom: PhantomData, + regs: self.instance.regs, + state: self.instance.state, + info: EndpointInfo { + addr: EndpointAddress::from_parts(index, D::dir()), + ep_type, + max_packet_size, + interval_ms, + }, + }) + } +} + +impl<'d> embassy_usb_driver::Driver<'d> for Driver<'d> { + type EndpointOut = Endpoint<'d, Out>; + type EndpointIn = Endpoint<'d, In>; + type ControlPipe = ControlPipe<'d>; + type Bus = Bus<'d>; + + fn alloc_endpoint_in( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + ) -> Result { + self.alloc_endpoint(ep_type, max_packet_size, interval_ms) + } + + fn alloc_endpoint_out( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + ) -> Result { + self.alloc_endpoint(ep_type, max_packet_size, interval_ms) + } + + fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { + let ep_out = self + .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) + .unwrap(); + let ep_in = self + .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) + .unwrap(); + assert_eq!(ep_out.info.addr.index(), 0); + assert_eq!(ep_in.info.addr.index(), 0); + + trace!("start"); + + let regs = self.instance.regs; + let quirk_setup_late_cnak = self.instance.quirk_setup_late_cnak; + ( + Bus { + config: self.config, + ep_in: self.ep_in, + ep_out: self.ep_out, + inited: false, + instance: self.instance, + }, + ControlPipe { + max_packet_size: control_max_packet_size, + ep_out, + ep_in, + regs, + quirk_setup_late_cnak, + }, + ) + } +} + +/// USB bus. +pub struct Bus<'d> { + config: Config, + ep_in: [Option; MAX_EP_COUNT], + ep_out: [Option; MAX_EP_COUNT], + instance: OtgInstance<'d>, + inited: bool, +} + +impl<'d> Bus<'d> { + fn restore_irqs(&mut self) { + self.instance.regs.gintmsk().write(|w| { + w.set_usbrst(true); + w.set_enumdnem(true); + w.set_usbsuspm(true); + w.set_wuim(true); + w.set_iepint(true); + w.set_oepint(true); + w.set_rxflvlm(true); + w.set_srqim(true); + w.set_otgint(true); + }); + } +} + +impl<'d> Bus<'d> { + /// Returns the PHY type. + pub fn phy_type(&self) -> PhyType { + self.instance.phy_type + } + + /// Configures the PHY as a device. + pub fn configure_as_device(&mut self) { + let r = self.instance.regs; + let phy_type = self.instance.phy_type; + r.gusbcfg().write(|w| { + // Force device mode + w.set_fdmod(true); + // Enable internal full-speed PHY + w.set_physel(phy_type.internal() && !phy_type.high_speed()); + }); + } + + /// Applies configuration specific to + /// Core ID 0x0000_1100 and 0x0000_1200 + pub fn config_v1(&mut self) { + let r = self.instance.regs; + let phy_type = self.instance.phy_type; + assert!(phy_type != PhyType::InternalHighSpeed); + + r.gccfg_v1().modify(|w| { + // Enable internal full-speed PHY, logic is inverted + w.set_pwrdwn(phy_type.internal()); + }); + + // F429-like chips have the GCCFG.NOVBUSSENS bit + r.gccfg_v1().modify(|w| { + w.set_novbussens(!self.config.vbus_detection); + w.set_vbusasen(false); + w.set_vbusbsen(self.config.vbus_detection); + w.set_sofouten(false); + }); + } + + /// Applies configuration specific to + /// Core ID 0x0000_2000, 0x0000_2100, 0x0000_2300, 0x0000_3000 and 0x0000_3100 + pub fn config_v2v3(&mut self) { + let r = self.instance.regs; + let phy_type = self.instance.phy_type; + + // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning + r.gccfg_v2().modify(|w| { + // Enable internal full-speed PHY, logic is inverted + w.set_pwrdwn(phy_type.internal() && !phy_type.high_speed()); + w.set_phyhsen(phy_type.internal() && phy_type.high_speed()); + }); + + r.gccfg_v2().modify(|w| { + w.set_vbden(self.config.vbus_detection); + }); + + // Force B-peripheral session + r.gotgctl().modify(|w| { + w.set_bvaloen(!self.config.vbus_detection); + w.set_bvaloval(true); + }); + } + + fn init(&mut self) { + let r = self.instance.regs; + let phy_type = self.instance.phy_type; + + // Soft disconnect. + r.dctl().write(|w| w.set_sdis(true)); + + // Set speed. + r.dcfg().write(|w| { + w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); + w.set_dspd(phy_type.to_dspd()); + }); + + // Unmask transfer complete EP interrupt + r.diepmsk().write(|w| { + w.set_xfrcm(true); + }); + + // Unmask and clear core interrupts + self.restore_irqs(); + r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); + + // Unmask global interrupt + r.gahbcfg().write(|w| { + w.set_gint(true); // unmask global interrupt + }); + + // Connect + r.dctl().write(|w| w.set_sdis(false)); + } + + fn init_fifo(&mut self) { + trace!("init_fifo"); + + let regs = self.instance.regs; + // ERRATA NOTE: Don't interrupt FIFOs being written to. The interrupt + // handler COULD interrupt us here and do FIFO operations, so ensure + // the interrupt does not occur. + critical_section::with(|_| { + // Configure RX fifo size. All endpoints share the same FIFO area. + let rx_fifo_size_words = self.instance.extra_rx_fifo_words + ep_fifo_size(&self.ep_out); + trace!("configuring rx fifo size={}", rx_fifo_size_words); + + regs.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)); + + // Configure TX (USB in direction) fifo size for each endpoint + let mut fifo_top = rx_fifo_size_words; + for i in 0..self.instance.endpoint_count { + if let Some(ep) = self.ep_in[i] { + trace!( + "configuring tx fifo ep={}, offset={}, size={}", + i, + fifo_top, + ep.fifo_size_words + ); + + let dieptxf = if i == 0 { regs.dieptxf0() } else { regs.dieptxf(i - 1) }; + + dieptxf.write(|w| { + w.set_fd(ep.fifo_size_words); + w.set_sa(fifo_top); + }); + + fifo_top += ep.fifo_size_words; + } + } + + assert!( + fifo_top <= self.instance.fifo_depth_words, + "FIFO allocations exceeded maximum capacity" + ); + + // Flush fifos + regs.grstctl().write(|w| { + w.set_rxfflsh(true); + w.set_txfflsh(true); + w.set_txfnum(0x10); + }); + }); + + loop { + let x = regs.grstctl().read(); + if !x.rxfflsh() && !x.txfflsh() { + break; + } + } + } + + fn configure_endpoints(&mut self) { + trace!("configure_endpoints"); + + let regs = self.instance.regs; + + // Configure IN endpoints + for (index, ep) in self.ep_in.iter().enumerate() { + if let Some(ep) = ep { + critical_section::with(|_| { + regs.diepctl(index).write(|w| { + if index == 0 { + w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); + } else { + w.set_mpsiz(ep.max_packet_size); + w.set_eptyp(to_eptyp(ep.ep_type)); + w.set_sd0pid_sevnfrm(true); + w.set_txfnum(index as _); + w.set_snak(true); + } + }); + }); + } + } + + // Configure OUT endpoints + for (index, ep) in self.ep_out.iter().enumerate() { + if let Some(ep) = ep { + critical_section::with(|_| { + regs.doepctl(index).write(|w| { + if index == 0 { + w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); + } else { + w.set_mpsiz(ep.max_packet_size); + w.set_eptyp(to_eptyp(ep.ep_type)); + w.set_sd0pid_sevnfrm(true); + } + }); + + regs.doeptsiz(index).modify(|w| { + w.set_xfrsiz(ep.max_packet_size as _); + if index == 0 { + w.set_rxdpid_stupcnt(1); + } else { + w.set_pktcnt(1); + } + }); + }); + } + } + + // Enable IRQs for allocated endpoints + regs.daintmsk().modify(|w| { + w.set_iepm(ep_irq_mask(&self.ep_in)); + // OUT interrupts not used, handled in RXFLVL + // w.set_oepm(ep_irq_mask(&self.ep_out)); + }); + } + + fn disable_all_endpoints(&mut self) { + for i in 0..self.instance.endpoint_count { + self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false); + self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false); + } + } +} + +impl<'d> embassy_usb_driver::Bus for Bus<'d> { + async fn poll(&mut self) -> Event { + poll_fn(move |cx| { + if !self.inited { + self.init(); + self.inited = true; + + // If no vbus detection, just return a single PowerDetected event at startup. + if !self.config.vbus_detection { + return Poll::Ready(Event::PowerDetected); + } + } + + let regs = self.instance.regs; + self.instance.state.bus_waker.register(cx.waker()); + + let ints = regs.gintsts().read(); + + if ints.srqint() { + trace!("vbus detected"); + + regs.gintsts().write(|w| w.set_srqint(true)); // clear + self.restore_irqs(); + + if self.config.vbus_detection { + return Poll::Ready(Event::PowerDetected); + } + } + + if ints.otgint() { + let otgints = regs.gotgint().read(); + regs.gotgint().write_value(otgints); // clear all + self.restore_irqs(); + + if otgints.sedet() { + trace!("vbus removed"); + if self.config.vbus_detection { + self.disable_all_endpoints(); + return Poll::Ready(Event::PowerRemoved); + } + } + } + + if ints.usbrst() { + trace!("reset"); + + self.init_fifo(); + self.configure_endpoints(); + + // Reset address + critical_section::with(|_| { + regs.dcfg().modify(|w| { + w.set_dad(0); + }); + }); + + regs.gintsts().write(|w| w.set_usbrst(true)); // clear + self.restore_irqs(); + } + + if ints.enumdne() { + trace!("enumdne"); + + let speed = regs.dsts().read().enumspd(); + let trdt = (self.instance.calculate_trdt_fn)(speed); + trace!(" speed={} trdt={}", speed.to_bits(), trdt); + regs.gusbcfg().modify(|w| w.set_trdt(trdt)); + + regs.gintsts().write(|w| w.set_enumdne(true)); // clear + self.restore_irqs(); + + return Poll::Ready(Event::Reset); + } + + if ints.usbsusp() { + trace!("suspend"); + regs.gintsts().write(|w| w.set_usbsusp(true)); // clear + self.restore_irqs(); + return Poll::Ready(Event::Suspend); + } + + if ints.wkupint() { + trace!("resume"); + regs.gintsts().write(|w| w.set_wkupint(true)); // clear + self.restore_irqs(); + return Poll::Ready(Event::Resume); + } + + Poll::Pending + }) + .await + } + + fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) { + trace!("endpoint_set_stalled ep={:?} en={}", ep_addr, stalled); + + assert!( + ep_addr.index() < self.instance.endpoint_count, + "endpoint_set_stalled index {} out of range", + ep_addr.index() + ); + + let regs = self.instance.regs; + let state = self.instance.state; + match ep_addr.direction() { + Direction::Out => { + critical_section::with(|_| { + regs.doepctl(ep_addr.index()).modify(|w| { + w.set_stall(stalled); + }); + }); + + state.ep_out_wakers[ep_addr.index()].wake(); + } + Direction::In => { + critical_section::with(|_| { + regs.diepctl(ep_addr.index()).modify(|w| { + w.set_stall(stalled); + }); + }); + + state.ep_in_wakers[ep_addr.index()].wake(); + } + } + } + + fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool { + assert!( + ep_addr.index() < self.instance.endpoint_count, + "endpoint_is_stalled index {} out of range", + ep_addr.index() + ); + + let regs = self.instance.regs; + match ep_addr.direction() { + Direction::Out => regs.doepctl(ep_addr.index()).read().stall(), + Direction::In => regs.diepctl(ep_addr.index()).read().stall(), + } + } + + fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) { + trace!("endpoint_set_enabled ep={:?} en={}", ep_addr, enabled); + + assert!( + ep_addr.index() < self.instance.endpoint_count, + "endpoint_set_enabled index {} out of range", + ep_addr.index() + ); + + let regs = self.instance.regs; + let state = self.instance.state; + match ep_addr.direction() { + Direction::Out => { + critical_section::with(|_| { + // cancel transfer if active + if !enabled && regs.doepctl(ep_addr.index()).read().epena() { + regs.doepctl(ep_addr.index()).modify(|w| { + w.set_snak(true); + w.set_epdis(true); + }) + } + + regs.doepctl(ep_addr.index()).modify(|w| { + w.set_usbaep(enabled); + }); + + // Flush tx fifo + regs.grstctl().write(|w| { + w.set_txfflsh(true); + w.set_txfnum(ep_addr.index() as _); + }); + loop { + let x = regs.grstctl().read(); + if !x.txfflsh() { + break; + } + } + }); + + // Wake `Endpoint::wait_enabled()` + state.ep_out_wakers[ep_addr.index()].wake(); + } + Direction::In => { + critical_section::with(|_| { + // cancel transfer if active + if !enabled && regs.diepctl(ep_addr.index()).read().epena() { + regs.diepctl(ep_addr.index()).modify(|w| { + w.set_snak(true); // set NAK + w.set_epdis(true); + }) + } + + regs.diepctl(ep_addr.index()).modify(|w| { + w.set_usbaep(enabled); + w.set_cnak(enabled); // clear NAK that might've been set by SNAK above. + }) + }); + + // Wake `Endpoint::wait_enabled()` + state.ep_in_wakers[ep_addr.index()].wake(); + } + } + } + + async fn enable(&mut self) { + trace!("enable"); + // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb + } + + async fn disable(&mut self) { + trace!("disable"); + + // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb + //Bus::disable(self); + } + + async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { + Err(Unsupported) + } +} + +/// USB endpoint direction. +pub trait Dir { + /// Returns the direction value. + fn dir() -> Direction; +} + +/// Marker type for the "IN" direction. +pub enum In {} +impl Dir for In { + fn dir() -> Direction { + Direction::In + } +} + +/// Marker type for the "OUT" direction. +pub enum Out {} +impl Dir for Out { + fn dir() -> Direction { + Direction::Out + } +} + +/// USB endpoint. +pub struct Endpoint<'d, D> { + _phantom: PhantomData, + regs: Otg, + info: EndpointInfo, + state: &'d State<{ MAX_EP_COUNT }>, +} + +impl<'d> embassy_usb_driver::Endpoint for Endpoint<'d, In> { + fn info(&self) -> &EndpointInfo { + &self.info + } + + async fn wait_enabled(&mut self) { + poll_fn(|cx| { + let ep_index = self.info.addr.index(); + + self.state.ep_in_wakers[ep_index].register(cx.waker()); + + if self.regs.diepctl(ep_index).read().usbaep() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await + } +} + +impl<'d> embassy_usb_driver::Endpoint for Endpoint<'d, Out> { + fn info(&self) -> &EndpointInfo { + &self.info + } + + async fn wait_enabled(&mut self) { + poll_fn(|cx| { + let ep_index = self.info.addr.index(); + + self.state.ep_out_wakers[ep_index].register(cx.waker()); + + if self.regs.doepctl(ep_index).read().usbaep() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await + } +} + +impl<'d> embassy_usb_driver::EndpointOut for Endpoint<'d, Out> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + trace!("read start len={}", buf.len()); + + poll_fn(|cx| { + let index = self.info.addr.index(); + self.state.ep_out_wakers[index].register(cx.waker()); + + let doepctl = self.regs.doepctl(index).read(); + trace!("read ep={:?}: doepctl {:08x}", self.info.addr, doepctl.0,); + if !doepctl.usbaep() { + trace!("read ep={:?} error disabled", self.info.addr); + return Poll::Ready(Err(EndpointError::Disabled)); + } + + let len = self.state.ep_out_size[index].load(Ordering::Relaxed); + if len != EP_OUT_BUFFER_EMPTY { + trace!("read ep={:?} done len={}", self.info.addr, len); + + if len as usize > buf.len() { + return Poll::Ready(Err(EndpointError::BufferOverflow)); + } + + // SAFETY: exclusive access ensured by `ep_out_size` atomic variable + let data = + unsafe { core::slice::from_raw_parts(*self.state.ep_out_buffers[index].get(), len as usize) }; + buf[..len as usize].copy_from_slice(data); + + // Release buffer + self.state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release); + + critical_section::with(|_| { + // Receive 1 packet + self.regs.doeptsiz(index).modify(|w| { + w.set_xfrsiz(self.info.max_packet_size as _); + w.set_pktcnt(1); + }); + + // Clear NAK to indicate we are ready to receive more data + self.regs.doepctl(index).modify(|w| { + w.set_cnak(true); + }); + }); + + Poll::Ready(Ok(len as usize)) + } else { + Poll::Pending + } + }) + .await + } +} + +impl<'d> embassy_usb_driver::EndpointIn for Endpoint<'d, In> { + async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> { + trace!("write ep={:?} data={:?}", self.info.addr, buf); + + if buf.len() > self.info.max_packet_size as usize { + return Err(EndpointError::BufferOverflow); + } + + let index = self.info.addr.index(); + // Wait for previous transfer to complete and check if endpoint is disabled + poll_fn(|cx| { + self.state.ep_in_wakers[index].register(cx.waker()); + + let diepctl = self.regs.diepctl(index).read(); + let dtxfsts = self.regs.dtxfsts(index).read(); + trace!( + "write ep={:?}: diepctl {:08x} ftxfsts {:08x}", + self.info.addr, + diepctl.0, + dtxfsts.0 + ); + if !diepctl.usbaep() { + trace!("write ep={:?} wait for prev: error disabled", self.info.addr); + Poll::Ready(Err(EndpointError::Disabled)) + } else if !diepctl.epena() { + trace!("write ep={:?} wait for prev: ready", self.info.addr); + Poll::Ready(Ok(())) + } else { + trace!("write ep={:?} wait for prev: pending", self.info.addr); + Poll::Pending + } + }) + .await?; + + if buf.len() > 0 { + poll_fn(|cx| { + self.state.ep_in_wakers[index].register(cx.waker()); + + let size_words = (buf.len() + 3) / 4; + + let fifo_space = self.regs.dtxfsts(index).read().ineptfsav() as usize; + if size_words > fifo_space { + // Not enough space in fifo, enable tx fifo empty interrupt + critical_section::with(|_| { + self.regs.diepempmsk().modify(|w| { + w.set_ineptxfem(w.ineptxfem() | (1 << index)); + }); + }); + + trace!("tx fifo for ep={} full, waiting for txfe", index); + + Poll::Pending + } else { + trace!("write ep={:?} wait for fifo: ready", self.info.addr); + Poll::Ready(()) + } + }) + .await + } + + // ERRATA: Transmit data FIFO is corrupted when a write sequence to the FIFO is interrupted with + // accesses to certain OTG_FS registers. + // + // Prevent the interrupt (which might poke FIFOs) from executing while copying data to FIFOs. + critical_section::with(|_| { + // Setup transfer size + self.regs.dieptsiz(index).write(|w| { + w.set_mcnt(1); + w.set_pktcnt(1); + w.set_xfrsiz(buf.len() as _); + }); + + // Enable endpoint + self.regs.diepctl(index).modify(|w| { + w.set_cnak(true); + w.set_epena(true); + }); + + // Write data to FIFO + for chunk in buf.chunks(4) { + let mut tmp = [0u8; 4]; + tmp[0..chunk.len()].copy_from_slice(chunk); + self.regs.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))); + } + }); + + trace!("write done ep={:?}", self.info.addr); + + Ok(()) + } +} + +/// USB control pipe. +pub struct ControlPipe<'d> { + max_packet_size: u16, + regs: Otg, + ep_in: Endpoint<'d, In>, + ep_out: Endpoint<'d, Out>, + quirk_setup_late_cnak: bool, +} + +impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> { + fn max_packet_size(&self) -> usize { + usize::from(self.max_packet_size) + } + + async fn setup(&mut self) -> [u8; 8] { + poll_fn(|cx| { + self.ep_out.state.ep_out_wakers[0].register(cx.waker()); + + if self.ep_out.state.ep0_setup_ready.load(Ordering::Relaxed) { + let data = unsafe { *self.ep_out.state.ep0_setup_data.get() }; + self.ep_out.state.ep0_setup_ready.store(false, Ordering::Release); + + // EP0 should not be controlled by `Bus` so this RMW does not need a critical section + // Receive 1 SETUP packet + self.regs.doeptsiz(self.ep_out.info.addr.index()).modify(|w| { + w.set_rxdpid_stupcnt(1); + }); + + // Clear NAK to indicate we are ready to receive more data + if !self.quirk_setup_late_cnak { + self.regs + .doepctl(self.ep_out.info.addr.index()) + .modify(|w| w.set_cnak(true)); + } + + trace!("SETUP received: {:?}", data); + Poll::Ready(data) + } else { + trace!("SETUP waiting"); + Poll::Pending + } + }) + .await + } + + async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result { + trace!("control: data_out"); + let len = self.ep_out.read(buf).await?; + trace!("control: data_out read: {:?}", &buf[..len]); + Ok(len) + } + + async fn data_in(&mut self, data: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> { + trace!("control: data_in write: {:?}", data); + self.ep_in.write(data).await?; + + // wait for status response from host after sending the last packet + if last { + trace!("control: data_in waiting for status"); + self.ep_out.read(&mut []).await?; + trace!("control: complete"); + } + + Ok(()) + } + + async fn accept(&mut self) { + trace!("control: accept"); + + self.ep_in.write(&[]).await.ok(); + + trace!("control: accept OK"); + } + + async fn reject(&mut self) { + trace!("control: reject"); + + // EP0 should not be controlled by `Bus` so this RMW does not need a critical section + self.regs.diepctl(self.ep_in.info.addr.index()).modify(|w| { + w.set_stall(true); + }); + self.regs.doepctl(self.ep_out.info.addr.index()).modify(|w| { + w.set_stall(true); + }); + } + + async fn accept_set_address(&mut self, addr: u8) { + trace!("setting addr: {}", addr); + critical_section::with(|_| { + self.regs.dcfg().modify(|w| { + w.set_dad(addr); + }); + }); + + // synopsys driver requires accept to be sent after changing address + self.accept().await + } +} + +/// Translates HAL [EndpointType] into PAC [vals::Eptyp] +fn to_eptyp(ep_type: EndpointType) -> vals::Eptyp { + match ep_type { + EndpointType::Control => vals::Eptyp::CONTROL, + EndpointType::Isochronous => vals::Eptyp::ISOCHRONOUS, + EndpointType::Bulk => vals::Eptyp::BULK, + EndpointType::Interrupt => vals::Eptyp::INTERRUPT, + } +} + +/// Calculates total allocated FIFO size in words +fn ep_fifo_size(eps: &[Option]) -> u16 { + eps.iter().map(|ep| ep.map(|ep| ep.fifo_size_words).unwrap_or(0)).sum() +} + +/// Generates IRQ mask for enabled endpoints +fn ep_irq_mask(eps: &[Option]) -> u16 { + eps.iter().enumerate().fold( + 0, + |mask, (index, ep)| { + if ep.is_some() { + mask | (1 << index) + } else { + mask + } + }, + ) +} + +/// Calculates MPSIZ value for EP0, which uses special values. +fn ep0_mpsiz(max_packet_size: u16) -> u16 { + match max_packet_size { + 8 => 0b11, + 16 => 0b10, + 32 => 0b01, + 64 => 0b00, + other => panic!("Unsupported EP0 size: {}", other), + } +} + +/// The number of maximum configurable EPs. +// TODO: this should at least be configurable, but ideally not a constant. +// Using OtgInstance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps +pub const MAX_EP_COUNT: usize = 9; + +/// USB instance. +pub struct OtgInstance<'d> { + /// The USB peripheral. + pub regs: Otg, + /// The USB state. + pub state: &'d State<{ MAX_EP_COUNT }>, + /// FIFO depth in words. + pub fifo_depth_words: u16, + /// Number of used endpoints. + pub endpoint_count: usize, + /// The PHY type. + pub phy_type: PhyType, + /// Extra RX FIFO words needed by some implementations. + pub extra_rx_fifo_words: u16, + /// Whether to set up late cnak + pub quirk_setup_late_cnak: bool, + /// Function to calculate TRDT value based on some internal clock speed. + pub calculate_trdt_fn: fn(speed: vals::Dspd) -> u8, +} diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs new file mode 100644 index 000000000..111bc4a63 --- /dev/null +++ b/embassy-usb-synopsys-otg/src/otg_v1.rs @@ -0,0 +1,4482 @@ +//! Register definitions for Synopsys DesignWare USB OTG core + +#![allow(missing_docs)] + +use core::marker::PhantomData; + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct RW; +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct R; +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct W; + +mod sealed { + use super::*; + pub trait Access {} + impl Access for R {} + impl Access for W {} + impl Access for RW {} +} + +pub trait Access: sealed::Access + Copy {} +impl Access for R {} +impl Access for W {} +impl Access for RW {} + +pub trait Read: Access {} +impl Read for RW {} +impl Read for R {} + +pub trait Write: Access {} +impl Write for RW {} +impl Write for W {} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Reg { + ptr: *mut u8, + phantom: PhantomData<*mut (T, A)>, +} +unsafe impl Send for Reg {} +unsafe impl Sync for Reg {} + +impl Reg { + #[allow(clippy::missing_safety_doc)] + #[inline(always)] + pub const unsafe fn from_ptr(ptr: *mut T) -> Self { + Self { + ptr: ptr as _, + phantom: PhantomData, + } + } + + #[inline(always)] + pub const fn as_ptr(&self) -> *mut T { + self.ptr as _ + } +} + +impl Reg { + #[inline(always)] + pub fn read(&self) -> T { + unsafe { (self.ptr as *mut T).read_volatile() } + } +} + +impl Reg { + #[inline(always)] + pub fn write_value(&self, val: T) { + unsafe { (self.ptr as *mut T).write_volatile(val) } + } +} + +impl Reg { + #[inline(always)] + pub fn write(&self, f: impl FnOnce(&mut T) -> R) -> R { + let mut val = Default::default(); + let res = f(&mut val); + self.write_value(val); + res + } +} + +impl Reg { + #[inline(always)] + pub fn modify(&self, f: impl FnOnce(&mut T) -> R) -> R { + let mut val = self.read(); + let res = f(&mut val); + self.write_value(val); + res + } +} + +#[doc = "USB on the go"] +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Otg { + ptr: *mut u8, +} +unsafe impl Send for Otg {} +unsafe impl Sync for Otg {} +impl Otg { + #[inline(always)] + pub const unsafe fn from_ptr(ptr: *mut ()) -> Self { + Self { ptr: ptr as _ } + } + #[inline(always)] + pub const fn as_ptr(&self) -> *mut () { + self.ptr as _ + } + #[doc = "Control and status register"] + #[inline(always)] + pub const fn gotgctl(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0usize) as _) } + } + #[doc = "Interrupt register"] + #[inline(always)] + pub const fn gotgint(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x04usize) as _) } + } + #[doc = "AHB configuration register"] + #[inline(always)] + pub const fn gahbcfg(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x08usize) as _) } + } + #[doc = "USB configuration register"] + #[inline(always)] + pub const fn gusbcfg(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0cusize) as _) } + } + #[doc = "Reset register"] + #[inline(always)] + pub const fn grstctl(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x10usize) as _) } + } + #[doc = "Core interrupt register"] + #[inline(always)] + pub const fn gintsts(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x14usize) as _) } + } + #[doc = "Interrupt mask register"] + #[inline(always)] + pub const fn gintmsk(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x18usize) as _) } + } + #[doc = "Receive status debug read register"] + #[inline(always)] + pub const fn grxstsr(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x1cusize) as _) } + } + #[doc = "Status read and pop register"] + #[inline(always)] + pub const fn grxstsp(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x20usize) as _) } + } + #[doc = "Receive FIFO size register"] + #[inline(always)] + pub const fn grxfsiz(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x24usize) as _) } + } + #[doc = "Endpoint 0 transmit FIFO size register (device mode)"] + #[inline(always)] + pub const fn dieptxf0(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x28usize) as _) } + } + #[doc = "Non-periodic transmit FIFO size register (host mode)"] + #[inline(always)] + pub const fn hnptxfsiz(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x28usize) as _) } + } + #[doc = "Non-periodic transmit FIFO/queue status register (host mode)"] + #[inline(always)] + pub const fn hnptxsts(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x2cusize) as _) } + } + #[doc = "OTG I2C access register"] + #[inline(always)] + pub const fn gi2cctl(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x30usize) as _) } + } + #[doc = "General core configuration register, for core_id 0x0000_1xxx"] + #[inline(always)] + pub const fn gccfg_v1(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) } + } + #[doc = "General core configuration register, for core_id 0x0000_\\[23\\]xxx"] + #[inline(always)] + pub const fn gccfg_v2(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) } + } + #[doc = "Core ID register"] + #[inline(always)] + pub const fn cid(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x3cusize) as _) } + } + #[doc = "OTG core LPM configuration register"] + #[inline(always)] + pub const fn glpmcfg(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x54usize) as _) } + } + #[doc = "Host periodic transmit FIFO size register"] + #[inline(always)] + pub const fn hptxfsiz(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0100usize) as _) } + } + #[doc = "Device IN endpoint transmit FIFO size register"] + #[inline(always)] + pub const fn dieptxf(self, n: usize) -> Reg { + assert!(n < 7usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0104usize + n * 4usize) as _) } + } + #[doc = "Host configuration register"] + #[inline(always)] + pub const fn hcfg(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0400usize) as _) } + } + #[doc = "Host frame interval register"] + #[inline(always)] + pub const fn hfir(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0404usize) as _) } + } + #[doc = "Host frame number/frame time remaining register"] + #[inline(always)] + pub const fn hfnum(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0408usize) as _) } + } + #[doc = "Periodic transmit FIFO/queue status register"] + #[inline(always)] + pub const fn hptxsts(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0410usize) as _) } + } + #[doc = "Host all channels interrupt register"] + #[inline(always)] + pub const fn haint(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0414usize) as _) } + } + #[doc = "Host all channels interrupt mask register"] + #[inline(always)] + pub const fn haintmsk(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0418usize) as _) } + } + #[doc = "Host port control and status register"] + #[inline(always)] + pub const fn hprt(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0440usize) as _) } + } + #[doc = "Host channel characteristics register"] + #[inline(always)] + pub const fn hcchar(self, n: usize) -> Reg { + assert!(n < 12usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0500usize + n * 32usize) as _) } + } + #[doc = "Host channel split control register"] + #[inline(always)] + pub const fn hcsplt(self, n: usize) -> Reg { + assert!(n < 12usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0504usize + n * 32usize) as _) } + } + #[doc = "Host channel interrupt register"] + #[inline(always)] + pub const fn hcint(self, n: usize) -> Reg { + assert!(n < 12usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0508usize + n * 32usize) as _) } + } + #[doc = "Host channel mask register"] + #[inline(always)] + pub const fn hcintmsk(self, n: usize) -> Reg { + assert!(n < 12usize); + unsafe { Reg::from_ptr(self.ptr.add(0x050cusize + n * 32usize) as _) } + } + #[doc = "Host channel transfer size register"] + #[inline(always)] + pub const fn hctsiz(self, n: usize) -> Reg { + assert!(n < 12usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0510usize + n * 32usize) as _) } + } + #[doc = "Device configuration register"] + #[inline(always)] + pub const fn dcfg(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0800usize) as _) } + } + #[doc = "Device control register"] + #[inline(always)] + pub const fn dctl(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0804usize) as _) } + } + #[doc = "Device status register"] + #[inline(always)] + pub const fn dsts(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0808usize) as _) } + } + #[doc = "Device IN endpoint common interrupt mask register"] + #[inline(always)] + pub const fn diepmsk(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0810usize) as _) } + } + #[doc = "Device OUT endpoint common interrupt mask register"] + #[inline(always)] + pub const fn doepmsk(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0814usize) as _) } + } + #[doc = "Device all endpoints interrupt register"] + #[inline(always)] + pub const fn daint(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0818usize) as _) } + } + #[doc = "All endpoints interrupt mask register"] + #[inline(always)] + pub const fn daintmsk(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x081cusize) as _) } + } + #[doc = "Device VBUS discharge time register"] + #[inline(always)] + pub const fn dvbusdis(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0828usize) as _) } + } + #[doc = "Device VBUS pulsing time register"] + #[inline(always)] + pub const fn dvbuspulse(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x082cusize) as _) } + } + #[doc = "Device IN endpoint FIFO empty interrupt mask register"] + #[inline(always)] + pub const fn diepempmsk(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0834usize) as _) } + } + #[doc = "Device IN endpoint control register"] + #[inline(always)] + pub const fn diepctl(self, n: usize) -> Reg { + assert!(n < 16usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0900usize + n * 32usize) as _) } + } + #[doc = "Device IN endpoint interrupt register"] + #[inline(always)] + pub const fn diepint(self, n: usize) -> Reg { + assert!(n < 16usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0908usize + n * 32usize) as _) } + } + #[doc = "Device IN endpoint transfer size register"] + #[inline(always)] + pub const fn dieptsiz(self, n: usize) -> Reg { + assert!(n < 16usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0910usize + n * 32usize) as _) } + } + #[doc = "Device IN endpoint transmit FIFO status register"] + #[inline(always)] + pub const fn dtxfsts(self, n: usize) -> Reg { + assert!(n < 16usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0918usize + n * 32usize) as _) } + } + #[doc = "Device OUT endpoint control register"] + #[inline(always)] + pub const fn doepctl(self, n: usize) -> Reg { + assert!(n < 16usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0b00usize + n * 32usize) as _) } + } + #[doc = "Device OUT endpoint interrupt register"] + #[inline(always)] + pub const fn doepint(self, n: usize) -> Reg { + assert!(n < 16usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0b08usize + n * 32usize) as _) } + } + #[doc = "Device OUT endpoint transfer size register"] + #[inline(always)] + pub const fn doeptsiz(self, n: usize) -> Reg { + assert!(n < 16usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0b10usize + n * 32usize) as _) } + } + #[doc = "Power and clock gating control register"] + #[inline(always)] + pub const fn pcgcctl(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x0e00usize) as _) } + } + #[doc = "Device endpoint / host channel FIFO register"] + #[inline(always)] + pub const fn fifo(self, n: usize) -> Reg { + assert!(n < 16usize); + unsafe { Reg::from_ptr(self.ptr.add(0x1000usize + n * 4096usize) as _) } + } +} +pub mod regs { + #[doc = "Core ID register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Cid(pub u32); + impl Cid { + #[doc = "Product ID field"] + #[inline(always)] + pub const fn product_id(&self) -> u32 { + let val = (self.0 >> 0usize) & 0xffff_ffff; + val as u32 + } + #[doc = "Product ID field"] + #[inline(always)] + pub fn set_product_id(&mut self, val: u32) { + self.0 = (self.0 & !(0xffff_ffff << 0usize)) | (((val as u32) & 0xffff_ffff) << 0usize); + } + } + impl Default for Cid { + #[inline(always)] + fn default() -> Cid { + Cid(0) + } + } + #[doc = "Device all endpoints interrupt register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Daint(pub u32); + impl Daint { + #[doc = "IN endpoint interrupt bits"] + #[inline(always)] + pub const fn iepint(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "IN endpoint interrupt bits"] + #[inline(always)] + pub fn set_iepint(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + #[doc = "OUT endpoint interrupt bits"] + #[inline(always)] + pub const fn oepint(&self) -> u16 { + let val = (self.0 >> 16usize) & 0xffff; + val as u16 + } + #[doc = "OUT endpoint interrupt bits"] + #[inline(always)] + pub fn set_oepint(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 16usize)) | (((val as u32) & 0xffff) << 16usize); + } + } + impl Default for Daint { + #[inline(always)] + fn default() -> Daint { + Daint(0) + } + } + #[doc = "All endpoints interrupt mask register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Daintmsk(pub u32); + impl Daintmsk { + #[doc = "IN EP interrupt mask bits"] + #[inline(always)] + pub const fn iepm(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "IN EP interrupt mask bits"] + #[inline(always)] + pub fn set_iepm(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + #[doc = "OUT EP interrupt mask bits"] + #[inline(always)] + pub const fn oepm(&self) -> u16 { + let val = (self.0 >> 16usize) & 0xffff; + val as u16 + } + #[doc = "OUT EP interrupt mask bits"] + #[inline(always)] + pub fn set_oepm(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 16usize)) | (((val as u32) & 0xffff) << 16usize); + } + } + impl Default for Daintmsk { + #[inline(always)] + fn default() -> Daintmsk { + Daintmsk(0) + } + } + #[doc = "Device configuration register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Dcfg(pub u32); + impl Dcfg { + #[doc = "Device speed"] + #[inline(always)] + pub const fn dspd(&self) -> super::vals::Dspd { + let val = (self.0 >> 0usize) & 0x03; + super::vals::Dspd::from_bits(val as u8) + } + #[doc = "Device speed"] + #[inline(always)] + pub fn set_dspd(&mut self, val: super::vals::Dspd) { + self.0 = (self.0 & !(0x03 << 0usize)) | (((val.to_bits() as u32) & 0x03) << 0usize); + } + #[doc = "Non-zero-length status OUT handshake"] + #[inline(always)] + pub const fn nzlsohsk(&self) -> bool { + let val = (self.0 >> 2usize) & 0x01; + val != 0 + } + #[doc = "Non-zero-length status OUT handshake"] + #[inline(always)] + pub fn set_nzlsohsk(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize); + } + #[doc = "Device address"] + #[inline(always)] + pub const fn dad(&self) -> u8 { + let val = (self.0 >> 4usize) & 0x7f; + val as u8 + } + #[doc = "Device address"] + #[inline(always)] + pub fn set_dad(&mut self, val: u8) { + self.0 = (self.0 & !(0x7f << 4usize)) | (((val as u32) & 0x7f) << 4usize); + } + #[doc = "Periodic frame interval"] + #[inline(always)] + pub const fn pfivl(&self) -> super::vals::Pfivl { + let val = (self.0 >> 11usize) & 0x03; + super::vals::Pfivl::from_bits(val as u8) + } + #[doc = "Periodic frame interval"] + #[inline(always)] + pub fn set_pfivl(&mut self, val: super::vals::Pfivl) { + self.0 = (self.0 & !(0x03 << 11usize)) | (((val.to_bits() as u32) & 0x03) << 11usize); + } + #[doc = "Transceiver delay"] + #[inline(always)] + pub const fn xcvrdly(&self) -> bool { + let val = (self.0 >> 14usize) & 0x01; + val != 0 + } + #[doc = "Transceiver delay"] + #[inline(always)] + pub fn set_xcvrdly(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 14usize)) | (((val as u32) & 0x01) << 14usize); + } + } + impl Default for Dcfg { + #[inline(always)] + fn default() -> Dcfg { + Dcfg(0) + } + } + #[doc = "Device control register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Dctl(pub u32); + impl Dctl { + #[doc = "Remote wakeup signaling"] + #[inline(always)] + pub const fn rwusig(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Remote wakeup signaling"] + #[inline(always)] + pub fn set_rwusig(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Soft disconnect"] + #[inline(always)] + pub const fn sdis(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Soft disconnect"] + #[inline(always)] + pub fn set_sdis(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "Global IN NAK status"] + #[inline(always)] + pub const fn ginsts(&self) -> bool { + let val = (self.0 >> 2usize) & 0x01; + val != 0 + } + #[doc = "Global IN NAK status"] + #[inline(always)] + pub fn set_ginsts(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize); + } + #[doc = "Global OUT NAK status"] + #[inline(always)] + pub const fn gonsts(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "Global OUT NAK status"] + #[inline(always)] + pub fn set_gonsts(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "Test control"] + #[inline(always)] + pub const fn tctl(&self) -> u8 { + let val = (self.0 >> 4usize) & 0x07; + val as u8 + } + #[doc = "Test control"] + #[inline(always)] + pub fn set_tctl(&mut self, val: u8) { + self.0 = (self.0 & !(0x07 << 4usize)) | (((val as u32) & 0x07) << 4usize); + } + #[doc = "Set global IN NAK"] + #[inline(always)] + pub const fn sginak(&self) -> bool { + let val = (self.0 >> 7usize) & 0x01; + val != 0 + } + #[doc = "Set global IN NAK"] + #[inline(always)] + pub fn set_sginak(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 7usize)) | (((val as u32) & 0x01) << 7usize); + } + #[doc = "Clear global IN NAK"] + #[inline(always)] + pub const fn cginak(&self) -> bool { + let val = (self.0 >> 8usize) & 0x01; + val != 0 + } + #[doc = "Clear global IN NAK"] + #[inline(always)] + pub fn set_cginak(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 8usize)) | (((val as u32) & 0x01) << 8usize); + } + #[doc = "Set global OUT NAK"] + #[inline(always)] + pub const fn sgonak(&self) -> bool { + let val = (self.0 >> 9usize) & 0x01; + val != 0 + } + #[doc = "Set global OUT NAK"] + #[inline(always)] + pub fn set_sgonak(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 9usize)) | (((val as u32) & 0x01) << 9usize); + } + #[doc = "Clear global OUT NAK"] + #[inline(always)] + pub const fn cgonak(&self) -> bool { + let val = (self.0 >> 10usize) & 0x01; + val != 0 + } + #[doc = "Clear global OUT NAK"] + #[inline(always)] + pub fn set_cgonak(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 10usize)) | (((val as u32) & 0x01) << 10usize); + } + #[doc = "Power-on programming done"] + #[inline(always)] + pub const fn poprgdne(&self) -> bool { + let val = (self.0 >> 11usize) & 0x01; + val != 0 + } + #[doc = "Power-on programming done"] + #[inline(always)] + pub fn set_poprgdne(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 11usize)) | (((val as u32) & 0x01) << 11usize); + } + } + impl Default for Dctl { + #[inline(always)] + fn default() -> Dctl { + Dctl(0) + } + } + #[doc = "Device endpoint control register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Diepctl(pub u32); + impl Diepctl { + #[doc = "MPSIZ"] + #[inline(always)] + pub const fn mpsiz(&self) -> u16 { + let val = (self.0 >> 0usize) & 0x07ff; + val as u16 + } + #[doc = "MPSIZ"] + #[inline(always)] + pub fn set_mpsiz(&mut self, val: u16) { + self.0 = (self.0 & !(0x07ff << 0usize)) | (((val as u32) & 0x07ff) << 0usize); + } + #[doc = "USBAEP"] + #[inline(always)] + pub const fn usbaep(&self) -> bool { + let val = (self.0 >> 15usize) & 0x01; + val != 0 + } + #[doc = "USBAEP"] + #[inline(always)] + pub fn set_usbaep(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 15usize)) | (((val as u32) & 0x01) << 15usize); + } + #[doc = "EONUM/DPID"] + #[inline(always)] + pub const fn eonum_dpid(&self) -> bool { + let val = (self.0 >> 16usize) & 0x01; + val != 0 + } + #[doc = "EONUM/DPID"] + #[inline(always)] + pub fn set_eonum_dpid(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 16usize)) | (((val as u32) & 0x01) << 16usize); + } + #[doc = "NAKSTS"] + #[inline(always)] + pub const fn naksts(&self) -> bool { + let val = (self.0 >> 17usize) & 0x01; + val != 0 + } + #[doc = "NAKSTS"] + #[inline(always)] + pub fn set_naksts(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize); + } + #[doc = "EPTYP"] + #[inline(always)] + pub const fn eptyp(&self) -> super::vals::Eptyp { + let val = (self.0 >> 18usize) & 0x03; + super::vals::Eptyp::from_bits(val as u8) + } + #[doc = "EPTYP"] + #[inline(always)] + pub fn set_eptyp(&mut self, val: super::vals::Eptyp) { + self.0 = (self.0 & !(0x03 << 18usize)) | (((val.to_bits() as u32) & 0x03) << 18usize); + } + #[doc = "SNPM"] + #[inline(always)] + pub const fn snpm(&self) -> bool { + let val = (self.0 >> 20usize) & 0x01; + val != 0 + } + #[doc = "SNPM"] + #[inline(always)] + pub fn set_snpm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize); + } + #[doc = "STALL"] + #[inline(always)] + pub const fn stall(&self) -> bool { + let val = (self.0 >> 21usize) & 0x01; + val != 0 + } + #[doc = "STALL"] + #[inline(always)] + pub fn set_stall(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 21usize)) | (((val as u32) & 0x01) << 21usize); + } + #[doc = "TXFNUM"] + #[inline(always)] + pub const fn txfnum(&self) -> u8 { + let val = (self.0 >> 22usize) & 0x0f; + val as u8 + } + #[doc = "TXFNUM"] + #[inline(always)] + pub fn set_txfnum(&mut self, val: u8) { + self.0 = (self.0 & !(0x0f << 22usize)) | (((val as u32) & 0x0f) << 22usize); + } + #[doc = "CNAK"] + #[inline(always)] + pub const fn cnak(&self) -> bool { + let val = (self.0 >> 26usize) & 0x01; + val != 0 + } + #[doc = "CNAK"] + #[inline(always)] + pub fn set_cnak(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 26usize)) | (((val as u32) & 0x01) << 26usize); + } + #[doc = "SNAK"] + #[inline(always)] + pub const fn snak(&self) -> bool { + let val = (self.0 >> 27usize) & 0x01; + val != 0 + } + #[doc = "SNAK"] + #[inline(always)] + pub fn set_snak(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 27usize)) | (((val as u32) & 0x01) << 27usize); + } + #[doc = "SD0PID/SEVNFRM"] + #[inline(always)] + pub const fn sd0pid_sevnfrm(&self) -> bool { + let val = (self.0 >> 28usize) & 0x01; + val != 0 + } + #[doc = "SD0PID/SEVNFRM"] + #[inline(always)] + pub fn set_sd0pid_sevnfrm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); + } + #[doc = "SODDFRM/SD1PID"] + #[inline(always)] + pub const fn soddfrm_sd1pid(&self) -> bool { + let val = (self.0 >> 29usize) & 0x01; + val != 0 + } + #[doc = "SODDFRM/SD1PID"] + #[inline(always)] + pub fn set_soddfrm_sd1pid(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); + } + #[doc = "EPDIS"] + #[inline(always)] + pub const fn epdis(&self) -> bool { + let val = (self.0 >> 30usize) & 0x01; + val != 0 + } + #[doc = "EPDIS"] + #[inline(always)] + pub fn set_epdis(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 30usize)) | (((val as u32) & 0x01) << 30usize); + } + #[doc = "EPENA"] + #[inline(always)] + pub const fn epena(&self) -> bool { + let val = (self.0 >> 31usize) & 0x01; + val != 0 + } + #[doc = "EPENA"] + #[inline(always)] + pub fn set_epena(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 31usize)) | (((val as u32) & 0x01) << 31usize); + } + } + impl Default for Diepctl { + #[inline(always)] + fn default() -> Diepctl { + Diepctl(0) + } + } + #[doc = "Device IN endpoint FIFO empty interrupt mask register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Diepempmsk(pub u32); + impl Diepempmsk { + #[doc = "IN EP Tx FIFO empty interrupt mask bits"] + #[inline(always)] + pub const fn ineptxfem(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "IN EP Tx FIFO empty interrupt mask bits"] + #[inline(always)] + pub fn set_ineptxfem(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + } + impl Default for Diepempmsk { + #[inline(always)] + fn default() -> Diepempmsk { + Diepempmsk(0) + } + } + #[doc = "Device endpoint interrupt register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Diepint(pub u32); + impl Diepint { + #[doc = "XFRC"] + #[inline(always)] + pub const fn xfrc(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "XFRC"] + #[inline(always)] + pub fn set_xfrc(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "EPDISD"] + #[inline(always)] + pub const fn epdisd(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "EPDISD"] + #[inline(always)] + pub fn set_epdisd(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "TOC"] + #[inline(always)] + pub const fn toc(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "TOC"] + #[inline(always)] + pub fn set_toc(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "ITTXFE"] + #[inline(always)] + pub const fn ittxfe(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "ITTXFE"] + #[inline(always)] + pub fn set_ittxfe(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + #[doc = "INEPNE"] + #[inline(always)] + pub const fn inepne(&self) -> bool { + let val = (self.0 >> 6usize) & 0x01; + val != 0 + } + #[doc = "INEPNE"] + #[inline(always)] + pub fn set_inepne(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 6usize)) | (((val as u32) & 0x01) << 6usize); + } + #[doc = "TXFE"] + #[inline(always)] + pub const fn txfe(&self) -> bool { + let val = (self.0 >> 7usize) & 0x01; + val != 0 + } + #[doc = "TXFE"] + #[inline(always)] + pub fn set_txfe(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 7usize)) | (((val as u32) & 0x01) << 7usize); + } + } + impl Default for Diepint { + #[inline(always)] + fn default() -> Diepint { + Diepint(0) + } + } + #[doc = "Device IN endpoint common interrupt mask register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Diepmsk(pub u32); + impl Diepmsk { + #[doc = "Transfer completed interrupt mask"] + #[inline(always)] + pub const fn xfrcm(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Transfer completed interrupt mask"] + #[inline(always)] + pub fn set_xfrcm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Endpoint disabled interrupt mask"] + #[inline(always)] + pub const fn epdm(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Endpoint disabled interrupt mask"] + #[inline(always)] + pub fn set_epdm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "Timeout condition mask (Non-isochronous endpoints)"] + #[inline(always)] + pub const fn tom(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "Timeout condition mask (Non-isochronous endpoints)"] + #[inline(always)] + pub fn set_tom(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "IN token received when TxFIFO empty mask"] + #[inline(always)] + pub const fn ittxfemsk(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "IN token received when TxFIFO empty mask"] + #[inline(always)] + pub fn set_ittxfemsk(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + #[doc = "IN token received with EP mismatch mask"] + #[inline(always)] + pub const fn inepnmm(&self) -> bool { + let val = (self.0 >> 5usize) & 0x01; + val != 0 + } + #[doc = "IN token received with EP mismatch mask"] + #[inline(always)] + pub fn set_inepnmm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 5usize)) | (((val as u32) & 0x01) << 5usize); + } + #[doc = "IN endpoint NAK effective mask"] + #[inline(always)] + pub const fn inepnem(&self) -> bool { + let val = (self.0 >> 6usize) & 0x01; + val != 0 + } + #[doc = "IN endpoint NAK effective mask"] + #[inline(always)] + pub fn set_inepnem(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 6usize)) | (((val as u32) & 0x01) << 6usize); + } + } + impl Default for Diepmsk { + #[inline(always)] + fn default() -> Diepmsk { + Diepmsk(0) + } + } + #[doc = "Device endpoint transfer size register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Dieptsiz(pub u32); + impl Dieptsiz { + #[doc = "Transfer size"] + #[inline(always)] + pub const fn xfrsiz(&self) -> u32 { + let val = (self.0 >> 0usize) & 0x0007_ffff; + val as u32 + } + #[doc = "Transfer size"] + #[inline(always)] + pub fn set_xfrsiz(&mut self, val: u32) { + self.0 = (self.0 & !(0x0007_ffff << 0usize)) | (((val as u32) & 0x0007_ffff) << 0usize); + } + #[doc = "Packet count"] + #[inline(always)] + pub const fn pktcnt(&self) -> u16 { + let val = (self.0 >> 19usize) & 0x03ff; + val as u16 + } + #[doc = "Packet count"] + #[inline(always)] + pub fn set_pktcnt(&mut self, val: u16) { + self.0 = (self.0 & !(0x03ff << 19usize)) | (((val as u32) & 0x03ff) << 19usize); + } + #[doc = "Multi count"] + #[inline(always)] + pub const fn mcnt(&self) -> u8 { + let val = (self.0 >> 29usize) & 0x03; + val as u8 + } + #[doc = "Multi count"] + #[inline(always)] + pub fn set_mcnt(&mut self, val: u8) { + self.0 = (self.0 & !(0x03 << 29usize)) | (((val as u32) & 0x03) << 29usize); + } + } + impl Default for Dieptsiz { + #[inline(always)] + fn default() -> Dieptsiz { + Dieptsiz(0) + } + } + #[doc = "Device endpoint control register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Doepctl(pub u32); + impl Doepctl { + #[doc = "MPSIZ"] + #[inline(always)] + pub const fn mpsiz(&self) -> u16 { + let val = (self.0 >> 0usize) & 0x07ff; + val as u16 + } + #[doc = "MPSIZ"] + #[inline(always)] + pub fn set_mpsiz(&mut self, val: u16) { + self.0 = (self.0 & !(0x07ff << 0usize)) | (((val as u32) & 0x07ff) << 0usize); + } + #[doc = "USBAEP"] + #[inline(always)] + pub const fn usbaep(&self) -> bool { + let val = (self.0 >> 15usize) & 0x01; + val != 0 + } + #[doc = "USBAEP"] + #[inline(always)] + pub fn set_usbaep(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 15usize)) | (((val as u32) & 0x01) << 15usize); + } + #[doc = "EONUM/DPID"] + #[inline(always)] + pub const fn eonum_dpid(&self) -> bool { + let val = (self.0 >> 16usize) & 0x01; + val != 0 + } + #[doc = "EONUM/DPID"] + #[inline(always)] + pub fn set_eonum_dpid(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 16usize)) | (((val as u32) & 0x01) << 16usize); + } + #[doc = "NAKSTS"] + #[inline(always)] + pub const fn naksts(&self) -> bool { + let val = (self.0 >> 17usize) & 0x01; + val != 0 + } + #[doc = "NAKSTS"] + #[inline(always)] + pub fn set_naksts(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize); + } + #[doc = "EPTYP"] + #[inline(always)] + pub const fn eptyp(&self) -> super::vals::Eptyp { + let val = (self.0 >> 18usize) & 0x03; + super::vals::Eptyp::from_bits(val as u8) + } + #[doc = "EPTYP"] + #[inline(always)] + pub fn set_eptyp(&mut self, val: super::vals::Eptyp) { + self.0 = (self.0 & !(0x03 << 18usize)) | (((val.to_bits() as u32) & 0x03) << 18usize); + } + #[doc = "SNPM"] + #[inline(always)] + pub const fn snpm(&self) -> bool { + let val = (self.0 >> 20usize) & 0x01; + val != 0 + } + #[doc = "SNPM"] + #[inline(always)] + pub fn set_snpm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize); + } + #[doc = "STALL"] + #[inline(always)] + pub const fn stall(&self) -> bool { + let val = (self.0 >> 21usize) & 0x01; + val != 0 + } + #[doc = "STALL"] + #[inline(always)] + pub fn set_stall(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 21usize)) | (((val as u32) & 0x01) << 21usize); + } + #[doc = "CNAK"] + #[inline(always)] + pub const fn cnak(&self) -> bool { + let val = (self.0 >> 26usize) & 0x01; + val != 0 + } + #[doc = "CNAK"] + #[inline(always)] + pub fn set_cnak(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 26usize)) | (((val as u32) & 0x01) << 26usize); + } + #[doc = "SNAK"] + #[inline(always)] + pub const fn snak(&self) -> bool { + let val = (self.0 >> 27usize) & 0x01; + val != 0 + } + #[doc = "SNAK"] + #[inline(always)] + pub fn set_snak(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 27usize)) | (((val as u32) & 0x01) << 27usize); + } + #[doc = "SD0PID/SEVNFRM"] + #[inline(always)] + pub const fn sd0pid_sevnfrm(&self) -> bool { + let val = (self.0 >> 28usize) & 0x01; + val != 0 + } + #[doc = "SD0PID/SEVNFRM"] + #[inline(always)] + pub fn set_sd0pid_sevnfrm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); + } + #[doc = "SODDFRM"] + #[inline(always)] + pub const fn soddfrm(&self) -> bool { + let val = (self.0 >> 29usize) & 0x01; + val != 0 + } + #[doc = "SODDFRM"] + #[inline(always)] + pub fn set_soddfrm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); + } + #[doc = "EPDIS"] + #[inline(always)] + pub const fn epdis(&self) -> bool { + let val = (self.0 >> 30usize) & 0x01; + val != 0 + } + #[doc = "EPDIS"] + #[inline(always)] + pub fn set_epdis(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 30usize)) | (((val as u32) & 0x01) << 30usize); + } + #[doc = "EPENA"] + #[inline(always)] + pub const fn epena(&self) -> bool { + let val = (self.0 >> 31usize) & 0x01; + val != 0 + } + #[doc = "EPENA"] + #[inline(always)] + pub fn set_epena(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 31usize)) | (((val as u32) & 0x01) << 31usize); + } + } + impl Default for Doepctl { + #[inline(always)] + fn default() -> Doepctl { + Doepctl(0) + } + } + #[doc = "Device endpoint interrupt register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Doepint(pub u32); + impl Doepint { + #[doc = "XFRC"] + #[inline(always)] + pub const fn xfrc(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "XFRC"] + #[inline(always)] + pub fn set_xfrc(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "EPDISD"] + #[inline(always)] + pub const fn epdisd(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "EPDISD"] + #[inline(always)] + pub fn set_epdisd(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "STUP"] + #[inline(always)] + pub const fn stup(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "STUP"] + #[inline(always)] + pub fn set_stup(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "OTEPDIS"] + #[inline(always)] + pub const fn otepdis(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "OTEPDIS"] + #[inline(always)] + pub fn set_otepdis(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + #[doc = "B2BSTUP"] + #[inline(always)] + pub const fn b2bstup(&self) -> bool { + let val = (self.0 >> 6usize) & 0x01; + val != 0 + } + #[doc = "B2BSTUP"] + #[inline(always)] + pub fn set_b2bstup(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 6usize)) | (((val as u32) & 0x01) << 6usize); + } + } + impl Default for Doepint { + #[inline(always)] + fn default() -> Doepint { + Doepint(0) + } + } + #[doc = "Device OUT endpoint common interrupt mask register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Doepmsk(pub u32); + impl Doepmsk { + #[doc = "Transfer completed interrupt mask"] + #[inline(always)] + pub const fn xfrcm(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Transfer completed interrupt mask"] + #[inline(always)] + pub fn set_xfrcm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Endpoint disabled interrupt mask"] + #[inline(always)] + pub const fn epdm(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Endpoint disabled interrupt mask"] + #[inline(always)] + pub fn set_epdm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "SETUP phase done mask"] + #[inline(always)] + pub const fn stupm(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "SETUP phase done mask"] + #[inline(always)] + pub fn set_stupm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "OUT token received when endpoint disabled mask"] + #[inline(always)] + pub const fn otepdm(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "OUT token received when endpoint disabled mask"] + #[inline(always)] + pub fn set_otepdm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + } + impl Default for Doepmsk { + #[inline(always)] + fn default() -> Doepmsk { + Doepmsk(0) + } + } + #[doc = "Device OUT endpoint transfer size register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Doeptsiz(pub u32); + impl Doeptsiz { + #[doc = "Transfer size"] + #[inline(always)] + pub const fn xfrsiz(&self) -> u32 { + let val = (self.0 >> 0usize) & 0x0007_ffff; + val as u32 + } + #[doc = "Transfer size"] + #[inline(always)] + pub fn set_xfrsiz(&mut self, val: u32) { + self.0 = (self.0 & !(0x0007_ffff << 0usize)) | (((val as u32) & 0x0007_ffff) << 0usize); + } + #[doc = "Packet count"] + #[inline(always)] + pub const fn pktcnt(&self) -> u16 { + let val = (self.0 >> 19usize) & 0x03ff; + val as u16 + } + #[doc = "Packet count"] + #[inline(always)] + pub fn set_pktcnt(&mut self, val: u16) { + self.0 = (self.0 & !(0x03ff << 19usize)) | (((val as u32) & 0x03ff) << 19usize); + } + #[doc = "Received data PID/SETUP packet count"] + #[inline(always)] + pub const fn rxdpid_stupcnt(&self) -> u8 { + let val = (self.0 >> 29usize) & 0x03; + val as u8 + } + #[doc = "Received data PID/SETUP packet count"] + #[inline(always)] + pub fn set_rxdpid_stupcnt(&mut self, val: u8) { + self.0 = (self.0 & !(0x03 << 29usize)) | (((val as u32) & 0x03) << 29usize); + } + } + impl Default for Doeptsiz { + #[inline(always)] + fn default() -> Doeptsiz { + Doeptsiz(0) + } + } + #[doc = "Device status register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Dsts(pub u32); + impl Dsts { + #[doc = "Suspend status"] + #[inline(always)] + pub const fn suspsts(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Suspend status"] + #[inline(always)] + pub fn set_suspsts(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Enumerated speed"] + #[inline(always)] + pub const fn enumspd(&self) -> super::vals::Dspd { + let val = (self.0 >> 1usize) & 0x03; + super::vals::Dspd::from_bits(val as u8) + } + #[doc = "Enumerated speed"] + #[inline(always)] + pub fn set_enumspd(&mut self, val: super::vals::Dspd) { + self.0 = (self.0 & !(0x03 << 1usize)) | (((val.to_bits() as u32) & 0x03) << 1usize); + } + #[doc = "Erratic error"] + #[inline(always)] + pub const fn eerr(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "Erratic error"] + #[inline(always)] + pub fn set_eerr(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "Frame number of the received SOF"] + #[inline(always)] + pub const fn fnsof(&self) -> u16 { + let val = (self.0 >> 8usize) & 0x3fff; + val as u16 + } + #[doc = "Frame number of the received SOF"] + #[inline(always)] + pub fn set_fnsof(&mut self, val: u16) { + self.0 = (self.0 & !(0x3fff << 8usize)) | (((val as u32) & 0x3fff) << 8usize); + } + } + impl Default for Dsts { + #[inline(always)] + fn default() -> Dsts { + Dsts(0) + } + } + #[doc = "Device IN endpoint transmit FIFO status register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Dtxfsts(pub u32); + impl Dtxfsts { + #[doc = "IN endpoint TxFIFO space available"] + #[inline(always)] + pub const fn ineptfsav(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "IN endpoint TxFIFO space available"] + #[inline(always)] + pub fn set_ineptfsav(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + } + impl Default for Dtxfsts { + #[inline(always)] + fn default() -> Dtxfsts { + Dtxfsts(0) + } + } + #[doc = "Device VBUS discharge time register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Dvbusdis(pub u32); + impl Dvbusdis { + #[doc = "Device VBUS discharge time"] + #[inline(always)] + pub const fn vbusdt(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "Device VBUS discharge time"] + #[inline(always)] + pub fn set_vbusdt(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + } + impl Default for Dvbusdis { + #[inline(always)] + fn default() -> Dvbusdis { + Dvbusdis(0) + } + } + #[doc = "Device VBUS pulsing time register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Dvbuspulse(pub u32); + impl Dvbuspulse { + #[doc = "Device VBUS pulsing time"] + #[inline(always)] + pub const fn dvbusp(&self) -> u16 { + let val = (self.0 >> 0usize) & 0x0fff; + val as u16 + } + #[doc = "Device VBUS pulsing time"] + #[inline(always)] + pub fn set_dvbusp(&mut self, val: u16) { + self.0 = (self.0 & !(0x0fff << 0usize)) | (((val as u32) & 0x0fff) << 0usize); + } + } + impl Default for Dvbuspulse { + #[inline(always)] + fn default() -> Dvbuspulse { + Dvbuspulse(0) + } + } + #[doc = "FIFO register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Fifo(pub u32); + impl Fifo { + #[doc = "Data"] + #[inline(always)] + pub const fn data(&self) -> u32 { + let val = (self.0 >> 0usize) & 0xffff_ffff; + val as u32 + } + #[doc = "Data"] + #[inline(always)] + pub fn set_data(&mut self, val: u32) { + self.0 = (self.0 & !(0xffff_ffff << 0usize)) | (((val as u32) & 0xffff_ffff) << 0usize); + } + } + impl Default for Fifo { + #[inline(always)] + fn default() -> Fifo { + Fifo(0) + } + } + #[doc = "FIFO size register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Fsiz(pub u32); + impl Fsiz { + #[doc = "RAM start address"] + #[inline(always)] + pub const fn sa(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "RAM start address"] + #[inline(always)] + pub fn set_sa(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + #[doc = "FIFO depth"] + #[inline(always)] + pub const fn fd(&self) -> u16 { + let val = (self.0 >> 16usize) & 0xffff; + val as u16 + } + #[doc = "FIFO depth"] + #[inline(always)] + pub fn set_fd(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 16usize)) | (((val as u32) & 0xffff) << 16usize); + } + } + impl Default for Fsiz { + #[inline(always)] + fn default() -> Fsiz { + Fsiz(0) + } + } + #[doc = "AHB configuration register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Gahbcfg(pub u32); + impl Gahbcfg { + #[doc = "Global interrupt mask"] + #[inline(always)] + pub const fn gint(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Global interrupt mask"] + #[inline(always)] + pub fn set_gint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Burst length/type"] + #[inline(always)] + pub const fn hbstlen(&self) -> u8 { + let val = (self.0 >> 1usize) & 0x0f; + val as u8 + } + #[doc = "Burst length/type"] + #[inline(always)] + pub fn set_hbstlen(&mut self, val: u8) { + self.0 = (self.0 & !(0x0f << 1usize)) | (((val as u32) & 0x0f) << 1usize); + } + #[doc = "DMA enable"] + #[inline(always)] + pub const fn dmaen(&self) -> bool { + let val = (self.0 >> 5usize) & 0x01; + val != 0 + } + #[doc = "DMA enable"] + #[inline(always)] + pub fn set_dmaen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 5usize)) | (((val as u32) & 0x01) << 5usize); + } + #[doc = "TxFIFO empty level"] + #[inline(always)] + pub const fn txfelvl(&self) -> bool { + let val = (self.0 >> 7usize) & 0x01; + val != 0 + } + #[doc = "TxFIFO empty level"] + #[inline(always)] + pub fn set_txfelvl(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 7usize)) | (((val as u32) & 0x01) << 7usize); + } + #[doc = "Periodic TxFIFO empty level"] + #[inline(always)] + pub const fn ptxfelvl(&self) -> bool { + let val = (self.0 >> 8usize) & 0x01; + val != 0 + } + #[doc = "Periodic TxFIFO empty level"] + #[inline(always)] + pub fn set_ptxfelvl(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 8usize)) | (((val as u32) & 0x01) << 8usize); + } + } + impl Default for Gahbcfg { + #[inline(always)] + fn default() -> Gahbcfg { + Gahbcfg(0) + } + } + #[doc = "General core configuration register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct GccfgV1(pub u32); + impl GccfgV1 { + #[doc = "Power down"] + #[inline(always)] + pub const fn pwrdwn(&self) -> bool { + let val = (self.0 >> 16usize) & 0x01; + val != 0 + } + #[doc = "Power down"] + #[inline(always)] + pub fn set_pwrdwn(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 16usize)) | (((val as u32) & 0x01) << 16usize); + } + #[doc = "Enable the VBUS \"A\" sensing device"] + #[inline(always)] + pub const fn vbusasen(&self) -> bool { + let val = (self.0 >> 18usize) & 0x01; + val != 0 + } + #[doc = "Enable the VBUS \"A\" sensing device"] + #[inline(always)] + pub fn set_vbusasen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 18usize)) | (((val as u32) & 0x01) << 18usize); + } + #[doc = "Enable the VBUS \"B\" sensing device"] + #[inline(always)] + pub const fn vbusbsen(&self) -> bool { + let val = (self.0 >> 19usize) & 0x01; + val != 0 + } + #[doc = "Enable the VBUS \"B\" sensing device"] + #[inline(always)] + pub fn set_vbusbsen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 19usize)) | (((val as u32) & 0x01) << 19usize); + } + #[doc = "SOF output enable"] + #[inline(always)] + pub const fn sofouten(&self) -> bool { + let val = (self.0 >> 20usize) & 0x01; + val != 0 + } + #[doc = "SOF output enable"] + #[inline(always)] + pub fn set_sofouten(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize); + } + #[doc = "VBUS sensing disable"] + #[inline(always)] + pub const fn novbussens(&self) -> bool { + let val = (self.0 >> 21usize) & 0x01; + val != 0 + } + #[doc = "VBUS sensing disable"] + #[inline(always)] + pub fn set_novbussens(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 21usize)) | (((val as u32) & 0x01) << 21usize); + } + } + impl Default for GccfgV1 { + #[inline(always)] + fn default() -> GccfgV1 { + GccfgV1(0) + } + } + #[doc = "General core configuration register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct GccfgV2(pub u32); + impl GccfgV2 { + #[doc = "Data contact detection (DCD) status"] + #[inline(always)] + pub const fn dcdet(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Data contact detection (DCD) status"] + #[inline(always)] + pub fn set_dcdet(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Primary detection (PD) status"] + #[inline(always)] + pub const fn pdet(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Primary detection (PD) status"] + #[inline(always)] + pub fn set_pdet(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "Secondary detection (SD) status"] + #[inline(always)] + pub const fn sdet(&self) -> bool { + let val = (self.0 >> 2usize) & 0x01; + val != 0 + } + #[doc = "Secondary detection (SD) status"] + #[inline(always)] + pub fn set_sdet(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize); + } + #[doc = "DM pull-up detection status"] + #[inline(always)] + pub const fn ps2det(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "DM pull-up detection status"] + #[inline(always)] + pub fn set_ps2det(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "Power down"] + #[inline(always)] + pub const fn pwrdwn(&self) -> bool { + let val = (self.0 >> 16usize) & 0x01; + val != 0 + } + #[doc = "Power down"] + #[inline(always)] + pub fn set_pwrdwn(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 16usize)) | (((val as u32) & 0x01) << 16usize); + } + #[doc = "Battery charging detector (BCD) enable"] + #[inline(always)] + pub const fn bcden(&self) -> bool { + let val = (self.0 >> 17usize) & 0x01; + val != 0 + } + #[doc = "Battery charging detector (BCD) enable"] + #[inline(always)] + pub fn set_bcden(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize); + } + #[doc = "Data contact detection (DCD) mode enable"] + #[inline(always)] + pub const fn dcden(&self) -> bool { + let val = (self.0 >> 18usize) & 0x01; + val != 0 + } + #[doc = "Data contact detection (DCD) mode enable"] + #[inline(always)] + pub fn set_dcden(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 18usize)) | (((val as u32) & 0x01) << 18usize); + } + #[doc = "Primary detection (PD) mode enable"] + #[inline(always)] + pub const fn pden(&self) -> bool { + let val = (self.0 >> 19usize) & 0x01; + val != 0 + } + #[doc = "Primary detection (PD) mode enable"] + #[inline(always)] + pub fn set_pden(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 19usize)) | (((val as u32) & 0x01) << 19usize); + } + #[doc = "Secondary detection (SD) mode enable"] + #[inline(always)] + pub const fn sden(&self) -> bool { + let val = (self.0 >> 20usize) & 0x01; + val != 0 + } + #[doc = "Secondary detection (SD) mode enable"] + #[inline(always)] + pub fn set_sden(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize); + } + #[doc = "USB VBUS detection enable"] + #[inline(always)] + pub const fn vbden(&self) -> bool { + let val = (self.0 >> 21usize) & 0x01; + val != 0 + } + #[doc = "USB VBUS detection enable"] + #[inline(always)] + pub fn set_vbden(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 21usize)) | (((val as u32) & 0x01) << 21usize); + } + #[doc = "Internal high-speed PHY enable."] + #[inline(always)] + pub const fn phyhsen(&self) -> bool { + let val = (self.0 >> 23usize) & 0x01; + val != 0 + } + #[doc = "Internal high-speed PHY enable."] + #[inline(always)] + pub fn set_phyhsen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 23usize)) | (((val as u32) & 0x01) << 23usize); + } + } + impl Default for GccfgV2 { + #[inline(always)] + fn default() -> GccfgV2 { + GccfgV2(0) + } + } + #[doc = "I2C access register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Gi2cctl(pub u32); + impl Gi2cctl { + #[doc = "I2C Read/Write Data"] + #[inline(always)] + pub const fn rwdata(&self) -> u8 { + let val = (self.0 >> 0usize) & 0xff; + val as u8 + } + #[doc = "I2C Read/Write Data"] + #[inline(always)] + pub fn set_rwdata(&mut self, val: u8) { + self.0 = (self.0 & !(0xff << 0usize)) | (((val as u32) & 0xff) << 0usize); + } + #[doc = "I2C Register Address"] + #[inline(always)] + pub const fn regaddr(&self) -> u8 { + let val = (self.0 >> 8usize) & 0xff; + val as u8 + } + #[doc = "I2C Register Address"] + #[inline(always)] + pub fn set_regaddr(&mut self, val: u8) { + self.0 = (self.0 & !(0xff << 8usize)) | (((val as u32) & 0xff) << 8usize); + } + #[doc = "I2C Address"] + #[inline(always)] + pub const fn addr(&self) -> u8 { + let val = (self.0 >> 16usize) & 0x7f; + val as u8 + } + #[doc = "I2C Address"] + #[inline(always)] + pub fn set_addr(&mut self, val: u8) { + self.0 = (self.0 & !(0x7f << 16usize)) | (((val as u32) & 0x7f) << 16usize); + } + #[doc = "I2C Enable"] + #[inline(always)] + pub const fn i2cen(&self) -> bool { + let val = (self.0 >> 23usize) & 0x01; + val != 0 + } + #[doc = "I2C Enable"] + #[inline(always)] + pub fn set_i2cen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 23usize)) | (((val as u32) & 0x01) << 23usize); + } + #[doc = "I2C ACK"] + #[inline(always)] + pub const fn ack(&self) -> bool { + let val = (self.0 >> 24usize) & 0x01; + val != 0 + } + #[doc = "I2C ACK"] + #[inline(always)] + pub fn set_ack(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 24usize)) | (((val as u32) & 0x01) << 24usize); + } + #[doc = "I2C Device Address"] + #[inline(always)] + pub const fn i2cdevadr(&self) -> u8 { + let val = (self.0 >> 26usize) & 0x03; + val as u8 + } + #[doc = "I2C Device Address"] + #[inline(always)] + pub fn set_i2cdevadr(&mut self, val: u8) { + self.0 = (self.0 & !(0x03 << 26usize)) | (((val as u32) & 0x03) << 26usize); + } + #[doc = "I2C DatSe0 USB mode"] + #[inline(always)] + pub const fn i2cdatse0(&self) -> bool { + let val = (self.0 >> 28usize) & 0x01; + val != 0 + } + #[doc = "I2C DatSe0 USB mode"] + #[inline(always)] + pub fn set_i2cdatse0(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); + } + #[doc = "Read/Write Indicator"] + #[inline(always)] + pub const fn rw(&self) -> bool { + let val = (self.0 >> 30usize) & 0x01; + val != 0 + } + #[doc = "Read/Write Indicator"] + #[inline(always)] + pub fn set_rw(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 30usize)) | (((val as u32) & 0x01) << 30usize); + } + #[doc = "I2C Busy/Done"] + #[inline(always)] + pub const fn bsydne(&self) -> bool { + let val = (self.0 >> 31usize) & 0x01; + val != 0 + } + #[doc = "I2C Busy/Done"] + #[inline(always)] + pub fn set_bsydne(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 31usize)) | (((val as u32) & 0x01) << 31usize); + } + } + impl Default for Gi2cctl { + #[inline(always)] + fn default() -> Gi2cctl { + Gi2cctl(0) + } + } + #[doc = "Interrupt mask register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Gintmsk(pub u32); + impl Gintmsk { + #[doc = "Mode mismatch interrupt mask"] + #[inline(always)] + pub const fn mmism(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Mode mismatch interrupt mask"] + #[inline(always)] + pub fn set_mmism(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "OTG interrupt mask"] + #[inline(always)] + pub const fn otgint(&self) -> bool { + let val = (self.0 >> 2usize) & 0x01; + val != 0 + } + #[doc = "OTG interrupt mask"] + #[inline(always)] + pub fn set_otgint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize); + } + #[doc = "Start of frame mask"] + #[inline(always)] + pub const fn sofm(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "Start of frame mask"] + #[inline(always)] + pub fn set_sofm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "Receive FIFO non-empty mask"] + #[inline(always)] + pub const fn rxflvlm(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "Receive FIFO non-empty mask"] + #[inline(always)] + pub fn set_rxflvlm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + #[doc = "Non-periodic TxFIFO empty mask"] + #[inline(always)] + pub const fn nptxfem(&self) -> bool { + let val = (self.0 >> 5usize) & 0x01; + val != 0 + } + #[doc = "Non-periodic TxFIFO empty mask"] + #[inline(always)] + pub fn set_nptxfem(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 5usize)) | (((val as u32) & 0x01) << 5usize); + } + #[doc = "Global non-periodic IN NAK effective mask"] + #[inline(always)] + pub const fn ginakeffm(&self) -> bool { + let val = (self.0 >> 6usize) & 0x01; + val != 0 + } + #[doc = "Global non-periodic IN NAK effective mask"] + #[inline(always)] + pub fn set_ginakeffm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 6usize)) | (((val as u32) & 0x01) << 6usize); + } + #[doc = "Global OUT NAK effective mask"] + #[inline(always)] + pub const fn gonakeffm(&self) -> bool { + let val = (self.0 >> 7usize) & 0x01; + val != 0 + } + #[doc = "Global OUT NAK effective mask"] + #[inline(always)] + pub fn set_gonakeffm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 7usize)) | (((val as u32) & 0x01) << 7usize); + } + #[doc = "Early suspend mask"] + #[inline(always)] + pub const fn esuspm(&self) -> bool { + let val = (self.0 >> 10usize) & 0x01; + val != 0 + } + #[doc = "Early suspend mask"] + #[inline(always)] + pub fn set_esuspm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 10usize)) | (((val as u32) & 0x01) << 10usize); + } + #[doc = "USB suspend mask"] + #[inline(always)] + pub const fn usbsuspm(&self) -> bool { + let val = (self.0 >> 11usize) & 0x01; + val != 0 + } + #[doc = "USB suspend mask"] + #[inline(always)] + pub fn set_usbsuspm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 11usize)) | (((val as u32) & 0x01) << 11usize); + } + #[doc = "USB reset mask"] + #[inline(always)] + pub const fn usbrst(&self) -> bool { + let val = (self.0 >> 12usize) & 0x01; + val != 0 + } + #[doc = "USB reset mask"] + #[inline(always)] + pub fn set_usbrst(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 12usize)) | (((val as u32) & 0x01) << 12usize); + } + #[doc = "Enumeration done mask"] + #[inline(always)] + pub const fn enumdnem(&self) -> bool { + let val = (self.0 >> 13usize) & 0x01; + val != 0 + } + #[doc = "Enumeration done mask"] + #[inline(always)] + pub fn set_enumdnem(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 13usize)) | (((val as u32) & 0x01) << 13usize); + } + #[doc = "Isochronous OUT packet dropped interrupt mask"] + #[inline(always)] + pub const fn isoodrpm(&self) -> bool { + let val = (self.0 >> 14usize) & 0x01; + val != 0 + } + #[doc = "Isochronous OUT packet dropped interrupt mask"] + #[inline(always)] + pub fn set_isoodrpm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 14usize)) | (((val as u32) & 0x01) << 14usize); + } + #[doc = "End of periodic frame interrupt mask"] + #[inline(always)] + pub const fn eopfm(&self) -> bool { + let val = (self.0 >> 15usize) & 0x01; + val != 0 + } + #[doc = "End of periodic frame interrupt mask"] + #[inline(always)] + pub fn set_eopfm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 15usize)) | (((val as u32) & 0x01) << 15usize); + } + #[doc = "Endpoint mismatch interrupt mask"] + #[inline(always)] + pub const fn epmism(&self) -> bool { + let val = (self.0 >> 17usize) & 0x01; + val != 0 + } + #[doc = "Endpoint mismatch interrupt mask"] + #[inline(always)] + pub fn set_epmism(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize); + } + #[doc = "IN endpoints interrupt mask"] + #[inline(always)] + pub const fn iepint(&self) -> bool { + let val = (self.0 >> 18usize) & 0x01; + val != 0 + } + #[doc = "IN endpoints interrupt mask"] + #[inline(always)] + pub fn set_iepint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 18usize)) | (((val as u32) & 0x01) << 18usize); + } + #[doc = "OUT endpoints interrupt mask"] + #[inline(always)] + pub const fn oepint(&self) -> bool { + let val = (self.0 >> 19usize) & 0x01; + val != 0 + } + #[doc = "OUT endpoints interrupt mask"] + #[inline(always)] + pub fn set_oepint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 19usize)) | (((val as u32) & 0x01) << 19usize); + } + #[doc = "Incomplete isochronous IN transfer mask"] + #[inline(always)] + pub const fn iisoixfrm(&self) -> bool { + let val = (self.0 >> 20usize) & 0x01; + val != 0 + } + #[doc = "Incomplete isochronous IN transfer mask"] + #[inline(always)] + pub fn set_iisoixfrm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize); + } + #[doc = "Incomplete periodic transfer mask (host mode) / Incomplete isochronous OUT transfer mask (device mode)"] + #[inline(always)] + pub const fn ipxfrm_iisooxfrm(&self) -> bool { + let val = (self.0 >> 21usize) & 0x01; + val != 0 + } + #[doc = "Incomplete periodic transfer mask (host mode) / Incomplete isochronous OUT transfer mask (device mode)"] + #[inline(always)] + pub fn set_ipxfrm_iisooxfrm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 21usize)) | (((val as u32) & 0x01) << 21usize); + } + #[doc = "Data fetch suspended mask"] + #[inline(always)] + pub const fn fsuspm(&self) -> bool { + let val = (self.0 >> 22usize) & 0x01; + val != 0 + } + #[doc = "Data fetch suspended mask"] + #[inline(always)] + pub fn set_fsuspm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 22usize)) | (((val as u32) & 0x01) << 22usize); + } + #[doc = "Reset detected interrupt mask"] + #[inline(always)] + pub const fn rstde(&self) -> bool { + let val = (self.0 >> 23usize) & 0x01; + val != 0 + } + #[doc = "Reset detected interrupt mask"] + #[inline(always)] + pub fn set_rstde(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 23usize)) | (((val as u32) & 0x01) << 23usize); + } + #[doc = "Host port interrupt mask"] + #[inline(always)] + pub const fn prtim(&self) -> bool { + let val = (self.0 >> 24usize) & 0x01; + val != 0 + } + #[doc = "Host port interrupt mask"] + #[inline(always)] + pub fn set_prtim(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 24usize)) | (((val as u32) & 0x01) << 24usize); + } + #[doc = "Host channels interrupt mask"] + #[inline(always)] + pub const fn hcim(&self) -> bool { + let val = (self.0 >> 25usize) & 0x01; + val != 0 + } + #[doc = "Host channels interrupt mask"] + #[inline(always)] + pub fn set_hcim(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 25usize)) | (((val as u32) & 0x01) << 25usize); + } + #[doc = "Periodic TxFIFO empty mask"] + #[inline(always)] + pub const fn ptxfem(&self) -> bool { + let val = (self.0 >> 26usize) & 0x01; + val != 0 + } + #[doc = "Periodic TxFIFO empty mask"] + #[inline(always)] + pub fn set_ptxfem(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 26usize)) | (((val as u32) & 0x01) << 26usize); + } + #[doc = "LPM interrupt mask"] + #[inline(always)] + pub const fn lpmintm(&self) -> bool { + let val = (self.0 >> 27usize) & 0x01; + val != 0 + } + #[doc = "LPM interrupt mask"] + #[inline(always)] + pub fn set_lpmintm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 27usize)) | (((val as u32) & 0x01) << 27usize); + } + #[doc = "Connector ID status change mask"] + #[inline(always)] + pub const fn cidschgm(&self) -> bool { + let val = (self.0 >> 28usize) & 0x01; + val != 0 + } + #[doc = "Connector ID status change mask"] + #[inline(always)] + pub fn set_cidschgm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); + } + #[doc = "Disconnect detected interrupt mask"] + #[inline(always)] + pub const fn discint(&self) -> bool { + let val = (self.0 >> 29usize) & 0x01; + val != 0 + } + #[doc = "Disconnect detected interrupt mask"] + #[inline(always)] + pub fn set_discint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); + } + #[doc = "Session request/new session detected interrupt mask"] + #[inline(always)] + pub const fn srqim(&self) -> bool { + let val = (self.0 >> 30usize) & 0x01; + val != 0 + } + #[doc = "Session request/new session detected interrupt mask"] + #[inline(always)] + pub fn set_srqim(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 30usize)) | (((val as u32) & 0x01) << 30usize); + } + #[doc = "Resume/remote wakeup detected interrupt mask"] + #[inline(always)] + pub const fn wuim(&self) -> bool { + let val = (self.0 >> 31usize) & 0x01; + val != 0 + } + #[doc = "Resume/remote wakeup detected interrupt mask"] + #[inline(always)] + pub fn set_wuim(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 31usize)) | (((val as u32) & 0x01) << 31usize); + } + } + impl Default for Gintmsk { + #[inline(always)] + fn default() -> Gintmsk { + Gintmsk(0) + } + } + #[doc = "Core interrupt register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Gintsts(pub u32); + impl Gintsts { + #[doc = "Current mode of operation"] + #[inline(always)] + pub const fn cmod(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Current mode of operation"] + #[inline(always)] + pub fn set_cmod(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Mode mismatch interrupt"] + #[inline(always)] + pub const fn mmis(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Mode mismatch interrupt"] + #[inline(always)] + pub fn set_mmis(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "OTG interrupt"] + #[inline(always)] + pub const fn otgint(&self) -> bool { + let val = (self.0 >> 2usize) & 0x01; + val != 0 + } + #[doc = "OTG interrupt"] + #[inline(always)] + pub fn set_otgint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize); + } + #[doc = "Start of frame"] + #[inline(always)] + pub const fn sof(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "Start of frame"] + #[inline(always)] + pub fn set_sof(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "RxFIFO non-empty"] + #[inline(always)] + pub const fn rxflvl(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "RxFIFO non-empty"] + #[inline(always)] + pub fn set_rxflvl(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + #[doc = "Non-periodic TxFIFO empty"] + #[inline(always)] + pub const fn nptxfe(&self) -> bool { + let val = (self.0 >> 5usize) & 0x01; + val != 0 + } + #[doc = "Non-periodic TxFIFO empty"] + #[inline(always)] + pub fn set_nptxfe(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 5usize)) | (((val as u32) & 0x01) << 5usize); + } + #[doc = "Global IN non-periodic NAK effective"] + #[inline(always)] + pub const fn ginakeff(&self) -> bool { + let val = (self.0 >> 6usize) & 0x01; + val != 0 + } + #[doc = "Global IN non-periodic NAK effective"] + #[inline(always)] + pub fn set_ginakeff(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 6usize)) | (((val as u32) & 0x01) << 6usize); + } + #[doc = "Global OUT NAK effective"] + #[inline(always)] + pub const fn goutnakeff(&self) -> bool { + let val = (self.0 >> 7usize) & 0x01; + val != 0 + } + #[doc = "Global OUT NAK effective"] + #[inline(always)] + pub fn set_goutnakeff(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 7usize)) | (((val as u32) & 0x01) << 7usize); + } + #[doc = "Early suspend"] + #[inline(always)] + pub const fn esusp(&self) -> bool { + let val = (self.0 >> 10usize) & 0x01; + val != 0 + } + #[doc = "Early suspend"] + #[inline(always)] + pub fn set_esusp(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 10usize)) | (((val as u32) & 0x01) << 10usize); + } + #[doc = "USB suspend"] + #[inline(always)] + pub const fn usbsusp(&self) -> bool { + let val = (self.0 >> 11usize) & 0x01; + val != 0 + } + #[doc = "USB suspend"] + #[inline(always)] + pub fn set_usbsusp(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 11usize)) | (((val as u32) & 0x01) << 11usize); + } + #[doc = "USB reset"] + #[inline(always)] + pub const fn usbrst(&self) -> bool { + let val = (self.0 >> 12usize) & 0x01; + val != 0 + } + #[doc = "USB reset"] + #[inline(always)] + pub fn set_usbrst(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 12usize)) | (((val as u32) & 0x01) << 12usize); + } + #[doc = "Enumeration done"] + #[inline(always)] + pub const fn enumdne(&self) -> bool { + let val = (self.0 >> 13usize) & 0x01; + val != 0 + } + #[doc = "Enumeration done"] + #[inline(always)] + pub fn set_enumdne(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 13usize)) | (((val as u32) & 0x01) << 13usize); + } + #[doc = "Isochronous OUT packet dropped interrupt"] + #[inline(always)] + pub const fn isoodrp(&self) -> bool { + let val = (self.0 >> 14usize) & 0x01; + val != 0 + } + #[doc = "Isochronous OUT packet dropped interrupt"] + #[inline(always)] + pub fn set_isoodrp(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 14usize)) | (((val as u32) & 0x01) << 14usize); + } + #[doc = "End of periodic frame interrupt"] + #[inline(always)] + pub const fn eopf(&self) -> bool { + let val = (self.0 >> 15usize) & 0x01; + val != 0 + } + #[doc = "End of periodic frame interrupt"] + #[inline(always)] + pub fn set_eopf(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 15usize)) | (((val as u32) & 0x01) << 15usize); + } + #[doc = "IN endpoint interrupt"] + #[inline(always)] + pub const fn iepint(&self) -> bool { + let val = (self.0 >> 18usize) & 0x01; + val != 0 + } + #[doc = "IN endpoint interrupt"] + #[inline(always)] + pub fn set_iepint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 18usize)) | (((val as u32) & 0x01) << 18usize); + } + #[doc = "OUT endpoint interrupt"] + #[inline(always)] + pub const fn oepint(&self) -> bool { + let val = (self.0 >> 19usize) & 0x01; + val != 0 + } + #[doc = "OUT endpoint interrupt"] + #[inline(always)] + pub fn set_oepint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 19usize)) | (((val as u32) & 0x01) << 19usize); + } + #[doc = "Incomplete isochronous IN transfer"] + #[inline(always)] + pub const fn iisoixfr(&self) -> bool { + let val = (self.0 >> 20usize) & 0x01; + val != 0 + } + #[doc = "Incomplete isochronous IN transfer"] + #[inline(always)] + pub fn set_iisoixfr(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize); + } + #[doc = "Incomplete periodic transfer (host mode) / Incomplete isochronous OUT transfer (device mode)"] + #[inline(always)] + pub const fn ipxfr_incompisoout(&self) -> bool { + let val = (self.0 >> 21usize) & 0x01; + val != 0 + } + #[doc = "Incomplete periodic transfer (host mode) / Incomplete isochronous OUT transfer (device mode)"] + #[inline(always)] + pub fn set_ipxfr_incompisoout(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 21usize)) | (((val as u32) & 0x01) << 21usize); + } + #[doc = "Data fetch suspended"] + #[inline(always)] + pub const fn datafsusp(&self) -> bool { + let val = (self.0 >> 22usize) & 0x01; + val != 0 + } + #[doc = "Data fetch suspended"] + #[inline(always)] + pub fn set_datafsusp(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 22usize)) | (((val as u32) & 0x01) << 22usize); + } + #[doc = "Host port interrupt"] + #[inline(always)] + pub const fn hprtint(&self) -> bool { + let val = (self.0 >> 24usize) & 0x01; + val != 0 + } + #[doc = "Host port interrupt"] + #[inline(always)] + pub fn set_hprtint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 24usize)) | (((val as u32) & 0x01) << 24usize); + } + #[doc = "Host channels interrupt"] + #[inline(always)] + pub const fn hcint(&self) -> bool { + let val = (self.0 >> 25usize) & 0x01; + val != 0 + } + #[doc = "Host channels interrupt"] + #[inline(always)] + pub fn set_hcint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 25usize)) | (((val as u32) & 0x01) << 25usize); + } + #[doc = "Periodic TxFIFO empty"] + #[inline(always)] + pub const fn ptxfe(&self) -> bool { + let val = (self.0 >> 26usize) & 0x01; + val != 0 + } + #[doc = "Periodic TxFIFO empty"] + #[inline(always)] + pub fn set_ptxfe(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 26usize)) | (((val as u32) & 0x01) << 26usize); + } + #[doc = "Connector ID status change"] + #[inline(always)] + pub const fn cidschg(&self) -> bool { + let val = (self.0 >> 28usize) & 0x01; + val != 0 + } + #[doc = "Connector ID status change"] + #[inline(always)] + pub fn set_cidschg(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); + } + #[doc = "Disconnect detected interrupt"] + #[inline(always)] + pub const fn discint(&self) -> bool { + let val = (self.0 >> 29usize) & 0x01; + val != 0 + } + #[doc = "Disconnect detected interrupt"] + #[inline(always)] + pub fn set_discint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); + } + #[doc = "Session request/new session detected interrupt"] + #[inline(always)] + pub const fn srqint(&self) -> bool { + let val = (self.0 >> 30usize) & 0x01; + val != 0 + } + #[doc = "Session request/new session detected interrupt"] + #[inline(always)] + pub fn set_srqint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 30usize)) | (((val as u32) & 0x01) << 30usize); + } + #[doc = "Resume/remote wakeup detected interrupt"] + #[inline(always)] + pub const fn wkupint(&self) -> bool { + let val = (self.0 >> 31usize) & 0x01; + val != 0 + } + #[doc = "Resume/remote wakeup detected interrupt"] + #[inline(always)] + pub fn set_wkupint(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 31usize)) | (((val as u32) & 0x01) << 31usize); + } + } + impl Default for Gintsts { + #[inline(always)] + fn default() -> Gintsts { + Gintsts(0) + } + } + #[doc = "Core LPM configuration register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Glpmcfg(pub u32); + impl Glpmcfg { + #[doc = "LPM support enable"] + #[inline(always)] + pub const fn lpmen(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "LPM support enable"] + #[inline(always)] + pub fn set_lpmen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "LPM token acknowledge enable"] + #[inline(always)] + pub const fn lpmack(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "LPM token acknowledge enable"] + #[inline(always)] + pub fn set_lpmack(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "Best effort service latency"] + #[inline(always)] + pub const fn besl(&self) -> u8 { + let val = (self.0 >> 2usize) & 0x0f; + val as u8 + } + #[doc = "Best effort service latency"] + #[inline(always)] + pub fn set_besl(&mut self, val: u8) { + self.0 = (self.0 & !(0x0f << 2usize)) | (((val as u32) & 0x0f) << 2usize); + } + #[doc = "bRemoteWake value"] + #[inline(always)] + pub const fn remwake(&self) -> bool { + let val = (self.0 >> 6usize) & 0x01; + val != 0 + } + #[doc = "bRemoteWake value"] + #[inline(always)] + pub fn set_remwake(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 6usize)) | (((val as u32) & 0x01) << 6usize); + } + #[doc = "L1 Shallow Sleep enable"] + #[inline(always)] + pub const fn l1ssen(&self) -> bool { + let val = (self.0 >> 7usize) & 0x01; + val != 0 + } + #[doc = "L1 Shallow Sleep enable"] + #[inline(always)] + pub fn set_l1ssen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 7usize)) | (((val as u32) & 0x01) << 7usize); + } + #[doc = "BESL threshold"] + #[inline(always)] + pub const fn beslthrs(&self) -> u8 { + let val = (self.0 >> 8usize) & 0x0f; + val as u8 + } + #[doc = "BESL threshold"] + #[inline(always)] + pub fn set_beslthrs(&mut self, val: u8) { + self.0 = (self.0 & !(0x0f << 8usize)) | (((val as u32) & 0x0f) << 8usize); + } + #[doc = "L1 deep sleep enable"] + #[inline(always)] + pub const fn l1dsen(&self) -> bool { + let val = (self.0 >> 12usize) & 0x01; + val != 0 + } + #[doc = "L1 deep sleep enable"] + #[inline(always)] + pub fn set_l1dsen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 12usize)) | (((val as u32) & 0x01) << 12usize); + } + #[doc = "LPM response"] + #[inline(always)] + pub const fn lpmrst(&self) -> u8 { + let val = (self.0 >> 13usize) & 0x03; + val as u8 + } + #[doc = "LPM response"] + #[inline(always)] + pub fn set_lpmrst(&mut self, val: u8) { + self.0 = (self.0 & !(0x03 << 13usize)) | (((val as u32) & 0x03) << 13usize); + } + #[doc = "Port sleep status"] + #[inline(always)] + pub const fn slpsts(&self) -> bool { + let val = (self.0 >> 15usize) & 0x01; + val != 0 + } + #[doc = "Port sleep status"] + #[inline(always)] + pub fn set_slpsts(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 15usize)) | (((val as u32) & 0x01) << 15usize); + } + #[doc = "Sleep State Resume OK"] + #[inline(always)] + pub const fn l1rsmok(&self) -> bool { + let val = (self.0 >> 16usize) & 0x01; + val != 0 + } + #[doc = "Sleep State Resume OK"] + #[inline(always)] + pub fn set_l1rsmok(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 16usize)) | (((val as u32) & 0x01) << 16usize); + } + #[doc = "LPM Channel Index"] + #[inline(always)] + pub const fn lpmchidx(&self) -> u8 { + let val = (self.0 >> 17usize) & 0x0f; + val as u8 + } + #[doc = "LPM Channel Index"] + #[inline(always)] + pub fn set_lpmchidx(&mut self, val: u8) { + self.0 = (self.0 & !(0x0f << 17usize)) | (((val as u32) & 0x0f) << 17usize); + } + #[doc = "LPM retry count"] + #[inline(always)] + pub const fn lpmrcnt(&self) -> u8 { + let val = (self.0 >> 21usize) & 0x07; + val as u8 + } + #[doc = "LPM retry count"] + #[inline(always)] + pub fn set_lpmrcnt(&mut self, val: u8) { + self.0 = (self.0 & !(0x07 << 21usize)) | (((val as u32) & 0x07) << 21usize); + } + #[doc = "Send LPM transaction"] + #[inline(always)] + pub const fn sndlpm(&self) -> bool { + let val = (self.0 >> 24usize) & 0x01; + val != 0 + } + #[doc = "Send LPM transaction"] + #[inline(always)] + pub fn set_sndlpm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 24usize)) | (((val as u32) & 0x01) << 24usize); + } + #[doc = "LPM retry count status"] + #[inline(always)] + pub const fn lpmrcntsts(&self) -> u8 { + let val = (self.0 >> 25usize) & 0x07; + val as u8 + } + #[doc = "LPM retry count status"] + #[inline(always)] + pub fn set_lpmrcntsts(&mut self, val: u8) { + self.0 = (self.0 & !(0x07 << 25usize)) | (((val as u32) & 0x07) << 25usize); + } + #[doc = "Enable best effort service latency"] + #[inline(always)] + pub const fn enbesl(&self) -> bool { + let val = (self.0 >> 28usize) & 0x01; + val != 0 + } + #[doc = "Enable best effort service latency"] + #[inline(always)] + pub fn set_enbesl(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); + } + } + impl Default for Glpmcfg { + #[inline(always)] + fn default() -> Glpmcfg { + Glpmcfg(0) + } + } + #[doc = "Control and status register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Gotgctl(pub u32); + impl Gotgctl { + #[doc = "Session request success"] + #[inline(always)] + pub const fn srqscs(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Session request success"] + #[inline(always)] + pub fn set_srqscs(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Session request"] + #[inline(always)] + pub const fn srq(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Session request"] + #[inline(always)] + pub fn set_srq(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "VBUS valid override enable"] + #[inline(always)] + pub const fn vbvaloen(&self) -> bool { + let val = (self.0 >> 2usize) & 0x01; + val != 0 + } + #[doc = "VBUS valid override enable"] + #[inline(always)] + pub fn set_vbvaloen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize); + } + #[doc = "VBUS valid override value"] + #[inline(always)] + pub const fn vbvaloval(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "VBUS valid override value"] + #[inline(always)] + pub fn set_vbvaloval(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "A-peripheral session valid override enable"] + #[inline(always)] + pub const fn avaloen(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "A-peripheral session valid override enable"] + #[inline(always)] + pub fn set_avaloen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + #[doc = "A-peripheral session valid override value"] + #[inline(always)] + pub const fn avaloval(&self) -> bool { + let val = (self.0 >> 5usize) & 0x01; + val != 0 + } + #[doc = "A-peripheral session valid override value"] + #[inline(always)] + pub fn set_avaloval(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 5usize)) | (((val as u32) & 0x01) << 5usize); + } + #[doc = "B-peripheral session valid override enable"] + #[inline(always)] + pub const fn bvaloen(&self) -> bool { + let val = (self.0 >> 6usize) & 0x01; + val != 0 + } + #[doc = "B-peripheral session valid override enable"] + #[inline(always)] + pub fn set_bvaloen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 6usize)) | (((val as u32) & 0x01) << 6usize); + } + #[doc = "B-peripheral session valid override value"] + #[inline(always)] + pub const fn bvaloval(&self) -> bool { + let val = (self.0 >> 7usize) & 0x01; + val != 0 + } + #[doc = "B-peripheral session valid override value"] + #[inline(always)] + pub fn set_bvaloval(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 7usize)) | (((val as u32) & 0x01) << 7usize); + } + #[doc = "Host negotiation success"] + #[inline(always)] + pub const fn hngscs(&self) -> bool { + let val = (self.0 >> 8usize) & 0x01; + val != 0 + } + #[doc = "Host negotiation success"] + #[inline(always)] + pub fn set_hngscs(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 8usize)) | (((val as u32) & 0x01) << 8usize); + } + #[doc = "HNP request"] + #[inline(always)] + pub const fn hnprq(&self) -> bool { + let val = (self.0 >> 9usize) & 0x01; + val != 0 + } + #[doc = "HNP request"] + #[inline(always)] + pub fn set_hnprq(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 9usize)) | (((val as u32) & 0x01) << 9usize); + } + #[doc = "Host set HNP enable"] + #[inline(always)] + pub const fn hshnpen(&self) -> bool { + let val = (self.0 >> 10usize) & 0x01; + val != 0 + } + #[doc = "Host set HNP enable"] + #[inline(always)] + pub fn set_hshnpen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 10usize)) | (((val as u32) & 0x01) << 10usize); + } + #[doc = "Device HNP enabled"] + #[inline(always)] + pub const fn dhnpen(&self) -> bool { + let val = (self.0 >> 11usize) & 0x01; + val != 0 + } + #[doc = "Device HNP enabled"] + #[inline(always)] + pub fn set_dhnpen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 11usize)) | (((val as u32) & 0x01) << 11usize); + } + #[doc = "Embedded host enable"] + #[inline(always)] + pub const fn ehen(&self) -> bool { + let val = (self.0 >> 12usize) & 0x01; + val != 0 + } + #[doc = "Embedded host enable"] + #[inline(always)] + pub fn set_ehen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 12usize)) | (((val as u32) & 0x01) << 12usize); + } + #[doc = "Connector ID status"] + #[inline(always)] + pub const fn cidsts(&self) -> bool { + let val = (self.0 >> 16usize) & 0x01; + val != 0 + } + #[doc = "Connector ID status"] + #[inline(always)] + pub fn set_cidsts(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 16usize)) | (((val as u32) & 0x01) << 16usize); + } + #[doc = "Long/short debounce time"] + #[inline(always)] + pub const fn dbct(&self) -> bool { + let val = (self.0 >> 17usize) & 0x01; + val != 0 + } + #[doc = "Long/short debounce time"] + #[inline(always)] + pub fn set_dbct(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize); + } + #[doc = "A-session valid"] + #[inline(always)] + pub const fn asvld(&self) -> bool { + let val = (self.0 >> 18usize) & 0x01; + val != 0 + } + #[doc = "A-session valid"] + #[inline(always)] + pub fn set_asvld(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 18usize)) | (((val as u32) & 0x01) << 18usize); + } + #[doc = "B-session valid"] + #[inline(always)] + pub const fn bsvld(&self) -> bool { + let val = (self.0 >> 19usize) & 0x01; + val != 0 + } + #[doc = "B-session valid"] + #[inline(always)] + pub fn set_bsvld(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 19usize)) | (((val as u32) & 0x01) << 19usize); + } + } + impl Default for Gotgctl { + #[inline(always)] + fn default() -> Gotgctl { + Gotgctl(0) + } + } + #[doc = "Interrupt register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Gotgint(pub u32); + impl Gotgint { + #[doc = "Session end detected"] + #[inline(always)] + pub const fn sedet(&self) -> bool { + let val = (self.0 >> 2usize) & 0x01; + val != 0 + } + #[doc = "Session end detected"] + #[inline(always)] + pub fn set_sedet(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize); + } + #[doc = "Session request success status change"] + #[inline(always)] + pub const fn srsschg(&self) -> bool { + let val = (self.0 >> 8usize) & 0x01; + val != 0 + } + #[doc = "Session request success status change"] + #[inline(always)] + pub fn set_srsschg(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 8usize)) | (((val as u32) & 0x01) << 8usize); + } + #[doc = "Host negotiation success status change"] + #[inline(always)] + pub const fn hnsschg(&self) -> bool { + let val = (self.0 >> 9usize) & 0x01; + val != 0 + } + #[doc = "Host negotiation success status change"] + #[inline(always)] + pub fn set_hnsschg(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 9usize)) | (((val as u32) & 0x01) << 9usize); + } + #[doc = "Host negotiation detected"] + #[inline(always)] + pub const fn hngdet(&self) -> bool { + let val = (self.0 >> 17usize) & 0x01; + val != 0 + } + #[doc = "Host negotiation detected"] + #[inline(always)] + pub fn set_hngdet(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize); + } + #[doc = "A-device timeout change"] + #[inline(always)] + pub const fn adtochg(&self) -> bool { + let val = (self.0 >> 18usize) & 0x01; + val != 0 + } + #[doc = "A-device timeout change"] + #[inline(always)] + pub fn set_adtochg(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 18usize)) | (((val as u32) & 0x01) << 18usize); + } + #[doc = "Debounce done"] + #[inline(always)] + pub const fn dbcdne(&self) -> bool { + let val = (self.0 >> 19usize) & 0x01; + val != 0 + } + #[doc = "Debounce done"] + #[inline(always)] + pub fn set_dbcdne(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 19usize)) | (((val as u32) & 0x01) << 19usize); + } + #[doc = "ID input pin changed"] + #[inline(always)] + pub const fn idchng(&self) -> bool { + let val = (self.0 >> 20usize) & 0x01; + val != 0 + } + #[doc = "ID input pin changed"] + #[inline(always)] + pub fn set_idchng(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize); + } + } + impl Default for Gotgint { + #[inline(always)] + fn default() -> Gotgint { + Gotgint(0) + } + } + #[doc = "Reset register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Grstctl(pub u32); + impl Grstctl { + #[doc = "Core soft reset"] + #[inline(always)] + pub const fn csrst(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Core soft reset"] + #[inline(always)] + pub fn set_csrst(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "HCLK soft reset"] + #[inline(always)] + pub const fn hsrst(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "HCLK soft reset"] + #[inline(always)] + pub fn set_hsrst(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "Host frame counter reset"] + #[inline(always)] + pub const fn fcrst(&self) -> bool { + let val = (self.0 >> 2usize) & 0x01; + val != 0 + } + #[doc = "Host frame counter reset"] + #[inline(always)] + pub fn set_fcrst(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize); + } + #[doc = "RxFIFO flush"] + #[inline(always)] + pub const fn rxfflsh(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "RxFIFO flush"] + #[inline(always)] + pub fn set_rxfflsh(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + #[doc = "TxFIFO flush"] + #[inline(always)] + pub const fn txfflsh(&self) -> bool { + let val = (self.0 >> 5usize) & 0x01; + val != 0 + } + #[doc = "TxFIFO flush"] + #[inline(always)] + pub fn set_txfflsh(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 5usize)) | (((val as u32) & 0x01) << 5usize); + } + #[doc = "TxFIFO number"] + #[inline(always)] + pub const fn txfnum(&self) -> u8 { + let val = (self.0 >> 6usize) & 0x1f; + val as u8 + } + #[doc = "TxFIFO number"] + #[inline(always)] + pub fn set_txfnum(&mut self, val: u8) { + self.0 = (self.0 & !(0x1f << 6usize)) | (((val as u32) & 0x1f) << 6usize); + } + #[doc = "DMA request signal enabled for USB OTG HS"] + #[inline(always)] + pub const fn dmareq(&self) -> bool { + let val = (self.0 >> 30usize) & 0x01; + val != 0 + } + #[doc = "DMA request signal enabled for USB OTG HS"] + #[inline(always)] + pub fn set_dmareq(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 30usize)) | (((val as u32) & 0x01) << 30usize); + } + #[doc = "AHB master idle"] + #[inline(always)] + pub const fn ahbidl(&self) -> bool { + let val = (self.0 >> 31usize) & 0x01; + val != 0 + } + #[doc = "AHB master idle"] + #[inline(always)] + pub fn set_ahbidl(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 31usize)) | (((val as u32) & 0x01) << 31usize); + } + } + impl Default for Grstctl { + #[inline(always)] + fn default() -> Grstctl { + Grstctl(0) + } + } + #[doc = "Receive FIFO size register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Grxfsiz(pub u32); + impl Grxfsiz { + #[doc = "RxFIFO depth"] + #[inline(always)] + pub const fn rxfd(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "RxFIFO depth"] + #[inline(always)] + pub fn set_rxfd(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + } + impl Default for Grxfsiz { + #[inline(always)] + fn default() -> Grxfsiz { + Grxfsiz(0) + } + } + #[doc = "Status read and pop register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Grxsts(pub u32); + impl Grxsts { + #[doc = "Endpoint number (device mode) / Channel number (host mode)"] + #[inline(always)] + pub const fn epnum(&self) -> u8 { + let val = (self.0 >> 0usize) & 0x0f; + val as u8 + } + #[doc = "Endpoint number (device mode) / Channel number (host mode)"] + #[inline(always)] + pub fn set_epnum(&mut self, val: u8) { + self.0 = (self.0 & !(0x0f << 0usize)) | (((val as u32) & 0x0f) << 0usize); + } + #[doc = "Byte count"] + #[inline(always)] + pub const fn bcnt(&self) -> u16 { + let val = (self.0 >> 4usize) & 0x07ff; + val as u16 + } + #[doc = "Byte count"] + #[inline(always)] + pub fn set_bcnt(&mut self, val: u16) { + self.0 = (self.0 & !(0x07ff << 4usize)) | (((val as u32) & 0x07ff) << 4usize); + } + #[doc = "Data PID"] + #[inline(always)] + pub const fn dpid(&self) -> super::vals::Dpid { + let val = (self.0 >> 15usize) & 0x03; + super::vals::Dpid::from_bits(val as u8) + } + #[doc = "Data PID"] + #[inline(always)] + pub fn set_dpid(&mut self, val: super::vals::Dpid) { + self.0 = (self.0 & !(0x03 << 15usize)) | (((val.to_bits() as u32) & 0x03) << 15usize); + } + #[doc = "Packet status (device mode)"] + #[inline(always)] + pub const fn pktstsd(&self) -> super::vals::Pktstsd { + let val = (self.0 >> 17usize) & 0x0f; + super::vals::Pktstsd::from_bits(val as u8) + } + #[doc = "Packet status (device mode)"] + #[inline(always)] + pub fn set_pktstsd(&mut self, val: super::vals::Pktstsd) { + self.0 = (self.0 & !(0x0f << 17usize)) | (((val.to_bits() as u32) & 0x0f) << 17usize); + } + #[doc = "Packet status (host mode)"] + #[inline(always)] + pub const fn pktstsh(&self) -> super::vals::Pktstsh { + let val = (self.0 >> 17usize) & 0x0f; + super::vals::Pktstsh::from_bits(val as u8) + } + #[doc = "Packet status (host mode)"] + #[inline(always)] + pub fn set_pktstsh(&mut self, val: super::vals::Pktstsh) { + self.0 = (self.0 & !(0x0f << 17usize)) | (((val.to_bits() as u32) & 0x0f) << 17usize); + } + #[doc = "Frame number (device mode)"] + #[inline(always)] + pub const fn frmnum(&self) -> u8 { + let val = (self.0 >> 21usize) & 0x0f; + val as u8 + } + #[doc = "Frame number (device mode)"] + #[inline(always)] + pub fn set_frmnum(&mut self, val: u8) { + self.0 = (self.0 & !(0x0f << 21usize)) | (((val as u32) & 0x0f) << 21usize); + } + } + impl Default for Grxsts { + #[inline(always)] + fn default() -> Grxsts { + Grxsts(0) + } + } + #[doc = "USB configuration register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Gusbcfg(pub u32); + impl Gusbcfg { + #[doc = "FS timeout calibration"] + #[inline(always)] + pub const fn tocal(&self) -> u8 { + let val = (self.0 >> 0usize) & 0x07; + val as u8 + } + #[doc = "FS timeout calibration"] + #[inline(always)] + pub fn set_tocal(&mut self, val: u8) { + self.0 = (self.0 & !(0x07 << 0usize)) | (((val as u32) & 0x07) << 0usize); + } + #[doc = "Full-speed internal serial transceiver enable"] + #[inline(always)] + pub const fn physel(&self) -> bool { + let val = (self.0 >> 6usize) & 0x01; + val != 0 + } + #[doc = "Full-speed internal serial transceiver enable"] + #[inline(always)] + pub fn set_physel(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 6usize)) | (((val as u32) & 0x01) << 6usize); + } + #[doc = "SRP-capable"] + #[inline(always)] + pub const fn srpcap(&self) -> bool { + let val = (self.0 >> 8usize) & 0x01; + val != 0 + } + #[doc = "SRP-capable"] + #[inline(always)] + pub fn set_srpcap(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 8usize)) | (((val as u32) & 0x01) << 8usize); + } + #[doc = "HNP-capable"] + #[inline(always)] + pub const fn hnpcap(&self) -> bool { + let val = (self.0 >> 9usize) & 0x01; + val != 0 + } + #[doc = "HNP-capable"] + #[inline(always)] + pub fn set_hnpcap(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 9usize)) | (((val as u32) & 0x01) << 9usize); + } + #[doc = "USB turnaround time"] + #[inline(always)] + pub const fn trdt(&self) -> u8 { + let val = (self.0 >> 10usize) & 0x0f; + val as u8 + } + #[doc = "USB turnaround time"] + #[inline(always)] + pub fn set_trdt(&mut self, val: u8) { + self.0 = (self.0 & !(0x0f << 10usize)) | (((val as u32) & 0x0f) << 10usize); + } + #[doc = "PHY Low-power clock select"] + #[inline(always)] + pub const fn phylpcs(&self) -> bool { + let val = (self.0 >> 15usize) & 0x01; + val != 0 + } + #[doc = "PHY Low-power clock select"] + #[inline(always)] + pub fn set_phylpcs(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 15usize)) | (((val as u32) & 0x01) << 15usize); + } + #[doc = "ULPI FS/LS select"] + #[inline(always)] + pub const fn ulpifsls(&self) -> bool { + let val = (self.0 >> 17usize) & 0x01; + val != 0 + } + #[doc = "ULPI FS/LS select"] + #[inline(always)] + pub fn set_ulpifsls(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize); + } + #[doc = "ULPI Auto-resume"] + #[inline(always)] + pub const fn ulpiar(&self) -> bool { + let val = (self.0 >> 18usize) & 0x01; + val != 0 + } + #[doc = "ULPI Auto-resume"] + #[inline(always)] + pub fn set_ulpiar(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 18usize)) | (((val as u32) & 0x01) << 18usize); + } + #[doc = "ULPI Clock SuspendM"] + #[inline(always)] + pub const fn ulpicsm(&self) -> bool { + let val = (self.0 >> 19usize) & 0x01; + val != 0 + } + #[doc = "ULPI Clock SuspendM"] + #[inline(always)] + pub fn set_ulpicsm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 19usize)) | (((val as u32) & 0x01) << 19usize); + } + #[doc = "ULPI External VBUS Drive"] + #[inline(always)] + pub const fn ulpievbusd(&self) -> bool { + let val = (self.0 >> 20usize) & 0x01; + val != 0 + } + #[doc = "ULPI External VBUS Drive"] + #[inline(always)] + pub fn set_ulpievbusd(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize); + } + #[doc = "ULPI external VBUS indicator"] + #[inline(always)] + pub const fn ulpievbusi(&self) -> bool { + let val = (self.0 >> 21usize) & 0x01; + val != 0 + } + #[doc = "ULPI external VBUS indicator"] + #[inline(always)] + pub fn set_ulpievbusi(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 21usize)) | (((val as u32) & 0x01) << 21usize); + } + #[doc = "TermSel DLine pulsing selection"] + #[inline(always)] + pub const fn tsdps(&self) -> bool { + let val = (self.0 >> 22usize) & 0x01; + val != 0 + } + #[doc = "TermSel DLine pulsing selection"] + #[inline(always)] + pub fn set_tsdps(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 22usize)) | (((val as u32) & 0x01) << 22usize); + } + #[doc = "Indicator complement"] + #[inline(always)] + pub const fn pcci(&self) -> bool { + let val = (self.0 >> 23usize) & 0x01; + val != 0 + } + #[doc = "Indicator complement"] + #[inline(always)] + pub fn set_pcci(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 23usize)) | (((val as u32) & 0x01) << 23usize); + } + #[doc = "Indicator pass through"] + #[inline(always)] + pub const fn ptci(&self) -> bool { + let val = (self.0 >> 24usize) & 0x01; + val != 0 + } + #[doc = "Indicator pass through"] + #[inline(always)] + pub fn set_ptci(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 24usize)) | (((val as u32) & 0x01) << 24usize); + } + #[doc = "ULPI interface protect disable"] + #[inline(always)] + pub const fn ulpiipd(&self) -> bool { + let val = (self.0 >> 25usize) & 0x01; + val != 0 + } + #[doc = "ULPI interface protect disable"] + #[inline(always)] + pub fn set_ulpiipd(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 25usize)) | (((val as u32) & 0x01) << 25usize); + } + #[doc = "Force host mode"] + #[inline(always)] + pub const fn fhmod(&self) -> bool { + let val = (self.0 >> 29usize) & 0x01; + val != 0 + } + #[doc = "Force host mode"] + #[inline(always)] + pub fn set_fhmod(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); + } + #[doc = "Force device mode"] + #[inline(always)] + pub const fn fdmod(&self) -> bool { + let val = (self.0 >> 30usize) & 0x01; + val != 0 + } + #[doc = "Force device mode"] + #[inline(always)] + pub fn set_fdmod(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 30usize)) | (((val as u32) & 0x01) << 30usize); + } + #[doc = "Corrupt Tx packet"] + #[inline(always)] + pub const fn ctxpkt(&self) -> bool { + let val = (self.0 >> 31usize) & 0x01; + val != 0 + } + #[doc = "Corrupt Tx packet"] + #[inline(always)] + pub fn set_ctxpkt(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 31usize)) | (((val as u32) & 0x01) << 31usize); + } + } + impl Default for Gusbcfg { + #[inline(always)] + fn default() -> Gusbcfg { + Gusbcfg(0) + } + } + #[doc = "Host all channels interrupt register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Haint(pub u32); + impl Haint { + #[doc = "Channel interrupts"] + #[inline(always)] + pub const fn haint(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "Channel interrupts"] + #[inline(always)] + pub fn set_haint(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + } + impl Default for Haint { + #[inline(always)] + fn default() -> Haint { + Haint(0) + } + } + #[doc = "Host all channels interrupt mask register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Haintmsk(pub u32); + impl Haintmsk { + #[doc = "Channel interrupt mask"] + #[inline(always)] + pub const fn haintm(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "Channel interrupt mask"] + #[inline(always)] + pub fn set_haintm(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + } + impl Default for Haintmsk { + #[inline(always)] + fn default() -> Haintmsk { + Haintmsk(0) + } + } + #[doc = "Host channel characteristics register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Hcchar(pub u32); + impl Hcchar { + #[doc = "Maximum packet size"] + #[inline(always)] + pub const fn mpsiz(&self) -> u16 { + let val = (self.0 >> 0usize) & 0x07ff; + val as u16 + } + #[doc = "Maximum packet size"] + #[inline(always)] + pub fn set_mpsiz(&mut self, val: u16) { + self.0 = (self.0 & !(0x07ff << 0usize)) | (((val as u32) & 0x07ff) << 0usize); + } + #[doc = "Endpoint number"] + #[inline(always)] + pub const fn epnum(&self) -> u8 { + let val = (self.0 >> 11usize) & 0x0f; + val as u8 + } + #[doc = "Endpoint number"] + #[inline(always)] + pub fn set_epnum(&mut self, val: u8) { + self.0 = (self.0 & !(0x0f << 11usize)) | (((val as u32) & 0x0f) << 11usize); + } + #[doc = "Endpoint direction"] + #[inline(always)] + pub const fn epdir(&self) -> bool { + let val = (self.0 >> 15usize) & 0x01; + val != 0 + } + #[doc = "Endpoint direction"] + #[inline(always)] + pub fn set_epdir(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 15usize)) | (((val as u32) & 0x01) << 15usize); + } + #[doc = "Low-speed device"] + #[inline(always)] + pub const fn lsdev(&self) -> bool { + let val = (self.0 >> 17usize) & 0x01; + val != 0 + } + #[doc = "Low-speed device"] + #[inline(always)] + pub fn set_lsdev(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize); + } + #[doc = "Endpoint type"] + #[inline(always)] + pub const fn eptyp(&self) -> super::vals::Eptyp { + let val = (self.0 >> 18usize) & 0x03; + super::vals::Eptyp::from_bits(val as u8) + } + #[doc = "Endpoint type"] + #[inline(always)] + pub fn set_eptyp(&mut self, val: super::vals::Eptyp) { + self.0 = (self.0 & !(0x03 << 18usize)) | (((val.to_bits() as u32) & 0x03) << 18usize); + } + #[doc = "Multicount"] + #[inline(always)] + pub const fn mcnt(&self) -> u8 { + let val = (self.0 >> 20usize) & 0x03; + val as u8 + } + #[doc = "Multicount"] + #[inline(always)] + pub fn set_mcnt(&mut self, val: u8) { + self.0 = (self.0 & !(0x03 << 20usize)) | (((val as u32) & 0x03) << 20usize); + } + #[doc = "Device address"] + #[inline(always)] + pub const fn dad(&self) -> u8 { + let val = (self.0 >> 22usize) & 0x7f; + val as u8 + } + #[doc = "Device address"] + #[inline(always)] + pub fn set_dad(&mut self, val: u8) { + self.0 = (self.0 & !(0x7f << 22usize)) | (((val as u32) & 0x7f) << 22usize); + } + #[doc = "Odd frame"] + #[inline(always)] + pub const fn oddfrm(&self) -> bool { + let val = (self.0 >> 29usize) & 0x01; + val != 0 + } + #[doc = "Odd frame"] + #[inline(always)] + pub fn set_oddfrm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); + } + #[doc = "Channel disable"] + #[inline(always)] + pub const fn chdis(&self) -> bool { + let val = (self.0 >> 30usize) & 0x01; + val != 0 + } + #[doc = "Channel disable"] + #[inline(always)] + pub fn set_chdis(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 30usize)) | (((val as u32) & 0x01) << 30usize); + } + #[doc = "Channel enable"] + #[inline(always)] + pub const fn chena(&self) -> bool { + let val = (self.0 >> 31usize) & 0x01; + val != 0 + } + #[doc = "Channel enable"] + #[inline(always)] + pub fn set_chena(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 31usize)) | (((val as u32) & 0x01) << 31usize); + } + } + impl Default for Hcchar { + #[inline(always)] + fn default() -> Hcchar { + Hcchar(0) + } + } + #[doc = "Host configuration register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Hcfg(pub u32); + impl Hcfg { + #[doc = "FS/LS PHY clock select"] + #[inline(always)] + pub const fn fslspcs(&self) -> u8 { + let val = (self.0 >> 0usize) & 0x03; + val as u8 + } + #[doc = "FS/LS PHY clock select"] + #[inline(always)] + pub fn set_fslspcs(&mut self, val: u8) { + self.0 = (self.0 & !(0x03 << 0usize)) | (((val as u32) & 0x03) << 0usize); + } + #[doc = "FS- and LS-only support"] + #[inline(always)] + pub const fn fslss(&self) -> bool { + let val = (self.0 >> 2usize) & 0x01; + val != 0 + } + #[doc = "FS- and LS-only support"] + #[inline(always)] + pub fn set_fslss(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize); + } + } + impl Default for Hcfg { + #[inline(always)] + fn default() -> Hcfg { + Hcfg(0) + } + } + #[doc = "Host channel interrupt register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Hcint(pub u32); + impl Hcint { + #[doc = "Transfer completed"] + #[inline(always)] + pub const fn xfrc(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Transfer completed"] + #[inline(always)] + pub fn set_xfrc(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Channel halted"] + #[inline(always)] + pub const fn chh(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Channel halted"] + #[inline(always)] + pub fn set_chh(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "STALL response received interrupt"] + #[inline(always)] + pub const fn stall(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "STALL response received interrupt"] + #[inline(always)] + pub fn set_stall(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "NAK response received interrupt"] + #[inline(always)] + pub const fn nak(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "NAK response received interrupt"] + #[inline(always)] + pub fn set_nak(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + #[doc = "ACK response received/transmitted interrupt"] + #[inline(always)] + pub const fn ack(&self) -> bool { + let val = (self.0 >> 5usize) & 0x01; + val != 0 + } + #[doc = "ACK response received/transmitted interrupt"] + #[inline(always)] + pub fn set_ack(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 5usize)) | (((val as u32) & 0x01) << 5usize); + } + #[doc = "Transaction error"] + #[inline(always)] + pub const fn txerr(&self) -> bool { + let val = (self.0 >> 7usize) & 0x01; + val != 0 + } + #[doc = "Transaction error"] + #[inline(always)] + pub fn set_txerr(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 7usize)) | (((val as u32) & 0x01) << 7usize); + } + #[doc = "Babble error"] + #[inline(always)] + pub const fn bberr(&self) -> bool { + let val = (self.0 >> 8usize) & 0x01; + val != 0 + } + #[doc = "Babble error"] + #[inline(always)] + pub fn set_bberr(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 8usize)) | (((val as u32) & 0x01) << 8usize); + } + #[doc = "Frame overrun"] + #[inline(always)] + pub const fn frmor(&self) -> bool { + let val = (self.0 >> 9usize) & 0x01; + val != 0 + } + #[doc = "Frame overrun"] + #[inline(always)] + pub fn set_frmor(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 9usize)) | (((val as u32) & 0x01) << 9usize); + } + #[doc = "Data toggle error"] + #[inline(always)] + pub const fn dterr(&self) -> bool { + let val = (self.0 >> 10usize) & 0x01; + val != 0 + } + #[doc = "Data toggle error"] + #[inline(always)] + pub fn set_dterr(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 10usize)) | (((val as u32) & 0x01) << 10usize); + } + } + impl Default for Hcint { + #[inline(always)] + fn default() -> Hcint { + Hcint(0) + } + } + #[doc = "Host channel mask register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Hcintmsk(pub u32); + impl Hcintmsk { + #[doc = "Transfer completed mask"] + #[inline(always)] + pub const fn xfrcm(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Transfer completed mask"] + #[inline(always)] + pub fn set_xfrcm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Channel halted mask"] + #[inline(always)] + pub const fn chhm(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Channel halted mask"] + #[inline(always)] + pub fn set_chhm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "STALL response received interrupt mask"] + #[inline(always)] + pub const fn stallm(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "STALL response received interrupt mask"] + #[inline(always)] + pub fn set_stallm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "NAK response received interrupt mask"] + #[inline(always)] + pub const fn nakm(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "NAK response received interrupt mask"] + #[inline(always)] + pub fn set_nakm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + #[doc = "ACK response received/transmitted interrupt mask"] + #[inline(always)] + pub const fn ackm(&self) -> bool { + let val = (self.0 >> 5usize) & 0x01; + val != 0 + } + #[doc = "ACK response received/transmitted interrupt mask"] + #[inline(always)] + pub fn set_ackm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 5usize)) | (((val as u32) & 0x01) << 5usize); + } + #[doc = "Response received interrupt mask"] + #[inline(always)] + pub const fn nyet(&self) -> bool { + let val = (self.0 >> 6usize) & 0x01; + val != 0 + } + #[doc = "Response received interrupt mask"] + #[inline(always)] + pub fn set_nyet(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 6usize)) | (((val as u32) & 0x01) << 6usize); + } + #[doc = "Transaction error mask"] + #[inline(always)] + pub const fn txerrm(&self) -> bool { + let val = (self.0 >> 7usize) & 0x01; + val != 0 + } + #[doc = "Transaction error mask"] + #[inline(always)] + pub fn set_txerrm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 7usize)) | (((val as u32) & 0x01) << 7usize); + } + #[doc = "Babble error mask"] + #[inline(always)] + pub const fn bberrm(&self) -> bool { + let val = (self.0 >> 8usize) & 0x01; + val != 0 + } + #[doc = "Babble error mask"] + #[inline(always)] + pub fn set_bberrm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 8usize)) | (((val as u32) & 0x01) << 8usize); + } + #[doc = "Frame overrun mask"] + #[inline(always)] + pub const fn frmorm(&self) -> bool { + let val = (self.0 >> 9usize) & 0x01; + val != 0 + } + #[doc = "Frame overrun mask"] + #[inline(always)] + pub fn set_frmorm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 9usize)) | (((val as u32) & 0x01) << 9usize); + } + #[doc = "Data toggle error mask"] + #[inline(always)] + pub const fn dterrm(&self) -> bool { + let val = (self.0 >> 10usize) & 0x01; + val != 0 + } + #[doc = "Data toggle error mask"] + #[inline(always)] + pub fn set_dterrm(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 10usize)) | (((val as u32) & 0x01) << 10usize); + } + } + impl Default for Hcintmsk { + #[inline(always)] + fn default() -> Hcintmsk { + Hcintmsk(0) + } + } + #[doc = "Host channel transfer size register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Hctsiz(pub u32); + impl Hctsiz { + #[doc = "Transfer size"] + #[inline(always)] + pub const fn xfrsiz(&self) -> u32 { + let val = (self.0 >> 0usize) & 0x0007_ffff; + val as u32 + } + #[doc = "Transfer size"] + #[inline(always)] + pub fn set_xfrsiz(&mut self, val: u32) { + self.0 = (self.0 & !(0x0007_ffff << 0usize)) | (((val as u32) & 0x0007_ffff) << 0usize); + } + #[doc = "Packet count"] + #[inline(always)] + pub const fn pktcnt(&self) -> u16 { + let val = (self.0 >> 19usize) & 0x03ff; + val as u16 + } + #[doc = "Packet count"] + #[inline(always)] + pub fn set_pktcnt(&mut self, val: u16) { + self.0 = (self.0 & !(0x03ff << 19usize)) | (((val as u32) & 0x03ff) << 19usize); + } + #[doc = "Data PID"] + #[inline(always)] + pub const fn dpid(&self) -> u8 { + let val = (self.0 >> 29usize) & 0x03; + val as u8 + } + #[doc = "Data PID"] + #[inline(always)] + pub fn set_dpid(&mut self, val: u8) { + self.0 = (self.0 & !(0x03 << 29usize)) | (((val as u32) & 0x03) << 29usize); + } + } + impl Default for Hctsiz { + #[inline(always)] + fn default() -> Hctsiz { + Hctsiz(0) + } + } + #[doc = "Host frame interval register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Hfir(pub u32); + impl Hfir { + #[doc = "Frame interval"] + #[inline(always)] + pub const fn frivl(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "Frame interval"] + #[inline(always)] + pub fn set_frivl(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + } + impl Default for Hfir { + #[inline(always)] + fn default() -> Hfir { + Hfir(0) + } + } + #[doc = "Host frame number/frame time remaining register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Hfnum(pub u32); + impl Hfnum { + #[doc = "Frame number"] + #[inline(always)] + pub const fn frnum(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "Frame number"] + #[inline(always)] + pub fn set_frnum(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + #[doc = "Frame time remaining"] + #[inline(always)] + pub const fn ftrem(&self) -> u16 { + let val = (self.0 >> 16usize) & 0xffff; + val as u16 + } + #[doc = "Frame time remaining"] + #[inline(always)] + pub fn set_ftrem(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 16usize)) | (((val as u32) & 0xffff) << 16usize); + } + } + impl Default for Hfnum { + #[inline(always)] + fn default() -> Hfnum { + Hfnum(0) + } + } + #[doc = "Non-periodic transmit FIFO/queue status register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Hnptxsts(pub u32); + impl Hnptxsts { + #[doc = "Non-periodic TxFIFO space available"] + #[inline(always)] + pub const fn nptxfsav(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "Non-periodic TxFIFO space available"] + #[inline(always)] + pub fn set_nptxfsav(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + #[doc = "Non-periodic transmit request queue space available"] + #[inline(always)] + pub const fn nptqxsav(&self) -> u8 { + let val = (self.0 >> 16usize) & 0xff; + val as u8 + } + #[doc = "Non-periodic transmit request queue space available"] + #[inline(always)] + pub fn set_nptqxsav(&mut self, val: u8) { + self.0 = (self.0 & !(0xff << 16usize)) | (((val as u32) & 0xff) << 16usize); + } + #[doc = "Top of the non-periodic transmit request queue"] + #[inline(always)] + pub const fn nptxqtop(&self) -> u8 { + let val = (self.0 >> 24usize) & 0x7f; + val as u8 + } + #[doc = "Top of the non-periodic transmit request queue"] + #[inline(always)] + pub fn set_nptxqtop(&mut self, val: u8) { + self.0 = (self.0 & !(0x7f << 24usize)) | (((val as u32) & 0x7f) << 24usize); + } + } + impl Default for Hnptxsts { + #[inline(always)] + fn default() -> Hnptxsts { + Hnptxsts(0) + } + } + #[doc = "Host port control and status register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Hprt(pub u32); + impl Hprt { + #[doc = "Port connect status"] + #[inline(always)] + pub const fn pcsts(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Port connect status"] + #[inline(always)] + pub fn set_pcsts(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Port connect detected"] + #[inline(always)] + pub const fn pcdet(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Port connect detected"] + #[inline(always)] + pub fn set_pcdet(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "Port enable"] + #[inline(always)] + pub const fn pena(&self) -> bool { + let val = (self.0 >> 2usize) & 0x01; + val != 0 + } + #[doc = "Port enable"] + #[inline(always)] + pub fn set_pena(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize); + } + #[doc = "Port enable/disable change"] + #[inline(always)] + pub const fn penchng(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "Port enable/disable change"] + #[inline(always)] + pub fn set_penchng(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "Port overcurrent active"] + #[inline(always)] + pub const fn poca(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "Port overcurrent active"] + #[inline(always)] + pub fn set_poca(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + #[doc = "Port overcurrent change"] + #[inline(always)] + pub const fn pocchng(&self) -> bool { + let val = (self.0 >> 5usize) & 0x01; + val != 0 + } + #[doc = "Port overcurrent change"] + #[inline(always)] + pub fn set_pocchng(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 5usize)) | (((val as u32) & 0x01) << 5usize); + } + #[doc = "Port resume"] + #[inline(always)] + pub const fn pres(&self) -> bool { + let val = (self.0 >> 6usize) & 0x01; + val != 0 + } + #[doc = "Port resume"] + #[inline(always)] + pub fn set_pres(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 6usize)) | (((val as u32) & 0x01) << 6usize); + } + #[doc = "Port suspend"] + #[inline(always)] + pub const fn psusp(&self) -> bool { + let val = (self.0 >> 7usize) & 0x01; + val != 0 + } + #[doc = "Port suspend"] + #[inline(always)] + pub fn set_psusp(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 7usize)) | (((val as u32) & 0x01) << 7usize); + } + #[doc = "Port reset"] + #[inline(always)] + pub const fn prst(&self) -> bool { + let val = (self.0 >> 8usize) & 0x01; + val != 0 + } + #[doc = "Port reset"] + #[inline(always)] + pub fn set_prst(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 8usize)) | (((val as u32) & 0x01) << 8usize); + } + #[doc = "Port line status"] + #[inline(always)] + pub const fn plsts(&self) -> u8 { + let val = (self.0 >> 10usize) & 0x03; + val as u8 + } + #[doc = "Port line status"] + #[inline(always)] + pub fn set_plsts(&mut self, val: u8) { + self.0 = (self.0 & !(0x03 << 10usize)) | (((val as u32) & 0x03) << 10usize); + } + #[doc = "Port power"] + #[inline(always)] + pub const fn ppwr(&self) -> bool { + let val = (self.0 >> 12usize) & 0x01; + val != 0 + } + #[doc = "Port power"] + #[inline(always)] + pub fn set_ppwr(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 12usize)) | (((val as u32) & 0x01) << 12usize); + } + #[doc = "Port test control"] + #[inline(always)] + pub const fn ptctl(&self) -> u8 { + let val = (self.0 >> 13usize) & 0x0f; + val as u8 + } + #[doc = "Port test control"] + #[inline(always)] + pub fn set_ptctl(&mut self, val: u8) { + self.0 = (self.0 & !(0x0f << 13usize)) | (((val as u32) & 0x0f) << 13usize); + } + #[doc = "Port speed"] + #[inline(always)] + pub const fn pspd(&self) -> u8 { + let val = (self.0 >> 17usize) & 0x03; + val as u8 + } + #[doc = "Port speed"] + #[inline(always)] + pub fn set_pspd(&mut self, val: u8) { + self.0 = (self.0 & !(0x03 << 17usize)) | (((val as u32) & 0x03) << 17usize); + } + } + impl Default for Hprt { + #[inline(always)] + fn default() -> Hprt { + Hprt(0) + } + } + #[doc = "Periodic transmit FIFO/queue status register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Hptxsts(pub u32); + impl Hptxsts { + #[doc = "Periodic transmit data FIFO space available"] + #[inline(always)] + pub const fn ptxfsavl(&self) -> u16 { + let val = (self.0 >> 0usize) & 0xffff; + val as u16 + } + #[doc = "Periodic transmit data FIFO space available"] + #[inline(always)] + pub fn set_ptxfsavl(&mut self, val: u16) { + self.0 = (self.0 & !(0xffff << 0usize)) | (((val as u32) & 0xffff) << 0usize); + } + #[doc = "Periodic transmit request queue space available"] + #[inline(always)] + pub const fn ptxqsav(&self) -> u8 { + let val = (self.0 >> 16usize) & 0xff; + val as u8 + } + #[doc = "Periodic transmit request queue space available"] + #[inline(always)] + pub fn set_ptxqsav(&mut self, val: u8) { + self.0 = (self.0 & !(0xff << 16usize)) | (((val as u32) & 0xff) << 16usize); + } + #[doc = "Top of the periodic transmit request queue"] + #[inline(always)] + pub const fn ptxqtop(&self) -> u8 { + let val = (self.0 >> 24usize) & 0xff; + val as u8 + } + #[doc = "Top of the periodic transmit request queue"] + #[inline(always)] + pub fn set_ptxqtop(&mut self, val: u8) { + self.0 = (self.0 & !(0xff << 24usize)) | (((val as u32) & 0xff) << 24usize); + } + } + impl Default for Hptxsts { + #[inline(always)] + fn default() -> Hptxsts { + Hptxsts(0) + } + } + #[doc = "Power and clock gating control register"] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Pcgcctl(pub u32); + impl Pcgcctl { + #[doc = "Stop PHY clock"] + #[inline(always)] + pub const fn stppclk(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Stop PHY clock"] + #[inline(always)] + pub fn set_stppclk(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Gate HCLK"] + #[inline(always)] + pub const fn gatehclk(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Gate HCLK"] + #[inline(always)] + pub fn set_gatehclk(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "PHY Suspended"] + #[inline(always)] + pub const fn physusp(&self) -> bool { + let val = (self.0 >> 4usize) & 0x01; + val != 0 + } + #[doc = "PHY Suspended"] + #[inline(always)] + pub fn set_physusp(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 4usize)) | (((val as u32) & 0x01) << 4usize); + } + } + impl Default for Pcgcctl { + #[inline(always)] + fn default() -> Pcgcctl { + Pcgcctl(0) + } + } +} +pub mod vals { + #[repr(u8)] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] + #[allow(non_camel_case_types)] + pub enum Dpid { + DATA0 = 0x0, + DATA2 = 0x01, + DATA1 = 0x02, + MDATA = 0x03, + } + impl Dpid { + #[inline(always)] + pub const fn from_bits(val: u8) -> Dpid { + unsafe { core::mem::transmute(val & 0x03) } + } + #[inline(always)] + pub const fn to_bits(self) -> u8 { + unsafe { core::mem::transmute(self) } + } + } + impl From for Dpid { + #[inline(always)] + fn from(val: u8) -> Dpid { + Dpid::from_bits(val) + } + } + impl From for u8 { + #[inline(always)] + fn from(val: Dpid) -> u8 { + Dpid::to_bits(val) + } + } + #[repr(u8)] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] + #[allow(non_camel_case_types)] + pub enum Dspd { + #[doc = "High speed"] + HIGH_SPEED = 0x0, + #[doc = "Full speed using external ULPI PHY"] + FULL_SPEED_EXTERNAL = 0x01, + _RESERVED_2 = 0x02, + #[doc = "Full speed using internal embedded PHY"] + FULL_SPEED_INTERNAL = 0x03, + } + impl Dspd { + #[inline(always)] + pub const fn from_bits(val: u8) -> Dspd { + unsafe { core::mem::transmute(val & 0x03) } + } + #[inline(always)] + pub const fn to_bits(self) -> u8 { + unsafe { core::mem::transmute(self) } + } + } + impl From for Dspd { + #[inline(always)] + fn from(val: u8) -> Dspd { + Dspd::from_bits(val) + } + } + impl From for u8 { + #[inline(always)] + fn from(val: Dspd) -> u8 { + Dspd::to_bits(val) + } + } + #[repr(u8)] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] + #[allow(non_camel_case_types)] + pub enum Eptyp { + CONTROL = 0x0, + ISOCHRONOUS = 0x01, + BULK = 0x02, + INTERRUPT = 0x03, + } + impl Eptyp { + #[inline(always)] + pub const fn from_bits(val: u8) -> Eptyp { + unsafe { core::mem::transmute(val & 0x03) } + } + #[inline(always)] + pub const fn to_bits(self) -> u8 { + unsafe { core::mem::transmute(self) } + } + } + impl From for Eptyp { + #[inline(always)] + fn from(val: u8) -> Eptyp { + Eptyp::from_bits(val) + } + } + impl From for u8 { + #[inline(always)] + fn from(val: Eptyp) -> u8 { + Eptyp::to_bits(val) + } + } + #[repr(u8)] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] + #[allow(non_camel_case_types)] + pub enum Pfivl { + #[doc = "80% of the frame interval"] + FRAME_INTERVAL_80 = 0x0, + #[doc = "85% of the frame interval"] + FRAME_INTERVAL_85 = 0x01, + #[doc = "90% of the frame interval"] + FRAME_INTERVAL_90 = 0x02, + #[doc = "95% of the frame interval"] + FRAME_INTERVAL_95 = 0x03, + } + impl Pfivl { + #[inline(always)] + pub const fn from_bits(val: u8) -> Pfivl { + unsafe { core::mem::transmute(val & 0x03) } + } + #[inline(always)] + pub const fn to_bits(self) -> u8 { + unsafe { core::mem::transmute(self) } + } + } + impl From for Pfivl { + #[inline(always)] + fn from(val: u8) -> Pfivl { + Pfivl::from_bits(val) + } + } + impl From for u8 { + #[inline(always)] + fn from(val: Pfivl) -> u8 { + Pfivl::to_bits(val) + } + } + #[repr(u8)] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] + #[allow(non_camel_case_types)] + pub enum Pktstsd { + _RESERVED_0 = 0x0, + #[doc = "Global OUT NAK (triggers an interrupt)"] + OUT_NAK = 0x01, + #[doc = "OUT data packet received"] + OUT_DATA_RX = 0x02, + #[doc = "OUT transfer completed (triggers an interrupt)"] + OUT_DATA_DONE = 0x03, + #[doc = "SETUP transaction completed (triggers an interrupt)"] + SETUP_DATA_DONE = 0x04, + _RESERVED_5 = 0x05, + #[doc = "SETUP data packet received"] + SETUP_DATA_RX = 0x06, + _RESERVED_7 = 0x07, + _RESERVED_8 = 0x08, + _RESERVED_9 = 0x09, + _RESERVED_a = 0x0a, + _RESERVED_b = 0x0b, + _RESERVED_c = 0x0c, + _RESERVED_d = 0x0d, + _RESERVED_e = 0x0e, + _RESERVED_f = 0x0f, + } + impl Pktstsd { + #[inline(always)] + pub const fn from_bits(val: u8) -> Pktstsd { + unsafe { core::mem::transmute(val & 0x0f) } + } + #[inline(always)] + pub const fn to_bits(self) -> u8 { + unsafe { core::mem::transmute(self) } + } + } + impl From for Pktstsd { + #[inline(always)] + fn from(val: u8) -> Pktstsd { + Pktstsd::from_bits(val) + } + } + impl From for u8 { + #[inline(always)] + fn from(val: Pktstsd) -> u8 { + Pktstsd::to_bits(val) + } + } + #[repr(u8)] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] + #[allow(non_camel_case_types)] + pub enum Pktstsh { + _RESERVED_0 = 0x0, + _RESERVED_1 = 0x01, + #[doc = "IN data packet received"] + IN_DATA_RX = 0x02, + #[doc = "IN transfer completed (triggers an interrupt)"] + IN_DATA_DONE = 0x03, + _RESERVED_4 = 0x04, + #[doc = "Data toggle error (triggers an interrupt)"] + DATA_TOGGLE_ERR = 0x05, + _RESERVED_6 = 0x06, + #[doc = "Channel halted (triggers an interrupt)"] + CHANNEL_HALTED = 0x07, + _RESERVED_8 = 0x08, + _RESERVED_9 = 0x09, + _RESERVED_a = 0x0a, + _RESERVED_b = 0x0b, + _RESERVED_c = 0x0c, + _RESERVED_d = 0x0d, + _RESERVED_e = 0x0e, + _RESERVED_f = 0x0f, + } + impl Pktstsh { + #[inline(always)] + pub const fn from_bits(val: u8) -> Pktstsh { + unsafe { core::mem::transmute(val & 0x0f) } + } + #[inline(always)] + pub const fn to_bits(self) -> u8 { + unsafe { core::mem::transmute(self) } + } + } + impl From for Pktstsh { + #[inline(always)] + fn from(val: u8) -> Pktstsh { + Pktstsh::from_bits(val) + } + } + impl From for u8 { + #[inline(always)] + fn from(val: Pktstsh) -> u8 { + Pktstsh::to_bits(val) + } + } +}