2024-12-09 04:37 PM - edited 2024-12-09 04:38 PM
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.
Solved! Go to Solution.
2024-12-09 06:06 PM
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.
2024-12-09 06:06 PM
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.
2024-12-10 11:16 AM
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"?
2024-12-10 12:36 PM
Full speed specification can only send 64 bytes at a time