[单片机][at32][填坑日记] [USB卡包] usb快速发包导致卡包

时间:2022-10-31 17:58:20


  1. 发送频率过快,导致pc或mcu未能及时应答每一包,造成缓存区遗留上一次数据。
  2. usb频发拔插枚举,导致pc/mcu数据丢失,①mcu丢失数据,每次发送都只能发送上次内容。②pc丢失数据,每次接收只会处理上次内容。
  3. 重启电脑过程中,mcu频繁发送usb数据,导致pc端丢失应答数据,PC端卡包(缺一包应答),只能处理上次数据,

现象:按键数据一直发送,且无释放按键数据。

解决方案如下:

1. usb_dcd_int.c --> USB_device_handle_UsbReset_intsts()

[单片机][at32][填坑日记] [USB卡包] usb快速发包导致卡包


[单片机][at32][填坑日记] [USB卡包] usb快速发包导致卡包

/**
* @brief USB_device_handle_UsbReset_intsts
* This interrupt occurs when a USB Reset is detected
* @param pusbdev: device instance
* @retval status
*/
static uint32_t USB_device_handle_UsbReset_intsts(USB_OTG_CORE_HANDLE *pusbdev)
{
USB_OTG_DAINT_TypeDef daintmsk;
USB_OTG_DOEPMSK_Type doepmsk;
USB_OTG_DIEPMSK_Type diepmsk;
USB_OTG_DCFG_Type dcfg;
USB_OTG_DCTL_Type dctl;
USB_OTG_GINTSTS_Type gintsts;
uint32_t i;

dctl.u32val = 0;
daintmsk.u32val = 0;
doepmsk.u32val = 0;
diepmsk.u32val = 0;
dcfg.u32val = 0;
gintsts.u32val = 0;
RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_USB, DISABLE);
__NOP();
RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_USB, ENABLE);
/* Clear the Remote Wake-up Signaling */
dctl.b.rwkupsig = 1;
USB_OTG_MODIFY_R32(&pusbdev->regs.DREGS->DCTRL, dctl.u32val, 0);

/* Flush the Tx FIFO */
USB_OTG_FlushTxFifo(pusbdev, 0);
USB_OTG_FlushTxFifo(pusbdev, EP1_IN);
USB_OTG_FlushTxFifo(pusbdev, EP2_IN);
#if BOOT_SUPPORT
USB_OTG_FlushTxFifo(pusbdev, EP3_IN);
#endif

for (i = 0; i < pusbdev->cfg.dev_endpoints; i++)
{
USB_OTG_WRITE_R32(&pusbdev->regs.INEP_REGS[i]->DINEPTINT, 0xFF);
USB_OTG_WRITE_R32(&pusbdev->regs.OUTEP_REGS[i]->DOUTEPTINT, 0xFF);
}
USB_OTG_WRITE_R32(&pusbdev->regs.DREGS->DAINT, 0xFFFFFFFF);

daintmsk.ept.in = 1;
daintmsk.ept.out = 1;
USB_OTG_WRITE_R32(&pusbdev->regs.DREGS->DAINTMASK, daintmsk.u32val);

doepmsk.b.setup = 1;
doepmsk.b.xferc = 1;
doepmsk.b.eptdis = 1;
USB_OTG_WRITE_R32(&pusbdev->regs.DREGS->DOUTEPTMASK, doepmsk.u32val);

diepmsk.b.xferc = 1;
diepmsk.b.timeout = 1;
diepmsk.b.eptdis = 1;

USB_OTG_WRITE_R32(&pusbdev->regs.DREGS->DINEPTMASK, diepmsk.u32val);
/* Reset Device Address */
dcfg.u32val = USB_OTG_READ_R32(&pusbdev->regs.DREGS->DCFG);
dcfg.b.devaddr = 0;
USB_OTG_WRITE_R32(&pusbdev->regs.DREGS->DCFG, dcfg.u32val);

/* setup EP0 to receive SETUP packets */
USB_OTG_EPT0_OutStart(pusbdev);

/* Clear interrupt */
gintsts.u32val = 0;
gintsts.b.usbrst = 1;
USB_OTG_WRITE_R32(&pusbdev->regs.GREGS->GINTSTS, gintsts.u32val);

/*Reset internal state machine */
USB_DEVICE_DCD_INT_fops->Reset(pusbdev);
return 1;
}

2. 补充USB协议忙状态

bool usb_tx_flag = false;

/**
* @brief USBD_HID 接口函数结构体
*/
USBD_Class_cb_Type USBD_HID_cb =
{
.Init = usb_device_hid_init,
.Reset = usb_device_hid_reset,
.Setup = usb_device_hid_setup,
.EPT0_TxSent = NULL, /*EPT0_TxSent*/
.EPT0_RxReady = NULL, /*EPT0_RxReady*/
.Data_In = usb_device_hid_datain, /*Data_In*/
.Data_Out = usb_device_hid_dataout, /*Data_Out*/
.SOF = usb_device_hid_sof, /*SOF */
.IsoINIncomplete = NULL,
.IsoOUTIncomplete = NULL,
.GetConfigDescriptor = usb_device_hid_getcfgdesc,
};

bool get_usb_tx_flag(void)
{
return usb_tx_flag;
}

/**
* @brief usb_device_hid_sof USB_FIFO空闲中断
* sof function
* @param pusbdev: device instance
* @retval status
*/
uint8_t usb_device_hid_sof(void *pusbdev)
{
usb_tx_flag = false;
return USB_DEVICE_OK;
}

/**
* @brief 发送hid报告
* @param pusbdev: usb设备指针
* @param report: 报告头指针
* @param len: 报告长度
* @retval status
*/
uint8_t usb_device_hid_sendreport(USB_OTG_CORE_HANDLE *pusbdev, uint8_t *report, uint16_t len)
{
if (usb_tx_flag)
{
return USB_DEVICE_BUSY;
}
uint8_t hid_ep;
if (report[0] == 0x02)
{
hid_ep = EP3_IN;
len = EP3_IN_SIZE;
}
else if (report[0] == 0x07)
{
hid_ep = EP2_IN;
len = EP2_IN_SIZE;
}
else if (report[0] == 0x09 || report[0] == 0x06 || report[0] == 0x01)
{
hid_ep = EP1_IN;
len = EP1_IN_SIZE;
}
else
{
LOG_E("<ERR> USB_DEVICE_FAIL2 report:%02x\r\n", report[0]);
return USB_DEVICE_FAIL;
}
memcpy(g_hid_txBuf, report, len);
if (pusbdev->dev.device_status == USB_OTG_CONFIGURED)
{
usb_tx_flag = true;
USB_DCD_EPT_Tx(pusbdev, hid_ep, g_hid_txBuf, len);
}
else
{
LOG_E("<ERR> USB_DEVICE_FAIL state:%02x\r\n", pusbdev->dev.device_status);
return USB_DEVICE_FAIL;
}
return USB_DEVICE_OK;
}

3. mcu端usb卡包解决方案,在主函数里面进行usb状态扫描,如果fifo异常,则推送数据

/**
* @brief 得到USB节点3,FIFO区状态
* @retval 0--正常 1--异常
*/
bool get_usb_fifo_state(void)
{
// LOG_D("<DEBUG> [get_usb_fifo_state] %d | %02x |\r\n", g_usb_init, USB_OTG_dev.regs.INEP_REGS[3]->DTXFSTS);
if (g_usb_init && USB_OTG_dev.regs.INEP_REGS[3]->DTXFSTS != 0x40 && USB_OTG_dev.regs.INEP_REGS[3]->DTXFSTS != 0x20)
{
LOG_E("<ERR> [usb_fifo_ste] Enter Fifo Fail %02x\r\n", USB_OTG_dev.regs.INEP_REGS[3]->DTXFSTS);
USBD_HID_cb.Data_In(&USB_OTG_dev, 3|0x80);
LOG_E("<ERR> [usb_fifo_ste] Exit Fifo Fail %02x\r\n", USB_OTG_dev.regs.INEP_REGS[3]->DTXFSTS);
return true;
}
else
{
return false;
}
}

4. 备用方案:usb拔插重新激活USB外设(带电池版本)

if (event.value.signals & SIGNAL_REFRESH_USB)
{
// USB拔出时,清除当前USB消息队列
if (!get_usb_state())
{
biz_usb_queue_init();
}
else
{
os_delay(100);
usb_init();
// 激活USB_DP让PC重新枚举
bsp_gpio_set_pin(BOARD_USB_DP_PORT, BOARD_USB_DP_PIN, BOARD_USB_DP_PRESS_LEVEL);
// 发送一次按键释放(防止按键按住)
g_combined_key_val = 0;
g_key_trigger_flag = true;
// 判断是否需要开机
if(get_sys_state() != SYS_STATE_POWER_ON)
{
main_send_signal(SIGNAL_SYS_POWER_ON);
}
}
if (!get_usb_state() && !get_usb_device_status())
{
bsp_gpio_set_pin(BOARD_USB_DP_PORT, BOARD_USB_DP_PIN, !BOARD_USB_DP_PRESS_LEVEL);
usb_deinit();
}
LOG_D("<DEBUG> SIGNAL_REFRESH_USB->%d %d\r\n", get_usb_state(), get_usb_device_status());
}

无电池版本

  1. USB上电反初始化
// USB拔出时,清除当前USB消息队列
if (!get_usb_state())
{
biz_usb_queue_init();
}
if (!get_usb_state() && !get_usb_device_status())
{
bsp_gpio_set_pin(BOARD_USB_DP_PORT, BOARD_USB_DP_PIN, !BOARD_USB_DP_PRESS_LEVEL);
usb_deinit();
}
  1. 上电稳定300ms再初始化USB。(建议用裸机用定时器,os用软定时器)
定时器100ms基准:
g_sys_run_times ++;
if(g_sys_run_times == 3 && get_usb_state() == false)
{
set_usb_state(true);
main_send_signal(SIGNAL_REFRESH_USB);
}
if (event.value.signals & SIGNAL_REFRESH_USB)
usb_init();
// 激活USB_DP让PC重新枚举
bsp_gpio_set_pin(BOARD_USB_DP_PORT, BOARD_USB_DP_PIN, BOARD_USB_DP_PRESS_LEVEL);
// 发送一次按键释放(防止按键按住)
g_combined_key_val = 0;
g_key_trigger_flag = true;
}