-
Notifications
You must be signed in to change notification settings - Fork 860
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3613 from mubes/stm32u5_otg_hs_support
Add support for stm32u595/5a5 OTG_HS in client mode
- Loading branch information
Showing
4 changed files
with
193 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
#![no_std] | ||
#![no_main] | ||
|
||
use defmt::{panic, *}; | ||
use defmt_rtt as _; // global logger | ||
use embassy_executor::Spawner; | ||
use embassy_futures::join::join; | ||
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 panic_probe as _; | ||
|
||
bind_interrupts!(struct Irqs { | ||
OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>; | ||
}); | ||
|
||
#[embassy_executor::main] | ||
async fn main(_spawner: Spawner) { | ||
info!("Hello World!"); | ||
|
||
let mut config = Config::default(); | ||
{ | ||
use embassy_stm32::rcc::*; | ||
use embassy_stm32::time::Hertz; | ||
config.rcc.hse = Some(Hse { | ||
freq: Hertz(16_000_000), | ||
mode: HseMode::Oscillator, | ||
}); | ||
config.rcc.pll1 = Some(Pll { | ||
source: PllSource::HSE, | ||
prediv: PllPreDiv::DIV2, // HSE / 2 = 8MHz | ||
mul: PllMul::MUL60, // 8MHz * 60 = 480MHz | ||
divr: Some(PllDiv::DIV3), // 480MHz / 3 = 160MHz (sys_ck) | ||
divq: Some(PllDiv::DIV10), // 480MHz / 10 = 48MHz (USB) | ||
divp: Some(PllDiv::DIV15), // 480MHz / 15 = 32MHz (USBOTG) | ||
}); | ||
config.rcc.mux.otghssel = mux::Otghssel::PLL1_P; | ||
config.rcc.voltage_range = VoltageScale::RANGE1; | ||
config.rcc.sys = Sysclk::PLL1_R; | ||
} | ||
|
||
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.PA12, p.PA11, &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?; | ||
} | ||
} |