diff options
| author | hathach <[email protected]> | 2018-11-29 22:24:09 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2018-11-29 22:24:09 +0700 |
| commit | 861e7e6a7982c3e2b7e3c05b566eb06cd32b15c4 (patch) | |
| tree | 4443ddb0fd7e0bc7197f7f9a101b4f3494731388 /src | |
| parent | ac66133ec065ec752742a39080187f6cb6e10dd8 (diff) | |
| parent | 57b85262b21333b3fe59f8abaeddda59c86b808b (diff) | |
Merge pull request #17 from hathach/devlocal
dcd lpc17xx update
Diffstat (limited to 'src')
| -rw-r--r-- | src/class/cdc/cdc_device.c | 12 | ||||
| -rw-r--r-- | src/class/cdc/cdc_device.h | 2 | ||||
| -rw-r--r-- | src/class/hid/hid_device.c | 1 | ||||
| -rw-r--r-- | src/class/msc/msc_device.c | 5 | ||||
| -rw-r--r-- | src/class/msc/msc_device.h | 6 | ||||
| -rw-r--r-- | src/device/usbd.c | 14 | ||||
| -rw-r--r-- | src/device/usbd_auto_desc.c | 63 | ||||
| -rw-r--r-- | src/device/usbd_control.c | 6 | ||||
| -rw-r--r-- | src/portable/microchip/samd51/dcd_samd51.c | 4 | ||||
| -rw-r--r-- | src/portable/nordic/nrf5x/dcd_nrf5x.c | 7 | ||||
| -rw-r--r-- | src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c | 741 | ||||
| -rw-r--r-- | src/portable/nxp/lpc17xx/dcd_lpc175x_6x.h | 78 | ||||
| -rw-r--r-- | src/portable/nxp/lpc17xx/hal_lpc175x_6x.c | 6 | ||||
| -rw-r--r-- | src/portable/nxp/lpc43xx_lpc18xx/dcd_lpc43xx.c | 9 | ||||
| -rw-r--r-- | src/tusb_option.h | 28 |
15 files changed, 508 insertions, 474 deletions
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index b68a6a7ff..040c8d4f4 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -302,6 +302,8 @@ tusb_error_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface // return false to stall control endpoint (e.g Host send non-sense DATA)
bool cdcd_control_request_complete(uint8_t rhport, tusb_control_request_t const * request)
{
+ (void) rhport;
+
//------------- Class Specific Request -------------//
TU_VERIFY (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
@@ -358,8 +360,10 @@ bool cdcd_control_request(uint8_t rhport, tusb_control_request_t const * request return true;
}
-tusb_error_t cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
+tusb_error_t cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
+ (void) result;
+
// TODO Support multiple interfaces
uint8_t const itf = 0;
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
@@ -367,16 +371,14 @@ tusb_error_t cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, // receive new data
if ( ep_addr == p_cdc->ep_out )
{
- char const wanted = p_cdc->wanted_char;
-
for(uint32_t i=0; i<xferred_bytes; i++)
{
tu_fifo_write(&p_cdc->rx_ff, &p_cdc->epout_buf[i]);
// Check for wanted char and invoke callback if needed
- if ( tud_cdc_rx_wanted_cb && ( wanted != -1 ) && ( wanted == p_cdc->epout_buf[i] ) )
+ if ( tud_cdc_rx_wanted_cb && ( ((signed char) p_cdc->wanted_char) != -1 ) && ( p_cdc->wanted_char == p_cdc->epout_buf[i] ) )
{
- tud_cdc_rx_wanted_cb(itf, wanted);
+ tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char);
}
}
diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index ad1100e9c..0a17aa916 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -116,7 +116,7 @@ void cdcd_init (void); tusb_error_t cdcd_open (uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
bool cdcd_control_request (uint8_t rhport, tusb_control_request_t const * p_request);
bool cdcd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
-tusb_error_t cdcd_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t event, uint32_t xferred_bytes);
+tusb_error_t cdcd_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes);
void cdcd_reset (uint8_t rhport);
#endif
diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index c89c15acc..6e2ea27db 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -418,7 +418,6 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque if (p_request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT)
{
- // Cast away the const on p_hid->desc_report because we know it won't be modified.
usbd_control_xfer(rhport, p_request, (void *)p_hid->desc_report, p_hid->desc_len);
}else
{
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 88f8da6db..4fc3dd1b5 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -146,6 +146,7 @@ void mscd_init(void) void mscd_reset(uint8_t rhport)
{
+ (void) rhport;
tu_memclr(&_mscd_itf, sizeof(mscd_interface_t));
}
@@ -201,6 +202,9 @@ bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque // return false to stall control endpoint (e.g Host send non-sense DATA)
bool mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
{
+ (void) rhport;
+ (void) p_request;
+
// nothing to do
return true;
}
@@ -208,6 +212,7 @@ bool mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const // return length of response (copied to buffer), -1 if it is not an built-in commands
int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t bufsize)
{
+ (void) bufsize; // TODO refractor later
int32_t ret;
switch ( p_cbw->command[0] )
diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index c4476f56f..4053679b8 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -71,12 +71,6 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct"); #error CFG_TUD_MSC_PRODUCT_REV 4-byte string must be defined
#endif
-// TODO highspeed device is 512
-#ifndef CFG_TUD_MSC_EPSIZE
-#define CFG_TUD_MSC_EPSIZE 64
-#endif
-
-
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/src/device/usbd.c b/src/device/usbd.c index 8c7e588e0..81fcfe959 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -170,7 +170,7 @@ static osal_queue_t _usbd_q; //--------------------------------------------------------------------+
static void mark_interface_endpoint(uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
-static bool process_set_config(uint8_t rhport, uint8_t config_number);
+static bool process_set_config(uint8_t rhport);
static void const* get_descriptor(tusb_control_request_t const * p_request, uint16_t* desc_len);
void usbd_control_reset (uint8_t rhport);
@@ -356,7 +356,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const dcd_set_config(rhport, config);
_usbd_dev.config_num = config;
- TU_ASSERT( TUSB_ERROR_NONE == process_set_config(rhport, config) );
+ TU_ASSERT( TUSB_ERROR_NONE == process_set_config(rhport) );
}
break;
@@ -427,7 +427,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const // Process Set Configure Request
// This function parse configuration descriptor & open drivers accordingly
-static bool process_set_config(uint8_t rhport, uint8_t config_number)
+static bool process_set_config(uint8_t rhport)
{
uint8_t const * desc_cfg = (uint8_t const *) usbd_desc_set->config;
TU_ASSERT(desc_cfg != NULL);
@@ -591,23 +591,23 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) // helper to send bus signal event
void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr)
{
- dcd_event_t event = { .rhport = 0, .event_id = eid, };
+ dcd_event_t event = { .rhport = rhport, .event_id = eid, };
dcd_event_handler(&event, in_isr);
}
// helper to send setup received
void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr)
{
- dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_SETUP_RECEIVED };
+ dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED };
memcpy(&event.setup_received, setup, 8);
- dcd_event_handler(&event, true);
+ dcd_event_handler(&event, in_isr);
}
// helper to send transfer complete event
void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr)
{
- dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_XFER_COMPLETE };
+ dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_XFER_COMPLETE };
event.xfer_complete.ep_addr = ep_addr;
event.xfer_complete.len = xferred_bytes;
diff --git a/src/device/usbd_auto_desc.c b/src/device/usbd_auto_desc.c index 2d54a934d..028d1b433 100644 --- a/src/device/usbd_auto_desc.c +++ b/src/device/usbd_auto_desc.c @@ -101,18 +101,19 @@ enum ITF_NUM_TOTAL }; -enum { - ITF_STR_LANGUAGE = 0 , - ITF_STR_MANUFACTURER , - ITF_STR_PRODUCT , - ITF_STR_SERIAL , +enum +{ + ITF_STR_LANGUAGE = 0 , + ITF_STR_MANUFACTURER , + ITF_STR_PRODUCT , + ITF_STR_SERIAL , #if CFG_TUD_CDC - ITF_STR_CDC , + ITF_STR_CDC , #endif #if CFG_TUD_MSC - ITF_STR_MSC , + ITF_STR_MSC , #endif #if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT @@ -133,23 +134,51 @@ enum { #define _EP_OUT(x) (x) // CDC -#define EP_CDC_NOTIF _EP_IN ( ITF_NUM_CDC+1 ) +#ifdef CFG_TUD_DESC_CDC_EPNUM_NOTIF + #define EP_CDC_NOTIF _EP_IN (CFG_TUD_DESC_CDC_EPNUM_NOTIF) +#else + #define EP_CDC_NOTIF _EP_IN ( ITF_NUM_CDC+1 ) +#endif #define EP_CDC_NOTIF_SIZE 8 -#define EP_CDC_OUT _EP_OUT( ITF_NUM_CDC+2 ) -#define EP_CDC_IN _EP_IN ( ITF_NUM_CDC+2 ) +#ifdef CFG_TUD_DESC_CDC_EPNUM + #define EP_CDC_OUT _EP_OUT( CFG_TUD_DESC_CDC_EPNUM ) + #define EP_CDC_IN _EP_IN ( CFG_TUD_DESC_CDC_EPNUM ) +#else + #define EP_CDC_OUT _EP_OUT( ITF_NUM_CDC+2 ) + #define EP_CDC_IN _EP_IN ( ITF_NUM_CDC+2 ) +#endif // Mass Storage -#define EP_MSC_OUT _EP_OUT( ITF_NUM_MSC+1 ) -#define EP_MSC_IN _EP_IN ( ITF_NUM_MSC+1 ) +#ifdef CFG_TUD_DESC_MSC_EPNUM + #define EP_MSC_OUT _EP_OUT( CFG_TUD_DESC_MSC_EPNUM ) + #define EP_MSC_IN _EP_IN ( CFG_TUD_DESC_MSC_EPNUM ) +#else + #define EP_MSC_OUT _EP_OUT( ITF_NUM_MSC+1 ) + #define EP_MSC_IN _EP_IN ( ITF_NUM_MSC+1 ) +#endif + +#if TUD_OPT_HIGH_SPEED +#define EP_MSC_SIZE 512 +#else +#define EP_MSC_SIZE 64 +#endif // HID Keyboard with boot protocol -#define EP_HID_KBD_BOOT _EP_IN ( ITF_NUM_HID_BOOT_KBD+1 ) +#ifdef CFG_TUD_DESC_HID_KEYBOARD_EPNUM + #define EP_HID_KBD_BOOT _EP_IN ( CFG_TUD_DESC_HID_KEYBOARD_EPNUM ) +#else + #define EP_HID_KBD_BOOT _EP_IN ( ITF_NUM_HID_BOOT_KBD+1 ) +#endif #define EP_HID_KBD_BOOT_SZ 8 // HID Mouse with boot protocol -#define EP_HID_MSE_BOOT _EP_IN ( ITF_NUM_HID_BOOT_MSE+1 ) +#ifdef CFG_TUD_DESC_HID_MOUSE_EPNUM + #define EP_HID_MSE_BOOT _EP_IN ( CFG_TUD_DESC_HID_MOUSE_EPNUM ) +#else + #define EP_HID_MSE_BOOT _EP_IN ( ITF_NUM_HID_BOOT_MSE+1 ) +#endif #define EP_HID_MSE_BOOT_SZ 8 // HID composite = keyboard + mouse + gamepad + etc ... @@ -466,7 +495,7 @@ desc_auto_cfg_t const _desc_auto_config_struct = .bDescriptorType = TUSB_DESC_ENDPOINT, .bEndpointAddress = EP_MSC_OUT, .bmAttributes = { .xfer = TUSB_XFER_BULK }, - .wMaxPacketSize = { .size = CFG_TUD_MSC_EPSIZE}, + .wMaxPacketSize = { .size = EP_MSC_SIZE}, .bInterval = 1 }, @@ -476,7 +505,7 @@ desc_auto_cfg_t const _desc_auto_config_struct = .bDescriptorType = TUSB_DESC_ENDPOINT, .bEndpointAddress = EP_MSC_IN, .bmAttributes = { .xfer = TUSB_XFER_BULK }, - .wMaxPacketSize = { .size = CFG_TUD_MSC_EPSIZE}, + .wMaxPacketSize = { .size = EP_MSC_SIZE}, .bInterval = 1 } }, @@ -563,7 +592,6 @@ desc_auto_cfg_t const _desc_auto_config_struct = #endif // boot mouse #if AUTO_DESC_HID_GENERIC - //------------- HID Generic Multiple report -------------// .hid_generic = { @@ -601,7 +629,6 @@ desc_auto_cfg_t const _desc_auto_config_struct = .bInterval = 0x0A } } - #endif // hid generic }; diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index 31d74edf0..ebeaaaa4d 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -68,6 +68,7 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t _usbd_ctrl_buf[CFG_TUD_ENDOINT0_ void usbd_control_reset (uint8_t rhport)
{
+ (void) rhport;
tu_varclr(&_control_state);
}
@@ -126,8 +127,11 @@ bool usbd_control_xfer(uint8_t rhport, tusb_control_request_t const * request, v }
// callback when a transaction complete on DATA stage of control endpoint
-bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
+bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
+ (void) result;
+ (void) ep_addr;
+
if ( _control_state.request.bmRequestType_bit.direction == TUSB_DIR_OUT )
{
memcpy(_control_state.buffer, _usbd_ctrl_buf, xferred_bytes);
diff --git a/src/portable/microchip/samd51/dcd_samd51.c b/src/portable/microchip/samd51/dcd_samd51.c index e76b5a1fa..d0ad17f92 100644 --- a/src/portable/microchip/samd51/dcd_samd51.c +++ b/src/portable/microchip/samd51/dcd_samd51.c @@ -84,11 +84,11 @@ bool dcd_init (uint8_t rhport) void dcd_connect (uint8_t rhport) { - + (void) rhport; } void dcd_disconnect (uint8_t rhport) { - + (void) rhport; } void dcd_set_address (uint8_t rhport, uint8_t dev_addr) diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 4fb88689c..e1e53a83e 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -197,16 +197,17 @@ bool dcd_init (uint8_t rhport) void dcd_connect (uint8_t rhport) { - + (void) rhport; } void dcd_disconnect (uint8_t rhport) { - + (void) rhport; } void dcd_set_address (uint8_t rhport, uint8_t dev_addr) { (void) rhport; + (void) dev_addr; // Set Address is automatically update by hw controller } @@ -362,7 +363,7 @@ void USBD_IRQHandler(void) volatile uint32_t* regevt = &NRF_USBD->EVENTS_USBRESET; - for(int i=0; i<USBD_INTEN_EPDATA_Pos+1; i++) + for(uint8_t i=0; i<USBD_INTEN_EPDATA_Pos+1; i++) { if ( BIT_TEST_(inten, i) && regevt[i] ) { diff --git a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c b/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c index ce8362546..517f037d0 100644 --- a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c +++ b/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c @@ -40,259 +40,179 @@ #if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X)
-#define _TINY_USB_SOURCE_FILE_
-//--------------------------------------------------------------------+
-// INCLUDE
-//--------------------------------------------------------------------+
#include "device/dcd.h"
#include "dcd_lpc175x_6x.h"
-#include "usbd_dcd.h"
+#include "LPC17xx.h"
+
+#include "osal/osal.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
-#define DCD_QHD_MAX 32
-#define DCD_QTD_MAX 32 // TODO scale with configure
-
-typedef struct {
- volatile dcd_dma_descriptor_t* udca[DCD_QHD_MAX]; // must be 128 byte aligned
- dcd_dma_descriptor_t dd[DCD_QTD_MAX][2]; // each endpoints can have up to 2 DD queued at a time TODO 0-1 are not used, offset to reduce memory
+#define DCD_ENDPOINT_MAX 32
- uint8_t class_code[DCD_QHD_MAX];
+typedef struct ATTR_ALIGNED(4)
+{
+ //------------- Word 0 -------------//
+ uint32_t next;
- struct {
- uint8_t* p_data;
- uint16_t remaining_bytes;
- uint8_t int_on_complete;
- }control_dma;
+ //------------- Word 1 -------------//
+ uint16_t atle_mode : 2; // 00: normal, 01: ATLE (auto length extraction)
+ uint16_t next_valid : 1;
+ uint16_t : 1; ///< reserved
+ uint16_t isochronous : 1; // is an iso endpoint
+ uint16_t max_packet_size : 11;
-}dcd_data_t;
+ volatile uint16_t buflen; // bytes for non-iso, number of packets for iso endpoint
-CFG_TUSB_MEM_SECTION ATTR_ALIGNED(128) STATIC_VAR dcd_data_t dcd_data;
+ //------------- Word 2 -------------//
+ volatile uint32_t buffer;
-//--------------------------------------------------------------------+
-// INTERNAL OBJECT & FUNCTION DECLARATION
-//--------------------------------------------------------------------+
-static void bus_reset(void);
-static tusb_error_t pipe_control_read(void * buffer, uint16_t length);
-static tusb_error_t pipe_control_write(void const * buffer, uint16_t length);
-static tusb_error_t pipe_control_xfer(uint8_t ep_id, uint8_t* p_buffer, uint16_t length);
+ //------------- Word 3 -------------//
+ volatile uint16_t retired : 1; // initialized to zero
+ volatile uint16_t status : 4;
+ volatile uint16_t iso_last_packet_valid : 1;
+ volatile uint16_t atle_lsb_extracted : 1; // used in ATLE mode
+ volatile uint16_t atle_msb_extracted : 1; // used in ATLE mode
+ volatile uint16_t atle_mess_len_position : 6; // used in ATLE mode
+ uint16_t : 2;
-//--------------------------------------------------------------------+
-// 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_IN_MASK) ? 1 : 0);
-}
-
-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;
+ volatile uint16_t present_count; // For non-iso : The number of bytes transferred by the DMA engine
+ // For iso : number of packets
-#ifndef _TEST_
- while ((LPC_USB->USBDevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {} // TODO can be omitted
- LPC_USB->USBDevIntClr = DEV_INT_ENDPOINT_REALIZED_MASK;
-#endif
+ //------------- Word 4 -------------//
+ // uint32_t iso_packet_size_addr; // iso only, can be omitted for non-iso
+}dma_desc_t;
-}
+TU_VERIFY_STATIC( sizeof(dma_desc_t) == 16, "size is not correct"); // TODO not support ISO for now
-//--------------------------------------------------------------------+
-// USBD-DCD API
-//--------------------------------------------------------------------+
-static void bus_reset(void)
+typedef struct
{
- // step 7 : slave mode set up
- LPC_USB->USBEpIntClr = 0xFFFFFFFF; // clear all pending interrupt
- LPC_USB->USBDevIntClr = 0xFFFFFFFF; // clear all pending interrupt
- 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
+ // must be 128 byte aligned
+ volatile dma_desc_t* udca[DCD_ENDPOINT_MAX];
- // 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;
+ // TODO DMA does not support control transfer (0-1 are not used, offset to reduce memory)
+ dma_desc_t dd[DCD_ENDPOINT_MAX];
- tu_memclr(&dcd_data, sizeof(dcd_data_t));
-}
+ struct
+ {
+ uint8_t* out_buffer;
+ uint8_t out_bytes;
+ volatile bool out_received; // indicate if data is already received in endpoint
-bool dcd_init(uint8_t rhport)
-{
- (void) rhport;
+ uint8_t in_bytes;
+ } control;
- //------------- user manual 11.13 usb device controller initialization -------------// LPC_USB->USBEpInd = 0;
- // step 6 : set up control endpoint
- edpt_set_max_packet_size(0, CFG_TUD_ENDOINT0_SIZE);
- edpt_set_max_packet_size(1, CFG_TUD_ENDOINT0_SIZE);
+} dcd_data_t;
- bus_reset();
+ATTR_ALIGNED(128) static dcd_data_t _dcd;
- 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 );
- sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 1); // connect
+//--------------------------------------------------------------------+
+// SIE Command
+//--------------------------------------------------------------------+
+static void sie_cmd_code (sie_cmdphase_t phase, uint8_t code_data)
+{
+ LPC_USB->USBDevIntClr = (DEV_INT_COMMAND_CODE_EMPTY_MASK | DEV_INT_COMMAND_DATA_FULL_MASK);
+ LPC_USB->USBCmdCode = (phase << 8) | (code_data << 16);
- NVIC_EnableIRQ(USB_IRQn);
+ uint32_t const wait_flag = (phase == SIE_CMDPHASE_READ) ? DEV_INT_COMMAND_DATA_FULL_MASK : DEV_INT_COMMAND_CODE_EMPTY_MASK;
+ while ((LPC_USB->USBDevIntSt & wait_flag) == 0) {}
- return TUSB_ERROR_NONE;
+ LPC_USB->USBDevIntClr = wait_flag;
}
-static void endpoint_non_control_isr(uint32_t eot_int)
+static void sie_write (uint8_t cmd_code, uint8_t data_len, uint8_t data)
{
- for(uint8_t ep_id = 2; ep_id < DCD_QHD_MAX; ep_id++ )
- {
- if ( BIT_TEST_(eot_int, ep_id) )
- {
- dcd_dma_descriptor_t* const p_first_dd = &dcd_data.dd[ep_id][0];
- dcd_dma_descriptor_t* const p_last_dd = dcd_data.dd[ep_id] + (p_first_dd->is_next_valid ? 1 : 0); // Maximum is 2 QTD are queued in an endpoint
+ sie_cmd_code(SIE_CMDPHASE_COMMAND, cmd_code);
- // only handle when Controller already finished the last DD
- if ( dcd_data.udca[ep_id] == p_last_dd )
- {
- dcd_data.udca[ep_id] = p_first_dd; // UDCA currently points to the last DD, change to the fixed DD
- p_first_dd->buffer_length = 0; // buffer length is used to determined if first dd is queued in pipe xfer function
-
- if ( p_last_dd->int_on_complete )
- {
- edpt_hdl_t edpt_hdl =
- {
- .rhport = 0,
- .index = ep_id,
- .class_code = dcd_data.class_code[ep_id]
- };
- bool succeeded = (p_last_dd->status == DD_STATUS_NORMAL || p_last_dd->status == DD_STATUS_DATA_UNDERUN) ? true : false;
-
- dcd_xfer_complete(edpt_hdl, p_last_dd->present_count, succeeded); // report only xferred bytes in the IOC qtd
- }
- }
- }
+ if (data_len)
+ {
+ sie_cmd_code(SIE_CMDPHASE_WRITE, data);
}
}
-static void endpoint_control_isr(void)
+static uint32_t sie_read (uint8_t cmd_code, uint8_t data_len)
{
- uint32_t const interrupt_enable = LPC_USB->USBEpIntEn;
- uint32_t const endpoint_int_status = LPC_USB->USBEpIntSt & interrupt_enable;
-// LPC_USB->USBEpIntClr = endpoint_int_status; // acknowledge interrupt TODO cannot immediately acknowledge setup packet
-
- dcd_event_t event = { .rhport = 0 };
+ // TODO multiple read
+ sie_cmd_code(SIE_CMDPHASE_COMMAND , cmd_code);
+ sie_cmd_code(SIE_CMDPHASE_READ , cmd_code);
+ return LPC_USB->USBCmdData;
+}
- //------------- Setup Recieved-------------//
- if ( (endpoint_int_status & BIT_(0)) &&
- (sie_read(SIE_CMDCODE_ENDPOINT_SELECT+0, 1) & SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK) )
- {
- (void) sie_read(SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT+0, 1); // clear setup bit
+//--------------------------------------------------------------------+
+// PIPE HELPER
+//--------------------------------------------------------------------+
+static inline uint8_t ep_addr2idx(uint8_t ep_addr)
+{
+ return 2*(ep_addr & 0x0F) + ((ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0);
+}
- event.event_id = DCD_EVENT_SETUP_RECEIVED;
- pipe_control_read(&event.setup_received, 8); // TODO read before clear setup above
+static void set_ep_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;
- dcd_event_handler(&event, true);
- }
- else if (endpoint_int_status & 0x03)
- {
- uint8_t const ep_id = ( endpoint_int_status & BIT_(0) ) ? 0 : 1;
+ while ((LPC_USB->USBDevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {}
+ LPC_USB->USBDevIntClr = DEV_INT_ENDPOINT_REALIZED_MASK;
+}
- if ( dcd_data.control_dma.remaining_bytes > 0 )
- { // there are still data to transfer
- pipe_control_xfer(ep_id, dcd_data.control_dma.p_data, dcd_data.control_dma.remaining_bytes);
- }
- else
- {
- dcd_data.control_dma.remaining_bytes = 0;
- if ( BIT_TEST_(dcd_data.control_dma.int_on_complete, ep_id) )
- {
- edpt_hdl_t edpt_hdl = { .rhport = 0, .class_code = 0 };
- dcd_data.control_dma.int_on_complete = 0;
+//--------------------------------------------------------------------+
+// CONTROLLER API
+//--------------------------------------------------------------------+
+static void bus_reset(void)
+{
+ // step 7 : slave mode set up
+ LPC_USB->USBEpIntClr = 0xFFFFFFFF; // clear all pending interrupt
+ LPC_USB->USBDevIntClr = 0xFFFFFFFF; // clear all pending interrupt
+ LPC_USB->USBEpIntEn = 0x03UL; // control endpoint cannot use DMA, non-control all use DMA
+ LPC_USB->USBEpIntPri = 0x03UL; // fast for control endpoint
- // FIXME xferred_byte for control xfer is not needed now !!!
- dcd_xfer_complete(edpt_hdl, 0, true);
- }
- }
- }
+ // 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;
- LPC_USB->USBEpIntClr = endpoint_int_status; // acknowledge interrupt TODO cannot immediately acknowledge setup packet
+ tu_memclr(&_dcd, sizeof(dcd_data_t));
}
-void hal_dcd_isr(uint8_t rhport)
+bool dcd_init(uint8_t rhport)
{
(void) rhport;
- uint32_t const device_int_enable = LPC_USB->USBDevIntEn;
- uint32_t const device_int_status = LPC_USB->USBDevIntSt & device_int_enable;
- LPC_USB->USBDevIntClr = device_int_status;// Acknowledge handled interrupt
- dcd_event_t event = { .rhport = rhport };
+ //------------- user manual 11.13 usb device controller initialization -------------// LPC_USB->USBEpInd = 0;
+ // step 6 : set up control endpoint
+ set_ep_size(0, CFG_TUD_ENDOINT0_SIZE);
+ set_ep_size(1, CFG_TUD_ENDOINT0_SIZE);
- //------------- usb bus event -------------//
- if (device_int_status & DEV_INT_DEVICE_STATUS_MASK)
- {
- uint8_t const dev_status_reg = sie_read(SIE_CMDCODE_DEVICE_STATUS, 1);
- if (dev_status_reg & SIE_DEV_STATUS_RESET_MASK)
- {
- bus_reset();
+ bus_reset();
- event.event_id = DCD_EVENT_BUS_RESET;
- dcd_event_handler(&event, true);
- }
+ LPC_USB->USBDevIntEn = (DEV_INT_DEVICE_STATUS_MASK | DEV_INT_ENDPOINT_FAST_MASK | DEV_INT_ENDPOINT_SLOW_MASK | DEV_INT_ERROR_MASK);
+ 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);
- if (dev_status_reg & SIE_DEV_STATUS_CONNECT_CHANGE_MASK)
- { // device is disconnected, require using VBUS (P1_30)
- event.event_id = DCD_EVENT_UNPLUGGED;
- dcd_event_handler(&event, true);
- }
+ sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 1); // connect
- if (dev_status_reg & SIE_DEV_STATUS_SUSPEND_CHANGE_MASK)
- {
- if (dev_status_reg & SIE_DEV_STATUS_SUSPEND_MASK)
- {
- event.event_id = DCD_EVENT_SUSPENDED;
- dcd_event_handler(&event, true);
- }
-// else
-// { // resume signal
-// event.event_id = DCD_EVENT_RESUME;
-// dcd_event_handler(&event, true);
-// }
-// }
- }
- }
-
- //------------- Control Endpoint (Slave Mode) -------------//
- if (device_int_status & DEV_INT_ENDPOINT_SLOW_MASK)
+ // USB IRQ priority should be set by application previously
+ // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
+#if CFG_TUSB_OS == OPT_OS_FREERTOS
+ if ( NVIC_GetPriority(USB_IRQn) < configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY )
{
- endpoint_control_isr();
+ NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
}
+#endif
- //------------- Non-Control Endpoint (DMA Mode) -------------//
- uint32_t const dma_int_enable = LPC_USB->USBDMAIntEn;
- uint32_t const dma_int_status = LPC_USB->USBDMAIntSt & dma_int_enable;
-
- 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
-
- endpoint_non_control_isr(eot_int);
- }
+ NVIC_ClearPendingIRQ(USB_IRQn);
+ NVIC_EnableIRQ(USB_IRQn);
- 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;
-// TU_ASSERT(false, (void) 0);
- }
+ return TUSB_ERROR_NONE;
}
-//--------------------------------------------------------------------+
-// USBD API - CONTROLLER
-//--------------------------------------------------------------------+
void dcd_connect(uint8_t rhport)
{
(void) rhport;
@@ -313,65 +233,45 @@ void dcd_set_config(uint8_t rhport, uint8_t config_num) }
//--------------------------------------------------------------------+
-// PIPE CONTROL HELPER
+// CONTROL HELPER
//--------------------------------------------------------------------+
-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)
+static inline uint8_t byte2dword(uint8_t bytes)
{
- return (length_in_bytes + 3) / 4; // length_in_dword
+ return (bytes + 3) / 4; // length in dwords
}
-static tusb_error_t pipe_control_xfer(uint8_t ep_id, uint8_t* p_buffer, uint16_t length)
+static void control_ep_write(void const * buffer, uint8_t len)
{
- uint16_t const packet_len = tu_min16(length, CFG_TUD_ENDOINT0_SIZE);
-
- if (ep_id)
- {
- TU_ASSERT_ERR ( pipe_control_write(p_buffer, packet_len) );
- }else
- {
- TU_ASSERT_ERR ( pipe_control_read(p_buffer, packet_len) );
- }
-
- dcd_data.control_dma.remaining_bytes -= packet_len;
- dcd_data.control_dma.p_data += packet_len;
-
- return TUSB_ERROR_NONE;
-}
-
-static tusb_error_t pipe_control_write(void const * buffer, uint16_t length)
-{
- uint32_t const * p_write_data = (uint32_t const *) buffer;
+ uint32_t const * buf32 = (uint32_t const *) buffer;
LPC_USB->USBCtrl = USBCTRL_WRITE_ENABLE_MASK; // logical endpoint = 0
- LPC_USB->USBTxPLen = length;
-
- for (uint16_t count = 0; count < length_byte2dword(length); count++)
- {
- LPC_USB->USBTxData = *p_write_data; // NOTE: cortex M3 have no problem with alignment
- p_write_data++;
- }
+ LPC_USB->USBTxPLen = (uint32_t) len;
- LPC_USB->USBCtrl = 0;
+ for (uint8_t count = 0; count < byte2dword(len); count++)
+ {
+ LPC_USB->USBTxData = *buf32; // NOTE: cortex M3 have no problem with alignment
+ buf32++;
+ }
- // select control IN & validate the endpoint
- sie_write(SIE_CMDCODE_ENDPOINT_SELECT+1, 0, 0);
- sie_write(SIE_CMDCODE_BUFFER_VALIDATE , 0, 0);
+ LPC_USB->USBCtrl = 0;
- return TUSB_ERROR_NONE;
+ // select control IN & validate the endpoint
+ sie_write(SIE_CMDCODE_ENDPOINT_SELECT+1, 0, 0);
+ sie_write(SIE_CMDCODE_BUFFER_VALIDATE , 0, 0);
}
-static tusb_error_t pipe_control_read(void * buffer, uint16_t length)
+static uint8_t control_ep_read(void * buffer, uint8_t len)
{
LPC_USB->USBCtrl = USBCTRL_READ_ENABLE_MASK; // logical endpoint = 0
while ((LPC_USB->USBRxPLen & USBRXPLEN_PACKET_READY_MASK) == 0) {} // TODO blocking, should have timeout
- uint16_t actual_length = tu_min16(length, (uint16_t) (LPC_USB->USBRxPLen & USBRXPLEN_PACKET_LENGTH_MASK) );
- uint32_t *p_read_data = (uint32_t*) buffer;
- for( uint16_t count=0; count < length_byte2dword(actual_length); count++)
+ len = tu_min8(len, (uint8_t) (LPC_USB->USBRxPLen & USBRXPLEN_PACKET_LENGTH_MASK) );
+ uint32_t *buf32 = (uint32_t*) buffer;
+
+ for (uint8_t count=0; count < byte2dword(len); count++)
{
- *p_read_data = LPC_USB->USBRxData;
- p_read_data++; // increase by 4 ( sizeof(uint32_t) )
+ *buf32 = LPC_USB->USBRxData;
+ buf32++;
}
LPC_USB->USBCtrl = 0;
@@ -380,164 +280,323 @@ static tusb_error_t pipe_control_read(void * buffer, uint16_t length) sie_write(SIE_CMDCODE_ENDPOINT_SELECT+0, 0, 0);
sie_write(SIE_CMDCODE_BUFFER_CLEAR , 0, 0);
- return TUSB_ERROR_NONE;
+ return len;
}
//--------------------------------------------------------------------+
-// CONTROL PIPE API
+// DCD Endpoint Port
//--------------------------------------------------------------------+
-void dcd_control_stall(uint8_t rhport)
-{
- sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+0, 1, SIE_SET_ENDPOINT_STALLED_MASK | SIE_SET_ENDPOINT_CONDITION_STALLED_MASK);
-}
-
-bool dcd_control_xfer(uint8_t rhport, uint8_t dir, uint8_t * p_buffer, uint16_t length, bool int_on_complete)
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
{
(void) rhport;
- TU_VERIFY( !(length != 0 && p_buffer == NULL) );
+ uint8_t const epnum = edpt_number(p_endpoint_desc->bEndpointAddress);
+ uint8_t const ep_id = ep_addr2idx(p_endpoint_desc->bEndpointAddress);
- // determine Endpoint where Data & Status phase occurred (IN or OUT)
- uint8_t const ep_data = (dir == TUSB_DIR_IN) ? 1 : 0;
- uint8_t const ep_status = 1 - ep_data;
+ // Endpoint type is fixed to endpoint number
+ // 1: interrupt, 2: Bulk, 3: Iso and so on
+ switch ( p_endpoint_desc->bmAttributes.xfer )
+ {
+ case TUSB_XFER_INTERRUPT:
+ TU_ASSERT((epnum % 3) == 1);
+ break;
- dcd_data.control_dma.int_on_complete = int_on_complete ? BIT_(ep_status) : 0;
+ case TUSB_XFER_BULK:
+ TU_ASSERT((epnum % 3) == 2 || (epnum == 15));
+ break;
- //------------- Data Phase -------------//
- if ( length )
- {
- dcd_data.control_dma.p_data = (uint8_t*) p_buffer;
- dcd_data.control_dma.remaining_bytes = length;
+ case TUSB_XFER_ISOCHRONOUS:
+ TU_ASSERT((epnum % 3) == 3 && (epnum != 15));
+ break;
- // lpc17xx already received the first DATA OUT packet by now
- TU_VERIFY_ERR ( pipe_control_xfer(ep_data, p_buffer, length), false );
+ default:
+ break;
}
- //------------- Status Phase (opposite direct to Data) -------------//
- if (dir == TUSB_DIR_OUT)
- { // only write for CONTROL OUT, CONTROL IN data will be retrieved in hal_dcd_isr // TODO ????
- TU_VERIFY_ERR ( pipe_control_write(NULL, 0), false );
- }
+ //------------- Realize Endpoint with Max Packet Size -------------//
+ set_ep_size(ep_id, p_endpoint_desc->wMaxPacketSize.size);
+
+ //------------- first DD prepare -------------//
+ dma_desc_t* const dd = &_dcd.dd[ep_id];
+ tu_memclr(dd, sizeof(dma_desc_t));
+
+ dd->isochronous = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
+ dd->max_packet_size = p_endpoint_desc->wMaxPacketSize.size;
+ dd->retired = 1; // invalid at first
+
+ sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS + ep_id, 1, 0); // clear all endpoint status
return true;
}
-//--------------------------------------------------------------------+
-// BULK/INTERRUPT/ISO PIPE API
-//--------------------------------------------------------------------+
-edpt_hdl_t dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc, uint8_t class_code)
+bool dcd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
- edpt_hdl_t const null_handle = { 0 };
-
- // 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
- TU_ASSERT (p_endpoint_desc->wMaxPacketSize.size <= 64, null_handle); // TODO ISO can be 1023, but ISO not supported now
+ uint8_t ep_id = ep_addr2idx( ep_addr );
+ return (_dcd.udca[ep_id] != NULL && !_dcd.udca[ep_id]->retired);
+}
- uint8_t ep_id = edpt_addr2phy( p_endpoint_desc->bEndpointAddress );
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
- //------------- Realize Endpoint with Max Packet Size -------------//
- edpt_set_max_packet_size(ep_id, p_endpoint_desc->wMaxPacketSize.size);
- dcd_data.class_code[ep_id] = class_code;
+ if ( edpt_number(ep_addr) == 0 )
+ {
+ sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+0, 1, SIE_SET_ENDPOINT_STALLED_MASK | SIE_SET_ENDPOINT_CONDITION_STALLED_MASK);
+ }else
+ {
+ uint8_t ep_id = ep_addr2idx( ep_addr );
+ sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, SIE_SET_ENDPOINT_STALLED_MASK);
+ }
+}
- //------------- first DD prepare -------------//
- dcd_dma_descriptor_t* const p_dd = &dcd_data.dd[ep_id][0];
- tu_memclr(p_dd, sizeof(dcd_dma_descriptor_t));
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ uint8_t ep_id = ep_addr2idx(ep_addr);
- 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+ep_id, 1, 0);
+}
- dcd_data.udca[ ep_id ] = p_dd; // hook to UDCA
+bool dcd_edpt_stalled (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
- sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, 0); // clear all endpoint status
+ uint32_t const ep_state = sie_read(SIE_CMDCODE_ENDPOINT_SELECT + ep_addr2idx(ep_addr), 1);
- return (edpt_hdl_t)
- {
- .rhport = 0,
- .index = ep_id,
- .class_code = class_code
- };
+ return (ep_state & SIE_SELECT_ENDPOINT_STALL_MASK) ? true : false;
}
-bool dcd_edpt_busy(edpt_hdl_t edpt_hdl)
+static bool control_xact(uint8_t rhport, uint8_t dir, uint8_t * buffer, uint8_t len)
{
- return (dcd_data.udca[edpt_hdl.index] != NULL && !dcd_data.udca[edpt_hdl.index]->is_retired);
+ (void) rhport;
+
+ if ( dir )
+ {
+ _dcd.control.in_bytes = len;
+ control_ep_write(buffer, len);
+ }else
+ {
+ if ( _dcd.control.out_received )
+ {
+ // Already received the DATA OUT packet
+ _dcd.control.out_received = false;
+ _dcd.control.out_buffer = NULL;
+ _dcd.control.out_bytes = 0;
+
+ uint8_t received = control_ep_read(buffer, len);
+ dcd_event_xfer_complete(0, 0, received, XFER_RESULT_SUCCESS, true);
+ }else
+ {
+ _dcd.control.out_buffer = buffer;
+ _dcd.control.out_bytes = len;
+ }
+ }
+
+ return true;
}
-void dcd_edpt_stall(edpt_hdl_t edpt_hdl)
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
{
- sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+edpt_hdl.index, 1, SIE_SET_ENDPOINT_STALLED_MASK);
+ // Control transfer is not DMA support, and must be done in slave mode
+ if ( edpt_number(ep_addr) == 0 )
+ {
+ return control_xact(rhport, edpt_dir(ep_addr), buffer, (uint8_t) total_bytes);
+ }
+ else
+ {
+ uint8_t ep_id = ep_addr2idx(ep_addr);
+ dma_desc_t* dd = &_dcd.dd[ep_id];
+
+ // Prepare DMA descriptor
+ // Isochronous & max packet size must be preserved, Other fields of dd should be clear
+ uint16_t const ep_size = dd->max_packet_size;
+ uint8_t is_iso = dd->isochronous;
+
+ tu_memclr(dd, sizeof(dma_desc_t));
+ dd->isochronous = is_iso;
+ dd->max_packet_size = ep_size;
+ dd->buffer = buffer;
+ dd->buflen = total_bytes;
+
+ _dcd.udca[ep_id] = dd;
+
+ if ( ep_id % 2 )
+ {
+ // Clear EP interrupt before Enable DMA
+ LPC_USB->USBEpIntEn &= ~BIT_(ep_id);
+ LPC_USB->USBEpDMAEn = BIT_(ep_id);
+
+ // endpoint IN need to actively raise DMA request
+ LPC_USB->USBDMARSet = BIT_(ep_id);
+ }else
+ {
+ // Enable DMA
+ LPC_USB->USBEpDMAEn = BIT_(ep_id);
+ }
+
+ return true;
+ }
}
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+
+// handle control xfer (slave mode)
+static void control_xfer_isr(uint8_t rhport, uint32_t ep_int_status)
{
- uint8_t ep_id = ep_addr2phy(ep_addr);
+ // Control out complete
+ if ( ep_int_status & BIT_(0) )
+ {
+ bool is_setup = sie_read(SIE_CMDCODE_ENDPOINT_SELECT+0, 1) & SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK;
- sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, 0);
+ LPC_USB->USBEpIntClr = BIT_(0);
+
+ if (is_setup)
+ {
+ uint8_t setup_packet[8];
+ control_ep_read(setup_packet, 8); // TODO read before clear setup above
+
+ dcd_event_setup_received(rhport, setup_packet, true);
+ }
+ else if ( _dcd.control.out_buffer )
+ {
+ // software queued transfer previously
+ uint8_t received = control_ep_read(_dcd.control.out_buffer, _dcd.control.out_bytes);
+
+ _dcd.control.out_buffer = NULL;
+ _dcd.control.out_bytes = 0;
+
+ dcd_event_xfer_complete(rhport, 0, received, XFER_RESULT_SUCCESS, true);
+ }else
+ {
+ // hardware auto ack packet -> mark as received
+ _dcd.control.out_received = true;
+ }
+ }
+
+ // Control In complete
+ if ( ep_int_status & BIT_(1) )
+ {
+ LPC_USB->USBEpIntClr = BIT_(1);
+ dcd_event_xfer_complete(rhport, TUSB_DIR_IN_MASK, _dcd.control.in_bytes, XFER_RESULT_SUCCESS, true);
+ }
}
-void dd_xfer_init(dcd_dma_descriptor_t* p_dd, void* buffer, uint16_t total_bytes)
+// handle bus event signal
+static void bus_event_isr(uint8_t rhport)
{
- 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;
- p_dd->iso_last_packet_valid = 0;
- p_dd->present_count = 0;
-}
+ uint8_t const dev_status = sie_read(SIE_CMDCODE_DEVICE_STATUS, 1);
+ if (dev_status & SIE_DEV_STATUS_RESET_MASK)
+ {
+ bus_reset();
+ dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true);
+ }
-tusb_error_t dcd_edpt_queue_xfer(edpt_hdl_t edpt_hdl, uint8_t * buffer, uint16_t total_bytes)
-{ // NOTE for sure the qhd has no dds
- dcd_dma_descriptor_t* const p_fixed_dd = &dcd_data.dd[edpt_hdl.index][0]; // always queue with the fixed DD
+ if (dev_status & SIE_DEV_STATUS_CONNECT_CHANGE_MASK)
+ {
+ // device is disconnected, require using VBUS (P1_30)
+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+ }
- dd_xfer_init(p_fixed_dd, buffer, total_bytes);
- p_fixed_dd->is_retired = 1;
- p_fixed_dd->int_on_complete = 0;
+ if (dev_status & SIE_DEV_STATUS_SUSPEND_CHANGE_MASK)
+ {
+ if (dev_status & SIE_DEV_STATUS_SUSPEND_MASK)
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPENDED, true);
+ }
+ else
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ }
+ }
+}
- return TUSB_ERROR_NONE;
+// Helper to complete a DMA descriptor for non-control transfer
+static void dd_complete_isr(uint8_t rhport, uint8_t ep_id)
+{
+ dma_desc_t* const dd = &_dcd.dd[ep_id];
+ uint8_t result = (dd->status == DD_STATUS_NORMAL || dd->status == DD_STATUS_DATA_UNDERUN) ? XFER_RESULT_SUCCESS : XFER_RESULT_FAILED;
+ uint8_t const ep_addr = (ep_id / 2) | ((ep_id & 0x01) ? TUSB_DIR_IN_MASK : 0);
+
+ dcd_event_xfer_complete(rhport, ep_addr, dd->present_count, result, true);
}
-tusb_error_t dcd_edpt_xfer(edpt_hdl_t edpt_hdl, uint8_t* buffer, uint16_t total_bytes, bool int_on_complete)
+// main USB IRQ handler
+void hal_dcd_isr(uint8_t rhport)
{
- dcd_dma_descriptor_t* const p_first_dd = &dcd_data.dd[edpt_hdl.index][0];
+ uint32_t const dev_int_status = LPC_USB->USBDevIntSt & LPC_USB->USBDevIntEn;
+ LPC_USB->USBDevIntClr = dev_int_status;// Acknowledge handled interrupt
- //------------- fixed DD is already queued a xfer -------------//
- if ( p_first_dd->buffer_length )
+ // Bus event
+ if (dev_int_status & DEV_INT_DEVICE_STATUS_MASK)
{
- // setup new dd
- dcd_dma_descriptor_t* const p_dd = &dcd_data.dd[ edpt_hdl.index ][1];
- tu_memclr(p_dd, sizeof(dcd_dma_descriptor_t));
-
- dd_xfer_init(p_dd, buffer, total_bytes);
+ bus_event_isr(rhport);
+ }
- p_dd->max_packet_size = p_first_dd->max_packet_size;
- p_dd->is_isochronous = p_first_dd->is_isochronous;
- p_dd->int_on_complete = int_on_complete;
+ // Endpoint interrupt
+ uint32_t const ep_int_status = LPC_USB->USBEpIntSt & LPC_USB->USBEpIntEn;
- // hook to fixed dd
- p_first_dd->next = (uint32_t) p_dd;
- p_first_dd->is_next_valid = 1;
+ // Control Endpoint are fast
+ if (dev_int_status & DEV_INT_ENDPOINT_FAST_MASK)
+ {
+ // Note clear USBEpIntClr will also clear the setup received bit --> clear after handle setup packet
+ // Only clear USBEpIntClr 1 endpoint each, and should wait for CDFULL bit set
+ control_xfer_isr(rhport, ep_int_status);
}
- //------------- fixed DD is free -------------//
- else
+
+ // non-control IN are slow
+ if (dev_int_status & DEV_INT_ENDPOINT_SLOW_MASK)
{
- dd_xfer_init(p_first_dd, buffer, total_bytes);
- p_first_dd->int_on_complete = int_on_complete;
+ for ( uint8_t ep_id = 3; ep_id < DCD_ENDPOINT_MAX; ep_id += 2 )
+ {
+ if ( BIT_TEST_(ep_int_status, ep_id) )
+ {
+ LPC_USB->USBEpIntClr = BIT_(ep_id);
+
+ // Clear Ep interrupt for next DMA
+ LPC_USB->USBEpIntEn &= ~BIT_(ep_id);
+
+ dd_complete_isr(rhport, ep_id);
+ }
+ }
}
- p_first_dd->is_retired = 0; // activate xfer
- dcd_data.udca[edpt_hdl.index] = p_first_dd;
- LPC_USB->USBEpDMAEn = BIT_(edpt_hdl.index);
+ // DMA transfer complete (RAM <-> EP) for Non-Control
+ // OUT: USB transfer is fully complete
+ // IN : UBS transfer is still on-going -> enable EpIntEn to know when it is complete
+ uint32_t const dma_int_status = LPC_USB->USBDMAIntSt & LPC_USB->USBDMAIntEn;
+ if (dma_int_status & DMA_INT_END_OF_XFER_MASK)
+ {
+ uint32_t const eot = LPC_USB->USBEoTIntSt;
+ LPC_USB->USBEoTIntClr = eot; // acknowledge interrupt source
- if ( edpt_hdl.index % 2 )
- { // endpoint IN need to actively raise DMA request
- LPC_USB->USBDMARSet = BIT_(edpt_hdl.index);
+ for ( uint8_t ep_id = 2; ep_id < DCD_ENDPOINT_MAX; ep_id++ )
+ {
+ if ( BIT_TEST_(eot, ep_id) )
+ {
+ if ( ep_id & 0x01 )
+ {
+ // IN enable EpInt for end of usb transfer
+ LPC_USB->USBEpIntEn |= BIT_(ep_id);
+ }else
+ {
+ // OUT
+ dd_complete_isr(rhport, ep_id);
+ }
+ }
+ }
}
- return TUSB_ERROR_NONE;
+ // Errors
+ if ( (dev_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;
+ TU_BREAKPOINT();
+ }
}
#endif
diff --git a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.h b/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.h index 4746b4acf..d6b76fcd1 100644 --- a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.h +++ b/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.h @@ -36,53 +36,15 @@ */ /**************************************************************************/ -/** \ingroup group_dcd - * \defgroup group_dcd_lpc175x_6x LPC175x_6x - * @{ */ - #ifndef _TUSB_DCD_LPC175X_6X_H_ #define _TUSB_DCD_LPC175X_6X_H_ -#include <common/tusb_common.h> +#include "common/tusb_common.h" #ifdef __cplusplus extern "C" { #endif - -typedef struct ATTR_ALIGNED(4) -{ - //------------- Word 0 -------------// - uint32_t next; - - //------------- Word 1 -------------// - uint16_t mode : 2; // either 00 normal or 01 ATLE(auto length extraction) - uint16_t is_next_valid : 1; - uint16_t int_on_complete : 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_addr; - - //------------- Word 3 -------------// - volatile uint16_t is_retired : 1; // initialized to zero - volatile uint16_t status : 4; - volatile uint16_t iso_last_packet_valid : 1; - volatile uint16_t atle_is_lsb_extracted : 1; // used in ATLE mode - 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; - 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 -}dcd_dma_descriptor_t; - -TU_VERIFY_STATIC( sizeof(dcd_dma_descriptor_t) == 16, "size is not correct"); // TODO not support ISO for now - - //--------------------------------------------------------------------+ // Register Interface //--------------------------------------------------------------------+ @@ -195,46 +157,8 @@ enum { DD_STATUS_SYSTEM_ERROR }; -//--------------------------------------------------------------------+ -// 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) -{ - LPC_USB->USBDevIntClr = (DEV_INT_COMMAND_CODE_EMPTY_MASK | DEV_INT_COMMAND_DATA_FULL_MASK); - LPC_USB->USBCmdCode = (phase << 8) | (code_data << 16); - - uint32_t const wait_flag = (phase == SIE_CMDPHASE_READ) ? DEV_INT_COMMAND_DATA_FULL_MASK : DEV_INT_COMMAND_CODE_EMPTY_MASK; -#ifndef _TEST_ - while ((LPC_USB->USBDevIntSt & wait_flag) == 0); // TODO blocking forever potential -#endif - LPC_USB->USBDevIntClr = wait_flag; -} - -static inline void sie_write (uint8_t cmd_code, uint8_t data_len, uint8_t data) ATTR_ALWAYS_INLINE; -static inline void sie_write (uint8_t cmd_code, uint8_t data_len, uint8_t data) -{ - sie_cmd_code(SIE_CMDPHASE_COMMAND, cmd_code); - - if (data_len) - { - sie_cmd_code(SIE_CMDPHASE_WRITE, data); - } -} - -static inline uint32_t sie_read (uint8_t cmd_code, uint8_t data_len) ATTR_ALWAYS_INLINE; -static inline uint32_t sie_read (uint8_t cmd_code, uint8_t data_len) -{ - // TODO multiple read - sie_cmd_code(SIE_CMDPHASE_COMMAND , cmd_code); - sie_cmd_code(SIE_CMDPHASE_READ , cmd_code); - return LPC_USB->USBCmdData; -} - #ifdef __cplusplus } #endif #endif /* _TUSB_DCD_LPC175X_6X_H_ */ - -/** @} */ diff --git a/src/portable/nxp/lpc17xx/hal_lpc175x_6x.c b/src/portable/nxp/lpc17xx/hal_lpc175x_6x.c index de9d9a86e..13cb178f2 100644 --- a/src/portable/nxp/lpc17xx/hal_lpc175x_6x.c +++ b/src/portable/nxp/lpc17xx/hal_lpc175x_6x.c @@ -37,9 +37,11 @@ /**************************************************************************/
#include "common/tusb_common.h"
+
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X
-#include "hal_usb.h"
+#include "LPC17xx.h"
+#include "lpc17xx_pinsel.h"
void tusb_hal_int_enable(uint8_t rhport)
{
@@ -102,6 +104,8 @@ bool tusb_hal_init(void) void USB_IRQHandler(void)
{
+ extern void hal_dcd_isr(uint8_t rhport);
+
#if MODE_HOST_SUPPORTED
hal_hcd_isr(0);
#endif
diff --git a/src/portable/nxp/lpc43xx_lpc18xx/dcd_lpc43xx.c b/src/portable/nxp/lpc43xx_lpc18xx/dcd_lpc43xx.c index 2f83f4203..66ca04b71 100644 --- a/src/portable/nxp/lpc43xx_lpc18xx/dcd_lpc43xx.c +++ b/src/portable/nxp/lpc43xx_lpc18xx/dcd_lpc43xx.c @@ -288,7 +288,7 @@ bool dcd_edpt_busy(uint8_t rhport, uint8_t ep_addr) // return !p_qhd->qtd_overlay.halted && p_qhd->qtd_overlay.active;
}
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
uint8_t const epnum = edpt_number(ep_addr);
uint8_t const dir = edpt_dir(ep_addr);
@@ -301,9 +301,8 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t while(LPC_USB[rhport]->ENDPTSETUPSTAT & BIT_(0)) {}
}
- dcd_data_t* p_dcd = dcd_data_ptr[rhport];
- dcd_qhd_t * p_qhd = &p_dcd->qhd[ep_idx];
- dcd_qtd_t * p_qtd = &p_dcd->qtd[ep_idx];
+ dcd_qhd_t * p_qhd = &dcd_data_ptr[rhport]->qhd[ep_idx];
+ dcd_qtd_t * p_qtd = &dcd_data_ptr[rhport]->qtd[ep_idx];
//------------- Prepare qtd -------------//
qtd_init(p_qtd, buffer, total_bytes);
@@ -393,7 +392,7 @@ void hal_dcd_isr(uint8_t rhport) uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED :
( p_qtd->xact_err ||p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS;
- uint8_t ep_addr = (ep_idx/2) | ( (ep_idx & 0x01) ? TUSB_DIR_IN_MASK : 0 );
+ uint8_t const ep_addr = (ep_idx/2) | ( (ep_idx & 0x01) ? TUSB_DIR_IN_MASK : 0 );
dcd_event_xfer_complete(rhport, ep_addr, p_qtd->expected_bytes - p_qtd->total_bytes, result, true); // only number of bytes in the IOC qtd
}
}
diff --git a/src/tusb_option.h b/src/tusb_option.h index 18e1e245e..e1aec3302 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -83,13 +83,16 @@ //--------------------------------------------------------------------
// CONTROLLER
+// Only 1 roothub port can be configured to be device and/or host.
+// tinyusb does not support dual devices or dual host configuration
//--------------------------------------------------------------------
/** \defgroup group_mode Controller Mode Selection
* \brief CFG_TUSB_CONTROLLER_N_MODE must be defined with these
* @{ */
-#define OPT_MODE_HOST 0x02 ///< Host Mode
-#define OPT_MODE_DEVICE 0x01 ///< Device Mode
-#define OPT_MODE_NONE 0x00 ///< Disabled
+#define OPT_MODE_NONE 0x00 ///< Disabled
+#define OPT_MODE_DEVICE 0x01 ///< Device Mode
+#define OPT_MODE_HOST 0x02 ///< Host Mode
+#define OPT_MODE_HIGH_SPEED 0x10 ///< Highspeed
/** @} */
#ifndef CFG_TUSB_RHPORT0_MODE
@@ -100,22 +103,35 @@ #define CFG_TUSB_RHPORT1_MODE OPT_MODE_NONE
#endif
+#if ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST) && (CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST)) || \
+ ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE) && (CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE))
+ #error "tinyusb does not support same modes on more than 1 roothub port"
+#endif
+
+// TODO remove
#define CONTROLLER_HOST_NUMBER (\
((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST) ? 1 : 0) + \
((CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST) ? 1 : 0))
#define MODE_HOST_SUPPORTED (CONTROLLER_HOST_NUMBER > 0)
+// Which roothub port is configured as host
#define TUH_OPT_RHPORT ( (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST) ? 0 : ((CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST) ? 1 : -1) )
#define TUSB_OPT_HOST_ENABLED ( TUH_OPT_RHPORT >= 0 )
+// Which roothub port is configured as device
#define TUD_OPT_RHPORT ( (CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE) ? 0 : ((CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE) ? 1 : -1) )
-#define TUSB_OPT_DEVICE_ENABLED ( TUD_OPT_RHPORT >= 0 )
-#if ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST) && (CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST)) || ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE) && (CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE))
- #error "tinyusb does not support same modes on more than 1 roothub port"
+
+#if TUD_OPT_RHPORT == 0
+#define TUD_OPT_HIGH_SPEED ( CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED )
+#else
+#define TUD_OPT_HIGH_SPEED ( CFG_TUSB_RHPORT1_MODE & OPT_MODE_HIGH_SPEED )
#endif
+#define TUSB_OPT_DEVICE_ENABLED ( TUD_OPT_RHPORT >= 0 )
+
+
//--------------------------------------------------------------------+
// COMMON OPTIONS
//--------------------------------------------------------------------+
|
