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}