aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-09-22 23:56:17 +0000
committerGitHub <[email protected]>2024-09-22 23:56:17 +0000
commit9705f3332b7d858aee94903ce433fba93d62332c (patch)
tree987c003cf3fb4edcb7352ca41522146bc3498879
parentb9553badb314b050be705bbb24d87a33304c55ac (diff)
parent85b7c8957cce3fef6011e63d7cb6ff85912ccb50 (diff)
Merge pull request #3337 from doesnotcompete/feature/h7rs-usb
Add OTG_HS support for STM32H7R/S
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/build.rs4
-rw-r--r--embassy-stm32/src/rcc/h.rs36
-rw-r--r--embassy-stm32/src/usb/mod.rs30
-rw-r--r--embassy-stm32/src/usb/otg.rs55
-rw-r--r--embassy-usb-synopsys-otg/src/lib.rs23
-rw-r--r--embassy-usb-synopsys-otg/src/otg_v1.rs171
-rw-r--r--examples/stm32h7rs/src/bin/usb_serial.rs140
8 files changed, 456 insertions, 7 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 3f4a5e3c4..575c4f20c 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -72,7 +72,7 @@ rand_core = "0.6.3"
72sdio-host = "0.5.0" 72sdio-host = "0.5.0"
73critical-section = "1.1" 73critical-section = "1.1"
74#stm32-metapac = { version = "15" } 74#stm32-metapac = { version = "15" }
75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364" } 75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-acaf04256034066bd5b3a8426224ccf3e4cb7d19" }
76 76
77vcell = "0.1.3" 77vcell = "0.1.3"
78nb = "1.0.0" 78nb = "1.0.0"
@@ -99,7 +99,7 @@ proc-macro2 = "1.0.36"
99quote = "1.0.15" 99quote = "1.0.15"
100 100
101#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 101#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
102stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364", default-features = false, features = ["metadata"] } 102stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-acaf04256034066bd5b3a8426224ccf3e4cb7d19", default-features = false, features = ["metadata"] }
103 103
104[features] 104[features]
105default = ["rt"] 105default = ["rt"]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 19cf193d9..28c619c6b 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -55,7 +55,7 @@ fn main() {
55 let mut singletons: Vec<String> = Vec::new(); 55 let mut singletons: Vec<String> = Vec::new();
56 for p in METADATA.peripherals { 56 for p in METADATA.peripherals {
57 if let Some(r) = &p.registers { 57 if let Some(r) = &p.registers {
58 if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" { 58 if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" || r.kind == "otg" {
59 // TODO: should we emit this for all peripherals? if so, we will need a list of all 59 // TODO: should we emit this for all peripherals? if so, we will need a list of all
60 // possible peripherals across all chips, so that we can declare the configs 60 // possible peripherals across all chips, so that we can declare the configs
61 // (replacing the hard-coded list of `peri_*` cfgs below) 61 // (replacing the hard-coded list of `peri_*` cfgs below)
@@ -111,6 +111,8 @@ fn main() {
111 "peri_sai4", 111 "peri_sai4",
112 "peri_ucpd1", 112 "peri_ucpd1",
113 "peri_ucpd2", 113 "peri_ucpd2",
114 "peri_usb_otg_fs",
115 "peri_usb_otg_hs",
114 ]); 116 ]);
115 cfgs.declare_all(&["mco", "mco1", "mco2"]); 117 cfgs.declare_all(&["mco", "mco1", "mco2"]);
116 118
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 376a0b454..55fe8ca9d 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -34,8 +34,10 @@ pub enum VoltageScale {
34 Scale2, 34 Scale2,
35 Scale3, 35 Scale3,
36} 36}
37#[cfg(any(stm32h7rs))] 37#[cfg(stm32h7rs)]
38pub use crate::pac::pwr::vals::Vos as VoltageScale; 38pub use crate::pac::pwr::vals::Vos as VoltageScale;
39#[cfg(all(stm32h7rs, peri_usb_otg_hs))]
40pub use crate::pac::rcc::vals::{Usbphycsel, Usbrefcksel};
39 41
40#[derive(Clone, Copy, Eq, PartialEq)] 42#[derive(Clone, Copy, Eq, PartialEq)]
41pub enum HseMode { 43pub enum HseMode {
@@ -557,6 +559,27 @@ pub(crate) unsafe fn init(config: Config) {
557 559
558 let rtc = config.ls.init(); 560 let rtc = config.ls.init();
559 561
562 #[cfg(all(stm32h7rs, peri_usb_otg_hs))]
563 let usb_refck = match config.mux.usbphycsel {
564 Usbphycsel::HSE => hse,
565 Usbphycsel::HSE_DIV_2 => hse.map(|hse_val| hse_val / 2u8),
566 Usbphycsel::PLL3_Q => pll3.q,
567 _ => None,
568 };
569 #[cfg(all(stm32h7rs, peri_usb_otg_hs))]
570 let usb_refck_sel = match usb_refck {
571 Some(clk_val) => match clk_val {
572 Hertz(16_000_000) => Usbrefcksel::MHZ16,
573 Hertz(19_200_000) => Usbrefcksel::MHZ19_2,
574 Hertz(20_000_000) => Usbrefcksel::MHZ20,
575 Hertz(24_000_000) => Usbrefcksel::MHZ24,
576 Hertz(26_000_000) => Usbrefcksel::MHZ26,
577 Hertz(32_000_000) => Usbrefcksel::MHZ32,
578 _ => panic!("cannot select USBPHYC reference clock with source frequency of {} Hz, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val),
579 },
580 None => Usbrefcksel::MHZ24,
581 };
582
560 #[cfg(stm32h7)] 583 #[cfg(stm32h7)]
561 { 584 {
562 RCC.d1cfgr().modify(|w| { 585 RCC.d1cfgr().modify(|w| {
@@ -593,6 +616,11 @@ pub(crate) unsafe fn init(config: Config) {
593 w.set_ppre4(config.apb4_pre); 616 w.set_ppre4(config.apb4_pre);
594 w.set_ppre5(config.apb5_pre); 617 w.set_ppre5(config.apb5_pre);
595 }); 618 });
619
620 #[cfg(peri_usb_otg_hs)]
621 RCC.ahbperckselr().modify(|w| {
622 w.set_usbrefcksel(usb_refck_sel);
623 });
596 } 624 }
597 #[cfg(stm32h5)] 625 #[cfg(stm32h5)]
598 { 626 {
@@ -698,7 +726,9 @@ pub(crate) unsafe fn init(config: Config) {
698 #[cfg(stm32h7rs)] 726 #[cfg(stm32h7rs)]
699 clk48mohci: None, // TODO 727 clk48mohci: None, // TODO
700 #[cfg(stm32h7rs)] 728 #[cfg(stm32h7rs)]
701 usb: None, // TODO 729 hse_div_2: hse.map(|clk| clk / 2u32),
730 #[cfg(stm32h7rs)]
731 usb: Some(Hertz(48_000_000)),
702 ); 732 );
703} 733}
704 734
@@ -769,7 +799,7 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
769 if num == 0 { 799 if num == 0 {
770 // on PLL1, DIVP must be even for most series. 800 // on PLL1, DIVP must be even for most series.
771 // The enum value is 1 less than the divider, so check it's odd. 801 // The enum value is 1 less than the divider, so check it's odd.
772 #[cfg(not(pwr_h7rm0468))] 802 #[cfg(not(any(pwr_h7rm0468, stm32h7rs)))]
773 assert!(div.to_bits() % 2 == 1); 803 assert!(div.to_bits() % 2 == 1);
774 #[cfg(pwr_h7rm0468)] 804 #[cfg(pwr_h7rm0468)]
775 assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0); 805 assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0);
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index ce9fe0a9b..a473285bf 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -13,9 +13,19 @@ fn common_init<T: Instance>() {
13 // Check the USB clock is enabled and running at exactly 48 MHz. 13 // Check the USB clock is enabled and running at exactly 48 MHz.
14 // frequency() will panic if not enabled 14 // frequency() will panic if not enabled
15 let freq = T::frequency(); 15 let freq = T::frequency();
16
17 // On the H7RS, the USBPHYC embeds a PLL accepting one of the input frequencies listed below and providing 48MHz to OTG_FS and 60MHz to OTG_HS internally
18 #[cfg(stm32h7rs)]
19 if ![16_000_000, 19_200_000, 20_000_000, 24_000_000, 26_000_000, 32_000_000].contains(&freq.0) {
20 panic!(
21 "USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but is {} Hz. Please double-check your RCC settings.",
22 freq.0
23 )
24 }
16 // Check frequency is within the 0.25% tolerance allowed by the spec. 25 // Check frequency is within the 0.25% tolerance allowed by the spec.
17 // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user 26 // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user
18 // has tight clock restrictions due to something else (like audio). 27 // has tight clock restrictions due to something else (like audio).
28 #[cfg(not(stm32h7rs))]
19 if freq.0.abs_diff(48_000_000) > 120_000 { 29 if freq.0.abs_diff(48_000_000) > 120_000 {
20 panic!( 30 panic!(
21 "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.", 31 "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.",
@@ -48,6 +58,26 @@ fn common_init<T: Instance>() {
48 while !crate::pac::PWR.cr3().read().usb33rdy() {} 58 while !crate::pac::PWR.cr3().read().usb33rdy() {}
49 } 59 }
50 60
61 #[cfg(stm32h7rs)]
62 {
63 // If true, VDD33USB is generated by internal regulator from VDD50USB
64 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
65 // TODO: unhardcode
66 let internal_regulator = false;
67
68 // Enable USB power
69 critical_section::with(|_| {
70 crate::pac::PWR.csr2().modify(|w| {
71 w.set_usbregen(internal_regulator);
72 w.set_usb33den(true);
73 w.set_usbhsregen(true);
74 })
75 });
76
77 // Wait for USB power to stabilize
78 while !crate::pac::PWR.csr2().read().usb33rdy() {}
79 }
80
51 #[cfg(stm32u5)] 81 #[cfg(stm32u5)]
52 { 82 {
53 // Enable USB power 83 // Enable USB power
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index e27b164e4..00cafe6e4 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -97,6 +97,45 @@ impl<'d, T: Instance> Driver<'d, T> {
97 } 97 }
98 } 98 }
99 99
100 /// Initializes USB OTG peripheral with internal High-Speed PHY.
101 ///
102 /// # Arguments
103 ///
104 /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
105 /// Must be large enough to fit all OUT endpoint max packet sizes.
106 /// Endpoint allocation will fail if it is too small.
107 pub fn new_hs(
108 _peri: impl Peripheral<P = T> + 'd,
109 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
110 dp: impl Peripheral<P = impl DpPin<T>> + 'd,
111 dm: impl Peripheral<P = impl DmPin<T>> + 'd,
112 ep_out_buffer: &'d mut [u8],
113 config: Config,
114 ) -> Self {
115 into_ref!(dp, dm);
116
117 dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
118 dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
119
120 let regs = T::regs();
121
122 let instance = OtgInstance {
123 regs,
124 state: T::state(),
125 fifo_depth_words: T::FIFO_DEPTH_WORDS,
126 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
127 endpoint_count: T::ENDPOINT_COUNT,
128 phy_type: PhyType::InternalHighSpeed,
129 quirk_setup_late_cnak: quirk_setup_late_cnak(regs),
130 calculate_trdt_fn: calculate_trdt::<T>,
131 };
132
133 Self {
134 inner: OtgDriver::new(ep_out_buffer, instance, config),
135 phantom: PhantomData,
136 }
137 }
138
100 /// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode). 139 /// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode).
101 /// 140 ///
102 /// # Arguments 141 /// # Arguments
@@ -272,6 +311,19 @@ impl<'d, T: Instance> Bus<'d, T> {
272 } 311 }
273 }); 312 });
274 313
314 #[cfg(stm32h7rs)]
315 critical_section::with(|_| {
316 let rcc = crate::pac::RCC;
317 rcc.ahb1enr().modify(|w| {
318 w.set_usbphycen(true);
319 w.set_usb_otg_hsen(true);
320 });
321 rcc.ahb1lpenr().modify(|w| {
322 w.set_usbphyclpen(true);
323 w.set_usb_otg_hslpen(true);
324 });
325 });
326
275 let r = T::regs(); 327 let r = T::regs();
276 let core_id = r.cid().read().0; 328 let core_id = r.cid().read().0;
277 trace!("Core id {:08x}", core_id); 329 trace!("Core id {:08x}", core_id);
@@ -286,6 +338,7 @@ impl<'d, T: Instance> Bus<'d, T> {
286 match core_id { 338 match core_id {
287 0x0000_1200 | 0x0000_1100 => self.inner.config_v1(), 339 0x0000_1200 | 0x0000_1100 => self.inner.config_v1(),
288 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(), 340 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(),
341 0x0000_5000 => self.inner.config_v5(),
289 _ => unimplemented!("Unknown USB core id {:X}", core_id), 342 _ => unimplemented!("Unknown USB core id {:X}", core_id),
290 } 343 }
291 } 344 }
@@ -501,7 +554,7 @@ fn calculate_trdt<T: Instance>(speed: Dspd) -> u8 {
501 match speed { 554 match speed {
502 Dspd::HIGH_SPEED => { 555 Dspd::HIGH_SPEED => {
503 // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446) 556 // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446)
504 if ahb_freq >= 30_000_000 { 557 if ahb_freq >= 30_000_000 || cfg!(stm32h7rs) {
505 0x9 558 0x9
506 } else { 559 } else {
507 panic!("AHB frequency is too low") 560 panic!("AHB frequency is too low")
diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs
index b145f4aa8..f90403936 100644
--- a/embassy-usb-synopsys-otg/src/lib.rs
+++ b/embassy-usb-synopsys-otg/src/lib.rs
@@ -584,6 +584,29 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> {
584 }); 584 });
585 } 585 }
586 586
587 /// Applies configuration specific to
588 /// Core ID 0x0000_5000
589 pub fn config_v5(&mut self) {
590 let r = self.instance.regs;
591 let phy_type = self.instance.phy_type;
592
593 if phy_type == PhyType::InternalHighSpeed {
594 r.gccfg_v3().modify(|w| {
595 w.set_vbvaloven(!self.config.vbus_detection);
596 w.set_vbvaloval(!self.config.vbus_detection);
597 w.set_vbden(self.config.vbus_detection);
598 });
599 } else {
600 r.gotgctl().modify(|w| {
601 w.set_bvaloen(!self.config.vbus_detection);
602 w.set_bvaloval(!self.config.vbus_detection);
603 });
604 r.gccfg_v3().modify(|w| {
605 w.set_vbden(self.config.vbus_detection);
606 });
607 }
608 }
609
587 fn init(&mut self) { 610 fn init(&mut self) {
588 let r = self.instance.regs; 611 let r = self.instance.regs;
589 let phy_type = self.instance.phy_type; 612 let phy_type = self.instance.phy_type;
diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs
index d3abc328d..18e760fd1 100644
--- a/embassy-usb-synopsys-otg/src/otg_v1.rs
+++ b/embassy-usb-synopsys-otg/src/otg_v1.rs
@@ -186,6 +186,11 @@ impl Otg {
186 pub const fn gccfg_v2(self) -> Reg<regs::GccfgV2, RW> { 186 pub const fn gccfg_v2(self) -> Reg<regs::GccfgV2, RW> {
187 unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) } 187 unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) }
188 } 188 }
189 #[doc = "General core configuration register, for core_id 0x0000_5xxx"]
190 #[inline(always)]
191 pub const fn gccfg_v3(self) -> Reg<regs::GccfgV3, RW> {
192 unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) }
193 }
189 #[doc = "Core ID register"] 194 #[doc = "Core ID register"]
190 #[inline(always)] 195 #[inline(always)]
191 pub const fn cid(self) -> Reg<regs::Cid, RW> { 196 pub const fn cid(self) -> Reg<regs::Cid, RW> {
@@ -1831,6 +1836,172 @@ pub mod regs {
1831 GccfgV2(0) 1836 GccfgV2(0)
1832 } 1837 }
1833 } 1838 }
1839 #[doc = "OTG general core configuration register."]
1840 #[repr(transparent)]
1841 #[derive(Copy, Clone, Eq, PartialEq)]
1842 pub struct GccfgV3(pub u32);
1843 impl GccfgV3 {
1844 #[doc = "Charger detection, result of the current mode (primary or secondary)."]
1845 #[inline(always)]
1846 pub const fn chgdet(&self) -> bool {
1847 let val = (self.0 >> 0usize) & 0x01;
1848 val != 0
1849 }
1850 #[doc = "Charger detection, result of the current mode (primary or secondary)."]
1851 #[inline(always)]
1852 pub fn set_chgdet(&mut self, val: bool) {
1853 self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize);
1854 }
1855 #[doc = "Single-Ended DP indicator This bit gives the voltage level on DP (also result of the comparison with V<sub>LGC</sub> threshold as defined in BC v1.2 standard)."]
1856 #[inline(always)]
1857 pub const fn fsvplus(&self) -> bool {
1858 let val = (self.0 >> 1usize) & 0x01;
1859 val != 0
1860 }
1861 #[doc = "Single-Ended DP indicator This bit gives the voltage level on DP (also result of the comparison with V<sub>LGC</sub> threshold as defined in BC v1.2 standard)."]
1862 #[inline(always)]
1863 pub fn set_fsvplus(&mut self, val: bool) {
1864 self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize);
1865 }
1866 #[doc = "Single-Ended DM indicator This bit gives the voltage level on DM (also result of the comparison with V<sub>LGC</sub> threshold as defined in BC v1.2 standard)."]
1867 #[inline(always)]
1868 pub const fn fsvminus(&self) -> bool {
1869 let val = (self.0 >> 2usize) & 0x01;
1870 val != 0
1871 }
1872 #[doc = "Single-Ended DM indicator This bit gives the voltage level on DM (also result of the comparison with V<sub>LGC</sub> threshold as defined in BC v1.2 standard)."]
1873 #[inline(always)]
1874 pub fn set_fsvminus(&mut self, val: bool) {
1875 self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize);
1876 }
1877 #[doc = "VBUS session indicator Indicates if VBUS is above VBUS session threshold."]
1878 #[inline(always)]
1879 pub const fn sessvld(&self) -> bool {
1880 let val = (self.0 >> 3usize) & 0x01;
1881 val != 0
1882 }
1883 #[doc = "VBUS session indicator Indicates if VBUS is above VBUS session threshold."]
1884 #[inline(always)]
1885 pub fn set_sessvld(&mut self, val: bool) {
1886 self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize);
1887 }
1888 #[doc = "Host CDP behavior enable."]
1889 #[inline(always)]
1890 pub const fn hcdpen(&self) -> bool {
1891 let val = (self.0 >> 16usize) & 0x01;
1892 val != 0
1893 }
1894 #[doc = "Host CDP behavior enable."]
1895 #[inline(always)]
1896 pub fn set_hcdpen(&mut self, val: bool) {
1897 self.0 = (self.0 & !(0x01 << 16usize)) | (((val as u32) & 0x01) << 16usize);
1898 }
1899 #[doc = "Host CDP port voltage detector enable on DP."]
1900 #[inline(always)]
1901 pub const fn hcdpdeten(&self) -> bool {
1902 let val = (self.0 >> 17usize) & 0x01;
1903 val != 0
1904 }
1905 #[doc = "Host CDP port voltage detector enable on DP."]
1906 #[inline(always)]
1907 pub fn set_hcdpdeten(&mut self, val: bool) {
1908 self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize);
1909 }
1910 #[doc = "Host CDP port Voltage source enable on DM."]
1911 #[inline(always)]
1912 pub const fn hvdmsrcen(&self) -> bool {
1913 let val = (self.0 >> 18usize) & 0x01;
1914 val != 0
1915 }
1916 #[doc = "Host CDP port Voltage source enable on DM."]
1917 #[inline(always)]
1918 pub fn set_hvdmsrcen(&mut self, val: bool) {
1919 self.0 = (self.0 & !(0x01 << 18usize)) | (((val as u32) & 0x01) << 18usize);
1920 }
1921 #[doc = "Data Contact Detection enable."]
1922 #[inline(always)]
1923 pub const fn dcden(&self) -> bool {
1924 let val = (self.0 >> 19usize) & 0x01;
1925 val != 0
1926 }
1927 #[doc = "Data Contact Detection enable."]
1928 #[inline(always)]
1929 pub fn set_dcden(&mut self, val: bool) {
1930 self.0 = (self.0 & !(0x01 << 19usize)) | (((val as u32) & 0x01) << 19usize);
1931 }
1932 #[doc = "Primary detection enable."]
1933 #[inline(always)]
1934 pub const fn pden(&self) -> bool {
1935 let val = (self.0 >> 20usize) & 0x01;
1936 val != 0
1937 }
1938 #[doc = "Primary detection enable."]
1939 #[inline(always)]
1940 pub fn set_pden(&mut self, val: bool) {
1941 self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize);
1942 }
1943 #[doc = "VBUS detection enable Enables VBUS Sensing Comparators in order to detect VBUS presence and/or perform OTG operation."]
1944 #[inline(always)]
1945 pub const fn vbden(&self) -> bool {
1946 let val = (self.0 >> 21usize) & 0x01;
1947 val != 0
1948 }
1949 #[doc = "VBUS detection enable Enables VBUS Sensing Comparators in order to detect VBUS presence and/or perform OTG operation."]
1950 #[inline(always)]
1951 pub fn set_vbden(&mut self, val: bool) {
1952 self.0 = (self.0 & !(0x01 << 21usize)) | (((val as u32) & 0x01) << 21usize);
1953 }
1954 #[doc = "Secondary detection enable."]
1955 #[inline(always)]
1956 pub const fn sden(&self) -> bool {
1957 let val = (self.0 >> 22usize) & 0x01;
1958 val != 0
1959 }
1960 #[doc = "Secondary detection enable."]
1961 #[inline(always)]
1962 pub fn set_sden(&mut self, val: bool) {
1963 self.0 = (self.0 & !(0x01 << 22usize)) | (((val as u32) & 0x01) << 22usize);
1964 }
1965 #[doc = "Software override value of the VBUS B-session detection."]
1966 #[inline(always)]
1967 pub const fn vbvaloval(&self) -> bool {
1968 let val = (self.0 >> 23usize) & 0x01;
1969 val != 0
1970 }
1971 #[doc = "Software override value of the VBUS B-session detection."]
1972 #[inline(always)]
1973 pub fn set_vbvaloval(&mut self, val: bool) {
1974 self.0 = (self.0 & !(0x01 << 23usize)) | (((val as u32) & 0x01) << 23usize);
1975 }
1976 #[doc = "Enables a software override of the VBUS B-session detection."]
1977 #[inline(always)]
1978 pub const fn vbvaloven(&self) -> bool {
1979 let val = (self.0 >> 24usize) & 0x01;
1980 val != 0
1981 }
1982 #[doc = "Enables a software override of the VBUS B-session detection."]
1983 #[inline(always)]
1984 pub fn set_vbvaloven(&mut self, val: bool) {
1985 self.0 = (self.0 & !(0x01 << 24usize)) | (((val as u32) & 0x01) << 24usize);
1986 }
1987 #[doc = "Force host mode pull-downs If the ID pin functions are enabled, the host mode pull-downs on DP and DM activate automatically. However, whenever that is not the case, yet host mode is required, this bit must be used to force the pull-downs active."]
1988 #[inline(always)]
1989 pub const fn forcehostpd(&self) -> bool {
1990 let val = (self.0 >> 25usize) & 0x01;
1991 val != 0
1992 }
1993 #[doc = "Force host mode pull-downs If the ID pin functions are enabled, the host mode pull-downs on DP and DM activate automatically. However, whenever that is not the case, yet host mode is required, this bit must be used to force the pull-downs active."]
1994 #[inline(always)]
1995 pub fn set_forcehostpd(&mut self, val: bool) {
1996 self.0 = (self.0 & !(0x01 << 25usize)) | (((val as u32) & 0x01) << 25usize);
1997 }
1998 }
1999 impl Default for GccfgV3 {
2000 #[inline(always)]
2001 fn default() -> GccfgV3 {
2002 GccfgV3(0)
2003 }
2004 }
1834 #[doc = "I2C access register"] 2005 #[doc = "I2C access register"]
1835 #[repr(transparent)] 2006 #[repr(transparent)]
1836 #[derive(Copy, Clone, Eq, PartialEq)] 2007 #[derive(Copy, Clone, Eq, PartialEq)]
diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs
new file mode 100644
index 000000000..6773f7843
--- /dev/null
+++ b/examples/stm32h7rs/src/bin/usb_serial.rs
@@ -0,0 +1,140 @@
1#![no_std]
2#![no_main]
3
4use defmt::{panic, *};
5use embassy_executor::Spawner;
6use embassy_futures::join::join;
7use embassy_stm32::time::Hertz;
8use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder;
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
17});
18
19// If you are trying this and your USB device doesn't connect, the most
20// common issues are the RCC config and vbus_detection
21//
22// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
23// for more information.
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 info!("Hello World!");
27
28 let mut config = Config::default();
29
30 {
31 use embassy_stm32::rcc::*;
32 config.rcc.hse = Some(Hse {
33 freq: Hertz(24_000_000),
34 mode: HseMode::Oscillator,
35 });
36 config.rcc.pll1 = Some(Pll {
37 source: PllSource::HSE,
38 prediv: PllPreDiv::DIV12,
39 mul: PllMul::MUL300,
40 divp: Some(PllDiv::DIV1), //600 MHz
41 divq: Some(PllDiv::DIV2), // 300 MHz
42 divr: Some(PllDiv::DIV2), // 300 MHz
43 });
44 config.rcc.sys = Sysclk::PLL1_P; // 600 MHz
45 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz
46 config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 MHz
47 config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 MHz
48 config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 MHz
49 config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 MHz
50 config.rcc.voltage_scale = VoltageScale::HIGH;
51 config.rcc.mux.usbphycsel = mux::Usbphycsel::HSE;
52 }
53
54 let p = embassy_stm32::init(config);
55
56 // Create the driver, from the HAL.
57 let mut ep_out_buffer = [0u8; 256];
58 let mut config = embassy_stm32::usb::Config::default();
59
60 // Do not enable vbus_detection. This is a safe default that works in all boards.
61 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
62 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
63 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
64 config.vbus_detection = false;
65
66 let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PM6, p.PM5, &mut ep_out_buffer, config);
67
68 // Create embassy-usb Config
69 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
70 config.manufacturer = Some("Embassy");
71 config.product = Some("USB-serial example");
72 config.serial_number = Some("12345678");
73 // Required for windows compatibility.
74 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
75 config.device_class = 0xEF;
76 config.device_sub_class = 0x02;
77 config.device_protocol = 0x01;
78 config.composite_with_iads = true;
79
80 // Create embassy-usb DeviceBuilder using the driver and config.
81 // It needs some buffers for building the descriptors.
82 let mut config_descriptor = [0; 256];
83 let mut bos_descriptor = [0; 256];
84 let mut control_buf = [0; 64];
85
86 let mut state = State::new();
87
88 let mut builder = Builder::new(
89 driver,
90 config,
91 &mut config_descriptor,
92 &mut bos_descriptor,
93 &mut [], // no msos descriptors
94 &mut control_buf,
95 );
96
97 // Create classes on the builder.
98 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
99
100 // Build the builder.
101 let mut usb = builder.build();
102
103 // Run the USB device.
104 let usb_fut = usb.run();
105
106 // Do stuff with the class!
107 let echo_fut = async {
108 loop {
109 class.wait_connection().await;
110 info!("Connected");
111 let _ = echo(&mut class).await;
112 info!("Disconnected");
113 }
114 };
115
116 // Run everything concurrently.
117 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
118 join(usb_fut, echo_fut).await;
119}
120
121struct Disconnected {}
122
123impl From<EndpointError> for Disconnected {
124 fn from(val: EndpointError) -> Self {
125 match val {
126 EndpointError::BufferOverflow => panic!("Buffer overflow"),
127 EndpointError::Disabled => Disconnected {},
128 }
129 }
130}
131
132async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
133 let mut buf = [0; 64];
134 loop {
135 let n = class.read_packet(&mut buf).await?;
136 let data = &buf[..n];
137 info!("data: {:x}", data);
138 class.write_packet(data).await?;
139 }
140}