mirror of
https://github.com/hathach/tinyusb.git
synced 2025-03-14 13:21:13 +00:00
add fix for stm32l4 (version 3.10a) which generate transfer complete when setup recieved and control out data complete
This commit is contained in:
parent
4ea8f1441d
commit
aa682d7301
@ -21,8 +21,9 @@ CFLAGS += -Wno-error=maybe-uninitialized -Wno-error=cast-align
|
||||
# All source paths should be relative to the top level.
|
||||
LD_FILE = hw/bsp/$(BOARD)/STM32L476VGTx_FLASH.ld
|
||||
|
||||
#src/portable/st/synopsys/dcd_synopsys.c
|
||||
SRC_C += \
|
||||
src/portable/st/synopsys/dcd_synopsys.c \
|
||||
src/portable/synopsys/dwc2/dcd_dwc2.c \
|
||||
$(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \
|
||||
$(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \
|
||||
$(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \
|
||||
@ -52,5 +53,4 @@ JLINK_DEVICE = stm32l476vg
|
||||
STM32Prog = STM32_Programmer_CLI
|
||||
|
||||
# flash target using on-board stlink
|
||||
flash: $(BUILD)/$(PROJECT).elf
|
||||
$(STM32Prog) --connect port=swd --write $< --go
|
||||
flash: flash-stlink
|
||||
|
@ -186,8 +186,12 @@ void board_init(void)
|
||||
/* Enable USB FS Clock */
|
||||
__HAL_RCC_USB_OTG_FS_CLK_ENABLE();
|
||||
|
||||
// Enable VBUS sense (B device) via pin PA9
|
||||
USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBDEN;
|
||||
// // Enable VBUS sense (B device) via pin PA9
|
||||
// USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBDEN;
|
||||
|
||||
// L476Disco use general GPIO PC11 for VBUS sensing instead of dedicated PA9 as others
|
||||
// Disable VBUS Sense and force device mode
|
||||
USB_OTG_FS->GCCFG &= ~USB_OTG_GCCFG_VBDEN;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
@ -125,6 +125,7 @@
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32L4)
|
||||
#if defined (STM32L475xx) || defined (STM32L476xx) || \
|
||||
defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \
|
||||
defined (STM32L4A6xx) || defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \
|
||||
defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \
|
||||
defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
|
||||
#define DCD_ATTR_ENDPOINT_MAX 6
|
||||
|
@ -123,8 +123,8 @@ static void bus_reset(uint8_t rhport)
|
||||
dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
|
||||
}
|
||||
|
||||
// 2. Un-mask interrupt bits
|
||||
dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos);
|
||||
// 2. Set up interrupt mask
|
||||
dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos);
|
||||
dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM;
|
||||
dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM;
|
||||
|
||||
@ -472,9 +472,6 @@ void dcd_init (uint8_t rhport)
|
||||
// Restart PHY clock
|
||||
dwc2->pcgctl &= ~(PCGCTL_STOPPCLK | PCGCTL_GATEHCLK | PCGCTL_PWRCLMP | PCGCTL_RSTPDWNMODULE);
|
||||
|
||||
// Force device mode
|
||||
dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD;
|
||||
|
||||
/* Set HS/FS Timeout Calibration to 7 (max available value).
|
||||
* The number of PHY clocks that the application programs in
|
||||
* this field is added to the high/full speed interpacket timeout
|
||||
@ -485,13 +482,16 @@ void dcd_init (uint8_t rhport)
|
||||
*/
|
||||
dwc2->gusbcfg |= (7ul << GUSBCFG_TOCAL_Pos);
|
||||
|
||||
// Force device mode
|
||||
dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD;
|
||||
|
||||
// Clear A override, force B Valid
|
||||
dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL;
|
||||
|
||||
// If USB host misbehaves during status portion of control xfer
|
||||
// (non zero-length packet), send STALL back and discard.
|
||||
dwc2->dcfg |= DCFG_NZLSOHSK;
|
||||
|
||||
// Clear A,B, VBus valid override
|
||||
dwc2->gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN);
|
||||
|
||||
// Clear all interrupts
|
||||
dwc2->gintsts |= dwc2->gintsts;
|
||||
dwc2->gotgint |= dwc2->gotgint;
|
||||
@ -609,7 +609,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
|
||||
(desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) |
|
||||
(xfer->max_size << DOEPCTL_MPSIZ_Pos);
|
||||
|
||||
dwc2->daintmsk |= (1 << (DAINTMSK_OEPM_Pos + epnum));
|
||||
dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -696,19 +696,21 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
|
||||
if(epnum == 0)
|
||||
{
|
||||
ep0_pending[dir] = total_bytes;
|
||||
|
||||
// Schedule the first transaction for EP0 transfer
|
||||
edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t num_packets = (total_bytes / xfer->max_size);
|
||||
uint16_t const short_packet_size = total_bytes % xfer->max_size;
|
||||
|
||||
uint16_t num_packets = (total_bytes / xfer->max_size);
|
||||
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++;
|
||||
|
||||
// Zero-size packet is special case.
|
||||
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);
|
||||
// Schedule packets to be sent within interrupt
|
||||
edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -924,21 +926,49 @@ static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const *
|
||||
static void handle_rxflvl_irq(uint8_t rhport)
|
||||
{
|
||||
dwc2_regs_t * dwc2 = DWC2_REG(rhport);
|
||||
volatile uint32_t * rx_fifo = dwc2->fifo[0];
|
||||
volatile uint32_t const * rx_fifo = dwc2->fifo[0];
|
||||
|
||||
// Pop control word off FIFO
|
||||
uint32_t ctl_word = dwc2->grxstsp;
|
||||
uint8_t pktsts = (ctl_word & GRXSTSP_PKTSTS_Msk ) >> GRXSTSP_PKTSTS_Pos;
|
||||
uint8_t epnum = (ctl_word & GRXSTSP_EPNUM_Msk ) >> GRXSTSP_EPNUM_Pos;
|
||||
uint16_t bcnt = (ctl_word & GRXSTSP_BCNT_Msk ) >> GRXSTSP_BCNT_Pos;
|
||||
uint32_t const ctl_word = dwc2->grxstsp;
|
||||
uint8_t const pktsts = (ctl_word & GRXSTSP_PKTSTS_Msk ) >> GRXSTSP_PKTSTS_Pos;
|
||||
uint8_t const epnum = (ctl_word & GRXSTSP_EPNUM_Msk ) >> GRXSTSP_EPNUM_Pos;
|
||||
uint16_t const bcnt = (ctl_word & GRXSTSP_BCNT_Msk ) >> GRXSTSP_BCNT_Pos;
|
||||
|
||||
dwc2_epout_t* epout = &dwc2->epout[epnum];
|
||||
|
||||
#if CFG_TUSB_DEBUG >= (DWC2_DEBUG + 1)
|
||||
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 = %04lX\r\n", dwc2->daint, epout->doepint);
|
||||
#endif
|
||||
|
||||
switch ( pktsts )
|
||||
{
|
||||
case 0x01: // Global OUT NAK (Interrupt)
|
||||
// Global OUT NAK: do nothign
|
||||
case GRXSTS_PKTSTS_GLOBALOUTNAK: break;
|
||||
|
||||
case GRXSTS_PKTSTS_SETUPRX:
|
||||
// Setup packet received
|
||||
|
||||
// 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 0x02: // Out packet received
|
||||
case GRXSTS_PKTSTS_SETUPDONE:
|
||||
// Setup packet done (Interrupt)
|
||||
epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
|
||||
break;
|
||||
|
||||
case GRXSTS_PKTSTS_OUTRX:
|
||||
{
|
||||
// Out packet received
|
||||
xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
|
||||
|
||||
// Read packet off RxFIFO
|
||||
@ -959,7 +989,7 @@ static void handle_rxflvl_irq(uint8_t rhport)
|
||||
// Truncate transfer length in case of short packet
|
||||
if ( bcnt < xfer->max_size )
|
||||
{
|
||||
xfer->total_len -= (dwc2->epout[epnum].doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos;
|
||||
xfer->total_len -= (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos;
|
||||
if ( epnum == 0 )
|
||||
{
|
||||
xfer->total_len -= ep0_pending[TUSB_DIR_OUT];
|
||||
@ -969,18 +999,28 @@ static void handle_rxflvl_irq(uint8_t rhport)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x03: // Out packet done (Interrupt)
|
||||
break;
|
||||
// Out packet done (Interrupt)
|
||||
case GRXSTS_PKTSTS_OUTDONE:
|
||||
// Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a
|
||||
// May (or not) be 3.10a specific feature/bug or depending on MCU configuration
|
||||
// XFRC complete is additionally generated when
|
||||
// - setup packet is received
|
||||
// - complete the data stage of control write is complete
|
||||
if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a))
|
||||
{
|
||||
if (epout->doepint & DOEPINT_STPKTRX)
|
||||
{
|
||||
// skip this "no-data" transfer complete event
|
||||
// STPKTRX will be clear later by setup received handler
|
||||
epout->doepint = DOEPINT_XFRC;
|
||||
}
|
||||
|
||||
case 0x04: // Setup packet done (Interrupt)
|
||||
dwc2->epout[epnum].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
|
||||
break;
|
||||
|
||||
case 0x06: // Setup packet recvd
|
||||
// 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);
|
||||
if (epout->doepint & DOEPINT_OTEPSPR)
|
||||
{
|
||||
// skip this "no-data" transfer complete event
|
||||
epout->doepint = DOEPINT_XFRC | DOEPINT_OTEPSPR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: // Invalid
|
||||
@ -992,27 +1032,38 @@ static void handle_rxflvl_irq(uint8_t rhport)
|
||||
static void handle_epout_irq (uint8_t rhport)
|
||||
{
|
||||
dwc2_regs_t *dwc2 = DWC2_REG(rhport);
|
||||
dwc2_epout_t* epout = dwc2->epout;
|
||||
|
||||
// DAINT for a given EP clears when DOEPINTx is cleared.
|
||||
// OEPINT will be cleared when DAINT's out bits are cleared.
|
||||
for ( uint8_t n = 0; n < DWC2_EP_MAX; n++ )
|
||||
{
|
||||
xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
|
||||
|
||||
if ( dwc2->daint & (1 << (DAINT_OEPINT_Pos + n)) )
|
||||
if ( dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n) )
|
||||
{
|
||||
dwc2_epout_t* epout = &dwc2->epout[n];
|
||||
|
||||
uint32_t const doepint = epout->doepint;
|
||||
|
||||
// SETUP packet Setup Phase done.
|
||||
if ( epout[n].doepint & DOEPINT_STUP )
|
||||
if ( doepint & DOEPINT_STUP )
|
||||
{
|
||||
epout[n].doepint = DOEPINT_STUP;
|
||||
dcd_event_setup_received(rhport, (uint8_t*) &_setup_packet[0], true);
|
||||
uint32_t clear_flag = DOEPINT_STUP;
|
||||
|
||||
// STPKTRX is only available for version from 3_00a
|
||||
if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a))
|
||||
{
|
||||
clear_flag |= DOEPINT_STPKTRX;
|
||||
}
|
||||
|
||||
epout->doepint = clear_flag;
|
||||
dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true);
|
||||
}
|
||||
|
||||
// OUT XFER complete
|
||||
if ( epout[n].doepint & DOEPINT_XFRC )
|
||||
if ( epout->doepint & DOEPINT_XFRC )
|
||||
{
|
||||
epout[n].doepint = DOEPINT_XFRC;
|
||||
epout->doepint = DOEPINT_XFRC;
|
||||
|
||||
xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
|
||||
|
||||
// EP0 can only handle one packet
|
||||
if ( (n == 0) && ep0_pending[TUSB_DIR_OUT] )
|
||||
@ -1038,11 +1089,11 @@ static void handle_epin_irq (uint8_t rhport)
|
||||
// IEPINT will be cleared when DAINT's out bits are cleared.
|
||||
for ( uint8_t n = 0; n < DWC2_EP_MAX; n++ )
|
||||
{
|
||||
xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
|
||||
|
||||
if ( dwc2->daint & (1 << (DAINT_IEPINT_Pos + n)) )
|
||||
if ( dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n) )
|
||||
{
|
||||
// IN XFER complete (entire xfer).
|
||||
xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
|
||||
|
||||
if ( epin[n].diepint & DIEPINT_XFRC )
|
||||
{
|
||||
epin[n].diepint = DIEPINT_XFRC;
|
||||
@ -1215,14 +1266,14 @@ void dcd_int_handler(uint8_t rhport)
|
||||
// OUT endpoint interrupt handling.
|
||||
if(int_status & GINTSTS_OEPINT)
|
||||
{
|
||||
// OEPINT is read-only
|
||||
// OEPINT is read-only, clear using DOEPINTn
|
||||
handle_epout_irq(rhport);
|
||||
}
|
||||
|
||||
// IN endpoint interrupt handling.
|
||||
if(int_status & GINTSTS_IEPINT)
|
||||
{
|
||||
// IEPINT bit read-only
|
||||
// IEPINT bit read-only, clear using DIEPINTn
|
||||
handle_epin_irq(rhport);
|
||||
}
|
||||
|
||||
|
@ -907,6 +907,17 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
||||
#define GRXSTSP_PKTSTS_Msk (0xFUL << GRXSTSP_PKTSTS_Pos) // 0x001E0000 */
|
||||
#define GRXSTSP_PKTSTS GRXSTSP_PKTSTS_Msk // OUT EP interrupt mask bits */
|
||||
|
||||
#define GRXSTS_PKTSTS_GLOBALOUTNAK 1
|
||||
#define GRXSTS_PKTSTS_OUTRX 2
|
||||
#define GRXSTS_PKTSTS_HCHIN 2
|
||||
#define GRXSTS_PKTSTS_OUTDONE 3
|
||||
#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3
|
||||
#define GRXSTS_PKTSTS_SETUPDONE 4
|
||||
#define GRXSTS_PKTSTS_DATATOGGLEERR 5
|
||||
#define GRXSTS_PKTSTS_SETUPRX 6
|
||||
#define GRXSTS_PKTSTS_HCHHALTED 7
|
||||
|
||||
|
||||
/******************** Bit definition for DAINTMSK register ********************/
|
||||
#define DAINTMSK_IEPM_Pos (0U)
|
||||
#define DAINTMSK_IEPM_Msk (0xFFFFUL << DAINTMSK_IEPM_Pos) // 0x0000FFFF */
|
||||
|
Loading…
x
Reference in New Issue
Block a user