问题描述
客户在开发我们的设备(固件版本 v0.3.32)的时候出现上电之后发送数据无响应的问题,上电插入USB必死,这个是客户打调试数据:
目前我们的测试情况如下:
- LINUX开发板(华为海思):上电必死
- windows PC电脑(win7/8/10):上电正常
- 华为荣耀平板(我们开发安卓同事使用的设备):上电正常
基本判断这个应该是个兼容问题,是我们的设备或者他们的设备兼容性问题。
问题分析
从显现上分析:像是设备在接入他们设备的时候就死了,需要断连一下才有效
上电过程中,有一段比较漫长的识别过程,从启动到USB识别有需要较长的时间来处理这些信息,但是刷卡则是直接重置USB,是否只这个地方导致的问题;
于是尝试修改如下:
- 直接将USB初始化的地方后移或者迁移,保证他们的设备能有效的识别到
测试无效:
- 于是尝试在启动设备的地方先断开一下,在链接上,看设备是否能正常识别:
测试无效
- 尝试人为增加一次物理断开
原来的初始化函数:
void app_usb_init(void)
{
if (((HAL_GetTick() - hid_tcb.rst_time) > 10000) || (hid_tcb.rst_enable == 0))
{
USB_DisableGlobalInt(USB_OTG_HS);
USBD_Init(&USBD_Device, &HID_Desc, 0);
USBD_RegisterClass(&USBD_Device, USBD_CUSTOM_HID_CLASS);
USBD_CUSTOM_HID_RegisterInterface(&USBD_Device, &USBD_CustomHID_fops);
USBD_Start(&USBD_Device);
hid_tcb.rst_time = HAL_GetTick();
log_print("DBG", NP, "USB app_usb_init\n");
}
}
修改之后:
void bsp_usb_init(void)
{
USB_DevDisconnect(USB_OTG_HS);
HAL_Delay(100);
USBD_Init(&USBD_Device, &HID_Desc, 0);
USBD_RegisterClass(&USBD_Device, USBD_CUSTOM_HID_CLASS);
USBD_CUSTOM_HID_RegisterInterface(&USBD_Device, &USBD_CustomHID_fops);
USBD_Start(&USBD_Device);
}
void app_usb_init(void)
{
if (((HAL_GetTick() - hid_tcb.rst_time) > 10000) || (hid_tcb.rst_enable == 0))
{
bsp_usb_init();
hid_tcb.rst_time = HAL_GetTick();
log_print("DBG", NP, "USB app_usb_init\n");
}
}
// 在上电初始化的地方直接调用 bsp_usb_init()
客户测试就没有出现异常了,上电之后就可以正常运行
后记(客户寄来设备验证)
虽然使用启动阶段断链接的方式能让设备恢复,但是是否固件有什么隐藏的问题还需要仔细验证,于是使用客户的设备调试看看当前接收器的状态:
数据上行是通的,就是下行我这边无法进入中断,无法收到数据
- 之前测试v0.3.7 的固件是可以运行的,于是短接BOOT管脚,断电在上电测试发现
数据收发正常
- 去掉 BOOT ,设置程序的启动
#define VECT_TAB_OFFSET 0x0000
程序可以运行,直接上电是可以通讯的
- 怀疑启动是和USB在BOOT中初始化有关
于是在BOOT中有如下修改:
/*
根据启动是否下载程序来,确认是否初始化 USB
boot_delay_flg = 0 :BOOT 管脚设置强制下载
fee_boot_flg = 4 :应用程序设置下载OK,直接启动
*/
if ((boot_delay_flg == 0) || (fee_boot_flg != 4))
{
app_usb_init();
while ((USBD_Device.dev_state < 3) && (try_cnt < 10))
{
HAL_Delay(100);
try_cnt++;
}
INIT_DEBUG("> USB %s\n", (USBD_Device.dev_state >= 3) ? "OK" : "FAIL");
}
测试有效,数据收发正常
经过上述测试,取消BOOT程序是可以直接运行,也就是本身程序是没有问题,出现异常时BOOT阶段对USB的操作导致的异常
问题总结
- 原先的初始化函数,有一个10s的限制,导致启动,只在BOOT中有完成USB真的初始化,在应用层没有再次初始化USB
- 即使在应用初始化了函数,但是没有断开连接,上层也无法知晓这个设备再次初始化了,有些数据发生的变化,只有通知上层,上层才能做出对应的动作
USB主机存在差异,BOOT中初始化了USB,在应用层如果再次初始化USB设备,需要断开通知主机端做好准备,如果没有断开,也可在BOOT中选择性的初始化USB。