[已解决] MASTER版本USB HOST批量传输时如数据长度正好是64的倍数导致HCD_PIPE_EVENT_ERROR_XFER错误
-
- Posts: 15
- Joined: Mon Oct 04, 2021 3:09 am
[已解决] MASTER版本USB HOST批量传输时如数据长度正好是64的倍数导致HCD_PIPE_EVENT_ERROR_XFER错误
【现象】
MASTER版本USB HOST批量传输时如数据长度正好是64的倍数导致HCD_PIPE_EVENT_ERROR_XFER错误,并且导致之后所有调用hcd_urb_enqueue失败,跟踪到函数hcd_urb_enqueue中,失败原因为下述判断前两个子条件失败
HCD_CHECK_FROM_CRIT(pipe->port->state == HCD_PORT_STATE_ENABLED // The pipe's port must be in the correct state
&& pipe->state == HCD_PIPE_STATE_ACTIVE //The pipe must be in the correct state
&& !pipe->cs_flags.pipe_cmd_processing //Pipe cannot currently be processing a pipe command
&& !pipe->cs_flags.reset_lock, //Pipe cannot be persisting through a port reset
ESP_ERR_INVALID_STATE);
同样的代码,只要发送长度不是64倍数的Bulk传输均能成功。
【代码】
申请URB时,针对长度正好是64倍数的Bulk传输已经设置如下标志
// Bulk Out对于正好MPS长度倍数的传输需要添加一个0长度包
if ((len % USB_EP_BULK_MAX_MPS) == 0) // USB_EP_BULK_MAX_MPS为64
transfer_dummy->flags |= USB_TRANSFER_FLAG_ZERO_PACK;
请问是URB哪里还需要设置吗?
@ESP_ICY
MASTER版本USB HOST批量传输时如数据长度正好是64的倍数导致HCD_PIPE_EVENT_ERROR_XFER错误,并且导致之后所有调用hcd_urb_enqueue失败,跟踪到函数hcd_urb_enqueue中,失败原因为下述判断前两个子条件失败
HCD_CHECK_FROM_CRIT(pipe->port->state == HCD_PORT_STATE_ENABLED // The pipe's port must be in the correct state
&& pipe->state == HCD_PIPE_STATE_ACTIVE //The pipe must be in the correct state
&& !pipe->cs_flags.pipe_cmd_processing //Pipe cannot currently be processing a pipe command
&& !pipe->cs_flags.reset_lock, //Pipe cannot be persisting through a port reset
ESP_ERR_INVALID_STATE);
同样的代码,只要发送长度不是64倍数的Bulk传输均能成功。
【代码】
申请URB时,针对长度正好是64倍数的Bulk传输已经设置如下标志
// Bulk Out对于正好MPS长度倍数的传输需要添加一个0长度包
if ((len % USB_EP_BULK_MAX_MPS) == 0) // USB_EP_BULK_MAX_MPS为64
transfer_dummy->flags |= USB_TRANSFER_FLAG_ZERO_PACK;
请问是URB哪里还需要设置吗?
@ESP_ICY
Re: MASTER版本USB HOST批量传输时如数据长度正好是64的倍数导致HCD_PIPE_EVENT_ERROR_XFER错误
在批量传输首次出现 HCD_PIPE_EVENT_ERROR_XFER 的时候,可以看看此传输的错误结果吗(transfer->status)?
之后的传输失败是正常的。当一个 Pipe 遇到错误,Pipe 会从活动状态 (HCD_PIPE_STATE_ACTIVE)转成停止状态 (HCD_PIPE_STATE_HALTED)。
停止后,Pipe 不会继续执行被入列的传输。处理停止事件通常有调用以下的命令。
1. 调用 hcd_pipe_command(pipe_hdl, HCD_PIPE_CMD_FLUSH); 将所有没执行的传输清除。Flush 之后要将要将每个被清除的传输用 hcd_urb_dequeue() 出列。
2. 用 hcd_pipe_command(pipe_hdl, HCD_PIPE_CMD_CLEAR) 将 pipe 回复到活动状态。
之后的传输失败是正常的。当一个 Pipe 遇到错误,Pipe 会从活动状态 (HCD_PIPE_STATE_ACTIVE)转成停止状态 (HCD_PIPE_STATE_HALTED)。
停止后,Pipe 不会继续执行被入列的传输。处理停止事件通常有调用以下的命令。
1. 调用 hcd_pipe_command(pipe_hdl, HCD_PIPE_CMD_FLUSH); 将所有没执行的传输清除。Flush 之后要将要将每个被清除的传输用 hcd_urb_dequeue() 出列。
2. 用 hcd_pipe_command(pipe_hdl, HCD_PIPE_CMD_CLEAR) 将 pipe 回复到活动状态。
-
- Posts: 15
- Joined: Mon Oct 04, 2021 3:09 am
Re: MASTER版本USB HOST批量传输时如数据长度正好是64的倍数导致HCD_PIPE_EVENT_ERROR_XFER错误
目前最新的现象是,只要发送长度为64倍数的bulk传输,就出现assert失败。暂时无法跟踪看到urb->transfer.status的取值。在usbh_hal_chan_decode_intr函数中assert失败,见红色字体
usbh_hal_chan_event_t usbh_hal_chan_decode_intr(usbh_hal_chan_t *chan_obj)
{
uint32_t chan_intrs = usbh_ll_chan_intr_read_and_clear(chan_obj->regs);
usbh_hal_chan_event_t chan_event;
if (chan_intrs & CHAN_INTRS_ERROR_MSK) { //Note: Errors are uncommon, so we check against the entire interrupt mask to reduce frequency of entering this call path
HAL_ASSERT(chan_intrs & USBH_LL_INTR_CHAN_CHHLTD); //An error should have halted the channel
【Monitor窗口输出】
assert failed: usbh_hal_chan_decode_intr IDF/components/hal/usbh_hal.c:371 (chan_intrs & USBH_LL_INTR_CHAN_CHHLTD)
Backtrace:0x40025872:0x3ffc82b00x4002bfc5:0x3ffc82d0 0x40032cb2:0x3ffc82f0 0x40096abd:0x3ffc8410 0x4008f7c0:0x3ffc8430 0x40026cce:0x3ffc8470 0x400f48df:0x3ff9f940 0x40095d02:0x3ff9f960 0x4002d0c7:0x3ff9f980
0x40025872: panic_abort at ~/esp/esp-idf/components/esp_system/panic.c:402
0x4002bfc5: esp_system_abort at ~/esp/esp-idf/components/esp_system/esp_system.c:129
0x40032cb2: __assert_func at ~/esp/esp-idf/components/newlib/assert.c:85
0x40096abd: usbh_hal_chan_decode_intr at ~/esp/esp-idf/components/hal/usbh_hal.c:371 (discriminator 1)
0x4008f7c0: _intr_hdlr_chan at ~/esp/esp-idf/components/usb/hcd.c:826
(inlined by) intr_hdlr_main at ~/Project/esp/esp-idf/components/usb/hcd.c:916
usbh_hal_chan_event_t usbh_hal_chan_decode_intr(usbh_hal_chan_t *chan_obj)
{
uint32_t chan_intrs = usbh_ll_chan_intr_read_and_clear(chan_obj->regs);
usbh_hal_chan_event_t chan_event;
if (chan_intrs & CHAN_INTRS_ERROR_MSK) { //Note: Errors are uncommon, so we check against the entire interrupt mask to reduce frequency of entering this call path
HAL_ASSERT(chan_intrs & USBH_LL_INTR_CHAN_CHHLTD); //An error should have halted the channel
【Monitor窗口输出】
assert failed: usbh_hal_chan_decode_intr IDF/components/hal/usbh_hal.c:371 (chan_intrs & USBH_LL_INTR_CHAN_CHHLTD)
Backtrace:0x40025872:0x3ffc82b00x4002bfc5:0x3ffc82d0 0x40032cb2:0x3ffc82f0 0x40096abd:0x3ffc8410 0x4008f7c0:0x3ffc8430 0x40026cce:0x3ffc8470 0x400f48df:0x3ff9f940 0x40095d02:0x3ff9f960 0x4002d0c7:0x3ff9f980
0x40025872: panic_abort at ~/esp/esp-idf/components/esp_system/panic.c:402
0x4002bfc5: esp_system_abort at ~/esp/esp-idf/components/esp_system/esp_system.c:129
0x40032cb2: __assert_func at ~/esp/esp-idf/components/newlib/assert.c:85
0x40096abd: usbh_hal_chan_decode_intr at ~/esp/esp-idf/components/hal/usbh_hal.c:371 (discriminator 1)
0x4008f7c0: _intr_hdlr_chan at ~/esp/esp-idf/components/usb/hcd.c:826
(inlined by) intr_hdlr_main at ~/Project/esp/esp-idf/components/usb/hcd.c:916
Re: MASTER版本USB HOST批量传输时如数据长度正好是64的倍数导致HCD_PIPE_EVENT_ERROR_XFER错误
如果不包括 USB_TRANSFER_FLAG_ZERO_PACK 还会出问题吗?你现在用的设备时什么 Device Class?
-
- Posts: 15
- Joined: Mon Oct 04, 2021 3:09 am
Re: MASTER版本USB HOST批量传输时如数据长度正好是64的倍数导致HCD_PIPE_EVENT_ERROR_XFER错误
如果不包括 USB_TRANSFER_FLAG_ZERO_PACK 还会出问题吗?你现在用的设备时什么 Device Class?
-- 对端设备为市场上的安卓手机。
-- 如果不设置这个USB_TRANSFER_FLAG_ZERO_PACK标志,不会出现assert失败,URB完成状态为USB_TRANSFER_STATUS_COMPLETED,但是再发送新的bulk传输就出现HCD_PIPE_EVENT_ERROR_XFER了,URB完成状态为USB_TRANSFER_STATUS_ERROR。
当前我做了特殊保护,一旦发现是64倍数则自动拆分成两个bulk传输,临时解决了这个问题。
目前,同样的报文,通过PC发出到同一个安卓手机是没问题的
-- 对端设备为市场上的安卓手机。
-- 如果不设置这个USB_TRANSFER_FLAG_ZERO_PACK标志,不会出现assert失败,URB完成状态为USB_TRANSFER_STATUS_COMPLETED,但是再发送新的bulk传输就出现HCD_PIPE_EVENT_ERROR_XFER了,URB完成状态为USB_TRANSFER_STATUS_ERROR。
当前我做了特殊保护,一旦发现是64倍数则自动拆分成两个bulk传输,临时解决了这个问题。
目前,同样的报文,通过PC发出到同一个安卓手机是没问题的
Last edited by Michael2021_esp on Thu Dec 09, 2021 6:12 am, edited 1 time in total.
-
- Posts: 15
- Joined: Mon Oct 04, 2021 3:09 am
Re: MASTER版本USB HOST批量传输时如数据长度正好是64的倍数导致HCD_PIPE_EVENT_ERROR_XFER错误
@ESP_Dazz 长度为64倍数的批量传输拆分为2个批量传输,目前看解决了大多数的情况,但是其中有一个256长度的报文,业务逻辑上不能拆分。还是请指导一下如何解决这个问题。
Re: MASTER版本USB HOST批量传输时如数据长度正好是64的倍数导致HCD_PIPE_EVENT_ERROR_XFER错误
看起来 USB_TRANSFER_FLAG_ZERO_PACK 可能有点问题。我会再检查。但是需要用 USB_TRANSFER_FLAG_ZERO_PACK 的情况很少。我不是很懂为什么你发bulk传输要加 USB_TRANSFER_FLAG_ZERO_PACK。当 urb->transfer.num_bytes 是端点 MPS (例如 64) 的 N 倍时,HCD 已经会自动加最后的 zero packet。Michael2021_esp wrote:如果不设置这个USB_TRANSFER_FLAG_ZERO_PACK标志,不会出现assert失败
我也不是很懂为什么要手动的拆分。如果 urb->transfer.num_bytes = 256,HCD 会自动将 256 拆成 N 个 MPS 长的 packet.Michael2021_esp wrote:但是其中有一个256长度的报文,业务逻辑上不能拆分。还是请指导一下如何解决这个问题
HCD 使用的 URB 时对应 USB2.0 协议里的 Transfer,而不是 Transaction。用户只需配 urb->transfer.num_bytes 然后 HCD 会处理所有拆分 MPS packet 的操作。
-
- Posts: 15
- Joined: Mon Oct 04, 2021 3:09 am
Re: MASTER版本USB HOST批量传输时如数据长度正好是64的倍数导致HCD_PIPE_EVENT_ERROR_XFER错误
是这样的:看起来 USB_TRANSFER_FLAG_ZERO_PACK 可能有点问题。我会再检查。但是需要用 USB_TRANSFER_FLAG_ZERO_PACK 的情况很少。我不是很懂为什么你发bulk传输要加 USB_TRANSFER_FLAG_ZERO_PACK。当 urb->transfer.num_bytes 是端点 MPS (例如 64) 的 N 倍时,HCD 已经会自动加最后的 zero packet。
STEP1. 最开始的时候,因为发送4096字节的Transfer的时候出现HCD_PIPE_EVENT_ERROR_XFER错误导致后面流程无法走下去,才尝试去添加USB_TRANSFER_FLAG_ZERO_PACK,结果出现assert失败。然后就去掉USB_TRANSFER_FLAG_ZERO_PACK,进入STEP2的方式进行尝试
STEP2. 然后尝试将4096字节的Transfer拆分为4096-32字节的Transfer1 + 32字节的Transfer2,目的是规避STEP1的错误。两个Transfer执行均成功
然后在上述尝试的过程中,发现只要是长度是64倍数的Transfer都会出现HCD_PIPE_EVENT_ERROR_XFER错误。长
期待这个结果,因为目前有一个256字节的Transfer无法采用上述STEP2拆分为两个Transfer,只能作为一个Transfer发送。如果USB_TRANSFER_FLAG_ZERO_PACK处理有更新,拜托通知一声看起来 USB_TRANSFER_FLAG_ZERO_PACK 可能有点问题。我会再检查。
-
- Posts: 15
- Joined: Mon Oct 04, 2021 3:09 am
Who is online
Users browsing this forum: Baidu [Spider], Google [Bot] and 80 guests