فهرست منبع

complete dcd for lpc175x_6x
cdc device demo can work but there is hardfault with dma descriptor with fast typing

hathach 12 سال پیش
والد
کامیت
2dafeee585

+ 1 - 1
demos/device/device_os_none/cdcd_app.c

@@ -46,7 +46,7 @@
 // INCLUDE
 //--------------------------------------------------------------------+
 enum {
-  CDCD_APP_BUFFER_SIZE = 16
+  CDCD_APP_BUFFER_SIZE = 64
 };
 
 //--------------------------------------------------------------------+

+ 12 - 9
demos/device/device_os_none/tusb_descriptors.h

@@ -44,25 +44,28 @@
 //--------------------------------------------------------------------+
 // Endpoints Address & Max Packet Size
 //--------------------------------------------------------------------+
+#define EDPT_IN(x)    (0x80 | x)
+#define EDPT_OUT(x)   (x)
+
 //------------- CDC -------------//
-#define  CDC_EDPT_NOTIFICATION_ADDR           ENDPOINT_IN_LOGICAL_TO_PHYSICAL(2)
-#define  CDC_EDPT_NOTIFICATION_PACKETSIZE     64
+#define CDC_EDPT_NOTIFICATION_ADDR            EDPT_IN(1)
+#define CDC_EDPT_NOTIFICATION_PACKETSIZE      64
 
-#define  CDC_EDPT_DATA_OUT                    ENDPOINT_OUT_LOGICAL_TO_PHYSICAL(3)
-#define  CDC_EDPT_DATA_IN                     ENDPOINT_IN_LOGICAL_TO_PHYSICAL(3)
-#define  CDC_EDPT_DATA_PACKETSIZE             64
+#define CDC_EDPT_DATA_OUT                     EDPT_OUT(2)
+#define CDC_EDPT_DATA_IN                      EDPT_IN(2)
+#define CDC_EDPT_DATA_PACKETSIZE              64
 
 //------------- HID Keyboard -------------//
-#define  HID_EDPT_KEYBOARD_ADDR       ENDPOINT_IN_LOGICAL_TO_PHYSICAL(1)
+#define HID_EDPT_KEYBOARD_ADDR                EDPT_IN(3)
 
 //------------- HID Mouse -------------//
-#define  HID_MOUSE_EP_IN          ENDPOINT_IN_LOGICAL_TO_PHYSICAL(4)
+#define HID_MOUSE_EP_IN                       EDPT_IN(4)
 
 //------------- HID Generic -------------//
 
 //------------- Mass Storage -------------//
-#define MSC_EDPT_IN   ENDPOINT_IN_LOGICAL_TO_PHYSICAL(3)
-#define MSC_EDPT_OUT  ENDPOINT_OUT_LOGICAL_TO_PHYSICAL(3)
+#define MSC_EDPT_IN                           EDPT_IN(3)
+#define MSC_EDPT_OUT                          EDPT_OUT(3)
 
 
 //--------------------------------------------------------------------+

+ 227 - 64
tinyusb/device/dcd_lpc175x_6x.c

@@ -52,31 +52,28 @@
 //--------------------------------------------------------------------+
 // MACRO CONSTANT TYPEDEF
 //--------------------------------------------------------------------+
-STATIC_ ATTR_ALIGNED(128) dcd_dma_descriptor_t* dcd_udca[32] TUSB_CFG_ATTR_USBRAM;
-STATIC_ dcd_dma_descriptor_t  dcd_dd[DCD_MAX_DD];
+#define DCD_QHD_MAX 32
+#define DCD_QTD_MAX  32 // TODO scale with configure
+
+typedef struct {
+  volatile ATTR_ALIGNED(128) dcd_dma_descriptor_t* udca[DCD_QHD_MAX];
+  dcd_dma_descriptor_t dd[DCD_QTD_MAX];
+
+  uint8_t ddat[DCD_QHD_MAX]; ///< DMA Descriptor Allocation Table. A fixed DD will be allocated for a UDCA pointer up on endpoint open
+  uint8_t class_code[DCD_QHD_MAX];
+
+}dcd_data_t;
+
+STATIC_ dcd_data_t dcd_data TUSB_CFG_ATTR_USBRAM;
 
 //--------------------------------------------------------------------+
 // INTERNAL OBJECT & FUNCTION DECLARATION
 //--------------------------------------------------------------------+
 static void bus_reset(void);
 
-static inline void endpoint_set_max_packet_size(uint8_t endpoint_idx, uint16_t max_packet_size) ATTR_ALWAYS_INLINE;
-static inline void endpoint_set_max_packet_size(uint8_t endpoint_idx, uint16_t max_packet_size)
-{
-  LPC_USB->USBReEp    |= BIT_(endpoint_idx);
-  LPC_USB->USBEpInd    = endpoint_idx; // select index before setting packet size
-  LPC_USB->USBMaxPSize = max_packet_size;
-
-#ifndef _TEST_
-  if( endpoint_idx > 2) // endpoint control is always realized
-	{
-    while ((LPC_USB->USBDevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {} // TODO can be omitted, or move to set max packet size
-    LPC_USB->USBDevIntClr = DEV_INT_ENDPOINT_REALIZED_MASK;
-	}
-#endif
-
-}
-
+//--------------------------------------------------------------------+
+// SIE Command
+//--------------------------------------------------------------------+
 static inline void sie_cmd_code (sie_cmdphase_t phase, uint8_t code_data) ATTR_ALWAYS_INLINE;
 static inline void sie_cmd_code (sie_cmdphase_t phase, uint8_t code_data)
 {
@@ -110,22 +107,44 @@ static inline uint32_t sie_read (uint8_t cmd_code, uint8_t data_len)
   return LPC_USB->USBCmdData;
 }
 
+static inline void edpt_set_max_packet_size(uint8_t ep_id, uint16_t max_packet_size) ATTR_ALWAYS_INLINE;
+static inline void edpt_set_max_packet_size(uint8_t ep_id, uint16_t max_packet_size)
+{ // follows example in 11.10.4.2
+  LPC_USB->USBReEp    |= BIT_(ep_id);
+  LPC_USB->USBEpInd    = ep_id; // select index before setting packet size
+  LPC_USB->USBMaxPSize = max_packet_size;
+
+#ifndef _TEST_
+  if( ep_id > 2) // endpoint control is always realized
+	{
+    while ((LPC_USB->USBDevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {} // TODO can be omitted, or move to set max packet size
+    LPC_USB->USBDevIntClr = DEV_INT_ENDPOINT_REALIZED_MASK;
+	}
+#endif
+
+}
+
+static inline dcd_dma_descriptor_t* qhd_get_fixed_dd(uint8_t ep_id) ATTR_PURE ATTR_ALWAYS_INLINE;
+static inline dcd_dma_descriptor_t* qhd_get_fixed_dd(uint8_t ep_id)
+{
+  return &dcd_data.dd[ dcd_data.ddat[ep_id] ];
+}
+
 static tusb_error_t pipe_control_write(void const * buffer, uint16_t length);
 static tusb_error_t pipe_control_read(void * buffer, uint16_t length);
 
 //--------------------------------------------------------------------+
 // IMPLEMENTATION
 //--------------------------------------------------------------------+
-void endpoint_control_isr(uint8_t coreid)
+void endpoint_control_isr(void)
 {
-  (void) coreid; // suppress compiler warning
   uint32_t const endpoint_int_status = LPC_USB->USBEpIntSt & LPC_USB->USBEpIntEn;
 
   //------------- control OUT -------------//
   if (endpoint_int_status & BIT_(0))
   {
     uint32_t const endpoint_status = sie_read(SIE_CMDCODE_ENDPOINT_SELECT+0, 1);
-    if (endpoint_status & SIE_ENDPOINT_STATUS_SETUP_RECEIVED_MASK)
+    if (endpoint_status & SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK)
     {
       tusb_control_request_t control_request;
 
@@ -137,7 +156,6 @@ void endpoint_control_isr(uint8_t coreid)
     }else
     {
       // Current not support any out control with data yet
-//      pipe_control_read(0,..
     }
     sie_write(SIE_CMDCODE_ENDPOINT_SELECT+0, 0, 0);
     sie_write(SIE_CMDCODE_BUFFER_CLEAR     , 0, 0);
@@ -146,10 +164,16 @@ void endpoint_control_isr(uint8_t coreid)
   //------------- control IN -------------//
   if (endpoint_int_status & BIT_(1))
   {
-    (void) endpoint_int_status;
+    endpoint_handle_t edpt_hdl =
+    {
+        .index      = 1 //BIT_TEST_(int_status, 1) ? 1 : 0
+    };
+
+    // FIXME xferred_byte for control xfer is not needed now !!!
+    usbd_xfer_isr(edpt_hdl, TUSB_EVENT_XFER_COMPLETE, 0);
   }
 
-  LPC_USB->USBEpIntClr = endpoint_int_status; // acknowledge interrupt
+  LPC_USB->USBEpIntClr = endpoint_int_status; // acknowledge interrupt TODO cannot immediately acknowledge setup packet
 }
 
 void dcd_isr(uint8_t coreid)
@@ -173,20 +197,59 @@ void dcd_isr(uint8_t coreid)
     }
   }
 
-  //------------- slave mode, control endpoint -------------//
+  //------------- Control Endpoint (Slave Mode) -------------//
   if (device_int_status & DEV_INT_ENDPOINT_SLOW_MASK)
   {
     // only occur on control endpoint, all other use DMA
-    endpoint_control_isr(coreid);
+    endpoint_control_isr();
   }
 
-  if (device_int_status & DEV_INT_ERROR_MASK)
+  //------------- Non-Control Endpoint (DMA Mode) -------------//
+  uint32_t dma_int_status = LPC_USB->USBDMAIntSt & LPC_USB->USBDMAIntEn;
+
+  if (dma_int_status & DMA_INT_END_OF_XFER_MASK)
+  {
+    uint32_t eot_int = LPC_USB->USBEoTIntSt;
+    LPC_USB->USBEoTIntClr = eot_int; // acknowledge interrupt source
+
+    for(uint8_t ep_id = 2; ep_id < DCD_QHD_MAX; ep_id++ )
+    {
+      if ( BIT_TEST_(eot_int, ep_id) )
+      {
+        dcd_dma_descriptor_t* p_dd;
+        dcd_dma_descriptor_t* const p_fixed_dd = qhd_get_fixed_dd(ep_id);
+
+        p_fixed_dd->buffer_length = 0; // buffer length is used to determined if fixed dd is queued in pipe xfer function
+
+        // Maximum is 2 QTD are queued in an endpoint
+        if (p_fixed_dd->is_next_valid)
+        {
+          p_dd = (dcd_dma_descriptor_t*) p_fixed_dd->next;
+          p_dd->used = 0; // free non-fixed dd
+        }else
+        {
+          p_dd = p_fixed_dd;
+        }
+
+        endpoint_handle_t edpt_hdl =
+        {
+            .coreid     = 0,
+            .index      = ep_id,
+            .class_code = dcd_data.class_code[ep_id]
+        };
+        tusb_event_t event = (p_dd->status == DD_STATUS_NORMAL || p_dd->status == DD_STATUS_DATA_UNDERUN) ? TUSB_EVENT_XFER_COMPLETE : TUSB_EVENT_XFER_ERROR;
+
+        usbd_xfer_isr(edpt_hdl, event, p_dd->present_count); // only number of bytes in the IOC qtd
+      }
+    }
+  }
+
+  if (device_int_status & DEV_INT_ERROR_MASK || dma_int_status & DMA_INT_ERROR_MASK)
   {
     uint32_t error_status = sie_read(SIE_CMDCODE_READ_ERROR_STATUS, 1);
     (void) error_status;
 //    ASSERT(false, (void) 0);
   }
-
 }
 
 //--------------------------------------------------------------------+
@@ -200,32 +263,28 @@ static void bus_reset(void)
 	LPC_USB->USBEpIntEn      = (uint32_t) BIN8(11); // control endpoint cannot use DMA, non-control all use DMA
 	LPC_USB->USBEpIntPri     = 0;                   // same priority for all endpoint
 
-
 	// step 8 : DMA set up
 	LPC_USB->USBEpDMADis     = 0xFFFFFFFF; // firstly disable all dma
 	LPC_USB->USBDMARClr      = 0xFFFFFFFF; // clear all pending interrupt
 	LPC_USB->USBEoTIntClr    = 0xFFFFFFFF;
 	LPC_USB->USBNDDRIntClr   = 0xFFFFFFFF;
 	LPC_USB->USBSysErrIntClr = 0xFFFFFFFF;
+
+	memclr_(&dcd_data, sizeof(dcd_data_t));
 }
 
 tusb_error_t dcd_init(void)
 {
   //------------- user manual 11.13 usb device controller initialization -------------//  LPC_USB->USBEpInd = 0;
   // step 6 : set up control endpoint
-  endpoint_set_max_packet_size(0, TUSB_CFG_DEVICE_CONTROL_ENDOINT_SIZE);
-  endpoint_set_max_packet_size(1, TUSB_CFG_DEVICE_CONTROL_ENDOINT_SIZE);
+  edpt_set_max_packet_size(0, TUSB_CFG_DEVICE_CONTROL_ENDOINT_SIZE);
+  edpt_set_max_packet_size(1, TUSB_CFG_DEVICE_CONTROL_ENDOINT_SIZE);
 
   bus_reset();
 
-  LPC_USB->USBDevIntEn     = (DEV_INT_DEVICE_STATUS_MASK | DEV_INT_ENDPOINT_SLOW_MASK | DEV_INT_ERROR_MASK);
-
-	for (uint8_t index = 0; index < DCD_MAX_DD; index++)
-	{
-		dcd_udca[index] = dcd_dd + index;
-	}
-	LPC_USB->USBUDCAH    = (uint32_t) dcd_udca;
-	LPC_USB->USBDMAIntEn = (DMA_INT_END_OF_XFER_MASK | DMA_INT_NEW_DD_REQUEST_MASK | DMA_INT_ERROR_MASK );
+  LPC_USB->USBDevIntEn = (DEV_INT_DEVICE_STATUS_MASK | DEV_INT_ENDPOINT_SLOW_MASK | DEV_INT_ERROR_MASK);
+	LPC_USB->USBUDCAH    = (uint32_t) dcd_data.udca;
+	LPC_USB->USBDMAIntEn = (DMA_INT_END_OF_XFER_MASK | DMA_INT_ERROR_MASK );
 
 	// clear all stall on control endpoint IN & OUT if any
 	sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS    , 1, 0);
@@ -252,10 +311,10 @@ void dcd_controller_set_configuration(uint8_t coreid)
 }
 
 //--------------------------------------------------------------------+
-// PIPE API
+// PIPE CONTROL HELPER
 //--------------------------------------------------------------------+
-static inline uint16_t length_unit_byte2dword(uint16_t length_in_bytes) ATTR_ALWAYS_INLINE ATTR_CONST;
-static inline uint16_t length_unit_byte2dword(uint16_t length_in_bytes)
+static inline uint16_t length_byte2dword(uint16_t length_in_bytes) ATTR_ALWAYS_INLINE ATTR_CONST;
+static inline uint16_t length_byte2dword(uint16_t length_in_bytes)
 {
   return (length_in_bytes + 3) / 4; // length_in_dword
 }
@@ -267,7 +326,7 @@ static tusb_error_t pipe_control_write(void const * buffer, uint16_t length)
   LPC_USB->USBCtrl   = SLAVE_CONTROL_WRITE_ENABLE_MASK; // logical endpoint = 0
 	LPC_USB->USBTxPLen = length;
 
-	for (uint16_t count = 0; count < length_unit_byte2dword(length); count++)
+	for (uint16_t count = 0; count < length_byte2dword(length); count++)
 	{
 		LPC_USB->USBTxData = *((uint32_t *)buffer); // NOTE: cortex M3 have no problem with alignment
 		buffer += 4;
@@ -288,7 +347,7 @@ static tusb_error_t pipe_control_read(void * buffer, uint16_t length)
 
   uint16_t actual_length = min16_of(length, (uint16_t) (LPC_USB->USBRxPLen & SLAVE_RXPLEN_PACKET_LENGTH_MASK) );
   uint32_t *p_read_data = (uint32_t*) buffer;
-  for( uint16_t count=0; count < length_unit_byte2dword(actual_length); count++)
+  for( uint16_t count=0; count < length_byte2dword(actual_length); count++)
   {
     *p_read_data = LPC_USB->USBRxData;
     p_read_data++; // increase by 4 ( sizeof(uint32_t) )
@@ -298,18 +357,12 @@ static tusb_error_t pipe_control_read(void * buffer, uint16_t length)
   return TUSB_ERROR_NONE;
 }
 
-static inline uint8_t endpoint_address_to_physical_index(uint8_t ep_address) ATTR_ALWAYS_INLINE ATTR_CONST;
-static inline uint8_t endpoint_address_to_physical_index(uint8_t ep_address)
-{
-  return (ep_address << 1) + (ep_address & 0x80 ? 1 : 0 );
-}
-
 //--------------------------------------------------------------------+
 // CONTROL PIPE API
 //--------------------------------------------------------------------+
 void dcd_pipe_control_stall(uint8_t coreid)
 {
-  ASSERT(false, VOID_RETURN);
+  sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+0, 1, SIE_SET_ENDPOINT_STALLED_MASK | SIE_SET_ENDPOINT_CONDITION_STALLED_MASK);
 }
 
 tusb_error_t dcd_pipe_control_xfer(uint8_t coreid, tusb_direction_t dir, void * p_buffer, uint16_t length)
@@ -327,6 +380,27 @@ tusb_error_t dcd_pipe_control_xfer(uint8_t coreid, tusb_direction_t dir, void *
   return TUSB_ERROR_NONE;
 }
 
+//--------------------------------------------------------------------+
+// PIPE HELPER
+//--------------------------------------------------------------------+
+static inline uint8_t edpt_addr2phy(uint8_t endpoint_addr) ATTR_CONST ATTR_ALWAYS_INLINE;
+static inline uint8_t edpt_addr2phy(uint8_t endpoint_addr)
+{
+  return 2*(endpoint_addr & 0x0F) + ((endpoint_addr & TUSB_DIR_DEV_TO_HOST_MASK) ? 1 : 0);
+}
+
+// retval UINT8_MAX: invalid
+static inline uint8_t dd_find_free(void) ATTR_PURE ATTR_ALWAYS_INLINE;
+static inline uint8_t dd_find_free(void)
+{
+  for(uint8_t i=0; i<DCD_QTD_MAX; i++)
+  {
+    if (dcd_data.dd[i].used == 0) return i;
+  }
+
+  return UINT8_MAX;
+}
+
 //--------------------------------------------------------------------+
 // BULK/INTERRUPT/ISO PIPE API
 //--------------------------------------------------------------------+
@@ -334,38 +408,127 @@ endpoint_handle_t dcd_pipe_open(uint8_t coreid, tusb_descriptor_endpoint_t const
 {
   (void) coreid;
 
-  return (endpoint_handle_t) { 0 };
+  endpoint_handle_t const null_handle = { 0 };
 
-  uint8_t phy_ep = endpoint_address_to_physical_index( p_endpoint_desc->bEndpointAddress );
+  // TODO refractor to universal pipe open validation function
+  if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) return null_handle; // TODO not support ISO yet
+  ASSERT (p_endpoint_desc->wMaxPacketSize.size <= 64, null_handle); // TODO ISO can be 1023, but ISO not supported now
+
+  uint8_t ep_id = edpt_addr2phy( p_endpoint_desc->bEndpointAddress );
 
   //------------- Realize Endpoint with Max Packet Size -------------//
-  endpoint_set_max_packet_size(phy_ep, p_endpoint_desc->wMaxPacketSize.size);
+  edpt_set_max_packet_size(ep_id, p_endpoint_desc->wMaxPacketSize.size);
+
+	//------------- fixed DD prepare -------------//
+	uint8_t const dd_idx = dd_find_free();
+	ASSERT(dd_idx != UINT8_MAX, null_handle);
+
+	dcd_data.ddat[ep_id]       = dd_idx; // fixed this DD to UDCA for this endpoint
+	dcd_data.class_code[ep_id] = class_code;
 
-	//------------- DMA set up -------------//
-	memclr_(dcd_dd + phy_ep, sizeof(dcd_dma_descriptor_t));
-	dcd_dd[phy_ep].is_isochronous  = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
-	dcd_dd[phy_ep].max_packet_size = p_endpoint_desc->wMaxPacketSize.size;
-	dcd_dd[phy_ep].is_retired      = 1; // dd is not active at first
+	dcd_dma_descriptor_t* const p_dd = &dcd_data.dd[dd_idx];
+	memclr_(p_dd, sizeof(dcd_dma_descriptor_t));
 
-	LPC_USB->USBEpDMAEn = BIT_(phy_ep);
+	p_dd->used            = 1;
+	p_dd->is_isochronous  = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
+	p_dd->max_packet_size = p_endpoint_desc->wMaxPacketSize.size;
+	p_dd->is_retired      = 1; // inactive at first
 
-	sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+phy_ep, 1, 0); // clear all endpoint status
+	dcd_data.udca[ ep_id ] = p_dd; // hook to UDCA
 
+	sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, 0); // clear all endpoint status
+
+  return (endpoint_handle_t)
+      {
+          .coreid     = 0,
+          .index      = ep_id,
+          .class_code = class_code
+      };
 }
 
 bool dcd_pipe_is_busy(endpoint_handle_t edpt_hdl)
 {
-  ASSERT(false, false);
+  return (dcd_data.udca[edpt_hdl.index] != NULL && !dcd_data.udca[edpt_hdl.index]->is_retired);
+}
+
+tusb_error_t dcd_pipe_stall(endpoint_handle_t edpt_hdl)
+{
+  sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+edpt_hdl.index, 1, SIE_SET_ENDPOINT_STALLED_MASK);
+  return TUSB_ERROR_NONE;
 }
 
 tusb_error_t dcd_pipe_clear_stall(uint8_t coreid, uint8_t edpt_addr)
 {
+  uint8_t ep_id = edpt_addr2phy(edpt_addr);
+
+  sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, 0);
+
   return TUSB_ERROR_FAILED;
 }
 
+void dd_xfer_init(dcd_dma_descriptor_t* p_dd, void* buffer, uint16_t total_bytes)
+{
+  p_dd->next            = 0;
+  p_dd->is_next_valid   = 0;
+  p_dd->buffer_addr     = (uint32_t) buffer;
+  p_dd->buffer_length   = total_bytes;
+  p_dd->status          = DD_STATUS_NOT_SERVICED;
+}
+
+tusb_error_t dcd_pipe_queue_xfer(endpoint_handle_t edpt_hdl, void * buffer, uint16_t total_bytes)
+{ // NOTE for sure the qhd has no dds
+  ASSERT( !dcd_pipe_is_busy(edpt_hdl), TUSB_ERROR_INTERFACE_IS_BUSY); // endpoint must not in transferring
+
+  dcd_dma_descriptor_t* const p_dd = qhd_get_fixed_dd(edpt_hdl.index); // always queue with the fixed DD
+
+  dd_xfer_init(p_dd, buffer, total_bytes);
+//  p_dd->int_on_complete = 0;
+  p_dd->is_retired      = 1;
+
+  return TUSB_ERROR_NONE;
+}
+
 tusb_error_t dcd_pipe_xfer(endpoint_handle_t edpt_hdl, void * buffer, uint16_t total_bytes, bool int_on_complete)
 {
-  ASSERT_STATUS(TUSB_ERROR_FAILED);
+  ASSERT( !dcd_pipe_is_busy(edpt_hdl), TUSB_ERROR_INTERFACE_IS_BUSY); // endpoint must not in transferring
+
+  dcd_dma_descriptor_t* const p_fixed_dd = qhd_get_fixed_dd(edpt_hdl.index);
+
+  if ( p_fixed_dd->buffer_length )
+  { // fixed DD is already queued a xfer
+    //------------- setup new dd -------------//
+    uint8_t dd_idx = dd_find_free();
+    ASSERT( dd_idx != UINT8_MAX, TUSB_ERROR_DCD_NOT_ENOUGH_QTD);
+
+    dcd_dma_descriptor_t* const p_dd = &dcd_data.dd[ dd_idx ];
+    memclr_(p_dd, sizeof(dcd_dma_descriptor_t));
+
+    dd_xfer_init(p_dd, buffer, total_bytes);
+
+    p_dd->used            = 1;
+    p_dd->max_packet_size = p_fixed_dd->max_packet_size;
+    p_dd->is_isochronous  = p_fixed_dd->is_isochronous;
+//    p_dd->int_on_complete = int_on_complete;
+
+    //------------- hook to fixed dd -------------//
+    p_fixed_dd->next          = (uint32_t) p_dd;
+    p_fixed_dd->is_next_valid = 1;
+  } else
+  { // fixed DD is free
+    dd_xfer_init(p_fixed_dd, buffer, total_bytes);
+//    p_fixed_dd->int_on_complete = int_on_complete;
+  }
+
+  p_fixed_dd->is_retired = 0;
+
+  dcd_data.udca[edpt_hdl.index] = p_fixed_dd;
+
+  LPC_USB->USBEpDMAEn = BIT_(edpt_hdl.index);
+
+  if ( edpt_hdl.index % 2 )
+  { // endpoint IN
+    LPC_USB->USBDMARSet = BIT_(edpt_hdl.index);
+  }
 
   return TUSB_ERROR_NONE;
 }

+ 19 - 15
tinyusb/device/dcd_lpc175x_6x.h

@@ -61,13 +61,13 @@ typedef struct
 	//------------- Word 1 -------------//
 	uint16_t mode            : 2; // either 00 normal or 01 ATLE(auto length extraction)
 	uint16_t is_next_valid   : 1;
-	uint16_t                 : 1;
+	uint16_t used            : 1; ///< make use of reserved bit
 	uint16_t is_isochronous  : 1; // is an iso endpoint
 	uint16_t max_packet_size : 11;
 	volatile uint16_t buffer_length;
 
 	//------------- Word 2 -------------//
-	volatile uint32_t buffer_start_addr;
+	volatile uint32_t buffer_addr;
 
 	//------------- Word 3 -------------//
 	volatile uint16_t is_retired                   : 1; // initialized to zero
@@ -77,18 +77,15 @@ typedef struct
 	volatile uint16_t atle_is_msb_extracted        : 1;	// used in ATLE mode
 	volatile uint16_t atle_message_length_position : 6; // used in ATLE mode
 	uint16_t                                       : 2;
+//	         uint16_t int_on_complete              : 1; ///< make use of reserved bit
 	volatile uint16_t present_count; // The number of bytes transferred by the DMA engine. The DMA engine updates this field after completing each packet transfer.
 
 	//------------- Word 4 -------------//
 //	uint32_t iso_packet_size_addr;		// iso only, can be omitted for non-iso
 } ATTR_ALIGNED(4) dcd_dma_descriptor_t;
 
-#define DCD_MAX_DD 32 // TODO scale with configure
+STATIC_ASSERT( sizeof(dcd_dma_descriptor_t) == 16, "size is not correct"); // TODO not support ISO for now
 
-//typedef struct {
-//  dcd_dma_descriptor_t dd[DCD_MAX_DD];
-//
-//}dcd_data_t;
 
 //--------------------------------------------------------------------+
 // Register Interface
@@ -178,17 +175,24 @@ enum {
   SIE_DEV_STATUS_RESET_MASK          = BIT_(4)
 };
 
-//------------- SIE Endpoint Status -------------//
+//------------- SIE Select Endpoint Command -------------//
 enum {
-  SIE_ENDPOINT_STATUS_FULL_EMPTY_MASK         = BIT_(0), // 0: empty, 1 full. IN endpoint checks empty, OUT endpoint check full
-  SIE_ENDPOINT_STATUS_STALL_MASK              = BIT_(1),
-  SIE_ENDPOINT_STATUS_SETUP_RECEIVED_MASK     = BIT_(2), // clear by SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT
-  SIE_ENDPOINT_STATUS_PACKET_OVERWRITTEN_MASK = BIT_(3), // previous packet is overwritten by a SETUP packet
-  SIE_ENDPOINT_STATUS_NAK_MASK                = BIT_(4), // last packet response is NAK (auto clear by an ACK)
-  SIE_ENDPOINT_STATUS_BUFFER1_FULL_MASK       = BIT_(5),
-  SIE_ENDPOINT_STATUS_BUFFER2_FULL_MASK       = BIT_(6)
+  SIE_SELECT_ENDPOINT_FULL_EMPTY_MASK         = BIT_(0), // 0: empty, 1 full. IN endpoint checks empty, OUT endpoint check full
+  SIE_SELECT_ENDPOINT_STALL_MASK              = BIT_(1),
+  SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK     = BIT_(2), // clear by SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT
+  SIE_SELECT_ENDPOINT_PACKET_OVERWRITTEN_MASK = BIT_(3), // previous packet is overwritten by a SETUP packet
+  SIE_SELECT_ENDPOINT_NAK_MASK                = BIT_(4), // last packet response is NAK (auto clear by an ACK)
+  SIE_SELECT_ENDPOINT_BUFFER1_FULL_MASK       = BIT_(5),
+  SIE_SELECT_ENDPOINT_BUFFER2_FULL_MASK       = BIT_(6)
 };
 
+typedef enum {
+  SIE_SET_ENDPOINT_STALLED_MASK           = BIT_(0),
+  SIE_SET_ENDPOINT_DISABLED_MASK          = BIT_(5),
+  SIE_SET_ENDPOINT_RATE_FEEDBACK_MASK     = BIT_(6),
+  SIE_SET_ENDPOINT_CONDITION_STALLED_MASK = BIT_(7),
+}sie_endpoint_set_status_mask_t;
+
 //------------- DMA Descriptor Status -------------//
 enum {
   DD_STATUS_NOT_SERVICED = 0,