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
//! Based on `stm32f3xx-hal` This module is a thin wrapper required to work with
//! the `usbd` crate.

//! USB peripheral
//!
//! Requires the `usb` feature.
//!
//! See [examples/usb_serial.rs] for a usage example.
//!
//! [examples/usb_serial.rs]: https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.6.1/examples/usb_serial.rs

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

pub use stm32_usbd::UsbBus;

/// USB Peripheral
///
/// Constructs the peripheral, which
/// than gets passed to the [`UsbBus`].
pub struct Peripheral {
    /// USB Register Block
    pub usb: USB,
}

unsafe impl Sync for Peripheral {}

unsafe impl UsbPeripheral for Peripheral {
    const REGISTERS: *const () = USB::ptr() as *const ();

    // Embedded pull-up resistor on USB_DP line
    const DP_PULL_UP_FEATURE: bool = true; // todo: What should this be?

    // Pointer to the endpoint memory
    const EP_MEMORY: *const () = 0x4000_6000 as _;

    // Endpoint memory access scheme. Check RM.
    // Set to `true` if "2x16 bits/word" access scheme is used, otherwise set to `false`.
    const EP_MEMORY_ACCESS_2X16: bool = true;
    // #[cfg(any(feature = "stm32f303xb", feature = "stm32f303xc"))]
    // const EP_MEMORY_SIZE: usize = 512;
    // #[cfg(any(feature = "stm32f303xd", feature = "stm32f303xe"))]

    // f303 subvariants have diff mem sizes and bits/word scheme. :/

    // todo: Is there a way to pass `EP_MEMORY_SIZE` as an arg?

    // Endpoint memory size in bytes
    #[cfg(feature = "f3")]
    const EP_MEMORY_SIZE: usize = 512;
    // todo: Feature-gate various memory sizes

    #[cfg(feature = "l4")]
    const EP_MEMORY_SIZE: usize = 1024;

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

        cortex_m::interrupt::free(|_| {
            cfg_if::cfg_if! {
                if #[cfg(feature = "f3")] {
                    // 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());
                } else if #[cfg(not(feature = "l4x3"))]{
                    rcc.apb1enr1.modify(|_, w| w.usbfsen().set_bit());

                    // Reset USB peripheral
                    rcc.apb1rstr1.modify(|_, w| w.usbfsrst().set_bit());
                    rcc.apb1rstr1.modify(|_, w| w.usbfsrst().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
///
/// As this MCU family has only USB peripheral,
/// this is the only possible concrete type construction.
pub type UsbBusType = UsbBus<Peripheral>;