Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stm32 hid Control Pipe data out is unstable #3459

Open
votrungchi opened this issue Oct 25, 2024 · 3 comments
Open

stm32 hid Control Pipe data out is unstable #3459

votrungchi opened this issue Oct 25, 2024 · 3 comments

Comments

@votrungchi
Copy link
Contributor

Hello, I am facing a problem with USB HID on STM32F407VG, the data out from Control Pipe is incorrect. The data I only send is [Tx Feature Report [2] --> 0102], but the Control Pipe data out sometime is [00, 00], sometime is [ ], the expected is [01, 02].

The code I use to reproduce the issue.

#![no_std]
#![no_main]

use {defmt_rtt as _, panic_probe as _};

use embassy_stm32::usb::Driver;
use embassy_stm32::{bind_interrupts, usb, Config};
use embassy_stm32::time::Hertz;

use embassy_executor::Spawner;
use embassy_stm32::peripherals::USB_OTG_FS;
use embassy_usb::class::hid::{HidWriter, State};
use embassy_usb::Builder;

use my_crate::handler::MyDeviceHandler;

#[rustfmt::skip]
pub const MY_TEST_DESCRIPTOR: [u8; 37] =
        [
            0x05, 0x01,              // USAGE_PAGE (Generic Desktop)
            0x09, 0x00,              // USAGE (Undefined)
            0xA1, 0x01,              // COLLECTION (Application)

            // Feature Report
            0x85, 0x01,          // REPORT_ID (1)
            0x09, 0x02,          // USAGE (Undefined)
            0x15, 0x00,          // LOGICAL_MINIMUM (0)
            0x26, 0xFF, 0x00,    // LOGICAL_MAXIMUM (255)
            0x75, 0x08,          // REPORT_SIZE (8)
            0x95, 0x01,          // REPORT_COUNT (1)
            0xB1, 0x02,          // FEATURE (Data,Var,Abs)

            // Output Report
            0x85, 0x02,          // REPORT_ID (2)
            0x09, 0x03,          // USAGE (Undefined)
            0x15, 0x00,          // LOGICAL_MINIMUM (0)
            0x26, 0xFF, 0x00,    // LOGICAL_MAXIMUM (255)
            0x75, 0x08,          // REPORT_SIZE (8)
            0x95, 0x01,          // REPORT_COUNT (1)
            0x91, 0x02,          // OUTPUT (Data,Var,Abs)

            0xC0
        ];

bind_interrupts!(struct Irqs {
    OTG_FS => usb::InterruptHandler<USB_OTG_FS>;
});

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    let mut config = Config::default();
    {
        use embassy_stm32::rcc::*;
        config.rcc.hse = Some(Hse {
            freq: Hertz(8_000_000),
            mode: HseMode::Bypass,
        });
        config.rcc.pll_src = PllSource::HSE;
        config.rcc.pll = Some(Pll {
            prediv: PllPreDiv::DIV4,
            mul: PllMul::MUL168,
            divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz.
            divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz.
            divr: None,
        });
        config.rcc.ahb_pre = AHBPrescaler::DIV1;
        config.rcc.apb1_pre = APBPrescaler::DIV4;
        config.rcc.apb2_pre = APBPrescaler::DIV2;
        config.rcc.sys = Sysclk::PLL1_P;
        config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q;
    }
    let p = embassy_stm32::init(config);

    // Create the driver, from the HAL.
    let mut ep_out_buffer = [0u8; 256];
    let mut stm32_usb_config = embassy_stm32::usb::Config::default();
    stm32_usb_config.vbus_detection = true;
    let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, stm32_usb_config);

    // Create embassy-usb Config
    let mut usb_config = embassy_usb::Config::new(0xc0de, 0xcafe);
    usb_config.manufacturer = Some("Embassy");
    usb_config.product = Some("HID test");
    usb_config.serial_number = Some("12345678");
    usb_config.max_power = 100;
    usb_config.max_packet_size_0 = 64;

    // Required for windows compatibility.
    // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
    usb_config.device_class = 0xEF;
    usb_config.device_sub_class = 0x02;
    usb_config.device_protocol = 0x01;
    usb_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];
    // You can also add a Microsoft OS descriptor.
    let mut msos_descriptor = [0; 256];
    let mut control_buf = [0; 64];

    let mut my_device_handler = MyDeviceHandler::new();

    let mut state = State::new();

    let mut builder = Builder::new(
        driver,
        usb_config,
        &mut config_descriptor,
        &mut bos_descriptor,
        &mut msos_descriptor,
        &mut control_buf,
    );

    builder.handler(&mut my_device_handler);

    // Create classes on the builder.
    let hid_config = embassy_usb::class::hid::Config {
        report_descriptor: &MY_TEST_DESCRIPTOR,
        request_handler: None,
        poll_ms: 1,
        max_packet_size: 64,
    };

    let _writer = HidWriter::<_, 64>::new(&mut builder, &mut state, hid_config);

    // Build the builder.
    let mut usb = builder.build();

    // Run the USB device.
    usb.run().await;
}

The log:

TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE control request: Request { direction: Out, request_type: Class, recipient: Interface, request: 9, value: 769, index: 0, length: 2 }
└─ embassy_usb::{impl#1}::handle_control::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:347
TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE   control out data: [00, 00]
└─ embassy_usb::{impl#1}::handle_control_out::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:425
TRACE HID control_out Request { direction: Out, request_type: Class, recipient: Interface, request: 9, value: 769, index: 0, length: 2 } [0, 0]
└─ embassy_usb::class::hid::{impl#8}::control_out @ embassy\embassy-usb\src\class\hid.rs:468
TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE control request: Request { direction: Out, request_type: Class, recipient: Interface, request: 9, value: 769, index: 0, length: 2 }
└─ embassy_usb::{impl#1}::handle_control::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:347
TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE   control out data: []
└─ embassy_usb::{impl#1}::handle_control_out::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:425
TRACE HID control_out Request { direction: Out, request_type: Class, recipient: Interface, request: 9, value: 769, index: 0, length: 2 } []
└─ embassy_usb::class::hid::{impl#8}::control_out @ embassy\embassy-usb\src\class\hid.rs:468
TRACE control request: Request { direction: Out, request_type: Standard, recipient: Device, request: 0, value: 488, index: 32, length: 485 }
└─ embassy_usb::{impl#1}::handle_control::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:347
WARN  got CONTROL OUT with length 485 higher than the control_buf len 64, rejecting.
└─ embassy_usb::{impl#1}::handle_control_out::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:399
TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE control request: Request { direction: Out, request_type: Class, recipient: Interface, request: 9, value: 769, index: 0, length: 2 }
└─ embassy_usb::{impl#1}::handle_control::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:347
TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE   control out data: [00, 00]
└─ embassy_usb::{impl#1}::handle_control_out::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:425
TRACE HID control_out Request { direction: Out, request_type: Class, recipient: Interface, request: 9, value: 769, index: 0, length: 2 } [0, 0]
└─ embassy_usb::class::hid::{impl#8}::control_out @ embassy\embassy-usb\src\class\hid.rs:468
TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE control request: Request { direction: Out, request_type: Class, recipient: Interface, request: 9, value: 769, index: 0, length: 2 }
└─ embassy_usb::{impl#1}::handle_control::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:347
TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE   control out data: [01, 02]
└─ embassy_usb::{impl#1}::handle_control_out::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:425
TRACE HID control_out Request { direction: Out, request_type: Class, recipient: Interface, request: 9, value: 769, index: 0, length: 2 } [1, 2]
└─ embassy_usb::class::hid::{impl#8}::control_out @ embassy\embassy-usb\src\class\hid.rs:468
TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE control request: Request { direction: Out, request_type: Class, recipient: Interface, request: 9, value: 769, index: 0, length: 2 }
└─ embassy_usb::{impl#1}::handle_control::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:347
TRACE irq
└─ embassy_stm32::usb::_version::{impl#0}::on_interrupt @ embassy\embassy-stm32\src\usb\otg.rs:27
TRACE   control out data: [01, 02]
└─ embassy_usb::{impl#1}::handle_control_out::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:425
TRACE HID control_out Request { direction: Out, request_type: Class, recipient: Interface, request: 9, value: 769, index: 0, length: 2 } [1, 2]
└─ embassy_usb::class::hid::{impl#8}::control_out @ embassy\embassy-usb\src\class\hid.rs:468
@Dirbaio
Copy link
Member

Dirbaio commented Oct 25, 2024

Can you try enabling trace logs in embassy-usb-synopsys-otg? Add it here https://github.com/embassy-rs/embassy/blob/main/embassy-stm32/Cargo.toml#L113 so the defmt feature of embassy-stm32 enables it, then make sure you have DEFMT_LOG=trace

@votrungchi
Copy link
Contributor Author

Hello, here is the trace: hid.log
Note: I have to comment out the assert because of compile error:

Compiling embassy-usb-synopsys-otg v0.1.0 (C:\Users\Chi\workspace\github.com\votrungchi\formula-rs\embassy\embassy-usb-synopsys-otg)
error[E0015]: cannot call non-const fn `defmt::export::acquire` in constant functions
   --> embassy\embassy-usb-synopsys-otg\src\fmt.rs:16:13
    |
16  |             ::defmt::assert!($($x)*);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
    #[doc = "Device IN endpoint transmit FIFO size register"]
    #[inline(always)]
    pub const fn dieptxf(self, n: usize) -> Reg<regs::Fsiz, RW> {
        // assert!(n < 7usize);
        unsafe { Reg::from_ptr(self.ptr.add(0x0104usize + n * 4usize) as _) }
    }

@votrungchi
Copy link
Contributor Author

This error also happen after the data is wrong:

TRACE control request: Request { direction: Out, request_type: Class, recipient: Interface, request: 9, value: 772, index: 0, length: 4 }
└─ embassy_usb::{impl#1}::handle_control::{async_fn#0} @ embassy\embassy-usb\src\lib.rs:347
ERROR panicked at C:\Users\Chi\workspace\github.com\votrungchi\formula-rs\embassy\embassy-usb-synopsys-otg\src\lib.rs:46:9:
assertion failed: ep_num < ep_count
└─ panic_probe::print_defmt::print @ C:\Users\Chi\.cargo\registry\src\index.crates.io-6f17d22bba15001f\panic-probe-0.3.2\src\lib.rs:104

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants