zoukankan      html  css  js  c++  java
  • STM32 USB HID BarCodeReader不兼容问题的解决

    STM32USB HID class的一部分 BarCodeScanner(条码枪)不兼容的解决

    硬件构成

    STM32F479-EVAL 评价板
    型号为FFTAA10AP条码枪

    现象

    最近用CubeMX生成的USB库做条形码枪的USB驱动,用的是HID协议。有的条形码枪,用标准的USB库一次就能成功。
    但是有的型号的条码枪貌似和标准USB库流程有所出入,执行后,函数在 USBH_HID_ClassRequest 里的
    USBH_HID_SetIdle 函数发生了Stall,以至于无法继续。

    USBH_HID_ClassRequest的调查结果(应该是枚举已经完了)

    usbh_hid.c

    • before
      case HID_REQ_SET_IDLE:
        
        classReqStatus = USBH_HID_SetIdle (phost, 0, 0);
        
        /* set Idle */
        if (classReqStatus == USBH_OK)
        {
          HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL;  
        }
        else if(classReqStatus == USBH_NOT_SUPPORTED) 
        {
          HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL;        
        } 
        break; 
        
    

    USBH_HID_SetIdle的返回值最初是1(busy),重试三次以后,返回值成了3(USBH_NOT_SUPPORTED),函数最底层发生了STALL。
    在网上查了一些资料,有个设备是不需要(不支持?不知道哪个描述更准确)setIdle。因此这一步骤可以省略。为了保持兼容性,我把代码做了一下修改。

    ※ 当然,我的那个case直接跳过最好,我修改的从逻辑上看完全不通,因为正常的情况是连续三次busy后,会出现Ok的情况,而我的代码则是在第一次busy后直接跳到下一个步骤。
    没办法,这个地方需要给领导看,这么写可以从一定程度上保持已有的代码逻辑完整。笑。当然,按照我这个写法修改也是没有错误的。

    • after
      case HID_REQ_SET_IDLE:
        
        classReqStatus = USBH_HID_SetIdle (phost, 0, 0);
        
        /* set Idle */
        if (classReqStatus == USBH_OK)
        {
          HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL;  
        }
        else if(classReqStatus == USBH_NOT_SUPPORTED) 
        {
          HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL;        
        }
    
        /*
         * SetIdleが三回リトライすると、USBH_URB_STALLが発生
         * あるKeyBoarにはsetIdleコマンドが必須ではないため、コマンド実施しなくて次に行ってもOK
         * ここで一回実施して成功しても、失敗しても全部次のSET_PROTOCOLに続く(直接削除もOK)
        */
    #if 1   
        else if( classReqStatus == USBH_BUSY)
        {
          HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL;
        } 
    #endif    
        break; 
    

    经过以上的修改,条码枪就可以进到ready状态栏。如果你的设备还是不可以,那么下面的东西就不需要再看了,我们的错误不一样。

    HID调试

    简单是了一下,看了log,在这以后的命令仍然出现STALL。经过一顿搜索,定位在进入Idle后的 USBH_HID_GetReport 函数。

    usbh_hid.c

    • before
    static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost)
    {
      USBH_StatusTypeDef status = USBH_OK;
      HID_HandleTypeDef *HID_Handle =  (HID_HandleTypeDef *) phost->pActiveClass->pData;
      
      switch (HID_Handle->state)
      {
      case HID_INIT:
        HID_Handle->Init(phost); 
      case HID_IDLE:
        if(USBH_HID_GetReport (phost,     //这里发生错误
                               0x01,
                                0,
                                HID_Handle->pData,
                                HID_Handle->length) == USBH_OK)
        {
          
          fifo_write(&HID_Handle->fifo, HID_Handle->pData, HID_Handle->length);  
          HID_Handle->state = HID_SYNC;
        }
        
        break;
    

    网上调查的结果是,有一部分设备不支持这个命令,因此可以直接跳过HID_IDLE这个case。修改后如下。

    • after
    static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost)
    {
      USBH_StatusTypeDef status = USBH_OK;
      HID_HandleTypeDef *HID_Handle =  (HID_HandleTypeDef *) phost->pActiveClass->pData;
      
      switch (HID_Handle->state)
      {
      case HID_INIT:
        HID_Handle->Init(phost); 
    
        /*
         * ネットで調べてGet_Reportサポートされないバーコードリーダーがあるため、
         * HID_IDLEを抜けて直接HID_SYNCに遷移する。
        */
    #if 1 
        HID_Handle->state = HID_SYNC;    // skip HID_IDLE state
        break;
    #endif   
     
      case HID_IDLE:
        if(USBH_HID_GetReport (phost,
                               0x01,
                                0,
                                HID_Handle->pData,
                                HID_Handle->length) == USBH_OK)
    

    也就是在初始化完了后,直接进入SYNC状态。

    经过上面的修改,条形码枪应该可以正常的工作量。

    不要问原因,不要问理由,因为我也不是很明白。笑

    其他内容

    还有个现象就是有的条形码枪,在STM32启动前就插入到USB的话,STM32启动后可以正常识别。
    但是如果,STM32启动后,再将条形码枪插入USB的话,那么STM32将无法识别USB。
    从log上看只有[USB device Attach],然后底层的是一直 busy的状态。
    经过反复的实验,考虑到可能是有的USB设备的启动时间比较慢(慢热型,哈哈)STM32的检测过快导致的。

    因此,在检测USB设备这块,需要多延迟一会,以确保设备内部确实初始化完成。
    修改代码如下

    usbh_core.c

    USBH_StatusTypeDef  USBH_Process(USBH_HandleTypeDef *phost)
    {
      __IO USBH_StatusTypeDef status = USBH_FAIL;
      uint8_t idx = 0;
      
      switch (phost->gState)
      {
      case HOST_IDLE :
        
        if (phost->device.is_connected)  
        {
          /* Wait for 200から500 ms after connection */
          phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT; 
    #if 1 
          USBH_Delay(300);   //あるバーコード設備の立ち上がる時間が普通より長いため 200から300へ変更
    #endif
          USBH_LL_ResetPort(phost);
    #if (USBH_USE_OS == 1)
          osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0);
    #endif
        }
        break;
    

    经过这几部分的修改,BarCodeReader 或者说 BarCodeScanner 或者说 条形码枪 就可以正确的工作了。
    不过这也仅限于我的设备。仅供参考。
    USBH_Delay(200); 里面的参数变成500后,以前好用的枪反而不好用了,所以说,这个时间既不能太长也不能太短。

  • 相关阅读:
    20172311《程序设计与数据结构》第六周学习总结
    20172311 2018-2019-1 《程序设计与数据结构》课堂测试修改报告
    20172323 2018-2019-1《程序设计与数据结构》课程总结
    20172323 2018-2019-1 《程序设计与数据结构》课堂测试报告
    20172323 2018-2019-1 《程序设计与数据结构》实验三报告
    20172323 2018-2019-1 《程序设计与数据结构》第九周学习总结
    20172323 2018-2019-1 《程序设计与数据结构》实验二报告
    20172323 2018-2019-1 《程序设计与数据结构》第八周学习总结
    20172323 2018-2019-1 《程序设计与数据结构》第七周学习总结
    20172323 2018-2019-1 《程序设计与数据结构》第六周学习总结
  • 原文地址:https://www.cnblogs.com/curtis-han/p/10258685.html
Copyright © 2011-2022 走看看