|
1 | 1 | #![no_std] |
| 2 | +#![feature(asm_experimental_arch)] |
2 | 3 |
|
3 | 4 | //! `atmega-hal` |
4 | 5 | //! ============= |
@@ -119,6 +120,93 @@ pub use avr_hal_generic::clock; |
119 | 120 | pub use avr_hal_generic::delay; |
120 | 121 | pub use avr_hal_generic::prelude; |
121 | 122 |
|
| 123 | +#[cfg(feature = "atmega32u4")] |
| 124 | +mod usb; |
| 125 | + |
| 126 | +// TODO: fix bad usb-device::UsbBus link |
| 127 | +/// This function provides a safe abstraction layer over the USB hardware, by way of the |
| 128 | +/// [UsbBus](usb-device::UsbBus) trait. |
| 129 | +/// |
| 130 | +/// There are a few notable limitations, however: |
| 131 | +/// |
| 132 | +/// * This implementation requires exclusive access to the PLL, even though on a hardware |
| 133 | +/// level it is possible for the PLL output to be used by both the USB controller and |
| 134 | +/// the high-speed timer (TC4) simultaneously. Refer to GitHub issue #TBD for details. |
| 135 | +/// |
| 136 | +/// TODO if Rahix agrees that this limitation isn't something we need to worry about |
| 137 | +/// as part of PR, then create a GitHub issue so that someone else can fix it later: |
| 138 | +/// |
| 139 | +/// > **Title** |
| 140 | +/// > |
| 141 | +/// > Allow the USB and TC4 hardware to both use the PLL output simultaneously |
| 142 | +/// > |
| 143 | +/// > **Description** |
| 144 | +/// > |
| 145 | +/// > Our current UsbBus implementation prevents TC4 from using PLL output, even though |
| 146 | +/// > the hardware supports it. There are two main |
| 147 | +/// > problems that we need to solve first: |
| 148 | +/// > |
| 149 | +/// > 1. The current UsbBus implementation sets the PLL output to 48MHz. This could |
| 150 | +/// > cause problems if the user has already configured TC4 to expect a different |
| 151 | +/// > clock speed from the PLL. |
| 152 | +/// > |
| 153 | +/// > 2. We need to make the USB suspend state configurable. Currently when the USB |
| 154 | +/// > bus is idle for 3ms or longer, it will disable the PLL to reduce power usage. |
| 155 | +/// > However, this may not be desirable if TC4 is also using the PLL. |
| 156 | +/// > |
| 157 | +/// > **Comment** |
| 158 | +/// > |
| 159 | +/// > I think we *might* be able to solve this by splitting the constructor's |
| 160 | +/// > argument into two separate parts. Instead of passing ownership of the entire PLL |
| 161 | +/// > configuration (`pll: avr_device::atmega32u4::PLL`), we'd have one argument for |
| 162 | +/// > the registers that config the PLL clock speed (e.g. `pll_config: &PLLFRQ`) and one |
| 163 | +/// > optional argument for the registers that we use to turn the PLL on and off |
| 164 | +/// > (e.g. `pll_suspend: Option<&mut pllcsr>`). A value of `None` would indicate that |
| 165 | +/// > the user wants us to keep the PLL running while USB is idle. |
| 166 | +/// > |
| 167 | +/// > A few disclaimers: |
| 168 | +/// > |
| 169 | +/// > * This is a simplification. Instead of `pll_suspend: Option<&mut pllcsr>` we'd |
| 170 | +/// > probably want to define a new trait, |
| 171 | +/// > similar to what is done [in the `agausmann/atmega-usbd` repo](https://github.com/agausmann/atmega-usbd/blob/5fc68ca813ce0a37dab65dd4d66efe1ec125f2a8/src/lib.rs#L590-L618). |
| 172 | +/// > |
| 173 | +/// > * This is just one possible solution; there are others. |
| 174 | +/// > |
| 175 | +/// > * I've not spent much time investigating this, so this proposed solution might not work. |
| 176 | +/// |
| 177 | +/// * The current implementation does not attempt to minimize power usage. For details, |
| 178 | +/// see GitHub issue #TBD. |
| 179 | +/// |
| 180 | +/// TODO if Rahix agrees that this limitation isn't something we need to worry about |
| 181 | +/// as part of PR, then create a GitHub issue so that someone else can fix it later: |
| 182 | +/// |
| 183 | +/// * Add support for using interrupts, in addition to polling. |
| 184 | +/// Similar to `agausmann/atmega-usbd`. |
| 185 | +/// |
| 186 | +/// * Shutdown the PLL when the USB module is suspended (TODO: do in this PR?) |
| 187 | +/// |
| 188 | +/// * and more? |
| 189 | +/// |
| 190 | +/// * The underlying struct that implements `UsbBus` is private. This is done intentionally |
| 191 | +/// in order to make it easier to address the other issues without breaking backwards |
| 192 | +/// compatibility. |
| 193 | +#[cfg(feature = "atmega32u4")] |
| 194 | +pub fn default_usb_bus_with_pll( |
| 195 | + usb: avr_device::atmega32u4::USB_DEVICE, |
| 196 | + pll: avr_device::atmega32u4::PLL, |
| 197 | +) -> impl usb_device::class_prelude::UsbBus { |
| 198 | + return usb::UsbdBus::new(usb, pll); |
| 199 | +} |
| 200 | + |
| 201 | +/// This macro is exactly equivalent to [default_usb_bus_with_pll](default_usb_bus_with_pll). |
| 202 | +#[cfg(feature = "atmega32u4")] |
| 203 | +#[macro_export] |
| 204 | +macro_rules! default_usb_bus_with_pll_macro { |
| 205 | + ($p:expr) => { |
| 206 | + $crate::default_usb_bus_with_pll($p.USB_DEVICE, $p.PLL) |
| 207 | + }; |
| 208 | +} |
| 209 | + |
122 | 210 | #[cfg(feature = "device-selected")] |
123 | 211 | pub mod adc; |
124 | 212 | #[cfg(feature = "device-selected")] |
|
0 commit comments