我在 Windows 主机端使用 WinUSB 与我的 WINUSB USB 设备进行通信。我的 USB 设备是全速设备。我能够获取设备句柄并进行 OUT 和 IN 数据传输。
我面临 FS WinUSB 设备上的 Bulk IN 传输问题。当我将数据从 PC 环回到设备并返回到 PC 时,从 1 到 64 的大小工作正常。当我传输 65 个字节时,前 64 个字节能够在 PC 中读回。但是最后一个字节不见了。
任何人都可以面临同样的问题或可以提出一些解决方案吗?
问候,尼希德
首先你应该读出MAXIMUM_TRANSFER_SIZE
. 对于发送,WinUSB “如有必要,将缓冲区划分为适当大小的块”(来源)。
还要检查以下备注WinUsb_ReadPipe
:
如果设备返回的数据大于最大传输长度,WinUSB会将请求分成最大传输长度的较小请求,依次提交。如果传输长度不是端点最大数据包大小的倍数(可通过 WINUSB_PIPE_INFORMATION 结构的 MaximumPacketSize 成员检索),WinUSB 会将传输大小增加到下一个 MaximumPacketSize 的倍数。
USB 数据包大小不会影响读取请求的传输。如果设备响应的数据包对于客户端缓冲区来说太大,则读取请求的行为对应于管道上设置的策略类型。如果管道的策略类型是 ALLOW_PARTIAL_READS,WinUSB 会将剩余数据添加到下一次传输的开头。如果未设置 ALLOW_PARTIAL_READS,则读取请求失败。有关策略类型的详细信息,请参阅用于管道策略修改的 WinUSB 函数。
检查您的设置以及最后一个字节是否通过第二次传输发送。您还应该测试实际写入/读取了多少字节。
最近,当我将我的STM32F4 发现板编程为 USB 设备并使用WINUSB使应用程序能够通过USB BULK传输环回消息时,我遇到了这个问题。
我做了三件事来让 PC 发送超过 64 字节的数据包并从设备接收作为环回消息传递方式:
1.对于应用程序,请设置管道策略允许部分读取:
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.对于固件,请让USB接收处理器只做它的读任务,并保持读指针偏移。
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.让传输任务在主循环中运行。
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;
}}
为了分享这个问题的更多细节,这是我在我的 GitHub 项目中的源代码。