Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate usb driver code to crate musb #21

Merged
merged 1 commit into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ log = { version = "0.4", optional = true }
critical-section = "1.2"
cfg-if = "1.0.0"
portable-atomic = { version = "1", features = ["unsafe-assume-single-core", "require-cas"], optional = true }
# musb = { version = "0.1.0", optional = true, features = ["prebuild"] }
musb = { git = "https://github.com/decaday/musb.git", optional = true, features = ["prebuild"] }
# musb = { path = "../musb", optional = true , features = ["prebuild"] }

futures-util = { version = "0.3.30", default-features = false }
embassy-hal-internal = { version = "0.2.0", features = [
Expand Down Expand Up @@ -87,11 +90,11 @@ exti = []
# PY32F07x: the IN and OUT buffers of the same endpoint being shared
# When this feature is enabled, the In and Out of an endpoint will not be used at the same time, except for ep0.
# PY32F403: IN and OUT do not share FIFO, this feature is invalid
allow-ep-shared-fifo = []
allow-ep-shared-fifo = ["musb/allow-ep-shared-fifo"]

py32f030k28 = ["py32-metapac/py32f030k28"]
py32f030f16 = ["py32-metapac/py32f030f16"]
py32f072c1b = ["py32-metapac/py32f072c1b"]
py32f072c1b = ["py32-metapac/py32f072c1b", "dep:musb", "musb/builtin-py32f07x"]

# As of 2023-12-04, this driver is implemented using CC1 as the halfway rollover interrupt, and any
# additional CC capabilities to provide timer alarms to embassy-time. embassy-time requires AT LEAST
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub mod time_driver;
#[cfg(feature = "time-driver-systick")]
pub mod systick_time_driver;
pub mod gpio;
#[cfg(usb)]
#[cfg(feature = "py32f072c1b")]
pub mod usb;

#[cfg(feature = "exti")]
Expand Down
127 changes: 127 additions & 0 deletions src/usb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/// Universal Serial Bus (USB)
///
/// The USB peripheral IP in PY32 is a mini Mentor USB (musb),
/// featuring a fixed FIFO size and with some register functionalities masked.
///
/// See more: https://github.com/decaday/musb
///
/// For the PY32F07x series, IN and OUT endpoints for the same endpoint share a FIFO.
/// By default, we don't use a single endpoint simultaneously for IN and OUT directions.
/// However, you can enable the `allow-ep-shared-fifo` feature to use an endpoint's IN
/// and OUT capabilities concurrently.

use core::marker::PhantomData;
use embassy_usb_driver as driver;

use crate::rcc::{self, RccPeripheral};
use crate::{interrupt, Peripheral};
use crate::interrupt::typelevel::Interrupt;

use embassy_usb_driver::EndpointType;

use musb::{MusbDriver,
Endpoint,
ControlPipe,
UsbInstance,
Bus,
Out,
In,
};

/// Interrupt handler.
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}

impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
musb::on_interrupt::<UsbInstance>();
}
}

/// USB driver.
pub struct Driver<'d, T: Instance> {
phantom: PhantomData<&'d mut T>,
inner: MusbDriver<'d, UsbInstance>,
}

impl<'d, T: Instance> Driver<'d, T> {
/// Create a new USB driver.
pub fn new(
_usb: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_dp: impl Peripheral<P = impl DpPin<T>> + 'd,
_dm: impl Peripheral<P = impl DmPin<T>> + 'd,
) -> Self {
let freq = T::frequency();
if freq.0 != 48_000_000 {
panic!("USB clock (PLL) must be 48MHz");
}

T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
rcc::enable_and_reset::<T>();

#[cfg(feature = "time")]
embassy_time::block_for(embassy_time::Duration::from_millis(100));
#[cfg(not(feature = "time"))]
cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 10);

Self {
inner: MusbDriver::new(),
phantom: PhantomData,
}
}
}

impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
type EndpointOut = Endpoint<'d, UsbInstance, Out>;
type EndpointIn = Endpoint<'d, UsbInstance, In>;
type ControlPipe = ControlPipe<'d, UsbInstance>;
type Bus = Bus<'d, UsbInstance>;

fn alloc_endpoint_in(
&mut self,
ep_type: EndpointType,
max_packet_size: u16,
interval_ms: u8,
) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
self.inner.alloc_endpoint(ep_type, max_packet_size, interval_ms, false)
}

fn alloc_endpoint_out(
&mut self,
ep_type: EndpointType,
max_packet_size: u16,
interval_ms: u8,
) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
self.inner.alloc_endpoint(ep_type, max_packet_size, interval_ms, false)
}

fn start(self, control_max_packet_size: u16) -> (Bus<'d, UsbInstance>, ControlPipe<'d, UsbInstance>) {
self.inner.start(control_max_packet_size)
}
}

trait SealedInstance {}

/// USB instance trait.
#[allow(private_bounds)]
pub trait Instance: SealedInstance + RccPeripheral + 'static {
/// Interrupt for this USB instance.
type Interrupt: interrupt::typelevel::Interrupt;
}

// Internal PHY pins
pin_trait!(DpPin, Instance);
pin_trait!(DmPin, Instance);

foreach_interrupt!(
($inst:ident, usb, $block:ident, LP, $irq:ident) => {
impl SealedInstance for crate::peripherals::$inst {}

impl Instance for crate::peripherals::$inst {
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
);
Loading
Loading