发帖赞下雅特力的技术支持,很给力。
项目中使用 主芯片AT32F437VMT7配合RT-Thread Studio 开发环境,RT-Thread 版本 4.1.0
使用USB host 接U盘,发现很不稳定,简单的读写没问题,长期写入测试,会不定时出现USB口卡死的问题,调试发现是drv_usbfsh.c 里面的drv_pipe_xfer函数进入死循环了,此问题手里有三个U盘,新旧不一,牌子不同,有两个会出现此故障,一个不会。
使用USB device 实现虚拟U盘功能,可以让电脑直接访问at32F437的flash,功能已经实现,虚拟出2M的U盘空间。但电脑往虚拟U盘中写入文件时,尤其时大于1M的文件时,电脑写入进度条会经常卡死,此时RT-thread并不会死机,拔插USB口后,电脑重新写入现象依旧。此故障仅当使用了qboot,程序过大,app部分运行于flash256k以后,才出现,如果程序较小,app运行在flash前面的256k,则不会卡死。
雅特力给出的新驱动 核心函数drv_pipe_xfer修改如下
static int drv_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
{
int timeout = timeouts;
volatile int retry = 0;
if(!connect_status)
{
return -1;
}
rt_completion_init(&urb_completion);
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].dir = (pipe->ep.bEndpointAddress & 0x80) >> 7;
if(token == 0U)
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_SETUP;
}
else
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
}
/* endpoint type */
switch(pipe->ep.bmAttributes)
{
/* endpoint is control type */
case EPT_CONTROL_TYPE:
if((token == 1U) && (((pipe->ep.bEndpointAddress & 0x80) >> 7) == 0U))
{
if(nbytes == 0U)
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_out = 1U;
}
if((&p_usbotg_instance->p_otg_core->host)->hch[pipe->pipe_index].toggle_out == 0U)
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
}
else
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
}
}
break;
/* endpoint is bulk type */
case EPT_BULK_TYPE:
if(((pipe->ep.bEndpointAddress & 0x80) >> 7) == 0U)
{
if( p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_out == 0U)
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
}
else
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
}
}
else
{
if( p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_in == 0U)
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
}
else
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
}
}
break;
/* endpoint is int type */
case EPT_INT_TYPE:
if(((pipe->ep.bEndpointAddress & 0x80) >> 7) == 0U)
{
if( p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_out == 0U)
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
}
else
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
}
}
else
{
if( p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].toggle_in == 0U)
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
}
else
{
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA1;
}
}
break;
/* endpoint is isoc type */
case EPT_ISO_TYPE:
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].data_pid = HCH_PID_DATA0;
break;
default:
break;
}
/* set transfer buffer */
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].trans_buf = buffer;
/* set transfer len*/
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].trans_len = nbytes;
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].urb_sts = URB_IDLE;
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].ch_num = pipe->pipe_index;
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].trans_count = 0;
p_usbotg_instance->p_otg_core->host.hch[pipe->pipe_index].state = HCH_IDLE;
__resend:
/* data in/out for host */
usbh_in_out_request((&p_usbotg_instance->p_otg_core->host), pipe->pipe_index);
retry = 10000;
while(retry --)
{
rt_completion_wait(&urb_completion, timeout);
if(usbh_get_urb_status((&p_usbotg_instance->p_otg_core->host), pipe->pipe_index) == URB_NOTREADY)
{
if((pipe->ep.bEndpointAddress & 0x80) == 0)
{
goto __resend;
}
}
else if (usbh_get_urb_status(&p_usbotg_instance->p_otg_core->host, pipe->pipe_index) == URB_STALL)
{
LOG_D("stall");
pipe->status = UPIPE_STATUS_STALL;
if (pipe->callback != RT_NULL)
{
pipe->callback(pipe);
}
return -1;
}
else if (usbh_get_urb_status(&p_usbotg_instance->p_otg_core->host, pipe->pipe_index) == URB_ERROR)
{
LOG_D("error");
pipe->status = UPIPE_STATUS_ERROR;
if (pipe->callback != RT_NULL)
{
pipe->callback(pipe);
}
return -1;
}
else if (usbh_get_urb_status(&p_usbotg_instance->p_otg_core->host, pipe->pipe_index) == URB_DONE)
{
LOG_D("ok");
pipe->status = UPIPE_STATUS_OK;
if (pipe->callback != RT_NULL)
{
pipe->callback(pipe);
}
rt_size_t size = (&p_usbotg_instance->p_otg_core->host)->hch[pipe->pipe_index].trans_count;
if (pipe->ep.bEndpointAddress & 0x80)
{
return size;
}
else if (pipe->ep.bEndpointAddress & 0x00)
{
return size;
}
return nbytes;
}
}
return 0;
}
有以下两个处理方法请参考:
1.加大usb邮箱队列深度,原内核层usb驱动中usbdevice_core.c定的深度为16个,我测试改为32个ok(视应用情况而定),usbdevice_core.c + 2236
行 #define USBD_MQ_MAX_MSG 32
2.如若确认应用中未使用到SOF相关的内容,将SOF中断关闭也可解决。usbd_core.c + 932
行USB_OTG_SOF_INT
中断宏定义删除。
雅特力的技术支持移植都很给力