1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! # USB peripheral.
//!
//! Mostly builds upon the [`stm32_usbd`] crate.
//!
//! ## Examples
//!
//! See [examples/usb_serial.rs] for a usage example.
//!
//! [examples/usb_serial.rs]: https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.8.0/examples/usb_serial.rs

use core::fmt;

use crate::pac::{RCC, USB};
use stm32_usbd::UsbPeripheral;

use crate::gpio;
use crate::gpio::gpioa::{PA11, PA12};
pub use stm32_usbd::UsbBus;

/// Trait implemented by all pins that can be the "D-" pin for the USB peripheral
pub trait DmPin: crate::private::Sealed {}

/// Trait implemented by all pins that can be the "D+" pin for the USB peripheral
pub trait DpPin: crate::private::Sealed {}

#[cfg(any(feature = "stm32f303xb", feature = "stm32f303xc"))]
impl DmPin for PA11<gpio::AF14<gpio::PushPull>> {}

#[cfg(any(feature = "stm32f303xb", feature = "stm32f303xc"))]
impl DpPin for PA12<gpio::AF14<gpio::PushPull>> {}

#[cfg(any(feature = "stm32f303xd", feature = "stm32f303xe"))]
impl<Mode> DmPin for PA11<Mode> {}

#[cfg(any(feature = "stm32f303xd", feature = "stm32f303xe"))]
impl<Mode> DpPin for PA12<Mode> {}

/// USB Peripheral
///
/// Constructs the peripheral, which
/// than gets passed to the [`UsbBus`].
pub struct Peripheral<Dm: DmPin, Dp: DpPin> {
    /// USB Register Block
    pub usb: USB,
    /// Data Negativ Pin
    pub pin_dm: Dm,
    /// Data Positiv Pin
    pub pin_dp: Dp,
}

#[cfg(feature = "defmt")]
impl<Dm: DmPin + defmt::Format, Dp: DpPin + defmt::Format> defmt::Format for Peripheral<Dm, Dp> {
    fn format(&self, f: defmt::Formatter) {
        defmt::write!(
            f,
            "Peripheral {{ usb: USB, pin_dm: {}, pin_dp: {}}}",
            self.pin_dm,
            self.pin_dp
        );
    }
}

impl<Dm, Dp> fmt::Debug for Peripheral<Dm, Dp>
where
    Dm: DmPin + fmt::Debug,
    Dp: DpPin + fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Peripheral")
            .field("usb", &"USB")
            .field("pin_dm", &self.pin_dm)
            .field("pin_dp", &self.pin_dp)
            .finish()
    }
}

unsafe impl<Dm: DmPin, Dp: DpPin> Sync for Peripheral<Dm, Dp> {}

unsafe impl<Dm: DmPin + Send, Dp: DpPin + Send> UsbPeripheral for Peripheral<Dm, Dp> {
    const REGISTERS: *const () = USB::ptr() as *const ();
    const DP_PULL_UP_FEATURE: bool = false;
    const EP_MEMORY: *const () = 0x4000_6000 as _;
    #[cfg(any(feature = "stm32f303xb", feature = "stm32f303xc"))]
    const EP_MEMORY_SIZE: usize = 512;
    #[cfg(any(feature = "stm32f303xd", feature = "stm32f303xe"))]
    const EP_MEMORY_SIZE: usize = 1024;
    #[cfg(any(feature = "stm32f303xb", feature = "stm32f303xc"))]
    const EP_MEMORY_ACCESS_2X16: bool = false;
    #[cfg(any(feature = "stm32f303xd", feature = "stm32f303xe"))]
    const EP_MEMORY_ACCESS_2X16: bool = true;

    fn enable() {
        let rcc = unsafe { &*RCC::ptr() };

        cortex_m::interrupt::free(|_| {
            // Enable USB peripheral
            rcc.apb1enr.modify(|_, w| w.usben().enabled());

            // Reset USB peripheral
            rcc.apb1rstr.modify(|_, w| w.usbrst().reset());
            rcc.apb1rstr.modify(|_, w| w.usbrst().clear_bit());
        });
    }

    fn startup_delay() {
        // There is a chip specific startup delay. For STM32F103xx it's 1µs and this should wait for
        // at least that long.
        // 72 Mhz is the highest frequency, so this ensures a minimum of 1µs wait time.
        cortex_m::asm::delay(72);
    }
}

/// Type of the UsbBus
#[cfg(any(feature = "stm32f303xb", feature = "stm32f303xc"))]
pub type UsbBusType<Dm = PA11<gpio::AF14<gpio::PushPull>>, Dp = PA12<gpio::AF14<gpio::PushPull>>> =
    UsbBus<Peripheral<Dm, Dp>>;

/// Type of the UsbBus
#[cfg(any(feature = "stm32f303xd", feature = "stm32f303xe"))]
pub type UsbBusType<Dm = PA11<gpio::Input>, Dp = PA12<gpio::Input>> = UsbBus<Peripheral<Dm, Dp>>;