stm32_usbd/
bus.rs

1//! USB peripheral driver.
2
3use core::mem::{self, MaybeUninit};
4use cortex_m::interrupt::{self, Mutex};
5use usb_device::bus::{PollResult, UsbBusAllocator};
6use usb_device::endpoint::{EndpointAddress, EndpointType};
7use usb_device::{Result, UsbDirection, UsbError};
8
9use crate::endpoint::{calculate_count_rx, Endpoint, EndpointStatus, NUM_ENDPOINTS};
10use crate::endpoint_memory::EndpointMemoryAllocator;
11use crate::registers::UsbRegisters;
12use crate::UsbPeripheral;
13
14/// USB peripheral driver for STM32 microcontrollers.
15pub struct UsbBus<USB> {
16    peripheral: USB,
17    regs: Mutex<UsbRegisters<USB>>,
18    endpoints: [Endpoint<USB>; NUM_ENDPOINTS],
19    ep_allocator: EndpointMemoryAllocator<USB>,
20    max_endpoint: usize,
21}
22
23impl<USB: UsbPeripheral> UsbBus<USB> {
24    /// Constructs a new USB peripheral driver.
25    pub fn new(peripheral: USB) -> UsbBusAllocator<Self> {
26        USB::enable();
27
28        let bus = UsbBus {
29            peripheral,
30            regs: Mutex::new(UsbRegisters::new()),
31            ep_allocator: EndpointMemoryAllocator::new(),
32            max_endpoint: 0,
33            endpoints: {
34                let mut endpoints: [MaybeUninit<Endpoint<USB>>; NUM_ENDPOINTS] =
35                    unsafe { MaybeUninit::uninit().assume_init() };
36
37                for i in 0..NUM_ENDPOINTS {
38                    endpoints[i] = MaybeUninit::new(Endpoint::new(i as u8));
39                }
40
41                unsafe { mem::transmute::<_, [Endpoint<USB>; NUM_ENDPOINTS]>(endpoints) }
42            },
43        };
44
45        UsbBusAllocator::new(bus)
46    }
47
48    pub fn free(self) -> USB {
49        self.peripheral
50    }
51
52    /// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the
53    /// device.
54    ///
55    /// Mostly used for development. By calling this at the start of your program ensures that the
56    /// host re-enumerates your device after a new program has been flashed.
57    ///
58    /// `disconnect` parameter is used to provide a custom disconnect function.
59    /// This function will be called with USB peripheral powered down
60    /// and interrupts disabled.
61    /// It should perform disconnect in a platform-specific way.
62    pub fn force_reenumeration<F: FnOnce()>(&self, disconnect: F) {
63        interrupt::free(|cs| {
64            let regs = self.regs.borrow(cs);
65
66            let pdwn = regs.cntr.read().pdwn().bit_is_set();
67            regs.cntr.modify(|_, w| w.pdwn().set_bit());
68
69            disconnect();
70
71            regs.cntr.modify(|_, w| w.pdwn().bit(pdwn));
72        });
73    }
74
75    /// Enter suspend low-power mode
76    ///
77    /// This should be used when in suspend mode if low-power mode needs to be entered during
78    /// suspend (bus-powered device). Application should call this when it is ready to decrease
79    /// power consumption to meet power consumption requirements of the USB suspend condition
80    /// (e.g. disable system clocks or reduce their frequency). When wake up event is received
81    /// low power mode will be automatically disabled.
82    ///
83    /// Will not enter low-power mode if not in suspend state. Returns `true` if entered.
84    pub fn suspend_low_power_mode(&self) -> bool {
85        interrupt::free(|cs| {
86            let regs = self.regs.borrow(cs);
87            if regs.cntr.read().fsusp().is_suspend() {
88                regs.cntr.modify(|_, w| w.lpmode().set_bit());
89                true
90            } else {
91                false
92            }
93        })
94    }
95
96    /// Set/clear remote wakeup bit
97    ///
98    /// Allows to modify CNTR.RESUME bit from device to perform remote wake up from suspend
99    /// (e.g. on keyboard/mouse input). To perform remote wake up: when a condition is met
100    /// during suspend mode, use this method with `true` to set the RESUME bit. Then, after
101    /// waiting between 1-15 ms (see reference manual) call it again with `false` to clear
102    /// the bit.
103    ///
104    /// This method will not set the bit if device is not suspended because performing remote
105    /// wake up in other mode is invalid and host will most likely disable such a device.
106    pub fn remote_wakeup(&self, resume: bool) {
107        interrupt::free(|cs| {
108            self.regs
109                .borrow(cs)
110                .cntr
111                .modify(|r, w| w.resume().bit(resume && r.fsusp().is_suspend()));
112        })
113    }
114}
115
116impl<USB: UsbPeripheral> usb_device::bus::UsbBus for UsbBus<USB> {
117    fn alloc_ep(
118        &mut self,
119        ep_dir: UsbDirection,
120        ep_addr: Option<EndpointAddress>,
121        ep_type: EndpointType,
122        max_packet_size: u16,
123        _interval: u8,
124    ) -> Result<EndpointAddress> {
125        for index in ep_addr.map(|a| a.index()..a.index() + 1).unwrap_or(1..NUM_ENDPOINTS) {
126            let ep = &mut self.endpoints[index];
127
128            match ep.ep_type() {
129                None => {
130                    ep.set_ep_type(ep_type);
131                }
132                Some(t) if t != ep_type => {
133                    continue;
134                }
135                _ => {}
136            };
137
138            match ep_dir {
139                UsbDirection::Out if !ep.is_out_buf_set() => {
140                    let (out_size, size_bits) = calculate_count_rx(max_packet_size as usize)?;
141
142                    let buffer = self.ep_allocator.allocate_buffer(out_size)?;
143
144                    ep.set_out_buf(buffer, size_bits);
145
146                    return Ok(EndpointAddress::from_parts(index, ep_dir));
147                }
148                UsbDirection::In if !ep.is_in_buf_set() => {
149                    let size = (max_packet_size as usize + 1) & !0x01;
150
151                    let buffer = self.ep_allocator.allocate_buffer(size)?;
152
153                    ep.set_in_buf(buffer);
154
155                    return Ok(EndpointAddress::from_parts(index, ep_dir));
156                }
157                _ => {}
158            }
159        }
160
161        Err(match ep_addr {
162            Some(_) => UsbError::InvalidEndpoint,
163            None => UsbError::EndpointOverflow,
164        })
165    }
166
167    fn enable(&mut self) {
168        let mut max = 0;
169        for (index, ep) in self.endpoints.iter().enumerate() {
170            if ep.is_out_buf_set() || ep.is_in_buf_set() {
171                max = index;
172            }
173        }
174
175        self.max_endpoint = max;
176
177        interrupt::free(|cs| {
178            let regs = self.regs.borrow(cs);
179
180            regs.cntr.modify(|_, w| w.pdwn().clear_bit());
181
182            USB::startup_delay();
183
184            regs.btable.modify(|_, w| w.btable().bits(0));
185            regs.cntr.modify(|_, w| {
186                w.fres().clear_bit();
187                w.resetm().set_bit();
188                w.suspm().set_bit();
189                w.wkupm().set_bit();
190                w.ctrm().set_bit()
191            });
192            regs.istr.modify(|_, w| unsafe { w.bits(0) });
193
194            if USB::DP_PULL_UP_FEATURE {
195                regs.bcdr.modify(|_, w| w.dppu().set_bit());
196            }
197        });
198    }
199
200    fn reset(&self) {
201        interrupt::free(|cs| {
202            let regs = self.regs.borrow(cs);
203
204            regs.istr.modify(|_, w| unsafe { w.bits(0) });
205            regs.daddr.modify(|_, w| w.ef().set_bit().add().bits(0));
206
207            for ep in self.endpoints.iter() {
208                ep.configure(cs);
209            }
210        });
211    }
212
213    fn set_device_address(&self, addr: u8) {
214        interrupt::free(|cs| {
215            self.regs.borrow(cs).daddr.modify(|_, w| w.add().bits(addr as u8));
216        });
217    }
218
219    fn poll(&self) -> PollResult {
220        interrupt::free(|cs| {
221            let regs = self.regs.borrow(cs);
222
223            let istr = regs.istr.read();
224
225            if istr.wkup().bit_is_set() {
226                // Interrupt flag bits are write-0-to-clear, other bits should be written as 1 to avoid
227                // race conditions
228                regs.istr.write(|w| unsafe { w.bits(0xffff) }.wkup().clear_bit());
229
230                // Required by datasheet
231                regs.cntr.modify(|_, w| w.fsusp().clear_bit());
232
233                PollResult::Resume
234            } else if istr.reset().bit_is_set() {
235                regs.istr.write(|w| unsafe { w.bits(0xffff) }.reset().clear_bit());
236
237                PollResult::Reset
238            } else if istr.susp().bit_is_set() {
239                regs.istr.write(|w| unsafe { w.bits(0xffff) }.susp().clear_bit());
240
241                PollResult::Suspend
242            } else if istr.ctr().bit_is_set() {
243                let mut ep_out = 0;
244                let mut ep_in_complete = 0;
245                let mut ep_setup = 0;
246                let mut bit = 1;
247
248                for ep in &self.endpoints[0..=self.max_endpoint] {
249                    let v = ep.read_reg();
250
251                    if v.ctr_rx().bit_is_set() {
252                        ep_out |= bit;
253
254                        if v.setup().bit_is_set() {
255                            ep_setup |= bit;
256                        }
257                    }
258
259                    if v.ctr_tx().bit_is_set() {
260                        ep_in_complete |= bit;
261                        ep.clear_ctr_tx(cs);
262                    }
263
264                    bit <<= 1;
265                }
266
267                PollResult::Data {
268                    ep_out,
269                    ep_in_complete,
270                    ep_setup,
271                }
272            } else {
273                PollResult::None
274            }
275        })
276    }
277
278    fn write(&self, ep_addr: EndpointAddress, buf: &[u8]) -> Result<usize> {
279        if !ep_addr.is_in() {
280            return Err(UsbError::InvalidEndpoint);
281        }
282
283        self.endpoints[ep_addr.index()].write(buf)
284    }
285
286    fn read(&self, ep_addr: EndpointAddress, buf: &mut [u8]) -> Result<usize> {
287        if !ep_addr.is_out() {
288            return Err(UsbError::InvalidEndpoint);
289        }
290
291        self.endpoints[ep_addr.index()].read(buf)
292    }
293
294    fn set_stalled(&self, ep_addr: EndpointAddress, stalled: bool) {
295        interrupt::free(|cs| {
296            if self.is_stalled(ep_addr) == stalled {
297                return;
298            }
299
300            let ep = &self.endpoints[ep_addr.index()];
301
302            match (stalled, ep_addr.direction()) {
303                (true, UsbDirection::In) => ep.set_stat_tx(cs, EndpointStatus::Stall),
304                (true, UsbDirection::Out) => ep.set_stat_rx(cs, EndpointStatus::Stall),
305                (false, UsbDirection::In) => ep.set_stat_tx(cs, EndpointStatus::Nak),
306                (false, UsbDirection::Out) => ep.set_stat_rx(cs, EndpointStatus::Valid),
307            };
308        });
309    }
310
311    fn is_stalled(&self, ep_addr: EndpointAddress) -> bool {
312        let ep = &self.endpoints[ep_addr.index()];
313        let reg_v = ep.read_reg();
314
315        let status = match ep_addr.direction() {
316            UsbDirection::In => reg_v.stat_tx().bits(),
317            UsbDirection::Out => reg_v.stat_rx().bits(),
318        };
319
320        status == (EndpointStatus::Stall as u8)
321    }
322
323    fn suspend(&self) {
324        interrupt::free(|cs| {
325            self.regs.borrow(cs).cntr.modify(|_, w| w.fsusp().set_bit());
326        });
327    }
328
329    fn resume(&self) {
330        interrupt::free(|cs| {
331            self.regs
332                .borrow(cs)
333                .cntr
334                .modify(|_, w| w.fsusp().clear_bit().lpmode().clear_bit());
335        });
336    }
337}