cancel
Showing results for 
Search instead for 
Did you mean: 

USB gadget device not working for STM32MP151

ATringali
Associate II

Hi everybody,

I would like to simulate a USB scanner device using libcomposite, so I modified the USB FIFO sizes in the DTS as follows:

usbotg_hs{
    u-boot,dm-pre-reloc;
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&usb_otg_hs_pins_mx>;
    pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
    status = "okay";
 
    /* USER CODE BEGIN usbotg_hs */
    phys = <&usbphyc_port1 0>;                  /* 0: UTMI switch selects the OTG */
    phy-names = "usb2-phy";
    u-boot,force-b-session-valid;
    u-boot,force-vbus-detection;
    dr_mode = "peripheral";
    g-rx-fifo-size = <256>;
    g-np-tx-fifo-size = <256>;
    g-tx-fifo-size = <128 128 64 16 16 16 16 16>;
    /* USER CODE END usbotg_hs */
};

This allows me to open the device declaring USB packet sizes of 512 bytes instead of the maximum which would be allowed by stm32mp151.dtsi (64 bytes, the kernel panics declaring 512).

After the configuration of configfs I pull up my application device-side, which borrows from the kernel example in tools/usb/ffs-aio-example/simple/device_app/aio_simple.c, defining three endpoints (IN, OUT, IN) like here:

#pragma pack(1)
typedef struct {
	struct usb_functionfs_descs_head_v2 header;
	__le32 fs_count;
	__le32 hs_count;
	struct {
		struct usb_interface_descriptor intf;
		struct usb_endpoint_descriptor_no_audio bulk_sink_command;
		struct usb_endpoint_descriptor_no_audio bulk_source_command;
		struct usb_endpoint_descriptor_no_audio bulk_sink_scanner;
	} __attribute__ ((__packed__)) fs_descs, hs_descs;
} t_usb_device_descriptors;
#pragma pack()
 
#pragma pack(1)
typedef struct {
	struct usb_functionfs_strings_head header;
	struct {
		__le16 code;
		const char str1[sizeof(STR_INTERFACE)];
	} __attribute__ ((__packed__)) lang0;
} t_scanner_string;
#pragma pack()
 
 
 
t_usb_device_descriptors descriptors = {
		.header = {
			.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
			.flags = htole32(FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC),
			.length = htole32(sizeof(descriptors)),
		},
		.fs_count = htole32(USB_NUM_ENDPOINTS + 1),
		.fs_descs = {
			.intf = {
				.bLength = sizeof(descriptors.fs_descs.intf),
				.bDescriptorType = USB_DT_INTERFACE,
				.bNumEndpoints = USB_NUM_ENDPOINTS,
				.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
				.iInterface = 1,
			},
			.bulk_sink_command = {
				.bLength = sizeof(descriptors.fs_descs.bulk_sink_command),
				.bDescriptorType = USB_DT_ENDPOINT,
				.bEndpointAddress = 1 | USB_DIR_IN,
				.bmAttributes = USB_ENDPOINT_XFER_BULK,
			},
			.bulk_source_command = {
				.bLength = sizeof(descriptors.fs_descs.bulk_source_command),
				.bDescriptorType = USB_DT_ENDPOINT,
				.bEndpointAddress = 2 | USB_DIR_OUT,
				.bmAttributes = USB_ENDPOINT_XFER_BULK,
			},
			.bulk_sink_scanner = {
				.bLength = sizeof(descriptors.fs_descs.bulk_sink_scanner),
				.bDescriptorType = USB_DT_ENDPOINT,
				.bEndpointAddress = 3 | USB_DIR_IN,
				.bmAttributes = USB_ENDPOINT_XFER_BULK,
			},
		},
		.hs_count = htole32(USB_NUM_ENDPOINTS + 1),
		.hs_descs = {
			.intf = {
				.bLength = sizeof(descriptors.hs_descs.intf),
				.bDescriptorType = USB_DT_INTERFACE,
				.bNumEndpoints = USB_NUM_ENDPOINTS,
				.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
				.iInterface = 1,
			},
			.bulk_sink_command = {
				.bLength = sizeof(descriptors.hs_descs.bulk_sink_command),
				.bDescriptorType = USB_DT_ENDPOINT,
				.bEndpointAddress = 1 | USB_DIR_IN,
				.bmAttributes = USB_ENDPOINT_XFER_BULK,
				.wMaxPacketSize = htole16(USB_MAX_PACKET_SIZE),
			},
			.bulk_source_command = {
				.bLength = sizeof(descriptors.hs_descs.bulk_source_command),
				.bDescriptorType = USB_DT_ENDPOINT,
				.bEndpointAddress = 2 | USB_DIR_OUT,
				.bmAttributes = USB_ENDPOINT_XFER_BULK,
				.wMaxPacketSize = htole16(USB_MAX_PACKET_SIZE),
			},
			.bulk_sink_scanner = {
				.bLength = sizeof(descriptors.hs_descs.bulk_sink_scanner),
				.bDescriptorType = USB_DT_ENDPOINT,
				.bEndpointAddress = 3 | USB_DIR_IN,
				.bmAttributes = USB_ENDPOINT_XFER_BULK,
				.wMaxPacketSize = htole16(USB_MAX_PACKET_SIZE),
			},
		},
	};
 
	t_scanner_string strings = {
		.header = {
			.magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
			.length = htole32(sizeof(strings)),
			.str_count = htole32(1),
			.lang_count = htole32(1),
		},
		.lang0 = {
			htole16(0x0409), /* en-us */
			STR_INTERFACE,
		},
	};

The target is to define host IN and OUT endpoints for commands, a IN endpoint to read chunks of data in bulk mode for a scanner.

The configuration seems successful, meaning that via lsusb -vvv I see the device:

Bus 001 Device 017: ID XXXX:YYYY DeviceName
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          255 Vendor Specific Class
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0xXXXX 
  idProduct          0xYYYY 
  bcdDevice            1.00
  iManufacturer           1 MANUFACTURER
  iProduct                2 PRODUCT
  iSerial                 3 SERIAL
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0027
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          4 Config 1: commands
    bmAttributes         0xc0
      Self Powered
    MaxPower              250mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           3
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              5 SOMESTRING
     Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass          255 Vendor Specific Class
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  bNumConfigurations      1
Device Status:     0x0000
  (Bus Powered)

(some information edited out for privacy).

I can send commands and receive answers from/to endpoints 1 and 2 using libusb_bulk_transfer() (libusb 1.0) from the host. However, I cannot receive any data through the third IN endpoint. Device-side writes are successful to the FunctionFS mounted endpoint files though.

So my problem is: both libusb_bulk_transfer() and async transfers with libusb_handle_events_timeout_completed() fail to read anything from the third endpoint host-side. Trying to read 26MB from the former it returns LIBUSB_ERROR_NO_MEM, while the latter tends to crash with SIGSEGV. I am using version 1.0.26 of libusb.

Since I do not see any error message from the kernel (both on device and host side), I am currently suspecting some DTS configuration problem. The hardware works: if I configure a usb-net gadget I can transfer at sustained speed.

I also tried to use 64 bytes packets instead of 512 ones. Same behavior.

Any ideas that could point me in the right direction?

Thank you,

Antonio

1 ACCEPTED SOLUTION

Accepted Solutions
ATringali
Associate II

Thank you Olivier.

I solved the problem fixing some of the code, which was otherwise structurally correct.

It was fine tuned as follows:

  1. The first IN endpoint was downsized to 64 bytes.
  2. I write 128kB towards FunctionFS file for the second IN endpoint.
  3. I read 256kB chunks through libusb host-side.
  4. The numbers in the FIFO configuration, starting from what was suggested by ST, are now:
    g-rx-fifo-size = <64>;
    g-np-tx-fifo-size = <64>;
    g-tx-fifo-size = <64 640 16 16 16 16 16 16>;

This allows to create for the second IN endpoint the room for five 512 bytes packets (640x4). The throughput is now nearing 40MB/s, which is about the practical limit for USB2.

Antonio

View solution in original post

3 REPLIES 3
Olivier GALLIEN
ST Employee

Hi @ATringali​ ,

An internal support case #BZ128324 has been open and is under investigation.

Keep you posted

Olivier

Olivier GALLIEN
In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.
ATringali
Associate II

Thank you Olivier.

I solved the problem fixing some of the code, which was otherwise structurally correct.

It was fine tuned as follows:

  1. The first IN endpoint was downsized to 64 bytes.
  2. I write 128kB towards FunctionFS file for the second IN endpoint.
  3. I read 256kB chunks through libusb host-side.
  4. The numbers in the FIFO configuration, starting from what was suggested by ST, are now:
    g-rx-fifo-size = <64>;
    g-np-tx-fifo-size = <64>;
    g-tx-fifo-size = <64 640 16 16 16 16 16 16>;

This allows to create for the second IN endpoint the room for five 512 bytes packets (640x4). The throughput is now nearing 40MB/s, which is about the practical limit for USB2.

Antonio

Hi @ATringali​ 

Thanks a lot to share this with the community !

Olivier

Olivier GALLIEN
In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.