Open shufps opened 9 months ago
I found out I can add this to the usb stm32 driver:
crate::pac::SYSCFG.pmc().modify(|w| w.set_usb_pu(true));
but my USB device still doesn't work with the L1 :disappointed:
I have GND level on D+ and D- ... maybe a sign something is wrong with the clock.
It also hangs here:
0.253234 TRACE usb: power detected
0.253265 TRACE RESET
0.253356 TRACE usb: reset
0.253417 TRACE SETUP read waiting
0.253479 TRACE wait_enabled OUT WAITING
0.253540 TRACE wait_enabled OUT WAITING
0.253601 TRACE wait_enabled IN WAITING
It's waiting for something :thinking:
have you configured the clocks correctly?
RM0038 page 132 6.2.4:
If the USB or SDIO interface is used in the application, the PLL VCO clock (defined by the PLL multiplication factor) must be programmed to output a 96 MHz frequency. This is required to provide a 48 MHz clock to the USB or SDIO (SDIOCLK or USBCLK = PLLVCO/2).
Yes, I'm 99.95% sure that I did it right and I looked over it a dozen times :see_no_evil:
let mut config = embassy_stm32::Config::default();
config.rcc.mux = ClockSrc::PLL1_R;
config.rcc.hse = Some(Hse {
freq: Hertz::mhz(8),
mode: HseMode::Bypass,
});
config.rcc.pll = Some(Pll {
source: PllSource::HSE,
div: PllDiv::DIV3,
mul: PllMul::MUL12,
});
let p = embassy_stm32::init(config);
I use CubeMX as reference for hardware settings:
In the meantime I tried C code with HAL and it works, so I can exclude a hardware defect :thinking:
are you sure your board has a 8Mhz HSE? Is it a digital clock instead of an oscillator?
you could also try HSI. It's not accurate enough to meet USB spec but it usually works anyway. If it works then it gives you a clue something's wrong with HSE, at least.
let mut config = embassy_stm32::Config::default();
{
use embassy_stm32::rcc::*;
config.rcc.hsi = true;
config.rcc.pll = Some(Pll {
source: PllSource::HSI,
mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz
div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3)
});
config.rcc.mux = ClockSrc::PLL1_R;
}
let p = embassy_stm32::init(config);
are you sure your board has a 8Mhz HSE? Is it a digital clock instead of an oscillator?
Yes, it's a custom board, it has an 8MHz oscillator. (not just a crystal, it has a real oscillator that requires bypass
clock config, otherwise clock is too slow)
you could also try HSI. It's not accurate enough to meet USB spec but it usually works anyway. If it works then it gives you a clue something's wrong with HSE, at least.
let mut config = embassy_stm32::Config::default(); { use embassy_stm32::rcc::*; config.rcc.hsi = true; config.rcc.pll = Some(Pll { source: PllSource::HSI, mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3) }); config.rcc.mux = ClockSrc::PLL1_R; } let p = embassy_stm32::init(config);
Hmm yes right, at least I could try it if it changes something ... :thinking:
Hmm, it's the same with HSI :pleading_face:
This is my code:
#![no_std]
#![no_main]
use defmt::{panic, *};
use embassy_executor::Spawner;
use embassy_stm32::rcc::Hse;
use embassy_stm32::rcc::HseMode;
use embassy_stm32::rcc::PllDiv;
use embassy_stm32::rcc::PllMul;
use embassy_stm32::rcc::{ClockSrc, Pll, PllSource};
use embassy_stm32::time::Hertz;
use embassy_stm32::usb::{self, Driver, Instance};
use embassy_stm32::{bind_interrupts, peripherals, Config};
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
use embassy_usb::driver::EndpointError;
use embassy_usb::Builder;
use futures::future::join;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
USB_LP => usb::InterruptHandler<peripherals::USB>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
/*
let mut config = embassy_stm32::Config::default();
config.rcc.mux = ClockSrc::PLL1_R;
config.rcc.hse = Some(Hse {
freq: Hertz::mhz(8),
mode: HseMode::Bypass,
});
config.rcc.pll = Some(Pll {
source: PllSource::HSE,
div: PllDiv::DIV3,
mul: PllMul::MUL12,
});
*/
let mut config = embassy_stm32::Config::default();
{
use embassy_stm32::rcc::*;
config.rcc.hsi = true;
config.rcc.pll = Some(Pll {
source: PllSource::HSI,
mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz
div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3)
});
config.rcc.mux = ClockSrc::PLL1_R;
}
let p = embassy_stm32::init(config);
info!("Hello World!");
let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
config.manufacturer = Some("Embassy");
config.product = Some("USB-Serial Example");
config.serial_number = Some("123456");
config.device_class = 0xEF;
config.device_sub_class = 0x02;
config.device_protocol = 0x01;
config.composite_with_iads = true;
let mut device_descriptor = [0; 256];
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 device_descriptor,
&mut config_descriptor,
&mut bos_descriptor,
&mut [], // no msos descriptors
&mut control_buf,
);
let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
let mut usb = builder.build();
let usb_fut = usb.run();
let echo_fut = async {
loop {
class.wait_connection().await;
info!("Connected");
let _ = echo(&mut class).await;
info!("Disconnected");
}
};
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?;
}
}
It's a bit different to the other usb_serial versions because it uses this weird USB_LP
interrupt :thinking:
can you try pulling D+ down on boot, to force reenumeration?
https://github.com/embassy-rs/embassy/blob/main/examples/stm32f1/src/bin/usb_serial.rs#L31-L38
Oh wait, it started working ... I think I found it ...
https://github.com/embassy-rs/embassy/blob/main/embassy-stm32/src/usb/usb.rs#L446
Here this is missing for the L1
crate::pac::SYSCFG.pmc().modify(|w| w.set_usb_pu(true));
And this seems to not be working for the L1 - removing both lines and it started working: https://github.com/embassy-rs/embassy/blob/main/embassy-stm32/src/usb/usb.rs#L289
The AF-Values are 0
- I tried with 10
but it didn't work either :man_shrugging: But removing both works.
Will do more tests tomorrow and then try to add for the L1
HSE is working too :partying_face:
nice!! :tada:
And this seems to not be working for the L1 - removing both lines and it started working: https://github.com/embassy-rs/embassy/blob/main/embassy-stm32/src/usb/usb.rs#L289
That's very strange, I've never seen any STM32 where you don't have to set DP/DM pins as AF! ... but if it works then ... :shrug:
Hi,
The L1s have an internal Pull-Up that needs to be enabled. Without enumeration doesn't work.
I was searching through embassy but couldn't find out how to enable it.
Please, has someone an idea? :pleading_face:
Thx in advance!