diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 7f8f67383..42ba867d7 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -285,15 +285,12 @@ void tusb_vbus_changed(bool present) } } -static void transmit_packet(xfer_ctl_t * xfer) +static void fill_tx_fifo(xfer_ctl_t * xfer) { int left_to_send; uint8_t const *src; EPx_REGS *regs = xfer->regs; - uint32_t txc; - - txc = USB_USB_TXC1_REG_USB_TX_EN_Msk | USB_USB_TXC1_REG_USB_IGN_ISOMSK_Msk; - if (xfer->data1) txc |= USB_USB_TXC1_REG_USB_TOGGLE_TX_Msk; + uint8_t const epnum = tu_edpt_number(xfer->ep_addr); src = &xfer->buffer[xfer->transferred]; left_to_send = xfer->total_len - xfer->transferred; @@ -310,22 +307,23 @@ static void transmit_packet(xfer_ctl_t * xfer) xfer->last_packet_size++; left_to_send--; } - if (tu_edpt_number(xfer->ep_addr) != 0) + if (epnum != 0) { if (left_to_send > 0) { // Max packet size is set to value greater then FIFO. Enable fifo level warning // to handle larger packets. - txc |= USB_USB_TXC1_REG_USB_TFWL_Msk; + regs->txc |= (3 << USB_USB_TXC1_REG_USB_TFWL_Pos); + USB->USB_FWMSK_REG |= 1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_TXWARN31_Pos); } else { + xfer->regs->txc &= ~USB_USB_TXC1_REG_USB_TFWL_Msk; + USB->USB_FWMSK_REG &= ~(1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_TXWARN31_Pos)); // Whole packet already in fifo, no need to refill it later. Mark last. - txc |= USB_USB_TXC1_REG_USB_LAST_Msk; + regs->txc |= USB_USB_TXC1_REG_USB_LAST_Msk; } } - // Enable transfer with correct interrupts enabled - regs->txc = txc; } static bool try_allocate_dma(uint8_t epnum, uint8_t dir) @@ -387,6 +385,43 @@ static void start_rx_packet(xfer_ctl_t *xfer) xfer->regs->rxc |= USB_USB_RXC1_REG_USB_RX_EN_Msk; } +static void start_tx_dma(void *src, volatile void *dst, uint16_t size) +{ + // Setup SRC and DST registers + TX_DMA_REGS->DMAx_A_START_REG = (uint32_t)src; + TX_DMA_REGS->DMAx_B_START_REG = (uint32_t)dst; + // Interrupt not needed + TX_DMA_REGS->DMAx_INT_REG = size; + TX_DMA_REGS->DMAx_LEN_REG = size - 1; + TX_DMA_REGS->DMAx_CTRL_REG = TX_DMA_START; +} + +static void start_tx_packet(xfer_ctl_t *xfer) +{ + uint8_t const epnum = tu_edpt_number(xfer->ep_addr); + uint16_t remaining = xfer->total_len - xfer->transferred; + uint16_t size = tu_min16(remaining, xfer->max_packet_size); + EPx_REGS *regs = xfer->regs; + + xfer->last_packet_size = 0; + + regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk; + regs->txc = USB_USB_TXC1_REG_USB_IGN_ISOMSK_Msk; + if (xfer->data1) xfer->regs->txc |= USB_USB_TXC1_REG_USB_TOGGLE_TX_Msk; + + if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE && try_allocate_dma(epnum, TUSB_DIR_IN)) + { + // Whole packet will be put in FIFO by DMA. Set LAST bit before start. + start_tx_dma(xfer->buffer + xfer->transferred, ®s->txd, size); + regs->txc |= USB_USB_TXC1_REG_USB_LAST_Msk; + } + else + { + fill_tx_fifo(xfer); + } + regs->txc |= USB_USB_TXC1_REG_USB_TX_EN_Msk; +} + static void read_rx_fifo(xfer_ctl_t *xfer, uint16_t bytes_in_fifo) { EPx_REGS *regs = xfer->regs; @@ -483,7 +518,7 @@ static void handle_ep0_tx(void) // Start from the beginning xfer->last_packet_size = 0; } - transmit_packet(xfer); + fill_tx_fifo(xfer); } } @@ -570,14 +605,23 @@ static void handle_rx_ev(void) static void handle_epx_tx_ev(xfer_ctl_t *xfer) { - uint32_t usb_txs1_reg; + uint8_t const epnum = tu_edpt_number(xfer->ep_addr); + uint32_t txs; EPx_REGS *regs = xfer->regs; - usb_txs1_reg = regs->USB_TXS1_REG; + txs = regs->txs; - if (GET_BIT(usb_txs1_reg, USB_USB_TXS1_REG_USB_TX_DONE)) + if (GET_BIT(txs, USB_USB_TXS1_REG_USB_TX_DONE)) { - if (GET_BIT(usb_txs1_reg, USB_USB_TXS1_REG_USB_ACK_STAT)) + if (_dcd.dma_ep[TUSB_DIR_IN] == epnum) + { + // Disable DMA and update last_packet_size with what DMA reported. + TX_DMA_REGS->DMAx_CTRL_REG &= ~DMA_DMA1_CTRL_REG_DMA_ON_Msk; + xfer->last_packet_size = TX_DMA_REGS->DMAx_IDX_REG + 1; + // Release DMA to used by other endpoints. + _dcd.dma_ep[TUSB_DIR_IN] = 0; + } + if (GET_BIT(txs, USB_USB_TXS1_REG_USB_ACK_STAT)) { // ACK received, update transfer state and DATA0/1 bit xfer->transferred += xfer->last_packet_size; @@ -590,12 +634,13 @@ static void handle_epx_tx_ev(xfer_ctl_t *xfer) return; } } - else - { - xfer->last_packet_size = 0; - } - transmit_packet(xfer); } + if (txs & USB_USB_TXS1_REG_USB_TX_URUN_Msk) + { + TU_LOG1("EP %d FIFO underrun\n", epnum); + } + // Start next or repeated packet. + start_tx_packet(xfer); } static void handle_tx_ev(void) @@ -665,9 +710,9 @@ static void handle_alt_ev(void) } } -static void handle_epx_tx_refill(uint8_t ep) +static void handle_epx_tx_warn_ev(uint8_t ep) { - transmit_packet(XFER_CTL_BASE(ep, TUSB_DIR_IN)); + fill_tx_fifo(XFER_CTL_BASE(ep, TUSB_DIR_IN)); } static void handle_fifo_warning(void) @@ -675,11 +720,11 @@ static void handle_fifo_warning(void) uint32_t fifo_warning = USB->USB_FWEV_REG; if (fifo_warning & 0x01) - handle_epx_tx_refill(1); + handle_epx_tx_warn_ev(1); if (fifo_warning & 0x02) - handle_epx_tx_refill(2); + handle_epx_tx_warn_ev(2); if (fifo_warning & 0x04) - handle_epx_tx_refill(3); + handle_epx_tx_warn_ev(3); if (fifo_warning & 0x10) handle_epx_rx_ev(1); if (fifo_warning & 0x20) @@ -884,7 +929,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t } else // IN { - transmit_packet(xfer); + start_tx_packet(xfer); } return true;