Skip to main content
ATringali
Associate II
May 3, 2022
Solved

USB gadget device not working for STM32MP151

  • May 3, 2022
  • 2 replies
  • 2287 views

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

This topic has been closed for replies.
Best answer by ATringali

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

2 replies

Olivier GALLIEN
Technical Moderator
May 17, 2022

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
ATringaliAuthorBest answer
Associate II
May 19, 2022

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

Olivier GALLIEN
Technical Moderator
May 31, 2022

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.