aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchemicstry <[email protected]>2022-02-09 02:02:23 +0200
committerchemicstry <[email protected]>2022-02-09 02:02:23 +0200
commit1f81a69347e0983f9a040125ed1532ca635e9d79 (patch)
treeccf6defc27e579e2d9c96353d342e27a5778c77c
parentdb0d798b4896e97bf40e42cb54344e7a3f77a5c8 (diff)
Merge USB FS and HS peripherals. Add ULPI.
-rw-r--r--embassy-stm32/Cargo.toml8
-rw-r--r--embassy-stm32/src/lib.rs6
-rw-r--r--embassy-stm32/src/usb_otg.rs328
-rw-r--r--embassy-stm32/src/usb_otg_fs.rs159
-rw-r--r--embassy-stm32/src/usb_otg_hs.rs147
-rw-r--r--examples/stm32f4/Cargo.toml2
-rw-r--r--examples/stm32f4/src/bin/usb_uart.rs4
-rw-r--r--examples/stm32f4/src/bin/usb_uart_ulpi.rs114
8 files changed, 449 insertions, 319 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 8f6504b50..3c639b781 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -23,7 +23,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
23rand_core = "0.6.3" 23rand_core = "0.6.3"
24sdio-host = "0.5.0" 24sdio-host = "0.5.0"
25embedded-sdmmc = { git = "https://github.com/thalesfragoso/embedded-sdmmc-rs", branch = "async", optional = true } 25embedded-sdmmc = { git = "https://github.com/thalesfragoso/embedded-sdmmc-rs", branch = "async", optional = true }
26synopsys-usb-otg = { version = "0.3", features = ["cortex-m"], optional = true } 26synopsys-usb-otg = { version = "0.3", features = ["cortex-m", "hs"], optional = true }
27critical-section = "0.2.5" 27critical-section = "0.2.5"
28bare-metal = "1.0.0" 28bare-metal = "1.0.0"
29atomic-polyfill = "0.1.5" 29atomic-polyfill = "0.1.5"
@@ -43,11 +43,7 @@ net = ["embassy-net", "vcell"]
43memory-x = ["stm32-metapac/memory-x"] 43memory-x = ["stm32-metapac/memory-x"]
44subghz = [] 44subghz = []
45exti = [] 45exti = []
46 46usb-otg = ["synopsys-usb-otg"]
47# These features are exclusive
48# synopsys-usb-otg does not support simultaneous FS and HS
49usb-otg-fs = ["synopsys-usb-otg", "synopsys-usb-otg/fs"]
50usb-otg-hs = ["synopsys-usb-otg", "synopsys-usb-otg/hs"]
51 47
52# Features starting with `_` are for internal use only. They're not intended 48# Features starting with `_` are for internal use only. They're not intended
53# to be enabled by other crates, and are not covered by semver guarantees. 49# to be enabled by other crates, and are not covered by semver guarantees.
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 3b9a61d45..2279b4042 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -50,10 +50,8 @@ pub mod sdmmc;
50pub mod spi; 50pub mod spi;
51#[cfg(usart)] 51#[cfg(usart)]
52pub mod usart; 52pub mod usart;
53#[cfg(feature = "usb-otg-fs")] 53#[cfg(feature = "usb-otg")]
54pub mod usb_otg_fs; 54pub mod usb_otg;
55#[cfg(feature = "usb-otg-hs")]
56pub mod usb_otg_hs;
57 55
58#[cfg(feature = "subghz")] 56#[cfg(feature = "subghz")]
59pub mod subghz; 57pub mod subghz;
diff --git a/embassy-stm32/src/usb_otg.rs b/embassy-stm32/src/usb_otg.rs
new file mode 100644
index 000000000..c2c47159d
--- /dev/null
+++ b/embassy-stm32/src/usb_otg.rs
@@ -0,0 +1,328 @@
1use crate::{peripherals, rcc::RccPeripheral};
2use core::marker::PhantomData;
3use embassy::util::Unborrow;
4use embassy_hal_common::unborrow;
5pub use embassy_hal_common::usb::*;
6pub use synopsys_usb_otg::UsbBus;
7use synopsys_usb_otg::{PhyType, UsbPeripheral};
8
9macro_rules! config_pins {
10 ($($pin:ident),*) => {
11 $(
12 $pin.configure();
13 )*
14 };
15}
16
17pub struct UsbOtg<'d, T: Instance> {
18 phantom: PhantomData<&'d mut T>,
19 phy_type: PhyType,
20}
21
22impl<'d, T: Instance> UsbOtg<'d, T> {
23 pub fn new_fs(
24 _peri: impl Unborrow<Target = T> + 'd,
25 dp: impl Unborrow<Target = impl DpPin<T>> + 'd,
26 dm: impl Unborrow<Target = impl DmPin<T>> + 'd,
27 ) -> Self {
28 unborrow!(dp, dm);
29 config_pins!(dp, dm);
30
31 Self {
32 phantom: PhantomData,
33 phy_type: PhyType::InternalFullSpeed,
34 }
35 }
36
37 pub fn new_hs_ulpi(
38 _peri: impl Unborrow<Target = T> + 'd,
39 ulpi_clk: impl Unborrow<Target = impl UlpiClkPin<T>> + 'd,
40 ulpi_dir: impl Unborrow<Target = impl UlpiDirPin<T>> + 'd,
41 ulpi_nxt: impl Unborrow<Target = impl UlpiNxtPin<T>> + 'd,
42 ulpi_stp: impl Unborrow<Target = impl UlpiStpPin<T>> + 'd,
43 ulpi_d0: impl Unborrow<Target = impl UlpiD0Pin<T>> + 'd,
44 ulpi_d1: impl Unborrow<Target = impl UlpiD1Pin<T>> + 'd,
45 ulpi_d2: impl Unborrow<Target = impl UlpiD2Pin<T>> + 'd,
46 ulpi_d3: impl Unborrow<Target = impl UlpiD3Pin<T>> + 'd,
47 ulpi_d4: impl Unborrow<Target = impl UlpiD4Pin<T>> + 'd,
48 ulpi_d5: impl Unborrow<Target = impl UlpiD5Pin<T>> + 'd,
49 ulpi_d6: impl Unborrow<Target = impl UlpiD6Pin<T>> + 'd,
50 ulpi_d7: impl Unborrow<Target = impl UlpiD7Pin<T>> + 'd,
51 ) -> Self {
52 unborrow!(ulpi_clk, ulpi_dir, ulpi_nxt, ulpi_stp);
53 unborrow!(ulpi_d0, ulpi_d1, ulpi_d2, ulpi_d3, ulpi_d4, ulpi_d5, ulpi_d6, ulpi_d7);
54 config_pins!(ulpi_clk, ulpi_dir, ulpi_nxt, ulpi_stp);
55 config_pins!(ulpi_d0, ulpi_d1, ulpi_d2, ulpi_d3, ulpi_d4, ulpi_d5, ulpi_d6, ulpi_d7);
56
57 Self {
58 phantom: PhantomData,
59 phy_type: PhyType::ExternalHighSpeed,
60 }
61 }
62}
63
64impl<'d, T: Instance> Drop for UsbOtg<'d, T> {
65 fn drop(&mut self) {
66 T::reset();
67 T::disable();
68 }
69}
70
71unsafe impl<'d, T: Instance> Send for UsbOtg<'d, T> {}
72unsafe impl<'d, T: Instance> Sync for UsbOtg<'d, T> {}
73
74unsafe impl<'d, T: Instance> UsbPeripheral for UsbOtg<'d, T> {
75 const REGISTERS: *const () = T::REGISTERS;
76 const HIGH_SPEED: bool = T::HIGH_SPEED;
77 const FIFO_DEPTH_WORDS: usize = T::FIFO_DEPTH_WORDS;
78 const ENDPOINT_COUNT: usize = T::ENDPOINT_COUNT;
79
80 fn enable() {
81 <T as crate::rcc::sealed::RccPeripheral>::enable();
82 <T as crate::rcc::sealed::RccPeripheral>::reset();
83 }
84
85 fn phy_type(&self) -> PhyType {
86 self.phy_type
87 }
88
89 fn ahb_frequency_hz(&self) -> u32 {
90 <T as crate::rcc::sealed::RccPeripheral>::frequency().0
91 }
92}
93
94pub(crate) mod sealed {
95 pub trait Instance {
96 const REGISTERS: *const ();
97 const HIGH_SPEED: bool;
98 const FIFO_DEPTH_WORDS: usize;
99 const ENDPOINT_COUNT: usize;
100 }
101
102 macro_rules! declare_pins {
103 ($name:ident) => {
104 pub trait $name<T: Instance> {
105 fn configure(&mut self);
106 }
107 };
108
109 ($name:ident, $($names:ident),+) => {
110 declare_pins!($name);
111 declare_pins!($($names),+);
112 }
113 }
114
115 // Internal PHY pins
116 declare_pins!(DpPin, DmPin);
117
118 // External PHY pins
119 declare_pins!(UlpiClkPin, UlpiDirPin, UlpiNxtPin, UlpiStpPin);
120 declare_pins!(UlpiD0Pin, UlpiD1Pin, UlpiD2Pin, UlpiD3Pin);
121 declare_pins!(UlpiD4Pin, UlpiD5Pin, UlpiD6Pin, UlpiD7Pin);
122}
123
124pub trait Instance: sealed::Instance + RccPeripheral {}
125
126macro_rules! declare_pins {
127 ($name:ident) => {
128 pub trait $name<T: Instance>: sealed::$name<T> {}
129 };
130
131 ($name:ident, $($names:ident),+) => {
132 declare_pins!($name);
133 declare_pins!($($names),+);
134 }
135}
136
137declare_pins!(DpPin, DmPin);
138declare_pins!(UlpiClkPin, UlpiDirPin, UlpiNxtPin, UlpiStpPin);
139declare_pins!(UlpiD0Pin, UlpiD1Pin, UlpiD2Pin, UlpiD3Pin);
140declare_pins!(UlpiD4Pin, UlpiD5Pin, UlpiD6Pin, UlpiD7Pin);
141
142crate::pac::peripherals!(
143 (otgfs, $inst:ident) => {
144 impl sealed::Instance for peripherals::$inst {
145 const REGISTERS: *const () = crate::pac::$inst.0 as *const ();
146 const HIGH_SPEED: bool = false;
147
148 cfg_if::cfg_if! {
149 if #[cfg(stm32f1)] {
150 const FIFO_DEPTH_WORDS: usize = 128;
151 const ENDPOINT_COUNT: usize = 8;
152 } else if #[cfg(any(
153 stm32f2,
154 stm32f401,
155 stm32f405,
156 stm32f407,
157 stm32f411,
158 stm32f415,
159 stm32f417,
160 stm32f427,
161 stm32f429,
162 stm32f437,
163 stm32f439,
164 ))] {
165 const FIFO_DEPTH_WORDS: usize = 320;
166 const ENDPOINT_COUNT: usize = 4;
167 } else if #[cfg(any(
168 stm32f412,
169 stm32f413,
170 stm32f423,
171 stm32f446,
172 stm32f469,
173 stm32f479,
174 stm32f7,
175 stm32l4,
176 stm32u5,
177 ))] {
178 const FIFO_DEPTH_WORDS: usize = 320;
179 const ENDPOINT_COUNT: usize = 6;
180 } else if #[cfg(stm32g0x1)] {
181 const FIFO_DEPTH_WORDS: usize = 512;
182 const ENDPOINT_COUNT: usize = 8;
183 } else {
184 compile_error!("USB_OTG_FS peripheral is not supported by this chip. Disable \"usb-otg-fs\" feature or select a different chip.");
185 }
186 }
187 }
188
189 impl Instance for peripherals::$inst {}
190 };
191
192 (otghs, $inst:ident) => {
193 impl sealed::Instance for peripherals::$inst {
194 const REGISTERS: *const () = crate::pac::$inst.0 as *const ();
195 const HIGH_SPEED: bool = true;
196
197 cfg_if::cfg_if! {
198 if #[cfg(any(
199 stm32f2,
200 stm32f405,
201 stm32f407,
202 stm32f415,
203 stm32f417,
204 stm32f427,
205 stm32f429,
206 stm32f437,
207 stm32f439,
208 ))] {
209 const FIFO_DEPTH_WORDS: usize = 1024;
210 const ENDPOINT_COUNT: usize = 6;
211 } else if #[cfg(any(
212 stm32f446,
213 stm32f469,
214 stm32f479,
215 stm32f7,
216 stm32h7,
217 ))] {
218 const FIFO_DEPTH_WORDS: usize = 1024;
219 const ENDPOINT_COUNT: usize = 9;
220 } else {
221 compile_error!("USB_OTG_HS peripheral is not supported by this chip. Disable \"usb-otg-hs\" feature or select a different chip.");
222 }
223 }
224 }
225
226 impl Instance for peripherals::$inst {}
227 };
228);
229
230crate::pac::interrupts!(
231 ($inst:ident, otgfs, $block:ident, GLOBAL, $irq:ident) => {
232 unsafe impl USBInterrupt for crate::interrupt::$irq {}
233 };
234 ($inst:ident, otghs, $block:ident, GLOBAL, $irq:ident) => {
235 unsafe impl USBInterrupt for crate::interrupt::$irq {}
236 };
237);
238
239macro_rules! impl_pin {
240 ($inst:ident, $pin:ident, $signal:ident, $af:expr) => {
241 impl $signal<peripherals::$inst> for peripherals::$pin {}
242
243 impl sealed::$signal<peripherals::$inst> for peripherals::$pin {
244 fn configure(&mut self) {
245 use crate::gpio::sealed::{AFType::OutputPushPull, Pin as SealedPin};
246
247 critical_section::with(|_| unsafe {
248 self.set_as_af($af, OutputPushPull);
249 });
250 }
251 }
252 };
253}
254
255// ULPI pins have to bet set to VeryHigh speed
256macro_rules! impl_ulpi_pin {
257 ($inst:ident, $pin:ident, $signal:ident, $af:expr) => {
258 impl $signal<peripherals::$inst> for peripherals::$pin {}
259
260 impl sealed::$signal<peripherals::$inst> for peripherals::$pin {
261 fn configure(&mut self) {
262 use crate::gpio::sealed::{AFType::OutputPushPull, Pin as SealedPin};
263 use crate::gpio::Speed;
264
265 critical_section::with(|_| unsafe {
266 self.set_as_af($af, OutputPushPull);
267 self.set_speed(Speed::VeryHigh);
268 });
269 }
270 }
271 };
272}
273
274crate::pac::peripheral_pins!(
275 // FS internal phy pins
276 ($inst:ident, otgfs, OTG_FS, $pin:ident, DP, $af:expr) => {
277 impl_pin!($inst, $pin, DpPin, $af);
278 };
279 ($inst:ident, otgfs, OTG_FS, $pin:ident, DM, $af:expr) => {
280 impl_pin!($inst, $pin, DmPin, $af);
281 };
282
283 // HS internal phy pins
284 ($inst:ident, otghs, OTG_HS, $pin:ident, DP, $af:expr) => {
285 impl_pin!($inst, $pin, DpPin, $af);
286 };
287 ($inst:ident, otghs, OTG_HS, $pin:ident, DM, $af:expr) => {
288 impl_pin!($inst, $pin, DmPin, $af);
289 };
290
291 // HS external phy pins
292 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_CK, $af:expr) => {
293 impl_ulpi_pin!($inst, $pin, UlpiClkPin, $af);
294 };
295 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_DIR, $af:expr) => {
296 impl_ulpi_pin!($inst, $pin, UlpiDirPin, $af);
297 };
298 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_NXT, $af:expr) => {
299 impl_ulpi_pin!($inst, $pin, UlpiNxtPin, $af);
300 };
301 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_STP, $af:expr) => {
302 impl_ulpi_pin!($inst, $pin, UlpiStpPin, $af);
303 };
304 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_D0, $af:expr) => {
305 impl_ulpi_pin!($inst, $pin, UlpiD0Pin, $af);
306 };
307 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_D1, $af:expr) => {
308 impl_ulpi_pin!($inst, $pin, UlpiD1Pin, $af);
309 };
310 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_D2, $af:expr) => {
311 impl_ulpi_pin!($inst, $pin, UlpiD2Pin, $af);
312 };
313 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_D3, $af:expr) => {
314 impl_ulpi_pin!($inst, $pin, UlpiD3Pin, $af);
315 };
316 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_D4, $af:expr) => {
317 impl_ulpi_pin!($inst, $pin, UlpiD4Pin, $af);
318 };
319 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_D5, $af:expr) => {
320 impl_ulpi_pin!($inst, $pin, UlpiD5Pin, $af);
321 };
322 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_D6, $af:expr) => {
323 impl_ulpi_pin!($inst, $pin, UlpiD6Pin, $af);
324 };
325 ($inst:ident, otghs, OTG_HS, $pin:ident, ULPI_D7, $af:expr) => {
326 impl_ulpi_pin!($inst, $pin, UlpiD7Pin, $af);
327 };
328);
diff --git a/embassy-stm32/src/usb_otg_fs.rs b/embassy-stm32/src/usb_otg_fs.rs
deleted file mode 100644
index 3e0cadb11..000000000
--- a/embassy-stm32/src/usb_otg_fs.rs
+++ /dev/null
@@ -1,159 +0,0 @@
1use crate::gpio::sealed::{AFType, Pin};
2use crate::{peripherals, rcc::RccPeripheral};
3use core::marker::PhantomData;
4use embassy::util::Unborrow;
5use embassy_hal_common::unborrow;
6pub use embassy_hal_common::usb::*;
7pub use synopsys_usb_otg::UsbBus;
8use synopsys_usb_otg::UsbPeripheral;
9
10pub struct UsbOtgFs<'d, T: Instance> {
11 phantom: PhantomData<&'d mut T>,
12}
13
14impl<'d, T: Instance> UsbOtgFs<'d, T> {
15 pub fn new(
16 _peri: impl Unborrow<Target = T> + 'd,
17 dp: impl Unborrow<Target = impl DpPin<T>> + 'd,
18 dm: impl Unborrow<Target = impl DmPin<T>> + 'd,
19 ) -> Self {
20 unborrow!(dp, dm);
21
22 unsafe {
23 dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
24 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
25 }
26
27 Self {
28 phantom: PhantomData,
29 }
30 }
31}
32
33impl<'d, T: Instance> Drop for UsbOtgFs<'d, T> {
34 fn drop(&mut self) {
35 T::reset();
36 T::disable();
37 }
38}
39
40unsafe impl<'d, T: Instance> Send for UsbOtgFs<'d, T> {}
41unsafe impl<'d, T: Instance> Sync for UsbOtgFs<'d, T> {}
42
43unsafe impl<'d, T: Instance> UsbPeripheral for UsbOtgFs<'d, T> {
44 const REGISTERS: *const () = T::REGISTERS;
45
46 const HIGH_SPEED: bool = false;
47
48 cfg_if::cfg_if! {
49 if #[cfg(stm32f1)] {
50 const FIFO_DEPTH_WORDS: usize = 128;
51 const ENDPOINT_COUNT: usize = 8;
52 } else if #[cfg(any(
53 stm32f2,
54 stm32f401,
55 stm32f405,
56 stm32f407,
57 stm32f411,
58 stm32f415,
59 stm32f417,
60 stm32f427,
61 stm32f429,
62 stm32f437,
63 stm32f439,
64 ))] {
65 const FIFO_DEPTH_WORDS: usize = 320;
66 const ENDPOINT_COUNT: usize = 4;
67 } else if #[cfg(any(
68 stm32f412,
69 stm32f413,
70 stm32f423,
71 stm32f446,
72 stm32f469,
73 stm32f479,
74 stm32f7,
75 stm32l4,
76 stm32u5,
77 ))] {
78 const FIFO_DEPTH_WORDS: usize = 320;
79 const ENDPOINT_COUNT: usize = 6;
80 } else if #[cfg(stm32g0x1)] {
81 const FIFO_DEPTH_WORDS: usize = 512;
82 const ENDPOINT_COUNT: usize = 8;
83 } else {
84 compile_error!("USB_OTG_FS peripheral is not supported by this chip. Disable \"usb-otg-fs\" feature or select a different chip.");
85 }
86 }
87
88 fn enable() {
89 <T as crate::rcc::sealed::RccPeripheral>::enable();
90 <T as crate::rcc::sealed::RccPeripheral>::reset();
91 }
92
93 fn ahb_frequency_hz(&self) -> u32 {
94 <T as crate::rcc::sealed::RccPeripheral>::frequency().0
95 }
96}
97
98pub(crate) mod sealed {
99 use super::*;
100
101 pub trait Instance {
102 const REGISTERS: *const ();
103 }
104
105 pub trait DpPin<T: Instance>: Pin {
106 fn af_num(&self) -> u8;
107 }
108
109 pub trait DmPin<T: Instance>: Pin {
110 fn af_num(&self) -> u8;
111 }
112}
113
114pub trait Instance: sealed::Instance + RccPeripheral {}
115pub trait DpPin<T: Instance>: sealed::DpPin<T> {}
116pub trait DmPin<T: Instance>: sealed::DmPin<T> {}
117
118crate::pac::peripherals!(
119 (otgfs, $inst:ident) => {
120 impl sealed::Instance for crate::peripherals::$inst {
121 const REGISTERS: *const () = crate::pac::$inst.0 as *const ();
122 }
123
124 impl Instance for peripherals::$inst {}
125 };
126);
127
128crate::pac::interrupts!(
129 ($inst:ident, otgfs, $block:ident, GLOBAL, $irq:ident) => {
130 unsafe impl USBInterrupt for crate::interrupt::$irq {}
131 };
132);
133
134macro_rules! impl_pin {
135 ($inst:ident, $pin:ident, $signal:ident, $af:expr) => {
136 impl $signal<peripherals::$inst> for peripherals::$pin {}
137
138 impl sealed::$signal<peripherals::$inst> for peripherals::$pin {
139 fn af_num(&self) -> u8 {
140 $af
141 }
142 }
143 };
144}
145
146crate::pac::peripheral_pins!(
147 ($inst:ident, otgfs, OTG_FS, $pin:ident, DP, $af:expr) => {
148 impl_pin!($inst, $pin, DpPin, $af);
149 };
150 ($inst:ident, otgfs, OTG_FS, $pin:ident, DM, $af:expr) => {
151 impl_pin!($inst, $pin, DmPin, $af);
152 };
153 ($inst:ident, otgfs, OTG_FS, $pin:ident, DP) => {
154 impl_pin!($inst, $pin, DpPin, 0);
155 };
156 ($inst:ident, otgfs, OTG_FS, $pin:ident, DM) => {
157 impl_pin!($inst, $pin, DmPin, 0);
158 };
159);
diff --git a/embassy-stm32/src/usb_otg_hs.rs b/embassy-stm32/src/usb_otg_hs.rs
deleted file mode 100644
index 8de4601e1..000000000
--- a/embassy-stm32/src/usb_otg_hs.rs
+++ /dev/null
@@ -1,147 +0,0 @@
1use crate::gpio::sealed::{AFType, Pin};
2use crate::{peripherals, rcc::RccPeripheral};
3use core::marker::PhantomData;
4use embassy::util::Unborrow;
5use embassy_hal_common::unborrow;
6pub use embassy_hal_common::usb::*;
7pub use synopsys_usb_otg::UsbBus;
8use synopsys_usb_otg::UsbPeripheral;
9
10pub struct UsbOtgHs<'d, T: Instance> {
11 phantom: PhantomData<&'d mut T>,
12}
13
14impl<'d, T: Instance> UsbOtgHs<'d, T> {
15 pub fn new(
16 _peri: impl Unborrow<Target = T> + 'd,
17 dp: impl Unborrow<Target = impl DpPin<T>> + 'd,
18 dm: impl Unborrow<Target = impl DmPin<T>> + 'd,
19 ) -> Self {
20 unborrow!(dp, dm);
21
22 unsafe {
23 dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
24 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
25 }
26
27 Self {
28 phantom: PhantomData,
29 }
30 }
31}
32
33impl<'d, T: Instance> Drop for UsbOtgHs<'d, T> {
34 fn drop(&mut self) {
35 T::reset();
36 T::disable();
37 }
38}
39
40unsafe impl<'d, T: Instance> Send for UsbOtgHs<'d, T> {}
41unsafe impl<'d, T: Instance> Sync for UsbOtgHs<'d, T> {}
42
43unsafe impl<'d, T: Instance> UsbPeripheral for UsbOtgHs<'d, T> {
44 const REGISTERS: *const () = T::REGISTERS;
45
46 const HIGH_SPEED: bool = true;
47
48 cfg_if::cfg_if! {
49 if #[cfg(any(
50 stm32f2,
51 stm32f405,
52 stm32f407,
53 stm32f415,
54 stm32f417,
55 stm32f427,
56 stm32f429,
57 stm32f437,
58 stm32f439,
59 ))] {
60 const FIFO_DEPTH_WORDS: usize = 1024;
61 const ENDPOINT_COUNT: usize = 6;
62 } else if #[cfg(any(
63 stm32f446,
64 stm32f469,
65 stm32f479,
66 stm32f7,
67 stm32h7,
68 ))] {
69 const FIFO_DEPTH_WORDS: usize = 1024;
70 const ENDPOINT_COUNT: usize = 9;
71 } else {
72 compile_error!("USB_OTG_HS peripheral is not supported by this chip. Disable \"usb-otg-hs\" feature or select a different chip.");
73 }
74 }
75
76 fn enable() {
77 <T as crate::rcc::sealed::RccPeripheral>::enable();
78 <T as crate::rcc::sealed::RccPeripheral>::reset();
79 }
80
81 fn ahb_frequency_hz(&self) -> u32 {
82 <T as crate::rcc::sealed::RccPeripheral>::frequency().0
83 }
84}
85
86pub(crate) mod sealed {
87 use super::*;
88
89 pub trait Instance {
90 const REGISTERS: *const ();
91 }
92
93 pub trait DpPin<T: Instance>: Pin {
94 fn af_num(&self) -> u8;
95 }
96
97 pub trait DmPin<T: Instance>: Pin {
98 fn af_num(&self) -> u8;
99 }
100}
101
102pub trait Instance: sealed::Instance + RccPeripheral {}
103pub trait DpPin<T: Instance>: sealed::DpPin<T> {}
104pub trait DmPin<T: Instance>: sealed::DmPin<T> {}
105
106crate::pac::peripherals!(
107 (otghs, $inst:ident) => {
108 impl sealed::Instance for crate::peripherals::$inst {
109 const REGISTERS: *const () = crate::pac::$inst.0 as *const ();
110 }
111
112 impl Instance for peripherals::$inst {}
113 };
114);
115
116crate::pac::interrupts!(
117 ($inst:ident, otghs, $block:ident, GLOBAL, $irq:ident) => {
118 unsafe impl USBInterrupt for crate::interrupt::$irq {}
119 };
120);
121
122macro_rules! impl_pin {
123 ($inst:ident, $pin:ident, $signal:ident, $af:expr) => {
124 impl $signal<peripherals::$inst> for peripherals::$pin {}
125
126 impl sealed::$signal<peripherals::$inst> for peripherals::$pin {
127 fn af_num(&self) -> u8 {
128 $af
129 }
130 }
131 };
132}
133
134crate::pac::peripheral_pins!(
135 ($inst:ident, otghs, OTG_HS, $pin:ident, DP, $af:expr) => {
136 impl_pin!($inst, $pin, DpPin, $af);
137 };
138 ($inst:ident, otghs, OTG_HS, $pin:ident, DM, $af:expr) => {
139 impl_pin!($inst, $pin, DmPin, $af);
140 };
141 ($inst:ident, otghs, OTG_HS, $pin:ident, DP) => {
142 impl_pin!($inst, $pin, DpPin, 0);
143 };
144 ($inst:ident, otghs, OTG_HS, $pin:ident, DM) => {
145 impl_pin!($inst, $pin, DmPin, 0);
146 };
147);
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index 8a5908e27..798144c2b 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -8,7 +8,7 @@ resolver = "2"
8 8
9[dependencies] 9[dependencies]
10embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "unstable-traits"] } 10embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "unstable-traits"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "usb-otg-fs"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "usb-otg"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.3" 14defmt-rtt = "0.3"
diff --git a/examples/stm32f4/src/bin/usb_uart.rs b/examples/stm32f4/src/bin/usb_uart.rs
index 7167a28b4..63059d51f 100644
--- a/examples/stm32f4/src/bin/usb_uart.rs
+++ b/examples/stm32f4/src/bin/usb_uart.rs
@@ -13,7 +13,7 @@ use panic_probe as _; // print out panic messages
13 13
14use embassy::executor::Spawner; 14use embassy::executor::Spawner;
15use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; 15use embassy::io::{AsyncBufReadExt, AsyncWriteExt};
16use embassy_stm32::usb_otg_fs::{State, Usb, UsbBus, UsbOtgFs, UsbSerial}; 16use embassy_stm32::usb_otg::{State, Usb, UsbBus, UsbOtg, UsbSerial};
17use embassy_stm32::{interrupt, time::Hertz, Config, Peripherals}; 17use embassy_stm32::{interrupt, time::Hertz, Config, Peripherals};
18use usb_device::device::{UsbDeviceBuilder, UsbVidPid}; 18use usb_device::device::{UsbDeviceBuilder, UsbVidPid};
19 19
@@ -32,7 +32,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
32 // we send back input + cr + lf 32 // we send back input + cr + lf
33 let mut tx_buffer = [0u8; 66]; 33 let mut tx_buffer = [0u8; 66];
34 34
35 let peri = UsbOtgFs::new(p.USB_OTG_FS, p.PA12, p.PA11); 35 let peri = UsbOtg::new_fs(p.USB_OTG_FS, p.PA12, p.PA11);
36 let usb_bus = UsbBus::new(peri, unsafe { &mut EP_MEMORY }); 36 let usb_bus = UsbBus::new(peri, unsafe { &mut EP_MEMORY });
37 37
38 let serial = UsbSerial::new(&usb_bus, &mut rx_buffer, &mut tx_buffer); 38 let serial = UsbSerial::new(&usb_bus, &mut rx_buffer, &mut tx_buffer);
diff --git a/examples/stm32f4/src/bin/usb_uart_ulpi.rs b/examples/stm32f4/src/bin/usb_uart_ulpi.rs
new file mode 100644
index 000000000..2cdc8e683
--- /dev/null
+++ b/examples/stm32f4/src/bin/usb_uart_ulpi.rs
@@ -0,0 +1,114 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7
8use defmt::{info, unwrap};
9use defmt_rtt as _; // global logger
10use embassy::interrupt::InterruptExt;
11use futures::pin_mut;
12use panic_probe as _; // print out panic messages
13
14use embassy::executor::Spawner;
15use embassy::io::{AsyncBufReadExt, AsyncWriteExt};
16use embassy_stm32::usb_otg::{State, Usb, UsbBus, UsbOtg, UsbSerial};
17use embassy_stm32::{interrupt, time::Hertz, Config, Peripherals};
18use usb_device::device::{UsbDeviceBuilder, UsbVidPid};
19
20static mut EP_MEMORY: [u32; 2048] = [0; 2048];
21
22// USB requires at least 48 MHz clock
23fn config() -> Config {
24 let mut config = Config::default();
25 config.rcc.sys_ck = Some(Hertz(48_000_000));
26 config
27}
28
29#[embassy::main(config = "config()")]
30async fn main(_spawner: Spawner, p: Peripherals) {
31 let mut rx_buffer = [0u8; 64];
32 // we send back input + cr + lf
33 let mut tx_buffer = [0u8; 66];
34
35 // USB with external high-speed PHY
36 let peri = UsbOtg::new_ulpi(
37 p.USB_OTG_HS,
38 p.PA5,
39 p.PC2,
40 p.PC3,
41 p.PC0,
42 p.PA3,
43 p.PB0,
44 p.PB1,
45 p.PB10,
46 p.PB11,
47 p.PB12,
48 p.PB13,
49 p.PB5,
50 );
51 let usb_bus = UsbBus::new(peri, unsafe { &mut EP_MEMORY });
52
53 let serial = UsbSerial::new(&usb_bus, &mut rx_buffer, &mut tx_buffer);
54
55 let device = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
56 .manufacturer("Fake company")
57 .product("Serial port")
58 .serial_number("TEST")
59 .device_class(0x02)
60 .build();
61
62 let irq = interrupt::take!(OTG_FS);
63 irq.set_priority(interrupt::Priority::P3);
64
65 let mut state = State::new();
66 let usb = unsafe { Usb::new(&mut state, device, serial, irq) };
67 pin_mut!(usb);
68
69 let (mut reader, mut writer) = usb.as_ref().take_serial_0();
70
71 info!("usb initialized!");
72
73 unwrap!(
74 writer
75 .write_all(b"\r\nInput returned upper cased on CR+LF\r\n")
76 .await
77 );
78
79 let mut buf = [0u8; 64];
80 loop {
81 let mut n = 0;
82
83 async {
84 loop {
85 let char = unwrap!(reader.read_byte().await);
86
87 if char == b'\r' || char == b'\n' {
88 break;
89 }
90
91 buf[n] = char;
92 n += 1;
93
94 // stop if we're out of room
95 if n == buf.len() {
96 break;
97 }
98 }
99 }
100 .await;
101
102 if n > 0 {
103 for char in buf[..n].iter_mut() {
104 // upper case
105 if 0x61 <= *char && *char <= 0x7a {
106 *char &= !0x20;
107 }
108 }
109 unwrap!(writer.write_all(&buf[..n]).await);
110 unwrap!(writer.write_all(b"\r\n").await);
111 unwrap!(writer.flush().await);
112 }
113 }
114}