cherry-embedded / CherryUSB

CherryUSB is a tiny, beautiful and portable USB host and device stack for embedded system with USB IP
https://cherryusb.readthedocs.io/
Apache License 2.0
1.21k stars 256 forks source link

开启gcc的o2优化后便无法枚举成功 #77

Closed supf1994 closed 1 year ago

supf1994 commented 1 year ago

image 开启o2优化后便无法枚举成功,开Og是正常的

sakumisu commented 1 year ago

keil没有问题,找其他原因吧

sakumisu commented 1 year ago

其次 hub出现的问题,只能自己解决了

sakumisu commented 1 year ago

大佬,readme底下有群,可以加群交流

sakumisu commented 1 year ago

复测了 O2 没有问题的。这个自己检查原因吧

supf1994 commented 1 year ago

经过我这边测试,问题出在 ` static void dwc2_inchan_irq_handler(uint8_t ch_num) { uint32_t chan_intstatus; struct dwc2_pipe chan; struct usbh_urb urb;

chan_intstatus = (USB_OTG_HC(ch_num)->HCINT) & (USB_OTG_HC((uint32_t)ch_num)->HCINTMSK);

chan = &g_dwc2_hcd.pipe_pool[ch_num];
urb = chan->urb;
//printf("s1:%08x\r\n", chan_intstatus);
for (uint32_t i = 0; i < 0xf; i++) {
}

if ((chan_intstatus & USB_OTG_HCINT_XFRC) == USB_OTG_HCINT_XFRC) {
    urb->errorcode = 0;

    USB_UNMASK_HALT_HC_INT(ch_num);
    dwc2_halt(ch_num);
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_XFRC);
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NAK);
} else if ((chan_intstatus & USB_OTG_HCINT_AHBERR) == USB_OTG_HCINT_AHBERR) {
    USB_UNMASK_HALT_HC_INT(ch_num);
    dwc2_halt(ch_num);
    urb->errorcode = -EIO;
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_AHBERR);
} else if ((chan_intstatus & USB_OTG_HCINT_STALL) == USB_OTG_HCINT_STALL) {
    USB_UNMASK_HALT_HC_INT(ch_num);
    dwc2_halt(ch_num);
    urb->errorcode = -EPERM;
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_STALL);
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NAK);
} else if ((chan_intstatus & USB_OTG_HCINT_NAK) == USB_OTG_HCINT_NAK) {
    USB_UNMASK_HALT_HC_INT(ch_num);
    dwc2_halt(ch_num);
    urb->errorcode = -EAGAIN;
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NAK);
} else if ((chan_intstatus & USB_OTG_HCINT_ACK) == USB_OTG_HCINT_ACK) {
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_ACK);
} else if ((chan_intstatus & USB_OTG_HCINT_NYET) == USB_OTG_HCINT_NYET) {
    USB_UNMASK_HALT_HC_INT(ch_num);
    dwc2_halt(ch_num);
    urb->errorcode = -EAGAIN;
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NYET);
} else if ((chan_intstatus & USB_OTG_HCINT_TXERR) == USB_OTG_HCINT_TXERR) {
    USB_UNMASK_HALT_HC_INT(ch_num);
    dwc2_halt(ch_num);
    urb->errorcode = -EIO;
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_TXERR);
} else if ((chan_intstatus & USB_OTG_HCINT_BBERR) == USB_OTG_HCINT_BBERR) {
    USB_UNMASK_HALT_HC_INT(ch_num);
    dwc2_halt(ch_num);
    urb->errorcode = -EIO;
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_BBERR);
} else if ((chan_intstatus & USB_OTG_HCINT_FRMOR) == USB_OTG_HCINT_FRMOR) {
    USB_UNMASK_HALT_HC_INT(ch_num);
    dwc2_halt(ch_num);
    urb->errorcode = -EPIPE;
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_FRMOR);
} else if ((chan_intstatus & USB_OTG_HCINT_DTERR) == USB_OTG_HCINT_DTERR) {
    USB_UNMASK_HALT_HC_INT(ch_num);
    dwc2_halt(ch_num);
    urb->errorcode = -EIO;
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NAK);
    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_DTERR);
} else if ((chan_intstatus & USB_OTG_HCINT_CHH) == USB_OTG_HCINT_CHH) {
    USB_MASK_HALT_HC_INT(ch_num);

    if (urb->errorcode == 0) {
        uint32_t count = chan->xferlen - (USB_OTG_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_XFRSIZ);                          /* size that has received */
        uint32_t has_sent_packets = chan->num_packets - ((USB_OTG_HC(ch_num)->HCTSIZ & USB_OTG_DIEPTSIZ_PKTCNT) >> 19); /*how many packets has sent*/

        chan->xfrd += count;

        if ((has_sent_packets % 2) == 1) /* Flip in odd numbers */
        {
            if (chan->data_pid == HC_PID_DATA0) {
                chan->data_pid = HC_PID_DATA1;
            } else {
                chan->data_pid = HC_PID_DATA0;
            }
        }

        if (chan->ep_type == 0x00) {
            if (chan->ep0_state == DWC2_EP0_STATE_INDATA) {
                chan->ep0_state = DWC2_EP0_STATE_OUTSTATUS;
                dwc2_control_pipe_init(chan, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
            } else if (chan->ep0_state == DWC2_EP0_STATE_INSTATUS) {
                chan->ep0_state = DWC2_EP0_STATE_SETUP;
                urb->actual_length = chan->xfrd;
                dwc2_pipe_waitup(chan);
            }
        } else if (chan->ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
            urb->iso_packet[chan->iso_frame_idx].actual_length = chan->xfrd;
            urb->iso_packet[chan->iso_frame_idx].errorcode = urb->errorcode;
            chan->iso_frame_idx++;

            if (chan->iso_frame_idx == urb->num_of_iso_packets) {
                dwc2_pipe_waitup(chan);
            } else {
                dwc2_iso_pipe_init(chan, &urb->iso_packet[chan->iso_frame_idx]);
            }
        } else {
            urb->actual_length = chan->xfrd;
            dwc2_pipe_waitup(chan);
        }
    } else if (urb->errorcode == -EAGAIN) {
        /* re-activate the channel */
        dwc2_bulk_intr_pipe_init(chan, urb->transfer_buffer, urb->transfer_buffer_length);
    } else {
        dwc2_pipe_waitup(chan);
    }

    CLEAR_HC_INT(ch_num, USB_OTG_HCINT_CHH);
}

} ` 函数下的 for (uint32_t i = 0; i < 0xf; i++) {} 循环,这应该是一个延时,当我在Og模式下将这个延时注释掉之后,也会无法枚举成功

sakumisu commented 1 year ago

那就这样吧,没办法

sakumisu commented 1 year ago

我在keil上 O0~O2 Os 都是没问题的

sakumisu commented 1 year ago

刚又复测了一遍

supf1994 commented 1 year ago

刚又复测了一遍

这种情况比较奇怪,我在另一个工程里并没有出现这个问题,在当前工程里,debug模式下开的是Og优化,如果把 for (uint32_t i = 0; i < 0xf; i++) {} 延迟保留,则程序一切正常,将延迟注释掉,便无法正常枚举,开了O2优化及时保留延迟依然无法正常枚举,延迟放在这边感觉应该是O2将这个空循环给优化掉了,延迟再这边的作用是什么,进了中断后还有其他的寄存器状态没有切换完成,所以等待吗?

supf1994 commented 1 year ago

并且我在进入 dwc2_inchan_irq_handler 前加上一个字符的串口打印,也就可以正常的枚举,感觉像是中断程序运行过快会出问题

sakumisu commented 1 year ago

那个加不加无所谓的,只是为了减少 NAK 次数,之前调试没有删掉罢了。

sakumisu commented 1 year ago

这个 ip 的状态获取有点误差,中断来了但是状态没有切换,猜测是这样。我这边是没有重试机制的,超时就拜拜,不会重试

sakumisu commented 1 year ago

加群了吗,群里说吧

sakumisu commented 1 year ago

应该是全局变量优化问题,晚点我改下

sakumisu commented 1 year ago

好吧,不是全局变量问题,我把控制传输的 NAK 重传功能打开了,虽然中断会多点,但是会比较稳定。

sakumisu commented 1 year ago

不过用了dma,还会受到NAK ,这种ip挺垃圾的

supf1994 commented 1 year ago

不过用了dma,还会受到NAK ,这种ip挺垃圾的

是的,这样频繁进中断性能损耗大,我目前是改成 for (volatile uint32_t i = 0; i < 0xf; i++) {} 添加 volatile 来防止编译器优化掉该循环,在公司里测试是可以稳定枚举成功,做虚拟串口通信也正常,但不清楚在用户现场有干扰的情况下会不会出问题

sakumisu commented 1 year ago

我用 O2 是正常的,O0 需要加这个循环。不过我已经加了 NAK重传了,也无所谓了

sakumisu commented 1 year ago

先关了哈,大佬有问题再 reopen.