cancel
Showing results for 
Search instead for 
Did you mean: 

USB HID: how to send more than 64 bytes of data (host-to-device)?

smoothmanifolds
Associate III

On an STM32F103CB, running as a Custom USB HID FS device, I have this USB HID Report Descriptor (I'm only showing Report ID 2):

 

 

	0x06,0x70,0xff,    // Usage Page: Vendor defined
	0x09,0x06,         // Usage
	0xa1,0x01,         // Collection: Application
	0x85,0x02,         // Report ID: 2 (Input & Output Reports)
		// Input Report
		0x09,0x06,       //   Usage:           Vendor Usage 0x06
		0x15,0x00,       //   Logical Minimum: 0
		0x26,0xff,0x00,  //   Logical Maximum: 255
		0x95,0x20,       //   Report Count:    32 elems
		0x75,0x08,       //   Report Size:     8 bits/elem
		0x81,0x00,       //   Input:           Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
		// Output Report
		0x09,0x06,       //   Usage:           Vendor Usage 0x06
		0x15,0x00,       //   Logical Minimum: 0
		0x26,0xff,0x00,  //   Logical Maximum: 255
		0x95,0x3f,       //   Report Count:    63 elems
		0x75,0x08,       //   Report Size:     8 bits/elem
		0x91,0x00,       //   Output:          0x00: Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
	0xc0,              // End Collection

 

 

which is intended to send 32 bytes of data (ie. from device to host) and receive 63 bytes of data (ie. from host to device).

 

It's working well, but I actually need to send around 100KB from host to device.

I understand that USB HID FS only allows up to 64 byte transfers.

So how can I actually do that?

 

As a reference, I also have the `CUSTOM_HID_OutEvent_FS()` function:

 

 

static int8_t CUSTOM_HID_OutEvent_FS(uint8_t* data){
	/* stuff goes here */
	return USBD_OK;
}

 

 

which triggers when the host sends data to the device.

 

1 ACCEPTED SOLUTION

Accepted Solutions
Karl Yamashita
Lead III

Assuming your 1st byte is a command, then set the next 3 bytes as a counter and last packet count (12 bits and 11 bits = 3 bytes). Then the MSB bit can be a start of packet bit to help determine the packet is new. That leaves you with 60 bytes for your data.

So on the 1st packet you set the counter to (100K/64) = 1563 and set the startOfPacket bit.

Then for each packet of 64 bytes, you decrement the counter and clear the startOfPacket bit. And continue sending packets until your counter reaches 0. Then you'll know you're at the end of the 100K packet. Then in your lastPacketCount you can say how many bytes to use in the last packet.

 

This is just an example, so you can tailor to your specific needs.

 

typedef union
{
	struct
	{
		uint8_t data[64];
	}Bytes;
	struct
	{
		uint8_t command;
		uint8_t counter:12; // 4096 * 64 = 262,080 bytes
		uint8_t lastPacketCount:11; // how many bytes in the last packet
		uint8_t startOfPacket:1; // indicates is start of packet.
		uint8_t data[60];
	}Status;
}__attribute__ ((aligned (32))) USB_Packet_T;

// some simple example
void test(void)
{
	USB_Packet_T usbPacket = {0};

	usbPacket.Status.command = 0x22; // command byte
	usbPacket.Status.counter = 1563; // how many packets to send
	usbPacket.Status.lastPacketCount = 16; // only 16 bytes to use in last packet.

	for(i = 0; i < 1563; i++)
	{
		// some function to copy your data 60 bytes at a time to usbPacket.Status.data

		// some USB function to send usbPacket.Bytes.data (the 64 bytes of data)

		--usbPacket.Status.counter; // decrement counter
	}
}

 

Your receiving side will need to parse and extract the 60 bytes from each packet. When you receive the last packet, you can check the lastPacketCount to see how many bytes to use out of the 60 bytes.

 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

View solution in original post

3 REPLIES 3
Karl Yamashita
Lead III

Assuming your 1st byte is a command, then set the next 3 bytes as a counter and last packet count (12 bits and 11 bits = 3 bytes). Then the MSB bit can be a start of packet bit to help determine the packet is new. That leaves you with 60 bytes for your data.

So on the 1st packet you set the counter to (100K/64) = 1563 and set the startOfPacket bit.

Then for each packet of 64 bytes, you decrement the counter and clear the startOfPacket bit. And continue sending packets until your counter reaches 0. Then you'll know you're at the end of the 100K packet. Then in your lastPacketCount you can say how many bytes to use in the last packet.

 

This is just an example, so you can tailor to your specific needs.

 

typedef union
{
	struct
	{
		uint8_t data[64];
	}Bytes;
	struct
	{
		uint8_t command;
		uint8_t counter:12; // 4096 * 64 = 262,080 bytes
		uint8_t lastPacketCount:11; // how many bytes in the last packet
		uint8_t startOfPacket:1; // indicates is start of packet.
		uint8_t data[60];
	}Status;
}__attribute__ ((aligned (32))) USB_Packet_T;

// some simple example
void test(void)
{
	USB_Packet_T usbPacket = {0};

	usbPacket.Status.command = 0x22; // command byte
	usbPacket.Status.counter = 1563; // how many packets to send
	usbPacket.Status.lastPacketCount = 16; // only 16 bytes to use in last packet.

	for(i = 0; i < 1563; i++)
	{
		// some function to copy your data 60 bytes at a time to usbPacket.Status.data

		// some USB function to send usbPacket.Bytes.data (the 64 bytes of data)

		--usbPacket.Status.counter; // decrement counter
	}
}

 

Your receiving side will need to parse and extract the 60 bytes from each packet. When you receive the last packet, you can check the lastPacketCount to see how many bytes to use out of the 60 bytes.

 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

Thank you for your help; that was insightful.
So this is the only way; you can't just crank up the Report Count

0x95,0x3f,       //   Report Count:    63 elems

to 100K and expect the USB stack to "just make it work"? 

Full speed specification can only send 64 bytes at a time

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.