情况是这样的,用的STM32的MSC库。用STM32F407作host驱动一个HUB集线器(一转四),当HUB上只接一个U盘时,可以成功枚举每个U盘。但是当同时插入两个U盘时,第二个U盘,前面都没有问题 Enumeration completed > USBH_USR_UserInput OK. (我只在原库基础上加了串口中断输出调试)
一直卡在USBH_MSC_Handle 里的USBH_MSC_GETMaxLUN 里的USBH_CtlReq等,卡在这了,谁知道是什么原因?如何解?
(1)卡在了USBH_MSC_BOT_REQ_GetMaxLUN函数里面;
static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost)
{
MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
USBH_StatusTypeDef status = USBH_BUSY;
uint8_t i;
/* Switch MSC REQ state machine */
switch (MSC_Handle->req_state)
{
case MSC_REQ_IDLE:
case MSC_REQ_GET_MAX_LUN:
/* Issue GetMaxLUN request */
status = USBH_MSC_BOT_REQ_GetMaxLUN(phost, (uint8_t *)&MSC_Handle->max_lun);
/* When devices do not support the GetMaxLun request, this should
be considred as only one logical unit is supported */
if(status == USBH_NOT_SUPPORTED)
{
MSC_Handle->max_lun = 0;
status = USBH_OK;
}
if(status == USBH_OK)
{
MSC_Handle->max_lun = (uint8_t )(MSC_Handle->max_lun) + 1;
USBH_UsrLog ("Number of supported LUN: %lu", (int32_t)(MSC_Handle->max_lun));
for(i = 0; i < MSC_Handle->max_lun; i++)
{
MSC_Handle->unit.prev_ready_state = USBH_FAIL;
MSC_Handle->unit.state_changed = 0;
}
}
break;
case MSC_REQ_ERROR :
/* a Clear Feature should be issued here */
if(USBH_ClrFeature(phost, 0x00) == USBH_OK)
{
MSC_Handle->req_state = MSC_Handle->prev_req_state;
}
break;
default:
break;
}
return status;
}
(2)深入分析(1)中的底层函数,是卡在USBH_HandleControl函数中的CTRL_DATA_IN_WAIT分支中了,应该是CTRL_DATA_IN分支中,接收数据失败,导致USBH_LL_GetURBState获取状态一直为IDLE。
static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost)
{
uint8_t tempStatus = 0;
uint8_t direction;
USBH_StatusTypeDef status = USBH_BUSY;
USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
switch (phost->Control.state)
{
case CTRL_SETUP:
/* send a SETUP packet */
USBH_CtlSendSetup(phost, (uint8_t *)phost->Control.setup.d8, phost->Control.pipe_out);
phost->Control.state = CTRL_SETUP_WAIT;
phost->Control.timer = phost->Timer;
break;
case CTRL_SETUP_WAIT:
URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
/* case SETUP packet sent successfully */
if(URB_Status == USBH_URB_DONE)
{
direction = (phost->Control.setup.b.bmRequestType & USB_REQ_DIR_MASK);
/* check if there is a data stage */
if (phost->Control.setup.b.wLength.w != 0 )
{
if (direction == USB_D2H)
{
/* Data Direction is IN */
phost->Control.state = CTRL_DATA_IN;
}
else
{
/* Data Direction is OUT */
phost->Control.state = CTRL_DATA_OUT;
}
}
/* No DATA stage */
else
{
/* If there is No Data Transfer Stage */
if (direction == USB_D2H)
{
/* Data Direction is IN */
phost->Control.state = CTRL_STATUS_OUT;
}
else
{
/* Data Direction is OUT */
phost->Control.state = CTRL_STATUS_IN;
}
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if(URB_Status == USBH_URB_ERROR || URB_Status == USBH_URB_NOTREADY)
{
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
break;
case CTRL_DATA_IN:
/* Issue an IN token */
phost->Control.timer = phost->Timer;
tempStatus = USBH_CtlReceiveData(phost,
phost->Control.buff,
phost->Control.length,
phost->Control.pipe_in);
USBH_UsrLog (&quot;tempStatus = %d
&quot;, tempStatus);
phost->Control.state = CTRL_DATA_IN_WAIT;
break;
case CTRL_DATA_IN_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in);
USBH_UsrLog (&quot;URB_Status = %d
&quot;, URB_Status);
/* check is DATA packet transferred successfully */
if (URB_Status == USBH_URB_DONE)
{
phost->Control.state = CTRL_STATUS_OUT;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
/* manage error cases*/
if (URB_Status == USBH_URB_STALL)
{
/* In stall case, return to previous machine state*/
status = USBH_NOT_SUPPORTED;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_ERROR)
{
/* Device error */
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
break;
case CTRL_DATA_OUT:
USBH_CtlSendData (phost,
phost->Control.buff,
phost->Control.length ,
phost->Control.pipe_out,
1);
phost->Control.timer = phost->Timer;
phost->Control.state = CTRL_DATA_OUT_WAIT;
break;
case CTRL_DATA_OUT_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out);
if (URB_Status == USBH_URB_DONE)
{ /* If the Setup Pkt is sent successful, then change the state */
//LOG1(&quot;+&quot;);
phost->Control.state = CTRL_STATUS_IN;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
/* handle error cases */
else if (URB_Status == USBH_URB_STALL)
{
/* In stall case, return to previous machine state*/
phost->Control.state = CTRL_STALLED;
status = USBH_NOT_SUPPORTED;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_NOTREADY)
{
/* Nack received from device */
phost->Control.state = CTRL_DATA_OUT;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_ERROR)
{
/* device error */
phost->Control.state = CTRL_ERROR;
status = USBH_FAIL;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
break;
case CTRL_STATUS_IN:
/* Send 0 bytes out packet */
USBH_CtlReceiveData (phost,
0,
0,
phost->Control.pipe_in);
phost->Control.timer = phost->Timer;
phost->Control.state = CTRL_STATUS_IN_WAIT;
break;
case CTRL_STATUS_IN_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in);
if ( URB_Status == USBH_URB_DONE)
{ /* Control transfers completed, Exit the State Machine */
phost->Control.state = CTRL_COMPLETE;
status = USBH_OK;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_ERROR)
{
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if(URB_Status == USBH_URB_STALL)
{
/* Control transfers completed, Exit the State Machine */
status = USBH_NOT_SUPPORTED;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
break;
case CTRL_STATUS_OUT:
USBH_CtlSendData (phost,
0,
0,
phost->Control.pipe_out,
1);
phost->Control.timer = phost->Timer;
phost->Control.state = CTRL_STATUS_OUT_WAIT;
break;
case CTRL_STATUS_OUT_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out);
if (URB_Status == USBH_URB_DONE)
{
status = USBH_OK;
phost->Control.state = CTRL_COMPLETE;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_NOTREADY)
{
phost->Control.state = CTRL_STATUS_OUT;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_ERROR)
{
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
break;
case CTRL_ERROR:
/*
After a halt condition is encountered or an error is detected by the
host, a control endpoint is allowed to recover by accepting the next Setup
PID; i.e., recovery actions via some other pipe are not required for control
endpoints. For the Default Control Pipe, a device reset will ultimately be
required to clear the halt or error condition if the next Setup PID is not
accepted.
*/
if (++ phost->Control.errorcount <= USBH_MAX_ERROR_COUNT)
{
/* try to recover control */
USBH_LL_Stop(phost);
/* Do the transmission again, starting from SETUP Packet */
phost->Control.state = CTRL_SETUP;
phost->RequestState = CMD_SEND;
}
else
{
if(phost->pUser != NULL)
phost->pUser(phost, HOST_USER_UNRECOVERED_ERROR);
phost->Control.errorcount = 0;
USBH_ErrLog(&quot;Control error&quot;);
status = USBH_FAIL;
}
break;
default:
break;
}
return status;
} |
|