This is an automated email from the ASF dual-hosted git repository. lupyuen pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 0b0769f8d97c81542d9d56d7e7ac1dc07a160a1d Author: daniellizewski <[email protected]> AuthorDate: Mon May 4 10:59:44 2026 -0400 arch/arm/src/stm32h5/stm32_usbdrdhost.c: Disable host channel when freed The host interrupt callback was incorrectly using the wrong IRQ for disconnected. In host mode the same IRQ is used for connect/disconnected and it must check a status bit to know which one. When a USB device was unplugged, the host channels were free'd, but if they happen to be mid-transfer, that transfer was never cancelled so the USB hardware might still be trying to perfrom a transfer after was free'd. Fixed by cancelling any transfers on free. Signed-off-by: daniellizewski <[email protected]> --- arch/arm/src/stm32h5/hardware/stm32_usbfs.h | 2 +- arch/arm/src/stm32h5/stm32_usbdrdhost.c | 32 ++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/arch/arm/src/stm32h5/hardware/stm32_usbfs.h b/arch/arm/src/stm32h5/hardware/stm32_usbfs.h index b4d800c986e..2f90303f545 100644 --- a/arch/arm/src/stm32h5/hardware/stm32_usbfs.h +++ b/arch/arm/src/stm32h5/hardware/stm32_usbfs.h @@ -174,7 +174,7 @@ #define USB_ISTR_PMAOVRN (1 << 14) /* Bit 14: Packet Memory Area Over / Underrun */ #define USB_ISTR_CTR (1 << 15) /* Bit 15: Correct Transfer */ #define USB_ISTR_THR512 (1 << 16) /* Bit 16: 512byte threshold interrupt */ -#define USB_ISTR_DDISC (1 << 17) /* Bit 17: Device disconnection */ +#define USB_ISTR_DDISC (1 << 17) /* Bit 17: Device connection */ #define USB_ISTR_DCON_STAT (1 << 29) /* Bit 29: Device connection status */ #define USB_ISTR_LS_DCONN (1 << 30) /* Bit 30: Low-speed device connected */ diff --git a/arch/arm/src/stm32h5/stm32_usbdrdhost.c b/arch/arm/src/stm32h5/stm32_usbdrdhost.c index 953fecd041b..46fb168b718 100644 --- a/arch/arm/src/stm32h5/stm32_usbdrdhost.c +++ b/arch/arm/src/stm32h5/stm32_usbdrdhost.c @@ -267,6 +267,10 @@ static int stm32_chan_wait(struct stm32_usbhost_s *priv, int timeout_ms); static void stm32_chan_wakeup(struct stm32_usbhost_s *priv, struct stm32_chan_s *chan); +static void stm32_set_chep_rx_status(struct stm32_usbhost_s *priv, + int chidx, uint32_t status); +static void stm32_set_chep_tx_status(struct stm32_usbhost_s *priv, + int chidx, uint32_t status); /* Control endpoint helpers */ @@ -579,6 +583,7 @@ static int stm32_chan_alloc(struct stm32_usbhost_s *priv) priv->chan[chidx].inuse = true; priv->chan[chidx].pmabufno = (uint8_t)bufno; priv->chan[chidx].pmaaddr = STM32H5_PMA_BUFNO2ADDR(bufno); + uinfo("Channel allocated: chidx=%d\n", chidx); return chidx; } } @@ -607,9 +612,12 @@ static inline void stm32_chan_free(struct stm32_usbhost_s *priv, if (chan->pmabufno != STM32H5_PMA_BUFFER_NONE) { + stm32_set_chep_rx_status(priv, chidx, USB_CHEP_RX_STRX_DIS); + stm32_set_chep_tx_status(priv, chidx, USB_CHEP_TX_STTX_DIS); stm32_pma_free_buffer(priv, chan->pmabufno); chan->pmabufno = STM32H5_PMA_BUFFER_NONE; chan->pmaaddr = 0; + uinfo("Channel freed: chidx=%d\n", chidx); } chan->inuse = false; @@ -1534,9 +1542,19 @@ static void stm32_hc_in_irq(struct stm32_usbhost_s *priv, int chidx) if (!transfer_complete && (chan->waiter || chan->callback)) { + /* Clear VTRX by writing 0 to it + * (toggle bit, write 1 keeps, write 0 clears) + */ + + chepval = stm32_getreg(STM32H5_USB_CHEP(chidx)); + chepval = (chepval & + (0xffff7fff & USB_CHEP_REG_MASK)) | USB_CHEP_VTTX; + stm32_putreg(STM32H5_USB_CHEP(chidx), chepval); + /* More data expected - reactivate channel for next packet */ stm32_transfer_start(priv, chidx); + return; } else { @@ -1737,7 +1755,10 @@ static int stm32_usbdrd_interrupt(int irq, void *context, void *arg) istr = stm32_getreg(STM32_USB_ISTR); - /* Device connection */ + /* Device connection/Disconnection. The STM32H5 has both USB_ISTR_DDISC + * and USB_ISTR_RESET to detect a connected device. Use USB_ISTR_RESET + * since it is signaled after 22 cycles (debounced) + */ if ((istr & USB_ISTR_RESET) != 0) { @@ -1745,15 +1766,20 @@ static int stm32_usbdrd_interrupt(int irq, void *context, void *arg) { stm32_gint_connected(priv); } + else + { + stm32_gint_disconnected(priv); + } stm32_putreg(STM32_USB_ISTR, ~USB_ISTR_RESET); } - /* Device disconnection */ + /* Device connection */ if ((istr & USB_ISTR_DDISC) != 0) { - stm32_gint_disconnected(priv); + /* Not used. USB_ISTR_RESET used instead */ + stm32_putreg(STM32_USB_ISTR, ~USB_ISTR_DDISC); }
