Skip to content

Commit 5b1b383

Browse files
authored
Merge pull request #1676 from tswan-quasi/master
dcd_lpc_ip3511: isochronous support and endpoint accidental write fix
2 parents bfcdef4 + e3b7ed9 commit 5b1b383

File tree

2 files changed

+68
-40
lines changed

2 files changed

+68
-40
lines changed

hw/bsp/lpc55/family.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ SRC_C += \
4343
$(MCU_DIR)/drivers/fsl_power.c \
4444
$(MCU_DIR)/drivers/fsl_reset.c \
4545
$(SDK_DIR)/drivers/lpc_gpio/fsl_gpio.c \
46+
$(SDK_DIR)/drivers/common/fsl_common_arm.c \
4647
$(SDK_DIR)/drivers/flexcomm/fsl_flexcomm.c \
4748
$(SDK_DIR)/drivers/flexcomm/fsl_usart.c \
4849
lib/sct_neopixel/sct_neopixel.c

src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c

Lines changed: 67 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,10 @@ typedef struct {
7878

7979
// Max nbytes for each control/bulk/interrupt transfer
8080
enum {
81-
NBYTES_CBI_FULLSPEED_MAX = 64,
82-
NBYTES_CBI_HIGHSPEED_MAX = 32767 // can be up to all 15-bit, but only tested with 4096
81+
NBYTES_ISO_FS_MAX = 1023, // FS ISO
82+
NBYTES_ISO_HS_MAX = 1024, // HS ISO
83+
NBYTES_CBI_FS_MAX = 64, // FS control/bulk/interrupt
84+
NBYTES_CBI_HS_MAX = 32767 // can be up to all 15-bit, but only tested with 4096
8385
};
8486

8587
enum {
@@ -112,6 +114,8 @@ enum {
112114
typedef union TU_ATTR_PACKED
113115
{
114116
// Full and High speed has different bit layout for buffer_offset and nbytes
117+
// TODO FS/HS layout depends on the max speed of controller e.g
118+
// lpc55s69 PORT0 is only FS but actually has the same layout as HS on port1
115119

116120
// Buffer (aligned 64) = DATABUFSTART [31:22] | buffer_offset [21:6]
117121
volatile struct {
@@ -175,6 +179,9 @@ typedef struct
175179
// Use CFG_TUSB_MEM_SECTION to place it accordingly.
176180
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
177181

182+
// Dummy buffer to fix ZLPs overwriting the buffer (probably an USB/DMA controller bug)
183+
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8];
184+
178185
//--------------------------------------------------------------------+
179186
// Multiple Controllers
180187
//--------------------------------------------------------------------+
@@ -225,8 +232,36 @@ static inline uint8_t ep_addr2id(uint8_t ep_addr)
225232
//--------------------------------------------------------------------+
226233
// CONTROLLER API
227234
//--------------------------------------------------------------------+
235+
236+
static void prepare_setup_packet(uint8_t rhport)
237+
{
238+
if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
239+
{
240+
_dcd.ep[0][1].buffer_fs.offset = get_buf_offset(_dcd.setup_packet);
241+
}else
242+
{
243+
_dcd.ep[0][1].buffer_hs.offset = get_buf_offset(_dcd.setup_packet);
244+
}
245+
}
246+
247+
static void edpt_reset(uint8_t rhport, uint8_t ep_id)
248+
{
249+
(void) rhport;
250+
tu_memclr(&_dcd.ep[ep_id], sizeof(_dcd.ep[ep_id]));
251+
}
252+
253+
static void edpt_reset_all(uint8_t rhport)
254+
{
255+
for (uint8_t ep_id = 0; ep_id < 2*_dcd_controller[rhport].ep_pairs; ++ep_id)
256+
{
257+
edpt_reset(rhport, ep_id);
258+
}
259+
prepare_setup_packet(rhport);
260+
}
228261
void dcd_init(uint8_t rhport)
229262
{
263+
edpt_reset_all(rhport);
264+
230265
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
231266

232267
dcd_reg->EPLISTSTART = (uint32_t) _dcd.ep;
@@ -310,18 +345,13 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
310345

311346
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
312347
{
313-
(void) rhport;
314-
315-
// TODO not support ISO yet
316-
TU_VERIFY(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
317-
318348
//------------- Prepare Queue Head -------------//
319349
uint8_t ep_id = ep_addr2id(p_endpoint_desc->bEndpointAddress);
320350

321351
// Check if endpoint is available
322352
TU_ASSERT( _dcd.ep[ep_id][0].disable && _dcd.ep[ep_id][1].disable );
323353

324-
tu_memclr(_dcd.ep[ep_id], 2*sizeof(ep_cmd_sts_t));
354+
edpt_reset(rhport, ep_id);
325355
_dcd.ep[ep_id][0].is_iso = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
326356

327357
// Enable EP interrupt
@@ -333,19 +363,20 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
333363

334364
void dcd_edpt_close_all (uint8_t rhport)
335365
{
336-
(void) rhport;
337-
// TODO implement dcd_edpt_close_all()
366+
for (uint8_t ep_id = 0; ep_id < 2*_dcd_controller[rhport].ep_pairs; ++ep_id)
367+
{
368+
_dcd.ep[ep_id][0].active = _dcd.ep[ep_id][0].active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual)
369+
_dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1;
370+
}
338371
}
339372

340-
static void prepare_setup_packet(uint8_t rhport)
373+
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
341374
{
342-
if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
343-
{
344-
_dcd.ep[0][1].buffer_fs.offset = get_buf_offset(_dcd.setup_packet);;
345-
}else
346-
{
347-
_dcd.ep[0][1].buffer_hs.offset = get_buf_offset(_dcd.setup_packet);;
348-
}
375+
(void) rhport;
376+
377+
uint8_t ep_id = ep_addr2id(ep_addr);
378+
_dcd.ep[ep_id][0].active = _dcd.ep[ep_id][0].active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual)
379+
_dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1;
349380
}
350381

351382
static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, uint16_t total_bytes)
@@ -354,13 +385,12 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset,
354385

355386
if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
356387
{
357-
// TODO ISO FullSpeed can have up to 1023 bytes
358-
nbytes = tu_min16(total_bytes, NBYTES_CBI_FULLSPEED_MAX);
388+
nbytes = tu_min16(total_bytes, _dcd.ep[ep_id][0].is_iso ? NBYTES_ISO_FS_MAX : NBYTES_CBI_FS_MAX);
359389
_dcd.ep[ep_id][0].buffer_fs.offset = buf_offset;
360390
_dcd.ep[ep_id][0].buffer_fs.nbytes = nbytes;
361391
}else
362392
{
363-
nbytes = tu_min16(total_bytes, NBYTES_CBI_HIGHSPEED_MAX);
393+
nbytes = tu_min16(total_bytes, NBYTES_CBI_HS_MAX);
364394
_dcd.ep[ep_id][0].buffer_hs.offset = buf_offset;
365395
_dcd.ep[ep_id][0].buffer_hs.nbytes = nbytes;
366396
}
@@ -372,13 +402,19 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset,
372402

373403
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
374404
{
375-
(void) rhport;
376-
377405
uint8_t const ep_id = ep_addr2id(ep_addr);
378406

379407
tu_memclr(&_dcd.dma[ep_id], sizeof(xfer_dma_t));
380408
_dcd.dma[ep_id].total_bytes = total_bytes;
381409

410+
if (!buffer)
411+
{
412+
// Although having no data, ZLPs can cause buffer overwritten to zeroes.
413+
// Probably due to USB/DMA controller side effect/bug.
414+
// Assigned buffer offset to (valid) dummy to prevent overwriting to DATABUFSTART
415+
buffer = (uint8_t*)(uint32_t)dummy;
416+
}
417+
382418
prepare_ep_xfer(rhport, ep_id, get_buf_offset(buffer), total_bytes);
383419

384420
return true;
@@ -390,15 +426,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
390426
static void bus_reset(uint8_t rhport)
391427
{
392428
tu_memclr(&_dcd, sizeof(dcd_data_t));
429+
edpt_reset_all(rhport);
393430

394-
// disable all non-control endpoints on bus reset
395-
for(uint8_t ep_id = 2; ep_id < 2*MAX_EP_PAIRS; ep_id++)
431+
// disable all endpoints as specified by LPC55S69 UM Table 778
432+
for(uint8_t ep_id = 0; ep_id < 2*MAX_EP_PAIRS; ep_id++)
396433
{
397434
_dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1;
398435
}
399436

400-
prepare_setup_packet(rhport);
401-
402437
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
403438

404439
dcd_reg->EPINUSE = 0;
@@ -506,23 +541,15 @@ void dcd_int_handler(uint8_t rhport)
506541
}
507542
}
508543

509-
// TODO support suspend & resume
510544
if (cmd_stat & CMDSTAT_SUSPEND_CHANGE_MASK)
511545
{
512-
if (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK)
513-
{ // suspend signal, bus idle for more than 3ms
514-
// Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
515-
if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
516-
{
517-
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
518-
}
546+
// suspend signal, bus idle for more than 3ms
547+
// Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
548+
if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
549+
{
550+
dcd_event_bus_signal(rhport, (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME, true);
519551
}
520552
}
521-
// else
522-
// { // resume signal
523-
// dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
524-
// }
525-
// }
526553
}
527554

528555
// Setup Receive

0 commit comments

Comments
 (0)