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);
     }
 

Reply via email to