STM32 USB HID BarCodeReader不兼容问题的解决

摘要:
STM32USBHIDclass的一部分BarCodeScanner(条码枪)不兼容的解决硬件构成STM32F479-EVAL评价板型号为FFTAA10AP条码枪现象最近用CubeMX生成的USB库做条形码枪的USB驱动,用的是HID协议。但是有的型号的条码枪貌似和标准USB库流程有所出入,执行后,函数在USBH_HID_ClassRequest里的USBH_HID_SetIdle函数发生了Stall,以至于无法继续。USBH_HID_ClassRequest的调查结果usbh_hid.cbeforecaseHID_REQ_SET_IDLE:classReqStatus=USBH_HID_SetIdle;/*setIdle*/if{HID_Handle-˃ctl_state=HID_REQ_SET_PROTOCOL;}elseif{HID_Handle-˃ctl_state=HID_REQ_SET_PROTOCOL;}break;USBH_HID_SetIdle的返回值最初是1,重试三次以后,返回值成了3,函数最底层发生了STALL。经过一顿搜索,定位在进入Idle后的USBH_HID_GetReport函数。

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

免责声明:文章转载自《STM32 USB HID BarCodeReader不兼容问题的解决》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【环境搭建】SonarScannerRedhat下 Apache, php, mysql的默认安装路径下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

vivo手机打开usb调试和mac os系统链接

下载工具 打开vivo官网https://www.vivo.com/,选择“服务”分页,在收索框中输入'USB',即可找到mac系统mtp管理工具 MAC版本的MTP管理工具下载地址: http://zs.vivo.com.cn/download.php?sel_type=12...

zz-rtl8188eu的linux-usb-wifi调试及驱动编译150210

//zz//#######################################################################zz-rtl8188eu的linux-usb-wifi调试及驱动编译150210zz-Write:@2015-2-4 22:11:14@2015-2-11 00:32:07@REF:嵌入式linux us...

STM32中assert_param的使用

在STM32的固件库和提供的例程中,到处都可以见到assert_param()的使用。如果打开任何一个例程中的stm32f10x_conf.h文件,就可以看到实际上assert_param是一个宏定义;在固件库中,它的作用就是检测传递给函数的参数是否是有效的参数。所谓有效的参数是指满足规定范围的参数,比如某个参数的取值范围只能是小于3的正整数,如果给出的参...

菜鸟学STM32之串口通讯

微信公众号:小樊Study关注共同学习,问题或建议,请公众号留言!!! 串口作为 MCU 的重要外部接口,同时也是软件开发重要的调试手段,其重要性不言而喻。现在基本上所有的MCU都会带有串口,STM32自然也不例外。STM32F4的串口资源相当丰富的,功能也相当强劲。STM32F4开发板所使用STM32F407ZGT6 最多可提供 6 路串口,有分数波特...

一、STM32简介、选型及其目标

STM32简介 STM32系列是由意法半导体公司推出的ARM Cortex-M内核单片机,从字面上来看,ST为意法半导体公司的缩写,M是Microcontrollers即单片机的缩写,32代表32位 芯片系列 STM32系列芯片分类 STM32后缀的型号说明 模块准备 STM8S103F3P6 STM8S芯片,20引脚,8KB闪存,TSSOP封装,工...

STM32学习笔记——AFIO时钟的配置问题

最近在写程序时发现设置外部中断出了问题,之前的程序好好的怎么就不能用了呢?经过了一晚上的折腾发现问题出在AFIO时钟的配置上,我没有使能AFIO时钟。 什么时候要开启AFIO呢?参考手册:  说的很明白,操作AFIO的三类寄存器时需要开启:  1.事件控制寄存器(AFIO_EVCR) 2.复用重映射和调试I/O配置寄存器(AFIO_MAPR) 3.外部...