1
+ /// Universal Serial Bus (USB)
2
+ ///
3
+ /// The USB peripheral IP in PY32 is a mini Mentor USB (musb),
4
+ /// featuring a fixed FIFO size and with some register functionalities masked.
5
+ ///
6
+ /// See more: https://github.com/decaday/musb
7
+ ///
8
+ /// For the PY32F07x series, IN and OUT endpoints for the same endpoint share a FIFO.
9
+ /// By default, we don't use a single endpoint simultaneously for IN and OUT directions.
10
+ /// However, you can enable the `allow-ep-shared-fifo` feature to use an endpoint's IN
11
+ /// and OUT capabilities concurrently.
12
+
13
+ use core:: marker:: PhantomData ;
14
+ use embassy_usb_driver as driver;
15
+
16
+ use crate :: rcc:: { self , RccPeripheral } ;
17
+ use crate :: { interrupt, Peripheral } ;
18
+ use crate :: interrupt:: typelevel:: Interrupt ;
19
+
20
+ use embassy_usb_driver:: EndpointType ;
21
+
22
+ use musb:: { MusbDriver ,
23
+ Endpoint ,
24
+ ControlPipe ,
25
+ UsbInstance ,
26
+ Bus ,
27
+ Out ,
28
+ In ,
29
+ } ;
30
+
31
+ /// Interrupt handler.
32
+ pub struct InterruptHandler < T : Instance > {
33
+ _phantom : PhantomData < T > ,
34
+ }
35
+
36
+ impl < T : Instance > interrupt:: typelevel:: Handler < T :: Interrupt > for InterruptHandler < T > {
37
+ unsafe fn on_interrupt ( ) {
38
+ musb:: on_interrupt :: < UsbInstance > ( ) ;
39
+ }
40
+ }
41
+
42
+ /// USB driver.
43
+ pub struct Driver < ' d , T : Instance > {
44
+ phantom : PhantomData < & ' d mut T > ,
45
+ inner : MusbDriver < ' d , UsbInstance > ,
46
+ }
47
+
48
+ impl < ' d , T : Instance > Driver < ' d , T > {
49
+ /// Create a new USB driver.
50
+ pub fn new (
51
+ _usb : impl Peripheral < P = T > + ' d ,
52
+ _irq : impl interrupt:: typelevel:: Binding < T :: Interrupt , InterruptHandler < T > > + ' d ,
53
+ _dp : impl Peripheral < P = impl DpPin < T > > + ' d ,
54
+ _dm : impl Peripheral < P = impl DmPin < T > > + ' d ,
55
+ ) -> Self {
56
+ let freq = T :: frequency ( ) ;
57
+ if freq. 0 != 48_000_000 {
58
+ panic ! ( "USB clock (PLL) must be 48MHz" ) ;
59
+ }
60
+
61
+ T :: Interrupt :: unpend ( ) ;
62
+ unsafe { T :: Interrupt :: enable ( ) } ;
63
+ rcc:: enable_and_reset :: < T > ( ) ;
64
+
65
+ #[ cfg( feature = "time" ) ]
66
+ embassy_time:: block_for ( embassy_time:: Duration :: from_millis ( 100 ) ) ;
67
+ #[ cfg( not( feature = "time" ) ) ]
68
+ cortex_m:: asm:: delay ( unsafe { crate :: rcc:: get_freqs ( ) } . sys . to_hertz ( ) . unwrap ( ) . 0 / 10 ) ;
69
+
70
+ Self {
71
+ inner : MusbDriver :: new ( ) ,
72
+ phantom : PhantomData ,
73
+ }
74
+ }
75
+ }
76
+
77
+ impl < ' d , T : Instance > driver:: Driver < ' d > for Driver < ' d , T > {
78
+ type EndpointOut = Endpoint < ' d , UsbInstance , Out > ;
79
+ type EndpointIn = Endpoint < ' d , UsbInstance , In > ;
80
+ type ControlPipe = ControlPipe < ' d , UsbInstance > ;
81
+ type Bus = Bus < ' d , UsbInstance > ;
82
+
83
+ fn alloc_endpoint_in (
84
+ & mut self ,
85
+ ep_type : EndpointType ,
86
+ max_packet_size : u16 ,
87
+ interval_ms : u8 ,
88
+ ) -> Result < Self :: EndpointIn , driver:: EndpointAllocError > {
89
+ self . inner . alloc_endpoint ( ep_type, max_packet_size, interval_ms, false )
90
+ }
91
+
92
+ fn alloc_endpoint_out (
93
+ & mut self ,
94
+ ep_type : EndpointType ,
95
+ max_packet_size : u16 ,
96
+ interval_ms : u8 ,
97
+ ) -> Result < Self :: EndpointOut , driver:: EndpointAllocError > {
98
+ self . inner . alloc_endpoint ( ep_type, max_packet_size, interval_ms, false )
99
+ }
100
+
101
+ fn start ( self , control_max_packet_size : u16 ) -> ( Bus < ' d , UsbInstance > , ControlPipe < ' d , UsbInstance > ) {
102
+ self . inner . start ( control_max_packet_size)
103
+ }
104
+ }
105
+
106
+ trait SealedInstance { }
107
+
108
+ /// USB instance trait.
109
+ #[ allow( private_bounds) ]
110
+ pub trait Instance : SealedInstance + RccPeripheral + ' static {
111
+ /// Interrupt for this USB instance.
112
+ type Interrupt : interrupt:: typelevel:: Interrupt ;
113
+ }
114
+
115
+ // Internal PHY pins
116
+ pin_trait ! ( DpPin , Instance ) ;
117
+ pin_trait ! ( DmPin , Instance ) ;
118
+
119
+ foreach_interrupt ! (
120
+ ( $inst: ident, usb, $block: ident, LP , $irq: ident) => {
121
+ impl SealedInstance for crate :: peripherals:: $inst { }
122
+
123
+ impl Instance for crate :: peripherals:: $inst {
124
+ type Interrupt = crate :: interrupt:: typelevel:: $irq;
125
+ }
126
+ } ;
127
+ ) ;
0 commit comments