enhance dwc2

This commit is contained in:
hathach 2024-10-09 21:47:23 +07:00
parent 07c14f30a6
commit 98e94a5d6d
No known key found for this signature in database
GPG Key ID: 26FAB84F615C3C52
3 changed files with 62 additions and 82 deletions

View File

@ -1,6 +1,7 @@
set(MCU_VARIANT XMC4500)
set(JLINK_DEVICE XMC4500-1024)
#set(JLINK_OPTION "-USB 000551005307")
set(LD_FILE_GNU ${SDK_DIR}/CMSIS/Infineon/COMPONENT_${MCU_VARIANT}/Source/TOOLCHAIN_GCC_ARM/XMC4500x1024.ld)
function(update_board TARGET)

View File

@ -398,12 +398,8 @@ static void bus_reset(uint8_t rhport) {
tu_memclr(xfer_status, sizeof(xfer_status));
_sof_en = false;
_allocated_ep_in_count = 1;
// clear device address
dwc2->dcfg &= ~DCFG_DAD_Msk;
// 1. NAK for all OUT endpoints
for (uint8_t n = 0; n < ep_count; n++) {
dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
@ -419,13 +415,17 @@ static void bus_reset(uint8_t rhport) {
dfifo_flush_tx(dwc2, 0x10); // all tx fifo
dfifo_flush_rx(dwc2);
// 3. Set up interrupt mask
// 3. Set up interrupt mask for EP0
dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos);
dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM;
dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM;
// 4. Set up DFIFO
dfifo_init(rhport);
// 5. Reset device address
dwc2->dcfg &= ~DCFG_DAD_Msk;
// Fixed both control EP0 size to 64 bytes
dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
dwc2->epout[0].doepctl &= ~(0x03 << DOEPCTL_MPSIZ_Pos);
@ -907,7 +907,9 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t
uint16_t const short_packet_size = total_bytes % xfer->max_size;
// Zero-size packet is special case.
if (short_packet_size > 0 || (total_bytes == 0)) num_packets++;
if (short_packet_size > 0 || (total_bytes == 0)) {
num_packets++;
}
// Schedule packets to be sent within interrupt
edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
@ -941,6 +943,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
// Interrupt Handler
//--------------------------------------------------------------------
// Process shared receive FIFO, this interrupt is only used in Slave mode
static void handle_rxflvl_irq(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
volatile uint32_t const* rx_fifo = dwc2->fifo[0];
@ -950,20 +953,8 @@ static void handle_rxflvl_irq(uint8_t rhport) {
uint8_t const pktsts = (grxstsp & GRXSTSP_PKTSTS_Msk) >> GRXSTSP_PKTSTS_Pos;
uint8_t const epnum = (grxstsp & GRXSTSP_EPNUM_Msk) >> GRXSTSP_EPNUM_Pos;
uint16_t const bcnt = (grxstsp & GRXSTSP_BCNT_Msk) >> GRXSTSP_BCNT_Pos;
dwc2_epout_t* epout = &dwc2->epout[epnum];
//#if CFG_TUSB_DEBUG >= DWC2_DEBUG
// const char * pktsts_str[] =
// {
// "ASSERT", "Global NAK (ISR)", "Out Data Received", "Out Transfer Complete (ISR)",
// "Setup Complete (ISR)", "ASSERT", "Setup Data Received"
// };
// TU_LOG_LOCATION();
// TU_LOG(DWC2_DEBUG, " EP %02X, Byte Count %u, %s\r\n", epnum, bcnt, pktsts_str[pktsts]);
// TU_LOG(DWC2_DEBUG, " daint = %08lX, doepint = %04X\r\n", (unsigned long) dwc2->daint, (unsigned int) epout->doepint);
//#endif
switch (pktsts) {
// Global OUT NAK: do nothing
case GRXSTS_PKTSTS_GLOBALOUTNAK:
@ -971,15 +962,14 @@ static void handle_rxflvl_irq(uint8_t rhport) {
case GRXSTS_PKTSTS_SETUPRX:
// Setup packet received
// We can receive up to three setup packets in succession, but
// only the last one is valid.
// We can receive up to three setup packets in succession, but only the last one is valid.
_setup_packet[0] = (*rx_fifo);
_setup_packet[1] = (*rx_fifo);
break;
case GRXSTS_PKTSTS_SETUPDONE:
// Setup packet done (Interrupt)
// Setup packet done:
// After popping this out, dwc2 asserts a DOEPINT_SETUP interrupt which is handled by handle_epout_irq()
epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
break;
@ -1011,8 +1001,8 @@ static void handle_rxflvl_irq(uint8_t rhport) {
}
case GRXSTS_PKTSTS_OUTDONE:
/* Out packet done (Interrupt)
After this entry is popped from the receive FIFO, the controller asserts a Transfer Completed interrupt on
/* Out packet done
After this entry is popped from the receive FIFO, dwc2 asserts a Transfer Completed interrupt on
the specified OUT endpoint which will be handled by handle_epout_irq() */
break;
@ -1034,51 +1024,56 @@ static void handle_epout_irq(uint8_t rhport) {
const uint32_t doepint = epout->doepint;
TU_ASSERT((epout->doepint & DOEPINT_AHBERR) == 0, );
TU_LOG1_HEX(doepint);
// Setup and/or STPKTRX/STSPHSRX (from 3.00a) can be set along with XFRC, and also set independently.
if (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a) {
if (doepint & DOEPINT_STSPHSRX) {
// Status phase received for control write: In token received from Host
epout->doepint = DOEPINT_STSPHSRX;
}
if (doepint & DOEPINT_STPKTRX) {
// New setup packet received, but wait for Setup done, since we can receive up to 3 setup consecutively
epout->doepint = DOEPINT_STPKTRX;
}
}
if (doepint & DOEPINT_SETUP) {
epout->doepint = DOEPINT_SETUP;
if(dma_enabled(dwc2)) {
dma_setup_prepare(rhport);
}
dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true);
}
// OUT XFER complete
if (doepint & DOEPINT_XFRC) {
epout->doepint = DOEPINT_XFRC;
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
// only handle data skip if it is setup or status related
// Normal OUT transfer complete
if (!(doepint & (DOEPINT_SETUP | DOEPINT_STPKTRX | DOEPINT_STSPHSRX))) {
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
if(dma_enabled(dwc2)) {
if (doepint & DOEPINT_SETUP) {
// STPKTRX is only available for version from 3_00a
if ((doepint & DOEPINT_DMA_STPKTRX) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) {
epout->doepint = DOEPINT_DMA_STPKTRX;
}
} else if (doepint & DOEPINT_STSPHSRX) {
epout->doepint = DOEPINT_STSPHSRX;
} else {
if ((doepint & DOEPINT_DMA_STPKTRX) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) {
epout->doepint = DOEPINT_DMA_STPKTRX;
if(dma_enabled(dwc2)) {
if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) {
// EP0 can only handle one packet Schedule another packet to be received.
edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]);
} else {
// EP0 can only handle one packet
if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) {
// Schedule another packet to be received.
edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]);
} else {
// Fix packet length
uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos;
xfer->total_len -= remain;
// this is ZLP, so prepare EP0 for next setup
if(epnum == 0 && xfer->total_len == 0) {
dma_setup_prepare(rhport);
}
dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true);
// Fix packet length
uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos;
xfer->total_len -= remain;
// this is ZLP, so prepare EP0 for next setup
if(epnum == 0 && xfer->total_len == 0) {
dma_setup_prepare(rhport);
}
}
}
} else {
// DMA_STPKTRX should only be set in Buffer DMA Mode. However, STM32L476 (slave-only) with v3.10a
// incorrectly set this along with SETUP bit. This may (or not) be STM32L476 or 3.10a specific bug
if ((doepint & DOEPINT_DMA_STPKTRX) && (dwc2->gsnpsid == DWC2_CORE_REV_3_10a)) {
epout->doepint = DOEPINT_DMA_STPKTRX;
} else {
if ((doepint & DOEPINT_STSPHSRX) && (dwc2->gsnpsid == DWC2_CORE_REV_3_10a)) {
epout->doepint = DOEPINT_STSPHSRX;
}
dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true);
}
} else {
// EP0 can only handle one packet
if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) {
// Schedule another packet to be received.
@ -1089,19 +1084,6 @@ static void handle_epout_irq(uint8_t rhport) {
}
}
}
// SETUP packet Setup Phase done.
if (doepint & DOEPINT_SETUP) {
epout->doepint = DOEPINT_SETUP;
if ((doepint & DOEPINT_DMA_STPKTRX) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) {
epout->doepint = DOEPINT_DMA_STPKTRX;
}
if(dma_enabled(dwc2) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) {
dma_setup_prepare(rhport);
}
dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true);
}
}
}
}
@ -1274,13 +1256,10 @@ void dcd_int_handler(uint8_t rhport) {
// RxFIFO non-empty interrupt handling.
if (int_status & GINTSTS_RXFLVL) {
// RXFLVL bit is read-only
// Mask out RXFLVL while reading data from FIFO
dwc2->gintmsk &= ~GINTMSK_RXFLVLM;
dwc2->gintmsk &= ~GINTMSK_RXFLVLM; // disable RXFLVL interrupt while reading
do {
// Loop until all available packets were handled
handle_rxflvl_irq(rhport);
handle_rxflvl_irq(rhport); // read all packets
} while(dwc2->gintsts & GINTSTS_RXFLVL);
dwc2->gintmsk |= GINTMSK_RXFLVLM;

View File

@ -1954,9 +1954,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#define DOEPINT_NYET_Msk (0x1UL << DOEPINT_NYET_Pos) // 0x00004000
#define DOEPINT_NYET DOEPINT_NYET_Msk // NYET interrupt
#define DOEPINT_DMA_STPKTRX_Pos (15U)
#define DOEPINT_DMA_STPKTRX_Msk (0x1UL << DOEPINT_DMA_STPKTRX_Pos) // 0x00008000
#define DOEPINT_DMA_STPKTRX DOEPINT_DMA_STPKTRX_Msk // Setup Packet Received in Buffer DMA Mode
#define DOEPINT_STPKTRX_Pos (15U)
#define DOEPINT_STPKTRX_Msk (0x1UL << DOEPINT_STPKTRX_Pos) // 0x00008000
#define DOEPINT_STPKTRX DOEPINT_STPKTRX_Msk // Setup Packet Received
/******************** Bit definition for DOEPTSIZ register ********************/
#define DOEPTSIZ_XFRSIZ_Pos (0U)