usb 802.11 wifi网卡,遇到点问题。
对tinyusb的架构有一点小了解了。
发送路径:
用户调用tud_vendor_write(urb_msg,urb_len); 启动传输
tud_vendor_write()
>tud_vendor_n_write(0, buffer, bufsize);
>>tu_fifo_write_n(&p_itf->tx_ff, buffer, bufsize) 写入fifo缓冲
>>maybe_transmit(p_itf) 尝试启动硬件传输
>>>usbd_edpt_busy(TUD_OPT_RHPORT, p_itf->ep_in) check busy
>>>u_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE); read data from fifo
>>>usbd_edpt_xfer(TUD_OPT_RHPORT, p_itf->ep_in, p_itf->epin_buf, count) ); start hardware xfer
>>>>dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) portable part
esp-idf-4.3-beta3\esp-idf-4.3-beta3\components\tinyusb\tinyusb\src\portable\espressif\esp32s2\dcd_esp32s2.c
esp32s2目前没有用DMA模式,是cpu模式,配置packet数量和size.
USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes;
启动ep和清NAK要启动
USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK
全能fifo empty中断
USB0.dtknqr4_fifoemptymsk |= (1 << epnum);
然后是中断推动方式。中断关系可以参考手册,里面讲了大的关系,小的没讲。
void handle_epin_ints(void)
if (int_status & USB_IEPINT_M) {
// IEPINT bit read-only
ESP_EARLY_LOGV(TAG, "dcd_int_handler - IN endpoint!");
handle_epin_ints();
}
遍历所有的中断,查找中断endpoint.
if (USB0.daint & (1 << (0 + n))) {
收到完成中断,表明所有的数据成功传输
if (USB0.in_ep_reg[n].diepint & USB_D_XFERCOMPL0_M)
调用d_event_xfer_complete(0, n | TUSB_DIR_IN_MASK)通知事件,
然后在tu_task()回调驱动的完成函数,再次启动maybe_transmit(p_itf)准备下一个数据包传输。
if (USB0.in_ep_reg[n].diepint & USB_D_TXFEMP0_M) { fifo空了,
填写fifo数据,以32bit方式写入。
transmit_packet(xfer, &USB0.in_ep_reg[n], n);
> remaining = (in_ep->dieptsiz & 0x7FFFFU) >> USB_D_XFERSIZE0_S;获取传输剩余数据长度,确定写入长度,一次最多写max_ep_size.
然后要说的是USB0.in_ep_reg[epnum].dieptsiz [19-21]是包数,每成功传输一个包就会减一。另外USB0.in_ep_reg[epnum].dtxfsts是fifo的可用长度,每成功传输就会少对应的32bit值。
当fifo传输完成,就会传输完成中断assert.(我根据实验猜测的)。因为我发现in_ep->dieptsiz的remaining为0,并不会将packet_cnt清掉。
接收路径:
vendord_open()
>!usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, sizeof(p_vendor->epout_buf)) ) 配置硬件接收数据。
>>dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes)
// Each complete packet for OUT xfers triggers XFRC. 每次只能接收一个包
USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
使能ep,清NAK.
USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
中断推动:
_dcd_int_handler(void* arg)
if (int_status & USB_RXFLVI_M) {
// RXFLVL bit is read-only
ESP_EARLY_LOGV(TAG, "dcd_int_handler - rx!");
// Mask out RXFLVL while reading data from FIFO
USB0.gintmsk &= ~USB_RXFLVIMSK_M;
read_rx_fifo(); 读取fifo,会更新对应传输的接收xfer->queued_len,并且会设置short_packet如果是的,
USB0.gintmsk |= USB_RXFLVIMSK_M;
}
// OUT endpoint interrupt handling.
if (int_status & USB_OEPINT_M) {
// OEPINT is read-only
handle_epout_ints(); 输出中断来了,
}
if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
xfer->short_packet = false; 传输结果,就通知上层,
dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true);
} else {
// Schedule another packet to be received. 启动下一个包接收工作。
USB0.out_ep_reg[n].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
USB0.out_ep_reg[n].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
}