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

猜你喜欢

转载自www.cnblogs.com/curtis-han/p/10258685.html