imxrt_usbd/
lib.rs

1//! A USB driver for i.MX RT processors
2//!
3//! `imxrt-usbd` provides a [`usb-device`] USB bus implementation, allowing you
4//! to add USB device features to your embedded Rust program. See each module
5//! for usage and examples.
6//!
7//! To interface the library, you must define a safe implementation of [`Peripherals`].
8//! See the trait documentation for more information.
9//!
10//! # General guidance
11//!
12//! The driver does not configure any of the CCM or CCM_ANALOG registers. You are
13//! responsible for configuring these peripherals for proper USB functionality. See
14//! the `imxrt-usbd` hardware examples to see different ways of configuring PLLs and
15//! clocks.
16//!
17//! [`usb-device`]: https://crates.io/crates/usb-device
18//!
19//! # Debugging features
20//!
21//! Enable the `defmt-03` feature to activate internal logging using defmt (version 0.3).
22
23#![no_std]
24#![warn(unsafe_op_in_unsafe_fn)]
25
26#[macro_use]
27mod log;
28
29mod buffer;
30mod bus;
31mod cache;
32mod driver;
33mod endpoint;
34mod qh;
35mod ral;
36mod state;
37mod td;
38mod vcell;
39
40pub use buffer::EndpointMemory;
41pub use bus::{BusAdapter, Speed};
42pub mod gpt;
43pub use state::{EndpointState, MAX_ENDPOINTS};
44
45/// A type that owns all USB register blocks
46///
47/// An implementation of `Peripherals` is expected to own the USB1
48/// or USB2 registers. This includes
49///
50/// - USB core registers
51/// - USB PHY registers
52///
53/// When an instance of `Peripherals` exists, you must make sure that
54/// nothing else, other than the owner of the `Peripherals` object,
55/// accesses those registers.
56///
57/// # Safety
58///
59/// `Peripherals` should only be implemented on a type that
60/// owns the various register blocks required for all USB
61/// operation. Incorrect usage, or failure to ensure exclusive
62/// ownership, could lead to data races and incorrect USB functionality.
63///
64/// All pointers are expected to point at the starting register block
65/// for the specified peripheral. Calls to the functions must return the
66/// the same value every time they're called.
67///
68/// # Example
69///
70/// A safe implementation of `Peripherals` that works with the
71/// `imxrt-ral` register access layer.
72///
73/// ```no_run
74/// # mod imxrt_ral {
75/// #   pub struct RegisterBlock;
76/// #   use core::ops::Deref; pub struct Instance; impl Deref for Instance { type Target = RegisterBlock; fn deref(&self) -> &RegisterBlock { unsafe { &*(0x402e0200 as *const RegisterBlock)} } }
77/// #   pub fn take() -> Result<Instance, ()> { Ok(Instance) }
78/// #   pub mod usb { pub use super::{Instance, RegisterBlock}; pub mod USB1 { pub use super::super::take; } }
79/// #   pub mod usbphy { pub use super::{Instance, RegisterBlock}; pub mod USBPHY1 { pub use super::super::take; } }
80/// #   pub mod usbnc { pub use super::Instance; pub mod USBNC1 { pub use super::super::take; } }
81/// #   pub mod usb_analog { pub use super::Instance; pub mod USB_ANALOG { pub use super::super::take; } }
82/// # }
83/// use imxrt_ral as ral;
84/// use ral::usb;
85///
86/// struct Peripherals {
87///     usb: ral::usb::Instance,
88///     phy: ral::usbphy::Instance,
89///     _nc: ral::usbnc::Instance,
90///     _analog: ral::usb_analog::Instance,
91/// }
92///
93/// impl Peripherals {
94///     /// Panics if the instances are already taken
95///     fn usb1() -> Peripherals {
96///         Self {
97///             usb: ral::usb::USB1::take().unwrap(),
98///             phy: ral::usbphy::USBPHY1::take().unwrap(),
99///             _nc: ral::usbnc::USBNC1::take().unwrap(),
100///             _analog: ral::usb_analog::USB_ANALOG::take().unwrap(),
101///         }
102///     }
103/// }
104///
105/// // This implementation is safe, because a `Peripherals` object
106/// // owns the four imxrt-ral instances, which are
107/// // guaranteed to be singletons. Given this approach, no one else
108/// // can safely access the USB registers.
109/// unsafe impl imxrt_usbd::Peripherals for Peripherals {
110///     fn usb(&self) -> *const () {
111///         let rb: &ral::usb::RegisterBlock = &self.usb;
112///         (rb as *const ral::usb::RegisterBlock).cast()
113///     }
114///     fn usbphy(&self) -> *const () {
115///         let rb: &ral::usbphy::RegisterBlock = &self.phy;
116///         (rb as *const ral::usbphy::RegisterBlock).cast()
117///     }
118/// }
119///
120/// let peripherals = Peripherals::usb1();
121/// let bus = imxrt_usbd::BusAdapter::new(
122///     peripherals,
123///     // Rest of setup...
124///     # { static EP_MEMORY: imxrt_usbd::EndpointMemory<1> = imxrt_usbd::EndpointMemory::new(); &EP_MEMORY },
125///     # { static EP_STATE: imxrt_usbd::EndpointState = imxrt_usbd::EndpointState::max_endpoints(); &EP_STATE }
126/// );
127/// ```
128pub unsafe trait Peripherals {
129    /// Returns the pointer to the USB register block.
130    fn usb(&self) -> *const ();
131    /// Returns the pointer to the USBPHY register block.
132    fn usbphy(&self) -> *const ();
133}