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后,以前好用的枪反而不好用了,所以说,这个时间既不能太长也不能太短。

  • 相关阅读:
    使用 Dockerfile 定制镜像
    UVA 10298 Power Strings 字符串的幂(KMP,最小循环节)
    UVA 11090 Going in Cycle!! 环平均权值(bellman-ford,spfa,二分)
    LeetCode Best Time to Buy and Sell Stock 买卖股票的最佳时机 (DP)
    LeetCode Number of Islands 岛的数量(DFS,BFS)
    LeetCode Triangle 三角形(最短路)
    LeetCode Swap Nodes in Pairs 交换结点对(单链表)
    LeetCode Find Minimum in Rotated Sorted Array 旋转序列找最小值(二分查找)
    HDU 5312 Sequence (规律题)
    LeetCode Letter Combinations of a Phone Number 电话号码组合
  • 原文地址:https://www.cnblogs.com/curtis-han/p/10258685.html
Copyright © 2011-2022 走看看