summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2018-12-04 16:06:50 +0700
committerhathach <[email protected]>2018-12-04 16:06:50 +0700
commit261e0f9801abc7f6d13afcad51b5feadd19f50ee (patch)
treeb4d70cbb31448abf9ccd738ec1cf1e11417782fd /src
parentd7c0f0aab5d4cca15133a47c398d0815f126629e (diff)
adding lpc40xx support
Diffstat (limited to 'src')
-rw-r--r--src/portable/nxp/lpc17_40/dcd_lpc17_40.c (renamed from src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c)1180
-rw-r--r--src/portable/nxp/lpc17_40/dcd_lpc17_40.h (renamed from src/portable/nxp/lpc17xx/dcd_lpc175x_6x.h)0
-rw-r--r--src/portable/nxp/lpc17_40/hal_lpc17_40.c (renamed from src/portable/nxp/lpc17xx/hal_lpc175x_6x.c)216
-rw-r--r--src/portable/nxp/lpc18_43/dcd_lpc18_43.c15
-rw-r--r--src/portable/nxp/lpc18_43/dcd_lpc18_43.h4
-rw-r--r--src/tusb_option.h5
6 files changed, 712 insertions, 708 deletions
diff --git a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
index e94670a92..549420f22 100644
--- a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c
+++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
@@ -1,590 +1,590 @@
-/**************************************************************************/
-/*!
- @file dcd_lpc175x_6x.c
- @author hathach (tinyusb.org)
-
- @section LICENSE
-
- Software License Agreement (BSD License)
-
- Copyright (c) 2013, hathach (tinyusb.org)
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the copyright holders nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- This file is part of the tinyusb stack.
-*/
-/**************************************************************************/
-
-#include "tusb_option.h"
-
-#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X)
-
-#include "device/dcd.h"
-#include "dcd_lpc175x_6x.h"
-#include "chip.h"
-
-//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF
-//--------------------------------------------------------------------+
-#define DCD_ENDPOINT_MAX 32
-
-typedef struct ATTR_ALIGNED(4)
-{
- //------------- Word 0 -------------//
- uint32_t next;
-
- //------------- 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;
-
- volatile uint16_t buflen; // bytes for non-iso, number of packets for iso endpoint
-
- //------------- Word 2 -------------//
- volatile uint32_t buffer;
-
- //------------- 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;
-
- volatile uint16_t present_count; // For non-iso : The number of bytes transferred by the DMA engine
- // For iso : number of packets
-
- //------------- 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
-
-typedef struct
-{
- // must be 128 byte aligned
- volatile dma_desc_t* udca[DCD_ENDPOINT_MAX];
-
- // TODO DMA does not support control transfer (0-1 are not used, offset to reduce memory)
- dma_desc_t dd[DCD_ENDPOINT_MAX];
-
- struct
- {
- uint8_t* out_buffer;
- uint8_t out_bytes;
- volatile bool out_received; // indicate if data is already received in endpoint
-
- uint8_t in_bytes;
- } control;
-
-} dcd_data_t;
-
-ATTR_ALIGNED(128) static dcd_data_t _dcd;
-
-
-//--------------------------------------------------------------------+
-// SIE Command
-//--------------------------------------------------------------------+
-static void sie_cmd_code (sie_cmdphase_t phase, uint8_t code_data)
-{
- LPC_USB->DevIntClr = (DEV_INT_COMMAND_CODE_EMPTY_MASK | DEV_INT_COMMAND_DATA_FULL_MASK);
- LPC_USB->CmdCode = (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;
- while ((LPC_USB->DevIntSt & wait_flag) == 0) {}
-
- LPC_USB->DevIntClr = wait_flag;
-}
-
-static 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 uint8_t sie_read (uint8_t cmd_code)
-{
- sie_cmd_code(SIE_CMDPHASE_COMMAND , cmd_code);
- sie_cmd_code(SIE_CMDPHASE_READ , cmd_code);
- return (uint8_t) LPC_USB->CmdData;
-}
-
-//--------------------------------------------------------------------+
-// 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);
-}
-
-static void set_ep_size(uint8_t ep_id, uint16_t max_packet_size)
-{
- // follows example in 11.10.4.2
- LPC_USB->ReEp |= BIT_(ep_id);
- LPC_USB->EpInd = ep_id; // select index before setting packet size
- LPC_USB->MaxPSize = max_packet_size;
-
- while ((LPC_USB->DevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {}
- LPC_USB->DevIntClr = DEV_INT_ENDPOINT_REALIZED_MASK;
-}
-
-
-//--------------------------------------------------------------------+
-// CONTROLLER API
-//--------------------------------------------------------------------+
-static void bus_reset(void)
-{
- // step 7 : slave mode set up
- LPC_USB->EpIntClr = 0xFFFFFFFF; // clear all pending interrupt
- LPC_USB->DevIntClr = 0xFFFFFFFF; // clear all pending interrupt
- LPC_USB->EpIntEn = 0x03UL; // control endpoint cannot use DMA, non-control all use DMA
- LPC_USB->EpIntPri = 0x03UL; // fast for control endpoint
-
- // step 8 : DMA set up
- LPC_USB->EpDMADis = 0xFFFFFFFF; // firstly disable all dma
- LPC_USB->DMARClr = 0xFFFFFFFF; // clear all pending interrupt
- LPC_USB->EoTIntClr = 0xFFFFFFFF;
- LPC_USB->NDDRIntClr = 0xFFFFFFFF;
- LPC_USB->SysErrIntClr = 0xFFFFFFFF;
-
- tu_memclr(&_dcd, sizeof(dcd_data_t));
-}
-
-bool dcd_init(uint8_t rhport)
-{
- (void) rhport;
-
- //------------- user manual 11.13 usb device controller initialization -------------//
- // step 6 : set up control endpoint
- set_ep_size(0, CFG_TUD_ENDOINT0_SIZE);
- set_ep_size(1, CFG_TUD_ENDOINT0_SIZE);
-
- bus_reset();
-
- LPC_USB->DevIntEn = (DEV_INT_DEVICE_STATUS_MASK | DEV_INT_ENDPOINT_FAST_MASK | DEV_INT_ENDPOINT_SLOW_MASK | DEV_INT_ERROR_MASK);
- LPC_USB->UDCAH = (uint32_t) _dcd.udca;
- LPC_USB->DMAIntEn = (DMA_INT_END_OF_XFER_MASK /*| DMA_INT_NEW_DD_REQUEST_MASK*/ | DMA_INT_ERROR_MASK);
-
- sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 1); // connect
-
- // USB IRQ priority should be set by application previously
- NVIC_ClearPendingIRQ(USB_IRQn);
- NVIC_EnableIRQ(USB_IRQn);
-
- return TUSB_ERROR_NONE;
-}
-
-void dcd_connect(uint8_t rhport)
-{
- (void) rhport;
- sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 1);
-}
-
-void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
-{
- (void) rhport;
- sie_write(SIE_CMDCODE_SET_ADDRESS, 1, 0x80 | dev_addr); // 7th bit is : device_enable
-}
-
-void dcd_set_config(uint8_t rhport, uint8_t config_num)
-{
- (void) rhport;
- (void) config_num;
- sie_write(SIE_CMDCODE_CONFIGURE_DEVICE, 1, 1);
-}
-
-//--------------------------------------------------------------------+
-// CONTROL HELPER
-//--------------------------------------------------------------------+
-static inline uint8_t byte2dword(uint8_t bytes)
-{
- return (bytes + 3) / 4; // length in dwords
-}
-
-static void control_ep_write(void const * buffer, uint8_t len)
-{
- uint32_t const * buf32 = (uint32_t const *) buffer;
-
- LPC_USB->Ctrl = USBCTRL_WRITE_ENABLE_MASK; // logical endpoint = 0
- LPC_USB->TxPLen = (uint32_t) len;
-
- for (uint8_t count = 0; count < byte2dword(len); count++)
- {
- LPC_USB->TxData = *buf32; // NOTE: cortex M3 have no problem with alignment
- buf32++;
- }
-
- LPC_USB->Ctrl = 0;
-
- // select control IN & validate the endpoint
- sie_write(SIE_CMDCODE_ENDPOINT_SELECT+1, 0, 0);
- sie_write(SIE_CMDCODE_BUFFER_VALIDATE , 0, 0);
-}
-
-static uint8_t control_ep_read(void * buffer, uint8_t len)
-{
- LPC_USB->Ctrl = USBCTRL_READ_ENABLE_MASK; // logical endpoint = 0
- while ((LPC_USB->RxPLen & USBRXPLEN_PACKET_READY_MASK) == 0) {} // TODO blocking, should have timeout
-
- len = tu_min8(len, (uint8_t) (LPC_USB->RxPLen & USBRXPLEN_PACKET_LENGTH_MASK) );
- uint32_t *buf32 = (uint32_t*) buffer;
-
- for (uint8_t count=0; count < byte2dword(len); count++)
- {
- *buf32 = LPC_USB->RxData;
- buf32++;
- }
-
- LPC_USB->Ctrl = 0;
-
- // select control OUT & clear the endpoint
- sie_write(SIE_CMDCODE_ENDPOINT_SELECT+0, 0, 0);
- sie_write(SIE_CMDCODE_BUFFER_CLEAR , 0, 0);
-
- return len;
-}
-
-//--------------------------------------------------------------------+
-// DCD Endpoint Port
-//--------------------------------------------------------------------+
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
-{
- (void) rhport;
-
- uint8_t const epnum = edpt_number(p_endpoint_desc->bEndpointAddress);
- uint8_t const ep_id = ep_addr2idx(p_endpoint_desc->bEndpointAddress);
-
- // 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;
-
- case TUSB_XFER_BULK:
- TU_ASSERT((epnum % 3) == 2 || (epnum == 15));
- break;
-
- case TUSB_XFER_ISOCHRONOUS:
- TU_ASSERT((epnum % 3) == 3 && (epnum != 15));
- break;
-
- default:
- break;
- }
-
- //------------- 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;
-}
-
-bool dcd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
-{
- (void) rhport;
-
- uint8_t ep_id = ep_addr2idx( ep_addr );
- return (_dcd.udca[ep_id] != NULL && !_dcd.udca[ep_id]->retired);
-}
-
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
-{
- (void) rhport;
-
- 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);
- }
-}
-
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
-{
- (void) rhport;
- uint8_t ep_id = ep_addr2idx(ep_addr);
-
- sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, 0);
-}
-
-bool dcd_edpt_stalled (uint8_t rhport, uint8_t ep_addr)
-{
- (void) rhport;
-
- uint8_t const ep_state = sie_read(SIE_CMDCODE_ENDPOINT_SELECT + ep_addr2idx(ep_addr));
- return (ep_state & SIE_SELECT_ENDPOINT_STALL_MASK) ? true : false;
-}
-
-static bool control_xact(uint8_t rhport, uint8_t dir, uint8_t * buffer, uint8_t len)
-{
- (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;
-}
-
-bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
-{
- // 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 = (uint32_t) buffer;
- dd->buflen = total_bytes;
-
- _dcd.udca[ep_id] = dd;
-
- if ( ep_id % 2 )
- {
- // Clear EP interrupt before Enable DMA
- LPC_USB->EpIntEn &= ~BIT_(ep_id);
- LPC_USB->EpDMAEn = BIT_(ep_id);
-
- // endpoint IN need to actively raise DMA request
- LPC_USB->DMARSet = BIT_(ep_id);
- }else
- {
- // Enable DMA
- LPC_USB->EpDMAEn = BIT_(ep_id);
- }
-
- return true;
- }
-}
-
-//--------------------------------------------------------------------+
-// ISR
-//--------------------------------------------------------------------+
-
-// handle control xfer (slave mode)
-static void control_xfer_isr(uint8_t rhport, uint32_t ep_int_status)
-{
- // Control out complete
- if ( ep_int_status & BIT_(0) )
- {
- bool is_setup = sie_read(SIE_CMDCODE_ENDPOINT_SELECT+0) & SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK;
-
- LPC_USB->EpIntClr = 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->EpIntClr = BIT_(1);
- dcd_event_xfer_complete(rhport, TUSB_DIR_IN_MASK, _dcd.control.in_bytes, XFER_RESULT_SUCCESS, true);
- }
-}
-
-// handle bus event signal
-static void bus_event_isr(uint8_t rhport)
-{
- uint8_t const dev_status = sie_read(SIE_CMDCODE_DEVICE_STATUS);
- if (dev_status & SIE_DEV_STATUS_RESET_MASK)
- {
- bus_reset();
- dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true);
- }
-
- 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);
- }
-
- 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);
- }
- }
-}
-
-// 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);
-}
-
-// main USB IRQ handler
-void hal_dcd_isr(uint8_t rhport)
-{
- uint32_t const dev_int_status = LPC_USB->DevIntSt & LPC_USB->DevIntEn;
- LPC_USB->DevIntClr = dev_int_status;// Acknowledge handled interrupt
-
- // Bus event
- if (dev_int_status & DEV_INT_DEVICE_STATUS_MASK)
- {
- bus_event_isr(rhport);
- }
-
- // Endpoint interrupt
- uint32_t const ep_int_status = LPC_USB->EpIntSt & LPC_USB->EpIntEn;
-
- // 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);
- }
-
- // non-control IN are slow
- if (dev_int_status & DEV_INT_ENDPOINT_SLOW_MASK)
- {
- for ( uint8_t ep_id = 3; ep_id < DCD_ENDPOINT_MAX; ep_id += 2 )
- {
- if ( BIT_TEST_(ep_int_status, ep_id) )
- {
- LPC_USB->EpIntClr = BIT_(ep_id);
-
- // Clear Ep interrupt for next DMA
- LPC_USB->EpIntEn &= ~BIT_(ep_id);
-
- dd_complete_isr(rhport, ep_id);
- }
- }
- }
-
- // 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->DMAIntSt & LPC_USB->DMAIntEn;
- if (dma_int_status & DMA_INT_END_OF_XFER_MASK)
- {
- uint32_t const eot = LPC_USB->EoTIntSt;
- LPC_USB->EoTIntClr = eot; // acknowledge interrupt source
-
- 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->EpIntEn |= BIT_(ep_id);
- }else
- {
- // OUT
- dd_complete_isr(rhport, ep_id);
- }
- }
- }
- }
-
- // 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);
- (void) error_status;
- TU_BREAKPOINT();
- }
-}
-
-#endif
+/**************************************************************************/
+/*!
+ @file dcd_lpc175x_6x.c
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2013, hathach (tinyusb.org)
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the copyright holders nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This file is part of the tinyusb stack.
+*/
+/**************************************************************************/
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
+
+#include "device/dcd.h"
+#include "dcd_lpc175x_6x.h"
+#include "chip.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+#define DCD_ENDPOINT_MAX 32
+
+typedef struct ATTR_ALIGNED(4)
+{
+ //------------- Word 0 -------------//
+ uint32_t next;
+
+ //------------- 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;
+
+ volatile uint16_t buflen; // bytes for non-iso, number of packets for iso endpoint
+
+ //------------- Word 2 -------------//
+ volatile uint32_t buffer;
+
+ //------------- 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;
+
+ volatile uint16_t present_count; // For non-iso : The number of bytes transferred by the DMA engine
+ // For iso : number of packets
+
+ //------------- 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
+
+typedef struct
+{
+ // must be 128 byte aligned
+ volatile dma_desc_t* udca[DCD_ENDPOINT_MAX];
+
+ // TODO DMA does not support control transfer (0-1 are not used, offset to reduce memory)
+ dma_desc_t dd[DCD_ENDPOINT_MAX];
+
+ struct
+ {
+ uint8_t* out_buffer;
+ uint8_t out_bytes;
+ volatile bool out_received; // indicate if data is already received in endpoint
+
+ uint8_t in_bytes;
+ } control;
+
+} dcd_data_t;
+
+ATTR_ALIGNED(128) static dcd_data_t _dcd;
+
+
+//--------------------------------------------------------------------+
+// SIE Command
+//--------------------------------------------------------------------+
+static void sie_cmd_code (sie_cmdphase_t phase, uint8_t code_data)
+{
+ LPC_USB->DevIntClr = (DEV_INT_COMMAND_CODE_EMPTY_MASK | DEV_INT_COMMAND_DATA_FULL_MASK);
+ LPC_USB->CmdCode = (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;
+ while ((LPC_USB->DevIntSt & wait_flag) == 0) {}
+
+ LPC_USB->DevIntClr = wait_flag;
+}
+
+static 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 uint8_t sie_read (uint8_t cmd_code)
+{
+ sie_cmd_code(SIE_CMDPHASE_COMMAND , cmd_code);
+ sie_cmd_code(SIE_CMDPHASE_READ , cmd_code);
+ return (uint8_t) LPC_USB->CmdData;
+}
+
+//--------------------------------------------------------------------+
+// 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);
+}
+
+static void set_ep_size(uint8_t ep_id, uint16_t max_packet_size)
+{
+ // follows example in 11.10.4.2
+ LPC_USB->ReEp |= BIT_(ep_id);
+ LPC_USB->EpInd = ep_id; // select index before setting packet size
+ LPC_USB->MaxPSize = max_packet_size;
+
+ while ((LPC_USB->DevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {}
+ LPC_USB->DevIntClr = DEV_INT_ENDPOINT_REALIZED_MASK;
+}
+
+
+//--------------------------------------------------------------------+
+// CONTROLLER API
+//--------------------------------------------------------------------+
+static void bus_reset(void)
+{
+ // step 7 : slave mode set up
+ LPC_USB->EpIntClr = 0xFFFFFFFF; // clear all pending interrupt
+ LPC_USB->DevIntClr = 0xFFFFFFFF; // clear all pending interrupt
+ LPC_USB->EpIntEn = 0x03UL; // control endpoint cannot use DMA, non-control all use DMA
+ LPC_USB->EpIntPri = 0x03UL; // fast for control endpoint
+
+ // step 8 : DMA set up
+ LPC_USB->EpDMADis = 0xFFFFFFFF; // firstly disable all dma
+ LPC_USB->DMARClr = 0xFFFFFFFF; // clear all pending interrupt
+ LPC_USB->EoTIntClr = 0xFFFFFFFF;
+ LPC_USB->NDDRIntClr = 0xFFFFFFFF;
+ LPC_USB->SysErrIntClr = 0xFFFFFFFF;
+
+ tu_memclr(&_dcd, sizeof(dcd_data_t));
+}
+
+bool dcd_init(uint8_t rhport)
+{
+ (void) rhport;
+
+ //------------- user manual 11.13 usb device controller initialization -------------//
+ // step 6 : set up control endpoint
+ set_ep_size(0, CFG_TUD_ENDOINT0_SIZE);
+ set_ep_size(1, CFG_TUD_ENDOINT0_SIZE);
+
+ bus_reset();
+
+ LPC_USB->DevIntEn = (DEV_INT_DEVICE_STATUS_MASK | DEV_INT_ENDPOINT_FAST_MASK | DEV_INT_ENDPOINT_SLOW_MASK | DEV_INT_ERROR_MASK);
+ LPC_USB->UDCAH = (uint32_t) _dcd.udca;
+ LPC_USB->DMAIntEn = (DMA_INT_END_OF_XFER_MASK /*| DMA_INT_NEW_DD_REQUEST_MASK*/ | DMA_INT_ERROR_MASK);
+
+ sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 1); // connect
+
+ // USB IRQ priority should be set by application previously
+ NVIC_ClearPendingIRQ(USB_IRQn);
+ NVIC_EnableIRQ(USB_IRQn);
+
+ return TUSB_ERROR_NONE;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+ sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 1);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void) rhport;
+ sie_write(SIE_CMDCODE_SET_ADDRESS, 1, 0x80 | dev_addr); // 7th bit is : device_enable
+}
+
+void dcd_set_config(uint8_t rhport, uint8_t config_num)
+{
+ (void) rhport;
+ (void) config_num;
+ sie_write(SIE_CMDCODE_CONFIGURE_DEVICE, 1, 1);
+}
+
+//--------------------------------------------------------------------+
+// CONTROL HELPER
+//--------------------------------------------------------------------+
+static inline uint8_t byte2dword(uint8_t bytes)
+{
+ return (bytes + 3) / 4; // length in dwords
+}
+
+static void control_ep_write(void const * buffer, uint8_t len)
+{
+ uint32_t const * buf32 = (uint32_t const *) buffer;
+
+ LPC_USB->Ctrl = USBCTRL_WRITE_ENABLE_MASK; // logical endpoint = 0
+ LPC_USB->TxPLen = (uint32_t) len;
+
+ for (uint8_t count = 0; count < byte2dword(len); count++)
+ {
+ LPC_USB->TxData = *buf32; // NOTE: cortex M3 have no problem with alignment
+ buf32++;
+ }
+
+ LPC_USB->Ctrl = 0;
+
+ // select control IN & validate the endpoint
+ sie_write(SIE_CMDCODE_ENDPOINT_SELECT+1, 0, 0);
+ sie_write(SIE_CMDCODE_BUFFER_VALIDATE , 0, 0);
+}
+
+static uint8_t control_ep_read(void * buffer, uint8_t len)
+{
+ LPC_USB->Ctrl = USBCTRL_READ_ENABLE_MASK; // logical endpoint = 0
+ while ((LPC_USB->RxPLen & USBRXPLEN_PACKET_READY_MASK) == 0) {} // TODO blocking, should have timeout
+
+ len = tu_min8(len, (uint8_t) (LPC_USB->RxPLen & USBRXPLEN_PACKET_LENGTH_MASK) );
+ uint32_t *buf32 = (uint32_t*) buffer;
+
+ for (uint8_t count=0; count < byte2dword(len); count++)
+ {
+ *buf32 = LPC_USB->RxData;
+ buf32++;
+ }
+
+ LPC_USB->Ctrl = 0;
+
+ // select control OUT & clear the endpoint
+ sie_write(SIE_CMDCODE_ENDPOINT_SELECT+0, 0, 0);
+ sie_write(SIE_CMDCODE_BUFFER_CLEAR , 0, 0);
+
+ return len;
+}
+
+//--------------------------------------------------------------------+
+// DCD Endpoint Port
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+{
+ (void) rhport;
+
+ uint8_t const epnum = edpt_number(p_endpoint_desc->bEndpointAddress);
+ uint8_t const ep_id = ep_addr2idx(p_endpoint_desc->bEndpointAddress);
+
+ // 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;
+
+ case TUSB_XFER_BULK:
+ TU_ASSERT((epnum % 3) == 2 || (epnum == 15));
+ break;
+
+ case TUSB_XFER_ISOCHRONOUS:
+ TU_ASSERT((epnum % 3) == 3 && (epnum != 15));
+ break;
+
+ default:
+ break;
+ }
+
+ //------------- 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;
+}
+
+bool dcd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+
+ uint8_t ep_id = ep_addr2idx( ep_addr );
+ return (_dcd.udca[ep_id] != NULL && !_dcd.udca[ep_id]->retired);
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+
+ 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);
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ uint8_t ep_id = ep_addr2idx(ep_addr);
+
+ sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, 0);
+}
+
+bool dcd_edpt_stalled (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+
+ uint8_t const ep_state = sie_read(SIE_CMDCODE_ENDPOINT_SELECT + ep_addr2idx(ep_addr));
+ return (ep_state & SIE_SELECT_ENDPOINT_STALL_MASK) ? true : false;
+}
+
+static bool control_xact(uint8_t rhport, uint8_t dir, uint8_t * buffer, uint8_t len)
+{
+ (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;
+}
+
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+ // 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 = (uint32_t) buffer;
+ dd->buflen = total_bytes;
+
+ _dcd.udca[ep_id] = dd;
+
+ if ( ep_id % 2 )
+ {
+ // Clear EP interrupt before Enable DMA
+ LPC_USB->EpIntEn &= ~BIT_(ep_id);
+ LPC_USB->EpDMAEn = BIT_(ep_id);
+
+ // endpoint IN need to actively raise DMA request
+ LPC_USB->DMARSet = BIT_(ep_id);
+ }else
+ {
+ // Enable DMA
+ LPC_USB->EpDMAEn = BIT_(ep_id);
+ }
+
+ return true;
+ }
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+
+// handle control xfer (slave mode)
+static void control_xfer_isr(uint8_t rhport, uint32_t ep_int_status)
+{
+ // Control out complete
+ if ( ep_int_status & BIT_(0) )
+ {
+ bool is_setup = sie_read(SIE_CMDCODE_ENDPOINT_SELECT+0) & SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK;
+
+ LPC_USB->EpIntClr = 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->EpIntClr = BIT_(1);
+ dcd_event_xfer_complete(rhport, TUSB_DIR_IN_MASK, _dcd.control.in_bytes, XFER_RESULT_SUCCESS, true);
+ }
+}
+
+// handle bus event signal
+static void bus_event_isr(uint8_t rhport)
+{
+ uint8_t const dev_status = sie_read(SIE_CMDCODE_DEVICE_STATUS);
+ if (dev_status & SIE_DEV_STATUS_RESET_MASK)
+ {
+ bus_reset();
+ dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+ }
+}
+
+// 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);
+}
+
+// main USB IRQ handler
+void hal_dcd_isr(uint8_t rhport)
+{
+ uint32_t const dev_int_status = LPC_USB->DevIntSt & LPC_USB->DevIntEn;
+ LPC_USB->DevIntClr = dev_int_status;// Acknowledge handled interrupt
+
+ // Bus event
+ if (dev_int_status & DEV_INT_DEVICE_STATUS_MASK)
+ {
+ bus_event_isr(rhport);
+ }
+
+ // Endpoint interrupt
+ uint32_t const ep_int_status = LPC_USB->EpIntSt & LPC_USB->EpIntEn;
+
+ // 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);
+ }
+
+ // non-control IN are slow
+ if (dev_int_status & DEV_INT_ENDPOINT_SLOW_MASK)
+ {
+ for ( uint8_t ep_id = 3; ep_id < DCD_ENDPOINT_MAX; ep_id += 2 )
+ {
+ if ( BIT_TEST_(ep_int_status, ep_id) )
+ {
+ LPC_USB->EpIntClr = BIT_(ep_id);
+
+ // Clear Ep interrupt for next DMA
+ LPC_USB->EpIntEn &= ~BIT_(ep_id);
+
+ dd_complete_isr(rhport, ep_id);
+ }
+ }
+ }
+
+ // 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->DMAIntSt & LPC_USB->DMAIntEn;
+ if (dma_int_status & DMA_INT_END_OF_XFER_MASK)
+ {
+ uint32_t const eot = LPC_USB->EoTIntSt;
+ LPC_USB->EoTIntClr = eot; // acknowledge interrupt source
+
+ 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->EpIntEn |= BIT_(ep_id);
+ }else
+ {
+ // OUT
+ dd_complete_isr(rhport, ep_id);
+ }
+ }
+ }
+ }
+
+ // 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);
+ (void) error_status;
+ TU_BREAKPOINT();
+ }
+}
+
+#endif
diff --git a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.h b/src/portable/nxp/lpc17_40/dcd_lpc17_40.h
index d6b76fcd1..d6b76fcd1 100644
--- a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.h
+++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.h
diff --git a/src/portable/nxp/lpc17xx/hal_lpc175x_6x.c b/src/portable/nxp/lpc17_40/hal_lpc17_40.c
index bc61178d8..668cabd80 100644
--- a/src/portable/nxp/lpc17xx/hal_lpc175x_6x.c
+++ b/src/portable/nxp/lpc17_40/hal_lpc17_40.c
@@ -1,108 +1,108 @@
-/**************************************************************************/
-/*!
- @file hal_lpc175x_6x.c
- @author hathach (tinyusb.org)
-
- @section LICENSE
-
- Software License Agreement (BSD License)
-
- Copyright (c) 2013, hathach (tinyusb.org)
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the copyright holders nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- This file is part of the tinyusb stack.
-*/
-/**************************************************************************/
-
-#include "common/tusb_common.h"
-
-#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X
-
-#include "chip.h"
-
-void tusb_hal_int_enable(uint8_t rhport)
-{
- (void) rhport;
- NVIC_EnableIRQ(USB_IRQn);
-}
-
-void tusb_hal_int_disable(uint8_t rhport)
-{
- (void) rhport;
- NVIC_DisableIRQ(USB_IRQn);
-}
-
-//--------------------------------------------------------------------+
-// IMPLEMENTATION
-//--------------------------------------------------------------------+
-bool tusb_hal_init(void)
-{
- enum {
- USBCLK_DEVCIE = 0x12, // AHB + Device
- USBCLK_HOST = 0x19, // AHB + Host + OTG (!)
- };
-
- Chip_USB_Init();
-
- /* Configure P0.29 as D+, P0.30 as D- */
- Chip_IOCON_PinMux(LPC_IOCON, 0, 29, IOCON_MODE_INACT, IOCON_FUNC1);
- Chip_IOCON_PinMux(LPC_IOCON, 0, 30, IOCON_MODE_INACT, IOCON_FUNC1);
-
-#if MODE_HOST_SUPPORTED
- PINSEL_ConfigPin( &(PINSEL_CFG_Type) { .Portnum = 1, .Pinnum = 22, .Funcnum = 2} ); // P1.22 as USB_PWRD
- PINSEL_ConfigPin( &(PINSEL_CFG_Type) { .Portnum = 1, .Pinnum = 19, .Funcnum = 2} ); // P1.19 as USB_PPWR
-
- // Enable host
- LPC_USB->USBClkCtrl = USBCLK_HOST;
- while ((LPC_USB->USBClkSt & USBCLK_HOST) != USBCLK_HOST);
- LPC_USB->OTGStCtrl = 0x3;
-#endif
-
-#if TUSB_OPT_DEVICE_ENABLED
- // P2_9 as USB Connect
- Chip_IOCON_PinMux(LPC_IOCON, 2, 9, IOCON_MODE_INACT, IOCON_FUNC1);
-
- // Enable Device
- LPC_USB->USBClkCtrl = USBCLK_DEVCIE;
- while ((LPC_USB->USBClkSt & USBCLK_DEVCIE) != USBCLK_DEVCIE);
-#endif
-
- return true;
-}
-
-void USB_IRQHandler(void)
-{
- extern void hal_dcd_isr(uint8_t rhport);
-
- #if MODE_HOST_SUPPORTED
- hal_hcd_isr(0);
- #endif
-
- #if TUSB_OPT_DEVICE_ENABLED
- hal_dcd_isr(0);
- #endif
-}
-
-#endif
+/**************************************************************************/
+/*!
+ @file hal_lpc175x_6x.c
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2013, hathach (tinyusb.org)
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the copyright holders nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This file is part of the tinyusb stack.
+*/
+/**************************************************************************/
+
+#include "common/tusb_common.h"
+
+#if (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
+
+#include "chip.h"
+
+void tusb_hal_int_enable(uint8_t rhport)
+{
+ (void) rhport;
+ NVIC_EnableIRQ(USB_IRQn);
+}
+
+void tusb_hal_int_disable(uint8_t rhport)
+{
+ (void) rhport;
+ NVIC_DisableIRQ(USB_IRQn);
+}
+
+//--------------------------------------------------------------------+
+// IMPLEMENTATION
+//--------------------------------------------------------------------+
+bool tusb_hal_init(void)
+{
+ enum {
+ USBCLK_DEVCIE = 0x12, // AHB + Device
+ USBCLK_HOST = 0x19, // AHB + Host + OTG (!)
+ };
+
+ Chip_USB_Init();
+
+ /* Configure P0.29 as D+, P0.30 as D- */
+ Chip_IOCON_PinMux(LPC_IOCON, 0, 29, IOCON_MODE_INACT, IOCON_FUNC1);
+ Chip_IOCON_PinMux(LPC_IOCON, 0, 30, IOCON_MODE_INACT, IOCON_FUNC1);
+
+#if MODE_HOST_SUPPORTED
+ PINSEL_ConfigPin( &(PINSEL_CFG_Type) { .Portnum = 1, .Pinnum = 22, .Funcnum = 2} ); // P1.22 as USB_PWRD
+ PINSEL_ConfigPin( &(PINSEL_CFG_Type) { .Portnum = 1, .Pinnum = 19, .Funcnum = 2} ); // P1.19 as USB_PPWR
+
+ // Enable host
+ LPC_USB->USBClkCtrl = USBCLK_HOST;
+ while ((LPC_USB->USBClkSt & USBCLK_HOST) != USBCLK_HOST);
+ LPC_USB->OTGStCtrl = 0x3;
+#endif
+
+#if TUSB_OPT_DEVICE_ENABLED
+ // P2_9 as USB Connect
+ Chip_IOCON_PinMux(LPC_IOCON, 2, 9, IOCON_MODE_INACT, IOCON_FUNC1);
+
+ // Enable Device
+ LPC_USB->USBClkCtrl = USBCLK_DEVCIE;
+ while ((LPC_USB->USBClkSt & USBCLK_DEVCIE) != USBCLK_DEVCIE);
+#endif
+
+ return true;
+}
+
+void USB_IRQHandler(void)
+{
+ extern void hal_dcd_isr(uint8_t rhport);
+
+ #if MODE_HOST_SUPPORTED
+ hal_hcd_isr(0);
+ #endif
+
+ #if TUSB_OPT_DEVICE_ENABLED
+ hal_dcd_isr(0);
+ #endif
+}
+
+#endif
diff --git a/src/portable/nxp/lpc18_43/dcd_lpc18_43.c b/src/portable/nxp/lpc18_43/dcd_lpc18_43.c
index af1fa619c..8f5e3b457 100644
--- a/src/portable/nxp/lpc18_43/dcd_lpc18_43.c
+++ b/src/portable/nxp/lpc18_43/dcd_lpc18_43.c
@@ -54,9 +54,14 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
+
+#define QHD_MAX 12
+#define QTD_NEXT_INVALID 0x01
+
typedef struct {
- dcd_qhd_t qhd[DCD_QHD_MAX] ATTR_ALIGNED(64); ///< Must be at 2K alignment
- dcd_qtd_t qtd[DCD_QTD_MAX] ATTR_ALIGNED(32);
+ // Must be at 2K alignment
+ dcd_qhd_t qhd[QHD_MAX] ATTR_ALIGNED(64);
+ dcd_qtd_t qtd[QHD_MAX] ATTR_ALIGNED(32);
}dcd_data_t;
#if (CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE)
@@ -229,7 +234,6 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
{
- // TODO USB1 only has 4 non-control enpoint (USB0 has 5)
// TODO not support ISO yet
TU_VERIFY ( p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
@@ -237,6 +241,9 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
uint8_t const dir = edpt_dir(p_endpoint_desc->bEndpointAddress);
uint8_t const ep_idx = 2*epnum + dir;
+ // USB0 has 5, USB1 has 3 non-control endpoints
+ TU_ASSERT( epnum <= (rhport ? 3 : 5) );
+
//------------- Prepare Queue Head -------------//
dcd_qhd_t * p_qhd = &dcd_data_ptr[rhport]->qhd[ep_idx];
tu_memclr(p_qhd, sizeof(dcd_qhd_t));
@@ -351,7 +358,7 @@ void hal_dcd_isr(uint8_t rhport)
if ( edpt_complete )
{
- for(uint8_t ep_idx = 0; ep_idx < DCD_QHD_MAX; ep_idx++)
+ for(uint8_t ep_idx = 0; ep_idx < QHD_MAX; ep_idx++)
{
if ( BIT_TEST_(edpt_complete, ep_idx2bit(ep_idx)) )
{
diff --git a/src/portable/nxp/lpc18_43/dcd_lpc18_43.h b/src/portable/nxp/lpc18_43/dcd_lpc18_43.h
index cd54cae7c..faf0e3b0f 100644
--- a/src/portable/nxp/lpc18_43/dcd_lpc18_43.h
+++ b/src/portable/nxp/lpc18_43/dcd_lpc18_43.h
@@ -52,10 +52,6 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
-#define DCD_QHD_MAX 12
-#define DCD_QTD_MAX 12
-
-#define QTD_NEXT_INVALID 0x01
/*---------- ENDPTCTRL ----------*/
enum {
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 1bcf6aa8d..d808a0518 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -53,8 +53,9 @@
#define OPT_MCU_LPC13XX 3 ///< NXP LPC13xx
#define OPT_MCU_LPC175X_6X 4 ///< NXP LPC175x, LPC176x
#define OPT_MCU_LPC177X_8X 5 ///< NXP LPC177x, LPC178x
-#define OPT_MCU_LPC18XX 6 ///< NXP LPC18xx series
-#define OPT_MCU_LPC43XX 7 ///< NXP LPC43xx series
+#define OPT_MCU_LPC18XX 6 ///< NXP LPC18xx
+#define OPT_MCU_LPC40XX 7 ///< NXP LPC40xx
+#define OPT_MCU_LPC43XX 8 ///< NXP LPC43xx
#define OPT_MCU_NRF5X 100 ///< Nordic nRF5x series