Browse Source

add Errata 104 for out transfer, seems to work with cdc bootloader

hathach 8 years ago
parent
commit
8af60fded3
1 changed files with 64 additions and 40 deletions
  1. 64 40
      tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c

+ 64 - 40
tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c

@@ -74,6 +74,7 @@ typedef struct
 
   // FIXME Errata 104 walkaround
   uint16_t frame_num;
+  uint8_t  prev_size;
 } nom_xfer_t;
 
 /*static*/ struct
@@ -142,7 +143,10 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num)
 static void edpt_dma_start(uint8_t epnum, uint8_t dir)
 {
   // Only one dma could be active, TODO resolve when this is called in ISR and dma is running
-  while ( _dcd.dma_running ) { }
+  while ( _dcd.dma_running ) 
+  {
+    TU_ASSERT ( 0 == (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk), );
+  }
 
   _dcd.dma_running = true;
 
@@ -187,25 +191,6 @@ static void control_xact_start(void)
   _dcd.control.len    -= xact_len;
 }
 
-//static void control_xact_done(void)
-//{
-//  if ( _dcd_data.control.xfer_len > 0 )
-//  {
-//    if ( _dcd_data.control.dir == TUSB_DIR_OUT )
-//    {
-//      // out control need to wait for END EPOUT event before updating Pointer
-//      edpt_dma_start(0, TUSB_DIR_OUT);
-//    }else
-//    {
-//      control_xact_start();
-//    }
-//  }else
-//  {
-//    dcd_xfer_complete(0, 0, 0, true);
-//  }
-//}
-
-
 bool dcd_control_xfer (uint8_t rhport, tusb_dir_t dir, uint8_t * buffer, uint16_t length)
 {
   (void) rhport;
@@ -310,7 +295,8 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
   // FIXME Errata 104 walkaround
   if ( nrf_drv_usbd_errata_104() )
   {
-    xfer->frame_num  = (uint16_t) NRF_USBD->FRAMECNTR;
+    xfer->frame_num = (uint16_t) NRF_USBD->FRAMECNTR;
+    xfer->prev_size = NRF_USBD->SIZE.EPOUT[epnum];
   }
 
   normal_xact_start(epnum, dir);
@@ -360,22 +346,35 @@ bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr)
 /*------------------------------------------------------------------*/
 /*
  *------------------------------------------------------------------*/
+
+static uint16_t frame_sofar(uint16_t fr)
+{
+  uint16_t diff = (uint16_t) NRF_USBD->FRAMECNTR;
+
+  if ( diff > fr )
+  {
+    diff -= fr;
+  }else
+  {
+    diff = (diff + 1024) - fr; // Frame counter cap at 1024
+  }
+}
+
 void USBD_IRQHandler(void)
 {
   uint32_t const inten  = NRF_USBD->INTEN;
   uint32_t int_status = 0;
 
-  volatile uint32_t* regclr = &NRF_USBD->EVENTS_USBRESET;
+  volatile uint32_t* regevt = &NRF_USBD->EVENTS_USBRESET;
 
   for(int i=0; i<32; i++)
   {
-    if ( BIT_TEST_(inten, i) && regclr[i]  )
+    if ( BIT_TEST_(inten, i) && regevt[i]  )
     {
       int_status |= BIT_(i);
 
-      // nrf_usbd_event_clear()
-      regclr[i] = 0;
-
+      // event clear
+      regevt[i] = 0;
       __ISB(); __DSB();
     }
   }
@@ -426,9 +425,9 @@ void USBD_IRQHandler(void)
     }
   }
 
+  // OUT data moved from Endpoint -> SRAM
   if ( int_status & USBD_INTEN_ENDEPOUT0_Msk)
   {
-    // OUT data moved from Endpoint -> SRAM
     if ( _dcd.control.len > 0 )
     {
       control_xact_start();
@@ -476,6 +475,14 @@ void USBD_IRQHandler(void)
 
         uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum];
 
+        TU_ASSERT(xfer->actual_len < xfer->total_len, );
+        // FIXME Errata 104 walkaround
+        if ( nrf_drv_usbd_errata_104() )
+        {
+          xfer->prev_size = xact_len;
+          xfer->frame_num = (uint16_t) NRF_USBD->FRAMECNTR;
+        }
+
         // Trigger DMA move data from Endpoint -> SRAM
         NRF_USBD->EPOUT[epnum].PTR    = (uint32_t) xfer->buffer;
         NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
@@ -516,12 +523,39 @@ void USBD_IRQHandler(void)
   // SOF interrupt
   if ( int_status & USBD_INTEN_SOF_Msk )
   {
-#if 0
+    dcd_bus_event(0, USBD_BUS_EVENT_SOF);
+
+#if 1
     // FIXME Errata 104 The EPDATA event might not be generated, and the related update of EPDATASTATUS does not occur.
     // There is no way for software to tell if a xfer is complete or not.
     // Walkaround: we will asssume an non-control IN transfer is always complete after 10 frames
     if ( nrf_drv_usbd_errata_104() )
     {
+      // Check all OUT transfer, if the SIZE changes --> consider it is complete
+      for (int ep=1; ep<= 8; ep++)
+      {
+        nom_xfer_t* xfer = get_td(ep, TUSB_DIR_OUT);
+        if ((xfer->actual_len < xfer->total_len) && (xfer->prev_size != NRF_USBD->SIZE.EPOUT[ep]) )
+        {
+          if ( frame_sofar(xfer->frame_num) > 2)
+          {
+            uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[ep];
+            xfer->prev_size = xact_len;
+            xfer->frame_num = (uint16_t) NRF_USBD->FRAMECNTR;
+
+            // Trigger DMA move data from Endpoint -> SRAM
+            NRF_USBD->EPOUT[ep].PTR    = (uint32_t) xfer->buffer;
+            NRF_USBD->EPOUT[ep].MAXCNT = xact_len;
+
+            edpt_dma_start(ep, TUSB_DIR_OUT);
+
+            xfer->buffer     += xact_len;
+            xfer->actual_len += xact_len;
+          }
+        }
+      }
+
+#if 0
       // Check all the queued IN transfer, retire all transfer if 10 frames has passed
       for (int ep=1; ep<= 8; ep++)
       {
@@ -529,28 +563,18 @@ void USBD_IRQHandler(void)
 
         if (xfer->actual_len < xfer->total_len)
         {
-          uint16_t diff = (uint16_t) NRF_USBD->FRAMECNTR;
-
-          if ( diff > xfer->frame_num )
-          {
-            diff -= xfer->frame_num;
-          }else
-          {
-            diff = (diff + 1024) - xfer->frame_num; // Frame counter cap at 1024
-          }
-
           // Walkaround, mark this transfer as complete
-          if (diff > 10)
+          if (frame_sofar(xfer->frame_num) > 10)
           {
             xfer->actual_len = xfer->total_len;
             dcd_xfer_complete(0, ep | TUSB_DIR_IN_MASK, xfer->actual_len, true);
           }
         }
       }
+#endif
     }
 #endif
 
-    dcd_bus_event(0, USBD_BUS_EVENT_SOF);
   }