mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 22:32:29 +00:00
Add OTG_HS support for STM32H7R/S
This commit is contained in:
parent
afd8a86962
commit
2f60d78ea3
@ -72,7 +72,8 @@ rand_core = "0.6.3"
|
|||||||
sdio-host = "0.5.0"
|
sdio-host = "0.5.0"
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
#stm32-metapac = { version = "15" }
|
#stm32-metapac = { version = "15" }
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364" }
|
# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364" }
|
||||||
|
stm32-metapac = { path = "../../stm32-data/build/stm32-metapac" }
|
||||||
|
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
@ -99,7 +100,8 @@ proc-macro2 = "1.0.36"
|
|||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
|
|
||||||
#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
|
#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364", default-features = false, features = ["metadata"] }
|
# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364", default-features = false, features = ["metadata"] }
|
||||||
|
stm32-metapac = { path = "../../stm32-data/build/stm32-metapac", default-features = false, features = ["metadata"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rt"]
|
default = ["rt"]
|
||||||
|
@ -698,7 +698,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
#[cfg(stm32h7rs)]
|
#[cfg(stm32h7rs)]
|
||||||
clk48mohci: None, // TODO
|
clk48mohci: None, // TODO
|
||||||
#[cfg(stm32h7rs)]
|
#[cfg(stm32h7rs)]
|
||||||
usb: None, // TODO
|
usb: Some(Hertz(48_000_000)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -769,7 +769,7 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
|
|||||||
if num == 0 {
|
if num == 0 {
|
||||||
// on PLL1, DIVP must be even for most series.
|
// on PLL1, DIVP must be even for most series.
|
||||||
// The enum value is 1 less than the divider, so check it's odd.
|
// The enum value is 1 less than the divider, so check it's odd.
|
||||||
#[cfg(not(pwr_h7rm0468))]
|
#[cfg(not(any(pwr_h7rm0468, stm32h7rs)))]
|
||||||
assert!(div.to_bits() % 2 == 1);
|
assert!(div.to_bits() % 2 == 1);
|
||||||
#[cfg(pwr_h7rm0468)]
|
#[cfg(pwr_h7rm0468)]
|
||||||
assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0);
|
assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0);
|
||||||
|
@ -48,6 +48,26 @@ fn common_init<T: Instance>() {
|
|||||||
while !crate::pac::PWR.cr3().read().usb33rdy() {}
|
while !crate::pac::PWR.cr3().read().usb33rdy() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(stm32h7rs)]
|
||||||
|
{
|
||||||
|
// If true, VDD33USB is generated by internal regulator from VDD50USB
|
||||||
|
// If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
|
||||||
|
// TODO: unhardcode
|
||||||
|
let internal_regulator = false;
|
||||||
|
|
||||||
|
// Enable USB power
|
||||||
|
critical_section::with(|_| {
|
||||||
|
crate::pac::PWR.csr2().modify(|w| {
|
||||||
|
w.set_usbregen(internal_regulator);
|
||||||
|
w.set_usb33den(true);
|
||||||
|
w.set_usbhsregen(true);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for USB power to stabilize
|
||||||
|
while !crate::pac::PWR.csr2().read().usb33rdy() {}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(stm32u5)]
|
#[cfg(stm32u5)]
|
||||||
{
|
{
|
||||||
// Enable USB power
|
// Enable USB power
|
||||||
|
@ -97,6 +97,45 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initializes USB OTG peripheral with internal High-Speed PHY.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
|
||||||
|
/// Must be large enough to fit all OUT endpoint max packet sizes.
|
||||||
|
/// Endpoint allocation will fail if it is too small.
|
||||||
|
pub fn new_hs(
|
||||||
|
_peri: impl Peripheral<P = T> + 'd,
|
||||||
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
|
dp: impl Peripheral<P = impl DpPin<T>> + 'd,
|
||||||
|
dm: impl Peripheral<P = impl DmPin<T>> + 'd,
|
||||||
|
ep_out_buffer: &'d mut [u8],
|
||||||
|
config: Config,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(dp, dm);
|
||||||
|
|
||||||
|
dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
|
||||||
|
dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
|
||||||
|
|
||||||
|
let regs = T::regs();
|
||||||
|
|
||||||
|
let instance = OtgInstance {
|
||||||
|
regs,
|
||||||
|
state: T::state(),
|
||||||
|
fifo_depth_words: T::FIFO_DEPTH_WORDS,
|
||||||
|
extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
|
||||||
|
endpoint_count: T::ENDPOINT_COUNT,
|
||||||
|
phy_type: PhyType::InternalHighSpeed,
|
||||||
|
quirk_setup_late_cnak: quirk_setup_late_cnak(regs),
|
||||||
|
calculate_trdt_fn: calculate_trdt::<T>,
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
inner: OtgDriver::new(ep_out_buffer, instance, config),
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode).
|
/// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode).
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
@ -272,6 +311,19 @@ impl<'d, T: Instance> Bus<'d, T> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[cfg(stm32h7rs)]
|
||||||
|
critical_section::with(|_| {
|
||||||
|
let rcc = crate::pac::RCC;
|
||||||
|
rcc.ahb1enr().modify(|w| {
|
||||||
|
w.set_usbphycen(true);
|
||||||
|
w.set_usb_otg_hsen(true);
|
||||||
|
});
|
||||||
|
rcc.ahb1lpenr().modify(|w| {
|
||||||
|
w.set_usbphyclpen(true);
|
||||||
|
w.set_usb_otg_hslpen(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let core_id = r.cid().read().0;
|
let core_id = r.cid().read().0;
|
||||||
trace!("Core id {:08x}", core_id);
|
trace!("Core id {:08x}", core_id);
|
||||||
@ -286,6 +338,7 @@ impl<'d, T: Instance> Bus<'d, T> {
|
|||||||
match core_id {
|
match core_id {
|
||||||
0x0000_1200 | 0x0000_1100 => self.inner.config_v1(),
|
0x0000_1200 | 0x0000_1100 => self.inner.config_v1(),
|
||||||
0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(),
|
0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(),
|
||||||
|
0x0000_5000 => self.inner.config_v5(),
|
||||||
_ => unimplemented!("Unknown USB core id {:X}", core_id),
|
_ => unimplemented!("Unknown USB core id {:X}", core_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -584,6 +584,22 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn config_v5(&mut self) {
|
||||||
|
let r = self.instance.regs;
|
||||||
|
|
||||||
|
r.gccfg_v3().modify(|w| {
|
||||||
|
w.set_vbvaloven(true);
|
||||||
|
w.set_vbvaloval(true);
|
||||||
|
w.set_vbden(self.config.vbus_detection);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Force B-peripheral session
|
||||||
|
r.gotgctl().modify(|w| {
|
||||||
|
w.set_vbvaloen(!self.config.vbus_detection);
|
||||||
|
w.set_bvaloval(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn init(&mut self) {
|
fn init(&mut self) {
|
||||||
let r = self.instance.regs;
|
let r = self.instance.regs;
|
||||||
let phy_type = self.instance.phy_type;
|
let phy_type = self.instance.phy_type;
|
||||||
|
@ -186,6 +186,11 @@ impl Otg {
|
|||||||
pub const fn gccfg_v2(self) -> Reg<regs::GccfgV2, RW> {
|
pub const fn gccfg_v2(self) -> Reg<regs::GccfgV2, RW> {
|
||||||
unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) }
|
unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) }
|
||||||
}
|
}
|
||||||
|
#[doc = "General core configuration register, for core_id 0x0000_5xxx"]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn gccfg_v3(self) -> Reg<regs::GccfgV3, RW> {
|
||||||
|
unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) }
|
||||||
|
}
|
||||||
#[doc = "Core ID register"]
|
#[doc = "Core ID register"]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub const fn cid(self) -> Reg<regs::Cid, RW> {
|
pub const fn cid(self) -> Reg<regs::Cid, RW> {
|
||||||
@ -1831,6 +1836,172 @@ pub mod regs {
|
|||||||
GccfgV2(0)
|
GccfgV2(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[doc = "OTG general core configuration register."]
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub struct GccfgV3(pub u32);
|
||||||
|
impl GccfgV3 {
|
||||||
|
#[doc = "Charger detection, result of the current mode (primary or secondary)."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn chgdet(&self) -> bool {
|
||||||
|
let val = (self.0 >> 0usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[doc = "Charger detection, result of the current mode (primary or secondary)."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_chgdet(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize);
|
||||||
|
}
|
||||||
|
#[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)."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn fsvplus(&self) -> bool {
|
||||||
|
let val = (self.0 >> 1usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[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)."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_fsvplus(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize);
|
||||||
|
}
|
||||||
|
#[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)."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn fsvminus(&self) -> bool {
|
||||||
|
let val = (self.0 >> 2usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[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)."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_fsvminus(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize);
|
||||||
|
}
|
||||||
|
#[doc = "VBUS session indicator Indicates if VBUS is above VBUS session threshold."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn sessvld(&self) -> bool {
|
||||||
|
let val = (self.0 >> 3usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[doc = "VBUS session indicator Indicates if VBUS is above VBUS session threshold."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_sessvld(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize);
|
||||||
|
}
|
||||||
|
#[doc = "Host CDP behavior enable."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn hcdpen(&self) -> bool {
|
||||||
|
let val = (self.0 >> 16usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[doc = "Host CDP behavior enable."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_hcdpen(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 16usize)) | (((val as u32) & 0x01) << 16usize);
|
||||||
|
}
|
||||||
|
#[doc = "Host CDP port voltage detector enable on DP."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn hcdpdeten(&self) -> bool {
|
||||||
|
let val = (self.0 >> 17usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[doc = "Host CDP port voltage detector enable on DP."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_hcdpdeten(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize);
|
||||||
|
}
|
||||||
|
#[doc = "Host CDP port Voltage source enable on DM."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn hvdmsrcen(&self) -> bool {
|
||||||
|
let val = (self.0 >> 18usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[doc = "Host CDP port Voltage source enable on DM."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_hvdmsrcen(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 18usize)) | (((val as u32) & 0x01) << 18usize);
|
||||||
|
}
|
||||||
|
#[doc = "Data Contact Detection enable."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn dcden(&self) -> bool {
|
||||||
|
let val = (self.0 >> 19usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[doc = "Data Contact Detection enable."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_dcden(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 19usize)) | (((val as u32) & 0x01) << 19usize);
|
||||||
|
}
|
||||||
|
#[doc = "Primary detection enable."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn pden(&self) -> bool {
|
||||||
|
let val = (self.0 >> 20usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[doc = "Primary detection enable."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_pden(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize);
|
||||||
|
}
|
||||||
|
#[doc = "VBUS detection enable Enables VBUS Sensing Comparators in order to detect VBUS presence and/or perform OTG operation."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn vbden(&self) -> bool {
|
||||||
|
let val = (self.0 >> 21usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[doc = "VBUS detection enable Enables VBUS Sensing Comparators in order to detect VBUS presence and/or perform OTG operation."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_vbden(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 21usize)) | (((val as u32) & 0x01) << 21usize);
|
||||||
|
}
|
||||||
|
#[doc = "Secondary detection enable."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn sden(&self) -> bool {
|
||||||
|
let val = (self.0 >> 22usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[doc = "Secondary detection enable."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_sden(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 22usize)) | (((val as u32) & 0x01) << 22usize);
|
||||||
|
}
|
||||||
|
#[doc = "Software override value of the VBUS B-session detection."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn vbvaloval(&self) -> bool {
|
||||||
|
let val = (self.0 >> 23usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[doc = "Software override value of the VBUS B-session detection."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_vbvaloval(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 23usize)) | (((val as u32) & 0x01) << 23usize);
|
||||||
|
}
|
||||||
|
#[doc = "Enables a software override of the VBUS B-session detection."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn vbvaloven(&self) -> bool {
|
||||||
|
let val = (self.0 >> 24usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[doc = "Enables a software override of the VBUS B-session detection."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_vbvaloven(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 24usize)) | (((val as u32) & 0x01) << 24usize);
|
||||||
|
}
|
||||||
|
#[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."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn forcehostpd(&self) -> bool {
|
||||||
|
let val = (self.0 >> 25usize) & 0x01;
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
#[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."]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_forcehostpd(&mut self, val: bool) {
|
||||||
|
self.0 = (self.0 & !(0x01 << 25usize)) | (((val as u32) & 0x01) << 25usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for GccfgV3 {
|
||||||
|
#[inline(always)]
|
||||||
|
fn default() -> GccfgV3 {
|
||||||
|
GccfgV3(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
#[doc = "I2C access register"]
|
#[doc = "I2C access register"]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
139
examples/stm32h7rs/src/bin/usb_serial.rs
Normal file
139
examples/stm32h7rs/src/bin/usb_serial.rs
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use defmt::{panic, *};
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_futures::join::join;
|
||||||
|
use embassy_stm32::time::Hertz;
|
||||||
|
use embassy_stm32::usb::{Driver, Instance};
|
||||||
|
use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
|
||||||
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
|
use embassy_usb::driver::EndpointError;
|
||||||
|
use embassy_usb::Builder;
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
|
||||||
|
});
|
||||||
|
|
||||||
|
// If you are trying this and your USB device doesn't connect, the most
|
||||||
|
// common issues are the RCC config and vbus_detection
|
||||||
|
//
|
||||||
|
// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
|
||||||
|
// for more information.
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let mut config = Config::default();
|
||||||
|
|
||||||
|
{
|
||||||
|
use embassy_stm32::rcc::*;
|
||||||
|
config.rcc.hse = Some(Hse {
|
||||||
|
freq: Hertz(24_000_000),
|
||||||
|
mode: HseMode::Oscillator,
|
||||||
|
});
|
||||||
|
config.rcc.pll1 = Some(Pll {
|
||||||
|
source: PllSource::HSE,
|
||||||
|
prediv: PllPreDiv::DIV12,
|
||||||
|
mul: PllMul::MUL300,
|
||||||
|
divp: Some(PllDiv::DIV1), //600 MHz
|
||||||
|
divq: Some(PllDiv::DIV2), // 300 MHz
|
||||||
|
divr: Some(PllDiv::DIV2), // 300 MHz
|
||||||
|
});
|
||||||
|
config.rcc.sys = Sysclk::PLL1_P; // 600 MHz
|
||||||
|
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz
|
||||||
|
config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 MHz
|
||||||
|
config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 MHz
|
||||||
|
config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 MHz
|
||||||
|
config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 MHz
|
||||||
|
config.rcc.voltage_scale = VoltageScale::HIGH;
|
||||||
|
}
|
||||||
|
|
||||||
|
let p = embassy_stm32::init(config);
|
||||||
|
|
||||||
|
// Create the driver, from the HAL.
|
||||||
|
let mut ep_out_buffer = [0u8; 256];
|
||||||
|
let mut config = embassy_stm32::usb::Config::default();
|
||||||
|
|
||||||
|
// Do not enable vbus_detection. This is a safe default that works in all boards.
|
||||||
|
// However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
|
||||||
|
// to enable vbus_detection to comply with the USB spec. If you enable it, the board
|
||||||
|
// has to support it or USB won't work at all. See docs on `vbus_detection` for details.
|
||||||
|
config.vbus_detection = false;
|
||||||
|
|
||||||
|
let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PM6, p.PM5, &mut ep_out_buffer, config);
|
||||||
|
|
||||||
|
// Create embassy-usb Config
|
||||||
|
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
|
||||||
|
config.manufacturer = Some("Embassy");
|
||||||
|
config.product = Some("USB-serial example");
|
||||||
|
config.serial_number = Some("12345678");
|
||||||
|
// Required for windows compatibility.
|
||||||
|
// https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
|
||||||
|
config.device_class = 0xEF;
|
||||||
|
config.device_sub_class = 0x02;
|
||||||
|
config.device_protocol = 0x01;
|
||||||
|
config.composite_with_iads = true;
|
||||||
|
|
||||||
|
// Create embassy-usb DeviceBuilder using the driver and config.
|
||||||
|
// It needs some buffers for building the descriptors.
|
||||||
|
let mut config_descriptor = [0; 256];
|
||||||
|
let mut bos_descriptor = [0; 256];
|
||||||
|
let mut control_buf = [0; 64];
|
||||||
|
|
||||||
|
let mut state = State::new();
|
||||||
|
|
||||||
|
let mut builder = Builder::new(
|
||||||
|
driver,
|
||||||
|
config,
|
||||||
|
&mut config_descriptor,
|
||||||
|
&mut bos_descriptor,
|
||||||
|
&mut [], // no msos descriptors
|
||||||
|
&mut control_buf,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create classes on the builder.
|
||||||
|
let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
|
||||||
|
|
||||||
|
// Build the builder.
|
||||||
|
let mut usb = builder.build();
|
||||||
|
|
||||||
|
// Run the USB device.
|
||||||
|
let usb_fut = usb.run();
|
||||||
|
|
||||||
|
// Do stuff with the class!
|
||||||
|
let echo_fut = async {
|
||||||
|
loop {
|
||||||
|
class.wait_connection().await;
|
||||||
|
info!("Connected");
|
||||||
|
let _ = echo(&mut class).await;
|
||||||
|
info!("Disconnected");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run everything concurrently.
|
||||||
|
// If we had made everything `'static` above instead, we could do this using separate tasks instead.
|
||||||
|
join(usb_fut, echo_fut).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Disconnected {}
|
||||||
|
|
||||||
|
impl From<EndpointError> for Disconnected {
|
||||||
|
fn from(val: EndpointError) -> Self {
|
||||||
|
match val {
|
||||||
|
EndpointError::BufferOverflow => panic!("Buffer overflow"),
|
||||||
|
EndpointError::Disabled => Disconnected {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
|
||||||
|
let mut buf = [0; 64];
|
||||||
|
loop {
|
||||||
|
let n = class.read_packet(&mut buf).await?;
|
||||||
|
let data = &buf[..n];
|
||||||
|
info!("data: {:x}", data);
|
||||||
|
class.write_packet(data).await?;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user