打印

[STM32F4] STM32F407的USB_Host模式下驱动U 盘问题卡在USBH_MSC_GETMaxLUN->USBH_CtlReq

[复制链接]
467|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
冰糖炖雪梨|  楼主 | 2018-7-6 15:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
情况是这样的,用的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 ("tempStatus = %d
", 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 ("URB_Status = %d
", 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("+");
      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("Control error");
      status = USBH_FAIL;
    }
    break;

  default:
    break;
  }
  return status;
}

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

430

主题

436

帖子

0

粉丝