user3560216
user3560216

Reputation: 21

WinUSB Bulk IN transfer fails on transfer size greater than maximum packet size

I am using WinUSB on the windows host side to communicate with my WINUSB USB device. My USB device is Full speed device. I am able to get the device handle and do the OUT and IN data transfers.

I am facing an issue with the Bulk IN transfer on FS WinUSB device. When i do a loop back of data from PC to device and back to PC, the sizes from 1 to 64 are working fine. When i transfer 65 bytes, first 64 bytes am able to read back in PC. But the last byte is missing.

Can anybody facing the same kind of issue or can suggest some solution?

Regards, Nisheedh

Upvotes: 2

Views: 2669

Answers (2)

Mou
Mou

Reputation: 165

Recently I meet this issue when I program my STM32F4 discovery board as an USB device and use WINUSB to have an application being able to transmit loop back messages through USB BULK.

Three things I did to have more than 64 bytes packet sent by PC and received from device as the loop back messaging way:

1.For application, please set pipe policy to allow partial read:

BOOL policy_allow_partial = true;
if (WinUsb_SetPipePolicy(deviceData.WinusbHandle, pipe_id.PipeInId, ALLOW_PARTIAL_READS,sizeof(UCHAR), &policy_allow_partial)) {
    printf("WinUsb_SetPipePolicy for ALLOW_PARTIAL_READS OK\n");   
}
else {
    printf("WinUsb_SetPipePolicy for ALLOW_PARTIAL_READS failed:%s\n", GetLastErrorAsString().c_str());
}

2.For firmware, please just let the USB receive handler do its read task only and maintain the read pointer offset well.

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) {
/* USER CODE BEGIN 6 */
extern void on_CDC_Receive_FS(uint32_t len);
extern volatile int8_t usb_rxne;
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
uint32_t len = *Len;
if ((ir + len) >= RX_DATA_LEN ) {
    len = RX_DATA_LEN - 1 - ir;
if (len > 0 ) {
    memcpy(usb_rx+ir, Buf, len);
}
    ir = RX_DATA_LEN - 1;
} 
else {     
    memcpy(usb_rx+ir, Buf, len);          
    ir += len;
}
usb_rxne = SET;
on_CDC_Receive_FS(len);
return (USBD_OK); }

void on_CDC_Receive_FS(uint32_t len) {
extern int8_t CDC_is_busy(void);
if (CDC_is_busy()) return;
//USB loopback method 2, transmit later but can support more than 64 bytes  
    if (iw < 512) {
        memcpy(usb_tx+iw, usb_rx, len);
        iw += len;
        tx_len += len;
    }
    else {
        memset(usb_tx, 0, 512);
        iw = 0;
        tx_len = 0;
    }   
}}

3.Let the transmit task running in the main loop.

int main(void) {
while (1) {
if (iw != 0) {
        usb_txe = RESET;
        ret_tran = CDC_Transmit_FS(usb_tx, tx_len); 
        iw = 0;
        tx_len = 0;
        usb_txe = SET;
    }
    else {
        usb_txe = SET;
}}

For sharing more details for this question, here is my source code at my GitHub project .

Upvotes: 1

ollo
ollo

Reputation: 25350

First you should read out MAXIMUM_TRANSFER_SIZE. For sending, WinUSB "divides the buffer into appropriately sized chunks, if necessary" (source).

Also check the remarks of WinUsb_ReadPipe:

If the data returned by the device is greater than a maximum transfer length, WinUSB divides the request into smaller requests of maximum transfer length and submits them serially. If the transfer length is not a multiple of the endpoint's maximum packet size (retrievable through the WINUSB_PIPE_INFORMATION structure's MaximumPacketSize member), WinUSB increases the size of the transfer to the next multiple of MaximumPacketSize.

USB packet size does not factor into the transfer for a read request. If the device responds with a packet that is too large for the client buffer, the behavior of the read request corresponds to the type of policy set on the pipe. If policy type for the pipe is ALLOW_PARTIAL_READS, WinUSB adds the remaining data to the beginning of the next transfer. If ALLOW_PARTIAL_READS is not set, the read request fails. For more information about policy types, see WinUSB Functions for Pipe Policy Modification.

Check your settings and whether the last Byte is send with a second transfer. You also should test how many bytes have been actually written / read.

Upvotes: 2

Related Questions