Browse Source

add nrf52 walkaround for errata 104, 171, 187.

clean up osal_none
hathach 8 years ago
parent
commit
9be8e7bef6

+ 44 - 44
tinyusb/osal/osal_none.h

@@ -74,27 +74,27 @@ static inline osal_task_t osal_task_create(osal_func_t code, const char* name, u
   return (osal_task_t) 1;
 }
 
-#define TASK_RESTART \
+#define TASK_RESTART                             \
   _state = 0
 
-#define OSAL_TASK_BEGIN \
-  static uint16_t _state = 0;               \
-  ATTR_UNUSED static uint32_t _timeout = 0; \
-  (void) _timeout;                          \
-  switch(_state) {                          \
+#define OSAL_TASK_BEGIN                          \
+  static uint16_t _state = 0;                    \
+  ATTR_UNUSED static uint32_t _timeout = 0;      \
+  (void) _timeout;                               \
+  switch(_state) {                               \
     case 0: {
 
-#define OSAL_TASK_END \
-  default:  TASK_RESTART; break; \
-  }}\
+#define OSAL_TASK_END                            \
+  default:  TASK_RESTART; break;                 \
+  }}                                             \
   return;
 
-#define osal_task_delay(msec) \
-  do {\
-    _timeout = tusb_hal_millis();\
-    _state = __LINE__; case __LINE__:\
+#define osal_task_delay(msec)                    \
+  do {                                           \
+    _timeout = tusb_hal_millis();                \
+    _state = __LINE__; case __LINE__:            \
       if ( _timeout + msec > tusb_hal_millis() ) \
-        return TUSB_ERROR_OSAL_WAITING;\
+        return TUSB_ERROR_OSAL_WAITING;          \
   }while(0)
 
 //--------------------------------------------------------------------+
@@ -156,23 +156,21 @@ static inline void osal_queue_flush(osal_queue_t const queue_hdl)
   queue_hdl->count = queue_hdl->rd_idx = queue_hdl->wr_idx = 0;
 }
 
-#define osal_queue_receive(queue_hdl, p_data, msec, p_error) \
-  do {\
-    _timeout = tusb_hal_millis();\
-    _state = __LINE__; case __LINE__:\
-    if( queue_hdl->count == 0 ) {\
-      if ( (msec != OSAL_TIMEOUT_WAIT_FOREVER) && ( _timeout + msec <= tusb_hal_millis()) ) /* time out */ \
-        *(p_error) = TUSB_ERROR_OSAL_TIMEOUT;\
-      else\
-        return TUSB_ERROR_OSAL_WAITING;\
-    } else{\
-      /*TODO mutex lock tusb_hal_int_disable */\
-      memcpy(p_data, queue_hdl->buffer + (queue_hdl->rd_idx * queue_hdl->item_size), queue_hdl->item_size);\
-      queue_hdl->rd_idx = (queue_hdl->rd_idx + 1) % queue_hdl->depth;\
-      queue_hdl->count--;\
-      /*TODO mutex unlock tusb_hal_int_enable */\
-      *(p_error) = TUSB_ERROR_NONE;\
-    }\
+#define osal_queue_receive(queue_hdl, p_data, msec, p_error)                                \
+  do {                                                                                      \
+    _timeout = tusb_hal_millis();                                                           \
+    _state = __LINE__; case __LINE__:                                                       \
+    if( queue_hdl->count == 0 ) {                                                           \
+      if ( (msec != OSAL_TIMEOUT_WAIT_FOREVER) && ( _timeout + msec <= tusb_hal_millis()) ) \
+        *(p_error) = TUSB_ERROR_OSAL_TIMEOUT;                                               \
+      else                                                                                  \
+        return TUSB_ERROR_OSAL_WAITING;                                                     \
+    } else{                                                                                 \
+      /*tusb_hal_int_disable_all();*/                                                       \
+      fifo_read(queue_hdl, p_data);                                                         \
+      /*tusb_hal_int_enable_all();*/                                                            \
+      *(p_error) = TUSB_ERROR_NONE;                                                         \
+    }                                                                                       \
   }while(0)
 
 
@@ -210,19 +208,21 @@ static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
   sem_hdl->count = 0;
 }
 
-#define osal_semaphore_wait(sem_hdl, msec, p_error) \
-  do {\
-    _timeout = tusb_hal_millis();\
-    _state = __LINE__; case __LINE__:\
-    if( sem_hdl->count == 0 ) {\
-      if ( (msec != OSAL_TIMEOUT_WAIT_FOREVER) && (_timeout + msec <= tusb_hal_millis()) ) /* time out */ \
-        *(p_error) = TUSB_ERROR_OSAL_TIMEOUT;\
-      else\
-        return TUSB_ERROR_OSAL_WAITING;\
-    } else{\
-      if (sem_hdl->count) sem_hdl->count--; /*TODO mutex tusb_hal_int_disable consideration*/\
-      *(p_error) = TUSB_ERROR_NONE;\
-    }\
+#define osal_semaphore_wait(sem_hdl, msec, p_error)                                        \
+  do {                                                                                     \
+    _timeout = tusb_hal_millis();                                                          \
+    _state = __LINE__; case __LINE__:                                                      \
+    if( sem_hdl->count == 0 ) {                                                            \
+      if ( (msec != OSAL_TIMEOUT_WAIT_FOREVER) && (_timeout + msec <= tusb_hal_millis()) ) \
+        *(p_error) = TUSB_ERROR_OSAL_TIMEOUT;                                              \
+      else                                                                                 \
+        return TUSB_ERROR_OSAL_WAITING;                                                    \
+    } else{                                                                                \
+      /*tusb_hal_int_disable_all();*/                                                          \
+      sem_hdl->count--;                                                                    \
+      /*tusb_hal_int_enable_all();*/                                                           \
+      *(p_error) = TUSB_ERROR_NONE;                                                        \
+    }                                                                                      \
   }while(0)
 
 //--------------------------------------------------------------------+

+ 63 - 16
tinyusb/portable/nordic/nrf5x/dcd_nrf5x.c

@@ -64,10 +64,14 @@ enum
 typedef struct
 {
   uint8_t* buffer;
+
   uint16_t total_len;
   uint16_t actual_len;
 
   uint8_t  mps; // max packet size
+
+  // FIXME Errata 104 walkaround
+  uint16_t frame_num;
 } nom_xfer_t;
 
 /*static*/ struct
@@ -80,7 +84,7 @@ typedef struct
   }control;
 
   // Non control: 7 endpoints IN & OUT (offset 1)
-  nom_xfer_t xfer[2][7];
+  nom_xfer_t xfer[7][2];
 
   volatile bool dma_running;
 }_dcd;
@@ -227,14 +231,14 @@ bool dcd_control_xfer (uint8_t rhport, tusb_dir_t dir, uint8_t * buffer, uint16_
  *------------------------------------------------------------------*/
 static void normal_xact_start(uint8_t epnum, uint8_t dir)
 {
-  nom_xfer_t* xfer = &_dcd.xfer[dir][epnum-1];
+  nom_xfer_t* xfer = &_dcd.xfer[epnum-1][dir];
 
   // Each transaction is up to Max Packet Size
   uint8_t const xact_len = min16_of(xfer->total_len - xfer->actual_len, xfer->mps);
 
   if ( dir == TUSB_DIR_OUT )
   {
-    // HW issue on nrf5284 sample, SIZE.EPOUT won't trigger ACK as spec
+    // Errata 135: HW issue on nrf5284 sample, SIZE.EPOUT won't trigger ACK as spec
     // use the back door interface as sdk for walk around
     if ( nrf_drv_usbd_errata_sizeepout_rw() )
     {
@@ -266,7 +270,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
   uint8_t const epnum = edpt_number(desc_edpt->bEndpointAddress);
   uint8_t const dir   = edpt_dir(desc_edpt->bEndpointAddress);
 
-  _dcd.xfer[dir][epnum-1].mps = desc_edpt->wMaxPacketSize.size;
+  _dcd.xfer[epnum-1][dir].mps = desc_edpt->wMaxPacketSize.size;
 
   if ( dir == TUSB_DIR_OUT )
   {
@@ -289,9 +293,17 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
   uint8_t const epnum = edpt_number(ep_addr);
   uint8_t const dir   = edpt_dir(ep_addr);
 
-  _dcd.xfer[dir][epnum-1].buffer     = buffer;
-  _dcd.xfer[dir][epnum-1].total_len  = total_bytes;
-  _dcd.xfer[dir][epnum-1].actual_len = 0;
+  nom_xfer_t* xfer = &_dcd.xfer[epnum-1][dir];
+
+  xfer->buffer     = buffer;
+  xfer->total_len  = total_bytes;
+  xfer->actual_len = 0;
+
+  // FIXME Errata 104 walkaround
+  if ( nrf_drv_usbd_errata_104() )
+  {
+    xfer->frame_num  = (uint16_t) NRF_USBD->FRAMECNTR;
+  }
 
   normal_xact_start(epnum, dir);
 
@@ -340,7 +352,7 @@ bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr)
   uint8_t const epnum = edpt_number(ep_addr);
   uint8_t const dir   = edpt_dir(ep_addr);
 
-  nom_xfer_t* xfer = &_dcd.xfer[dir][epnum-1];
+  nom_xfer_t* xfer = &_dcd.xfer[epnum-1][dir];
 
   return xfer->actual_len < xfer->total_len;
 }
@@ -376,11 +388,6 @@ void USBD_IRQHandler(void)
     dcd_bus_event(0, USBD_BUS_EVENT_RESET);
   }
 
-  if ( int_status & USBD_INTEN_SOF_Msk )
-  {
-    dcd_bus_event(0, USBD_BUS_EVENT_SOF);
-  }
-
   if ( int_status & EDPT_END_ALL_MASK )
   {
     // DMA complete move data from SRAM -> Endpoint
@@ -444,7 +451,7 @@ void USBD_IRQHandler(void)
     {
       if ( BIT_TEST_(data_status, epnum ) )
       {
-        nom_xfer_t* xfer = &_dcd.xfer[TUSB_DIR_IN][epnum-1];
+        nom_xfer_t* xfer = &_dcd.xfer[epnum-1][TUSB_DIR_IN];
 
         xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT;
 
@@ -465,7 +472,7 @@ void USBD_IRQHandler(void)
     {
       if ( BIT_TEST_(data_status, 16+epnum ) )
       {
-        nom_xfer_t* xfer = &_dcd.xfer[TUSB_DIR_OUT][epnum-1];
+        nom_xfer_t* xfer = &_dcd.xfer[epnum-1][TUSB_DIR_OUT];
 
         uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum];
 
@@ -486,7 +493,7 @@ void USBD_IRQHandler(void)
   {
     if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum) )
     {
-      nom_xfer_t* xfer = &_dcd.xfer[TUSB_DIR_OUT][epnum-1];
+      nom_xfer_t* xfer = &_dcd.xfer[epnum-1][TUSB_DIR_OUT];
 
       // Transfer complete if transaction len < Max Packet Size or total len is transferred
       if ( (NRF_USBD->EPOUT[epnum].AMOUNT == xfer->mps) && (xfer->actual_len < xfer->total_len) )
@@ -517,6 +524,46 @@ void USBD_IRQHandler(void)
     }
   }
 
+
+  // SOF interrupt
+  if ( int_status & USBD_INTEN_SOF_Msk )
+  {
+    // 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 the queued IN transfer, retire all transfer if 10 frames has passed
+      for (int i=0; i<7; i++)
+      {
+        nom_xfer_t* xfer = &_dcd.xfer[i][TUSB_DIR_IN];
+
+        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)
+          {
+            xfer->actual_len = xfer->total_len;
+            dcd_xfer_complete(0, (i+1) | TUSB_DIR_IN_MASK, xfer->actual_len, true);
+          }
+        }
+      }
+    }
+
+    dcd_bus_event(0, USBD_BUS_EVENT_SOF);
+  }
+
+
 }
 
 #endif

+ 70 - 4
tinyusb/portable/nordic/nrf5x/hal_nrf5x.c

@@ -199,6 +199,40 @@ void power_usb_event_handler(uint32_t event)
         nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK);
 
         /* Enable the peripheral */
+        // ERRATA 171, 187
+
+        if (nrf_drv_usbd_errata_187())
+        {
+//          CRITICAL_REGION_ENTER();
+          if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
+          {
+            *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
+            *((volatile uint32_t *)(0x4006ED14)) = 0x00000003;
+            *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
+          }
+          else
+          {
+            *((volatile uint32_t *)(0x4006ED14)) = 0x00000003;
+          }
+//          CRITICAL_REGION_EXIT();
+        }
+
+        if (nrf_drv_usbd_errata_171())
+        {
+//          CRITICAL_REGION_ENTER();
+          if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
+          {
+            *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
+            *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0;
+            *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
+          }
+          else
+          {
+            *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0;
+          }
+//          CRITICAL_REGION_EXIT();
+        }
+
         nrf_usbd_enable();
 
         // Enable HFCLK
@@ -212,6 +246,39 @@ void power_usb_event_handler(uint32_t event)
       nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK);
       nrf_usbd_event_clear(NRF_USBD_EVENT_USBEVENT);
 
+      if (nrf_drv_usbd_errata_171())
+      {
+//          CRITICAL_REGION_ENTER();
+          if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
+          {
+              *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
+              *((volatile uint32_t *)(0x4006EC14)) = 0x00000000;
+              *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
+          }
+          else
+          {
+              *((volatile uint32_t *)(0x4006EC14)) = 0x00000000;
+          }
+
+//          CRITICAL_REGION_EXIT();
+      }
+
+      if (nrf_drv_usbd_errata_187())
+      {
+//          CRITICAL_REGION_ENTER();
+          if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
+          {
+              *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
+              *((volatile uint32_t *)(0x4006ED14)) = 0x00000000;
+              *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
+          }
+          else
+          {
+              *((volatile uint32_t *)(0x4006ED14)) = 0x00000000;
+          }
+//          CRITICAL_REGION_EXIT();
+      }
+
       if ( nrf_drv_usbd_errata_166() )
       {
         *((volatile uint32_t *) (NRF_USBD_BASE + 0x800)) = 0x7E3;
@@ -227,10 +294,9 @@ void power_usb_event_handler(uint32_t event)
                            USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk |  USBD_INTEN_ENDEPOUT0_Msk |
                            USBD_INTEN_EPDATA_Msk   | USBD_INTEN_SOF_Msk;
 
-      //  if (enable_sof || nrf_drv_usbd_errata_104())
-      //  {
-      //    ints_to_enable |= NRF_USBD_INT_SOF_MASK;
-      //  }
+      // FIXME Errata 104: USB complete event is not generated (happedn randomly).
+      // Requires to enable SOF to perform clean up task.
+      // nrf_drv_usbd_errata_104()
 
       // Enable interrupt, Priorities 0,1,4,5 (nRF52) are reserved for SoftDevice
       NVIC_SetPriority(USBD_IRQn, 7);

+ 27 - 0
tinyusb/tusb_hal.h

@@ -78,6 +78,33 @@ void tusb_hal_int_disable(uint8_t rhport);
 // Only required to implement if using No RTOS (osal_none)
 uint32_t tusb_hal_millis(void);
 
+
+// Enable all ports' interrupt
+static inline void tusb_hal_int_enable_all(void)
+{
+#ifdef TUSB_CFG_CONTROLLER_0_MODE
+  tusb_hal_int_enable(0);
+#endif
+
+#ifdef TUSB_CFG_CONTROLLER_0_MODE
+  tusb_hal_int_enable(1);
+#endif
+}
+
+// Disable all ports' interrupt
+static inline void tusb_hal_int_disable_all(void)
+{
+#ifdef TUSB_CFG_CONTROLLER_0_MODE
+  tusb_hal_int_disable(0);
+#endif
+
+#ifdef TUSB_CFG_CONTROLLER_0_MODE
+  tusb_hal_int_disable(1);
+#endif
+}
+
+
+
 #ifdef __cplusplus
  }
 #endif

+ 2 - 0
tinyusb/tusb_option.h

@@ -45,6 +45,7 @@
 #define TUSB_VERSION_NAME   "alpha"
 #define TUSB_VERSION        XSTRING_(TUSB_VERSION_YEAR) "." XSTRING_(TUSB_VERSION_MONTH)
 
+// TODO remove, use vendor specific flag
 /** \defgroup group_mcu Supported MCU
  * \ref TUSB_CFG_MCU must be defined to one of these
  *  @{ */
@@ -57,6 +58,7 @@
 #define MCU_LPC43XX        7 ///< NXP LPC43xx family
 /** @} */
 
+// Allow to use command line to change the config name/location
 #ifndef TUSB_CFG_CONFIG_FILE
   #define TUSB_CFG_CONFIG_FILE "tusb_config.h"
 #endif