天天看点

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

  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;
    }
}      
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;
}