lpc13xx build ok (not work) with lpcopen

This commit is contained in:
hathach
2018-11-30 23:39:18 +07:00
parent 804c60304e
commit d246cc2e6c
86 changed files with 15932 additions and 6276 deletions

View File

@@ -40,21 +40,12 @@
#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13XX)
#define _TINY_USB_SOURCE_FILE_
// NOTE: despite of being very the same to lpc13uxx controller, lpc11u's controller cannot queue transfer more than
// endpoint's max packet size and need some soft DMA helper
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "common/tusb_common.h"
#include "hal/hal.h"
#include "osal/osal.h"
#include "chip.h"
#include "device/dcd.h"
#include "usbd_dcd.h"
#include "dcd_lpc_11uxx_13uxx.h"
#include "dcd_lpc11_13_15.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
@@ -134,8 +125,6 @@ typedef struct {
uint16_t queued_bytes_in_buff[2]; ///< expected bytes that are queued for each buffer
}current_td[DCD_11U_13U_QHD_COUNT];
uint8_t class_code[DCD_11U_13U_QHD_COUNT]; ///< class where the endpoints belongs to TODO no need for control endpoints
}dcd_11u_13u_data_t;
//--------------------------------------------------------------------+
@@ -194,7 +183,7 @@ bool dcd_init(uint8_t rhport)
LPC_USB->DEVCMDSTAT |= CMDSTAT_DEVICE_ENABLE_MASK | CMDSTAT_DEVICE_CONNECT_MASK |
CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
NVIC_EnableIRQ(USB_IRQn);
NVIC_EnableIRQ(USB0_IRQn);
return true;
}
@@ -247,17 +236,12 @@ static void endpoint_non_control_isr(uint32_t int_status)
if ( BIT_TEST_(dcd_data.current_ioc, ep_id) )
{
edpt_hdl_t edpt_hdl =
{
.rhport = 0,
.index = ep_id,
.class_code = dcd_data.class_code[ep_id]
};
dcd_data.current_ioc = BIT_CLR_(dcd_data.current_ioc, ep_id);
dcd_data.current_ioc = BIT_CLR_(dcd_data.current_ioc, edpt_hdl.index);
uint8_t const ep_addr = (ep_id / 2) | ((ep_id & 0x01) ? TUSB_DIR_IN_MASK : 0);
// TODO no way determine if the transfer is failed or not
dcd_xfer_complete(edpt_hdl, dcd_data.current_td[ep_id].xferred_total, true);
dcd_event_xfer_complete(0, ep_addr, dcd_data.current_td[ep_id].xferred_total, XFER_RESULT_SUCCESS, true);
}
//------------- Next TD is available -------------//
@@ -287,100 +271,14 @@ static void endpoint_control_isr(uint32_t int_status)
if ( BIT_TEST_(dcd_data.current_ioc, ep_id) )
{
edpt_hdl_t edpt_hdl = { .rhport = 0 };
dcd_data.current_ioc = BIT_CLR_(dcd_data.current_ioc, ep_id);
// FIXME xferred_byte for control xfer is not needed now !!!
dcd_xfer_complete(edpt_hdl, 0, true);
// FIXME control xferred bytes
dcd_event_xfer_complete(0, ep_id ? TUSB_DIR_IN_MASK : 0, 0, XFER_RESULT_SUCCESS, true);
}
}
}
void hal_dcd_isr(uint8_t rhport)
{
(void) rhport;
uint32_t const int_enable = LPC_USB->INTEN;
uint32_t const int_status = LPC_USB->INTSTAT & int_enable;
LPC_USB->INTSTAT = int_status; // Acknowledge handled interrupt
if (int_status == 0) return;
uint32_t const dev_cmd_stat = LPC_USB->DEVCMDSTAT;
dcd_event_t event = { .rhport = rhport };
//------------- Device Status -------------//
if ( int_status & INT_MASK_DEVICE_STATUS )
{
LPC_USB->DEVCMDSTAT |= CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
if ( dev_cmd_stat & CMDSTAT_RESET_CHANGE_MASK) // bus reset
{
bus_reset();
event.event_id = DCD_EVENT_BUS_RESET;
dcd_event_handler(&event, true);
}
if (dev_cmd_stat & CMDSTAT_CONNECT_CHANGE_MASK)
{ // device disconnect
if (dev_cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
{ // debouncing as this can be set when device is powering
event.event_id = DCD_EVENT_UNPLUGGED;
dcd_event_handler(&event, true);
}
}
// TODO support suspend & resume
if (dev_cmd_stat & CMDSTAT_SUSPEND_CHANGE_MASK)
{
if (dev_cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK)
{ // suspend signal, bus idle for more than 3ms
// Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
if (dev_cmd_stat & CMDSTAT_DEVICE_ADDR_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);
// }
// }
}
//------------- Setup Received -------------//
if ( BIT_TEST_(int_status, 0) && (dev_cmd_stat & CMDSTAT_SETUP_RECEIVED_MASK) )
{ // received control request from host
// copy setup request & acknowledge so that the next setup can be received by hw
event.event_id = DCD_EVENT_SETUP_RECEIVED;
event.setup_received = dcd_data.setup_request;
dcd_event_handler(&event, true);
// NXP control flowchart clear Active & Stall on both Control IN/OUT endpoints
dcd_data.qhd[0][0].stall = dcd_data.qhd[1][0].stall = 0;
LPC_USB->DEVCMDSTAT |= CMDSTAT_SETUP_RECEIVED_MASK;
dcd_data.qhd[0][1].buff_addr_offset = addr_offset(&dcd_data.setup_request);
}
//------------- Control Endpoint -------------//
else if ( int_status & 0x03 )
{
endpoint_control_isr(int_status);
}
//------------- Non-Control Endpoints -------------//
if( int_status & ~(0x03UL) )
{
endpoint_non_control_isr(int_status);
}
}
//--------------------------------------------------------------------+
// CONTROL PIPE API
//--------------------------------------------------------------------+
@@ -439,19 +337,21 @@ static inline uint8_t edpt_phy2log(uint8_t physical_endpoint)
//--------------------------------------------------------------------+
// BULK/INTERRUPT/ISOCHRONOUS PIPE API
//--------------------------------------------------------------------+
void dcd_edpt_stall(edpt_hdl_t edpt_hdl)
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
dcd_data.qhd[edpt_hdl.index][0].stall = dcd_data.qhd[edpt_hdl.index][1].stall = 1;
uint8_t const ep_id = edpt_addr2phy(edpt_addr);
dcd_data.qhd[ep_id][0].stall = dcd_data.qhd[ep_id][1].stall = 1;
}
bool dcd_pipe_is_stalled(edpt_hdl_t edpt_hdl)
bool dcd_edpt_stalled(uint8_t rhport, uint8_t ep_addr)
{
return dcd_data.qhd[edpt_hdl.index][0].stall || dcd_data.qhd[edpt_hdl.index][1].stall;
uint8_t const ep_id = edpt_addr2phy(edpt_addr);
return dcd_data.qhd[ep_id][0].stall || dcd_data.qhd[ep_id][1].stall;
}
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t edpt_addr)
{
uint8_t ep_id = edpt_addr2phy(edpt_addr);
uint8_t const ep_id = edpt_addr2phy(edpt_addr);
// uint8_t active_buffer = BIT_TEST_(LPC_USB->EPINUSE, ep_id) ? 1 : 0;
dcd_data.qhd[ep_id][0].stall = dcd_data.qhd[ep_id][1].stall = 0;
@@ -467,42 +367,33 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t edpt_addr)
}
}
edpt_hdl_t dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc, uint8_t class_code)
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
{
(void) rhport;
edpt_hdl_t const null_handle = { 0 };
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
// TODO prevent to open if endpoint size is not 64
// TODO not support ISO yet
if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) return false;
//------------- Prepare Queue Head -------------//
uint8_t ep_id = edpt_addr2phy(p_endpoint_desc->bEndpointAddress);
TU_ASSERT( dcd_data.qhd[ep_id][0].disable && dcd_data.qhd[ep_id][1].disable, null_handle ); // endpoint must not previously opened, normally this means running out of endpoints
// endpoint must not previously opened, normally this means running out of endpoints
TU_ASSERT( dcd_data.qhd[ep_id][0].disable && dcd_data.qhd[ep_id][1].disable );
tu_memclr(dcd_data.qhd[ep_id], 2*sizeof(dcd_11u_13u_qhd_t));
dcd_data.qhd[ep_id][0].is_isochronous = dcd_data.qhd[ep_id][1].is_isochronous = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
dcd_data.class_code[ep_id] = class_code;
dcd_data.qhd[ep_id][0].disable = dcd_data.qhd[ep_id][1].disable = 0;
LPC_USB->EPBUFCFG |= BIT_(ep_id);
LPC_USB->INTEN |= BIT_(ep_id);
return (edpt_hdl_t)
{
.rhport = 0,
.index = ep_id,
.class_code = class_code
};
return true;
}
bool dcd_edpt_busy(edpt_hdl_t edpt_hdl)
bool dcd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
{
return dcd_data.qhd[edpt_hdl.index][0].active || dcd_data.qhd[edpt_hdl.index][1].active;
uint8_t const ep_id = edpt_addr2phy(ep_addr);
return dcd_data.qhd[ep_id][0].active || dcd_data.qhd[ep_id][1].active;
}
static void queue_xfer_to_buffer(uint8_t ep_id, uint8_t buff_idx, uint16_t buff_addr_offset, uint16_t total_bytes)
@@ -546,33 +437,138 @@ static void queue_xfer_in_next_td(uint8_t ep_id)
dcd_data.next_td[ep_id].total_bytes = 0; // clear this field as it is used to indicate whehther next TD available
}
tusb_error_t dcd_edpt_queue_xfer(edpt_hdl_t edpt_hdl, uint8_t * buffer, uint16_t total_bytes)
tusb_error_t dcd_edpt_queue_xfer(uint8_t ep_id , uint8_t * buffer, uint16_t total_bytes)
{
TU_ASSERT( !dcd_edpt_busy(edpt_hdl), TUSB_ERROR_INTERFACE_IS_BUSY); // endpoint must not in transferring
dcd_data.current_ioc = BIT_CLR_(dcd_data.current_ioc, edpt_hdl.index);
pipe_queue_xfer(edpt_hdl.index, addr_offset(buffer), total_bytes);
dcd_data.current_ioc = BIT_CLR_(dcd_data.current_ioc, ep_id);
pipe_queue_xfer(ep_id, addr_offset(buffer), total_bytes);
return TUSB_ERROR_NONE;
}
tusb_error_t dcd_edpt_xfer(edpt_hdl_t edpt_hdl, uint8_t* buffer, uint16_t total_bytes, bool int_on_complete)
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
{
if( dcd_edpt_busy(edpt_hdl) || dcd_pipe_is_stalled(edpt_hdl) )
{ // save this transfer data to next td if pipe is busy or already been stalled
dcd_data.next_td[edpt_hdl.index].buff_addr_offset = addr_offset(buffer);
dcd_data.next_td[edpt_hdl.index].total_bytes = total_bytes;
uint8_t const ep_id = edpt_addr2phy(ep_addr);
dcd_data.next_ioc = int_on_complete ? BIT_SET_(dcd_data.next_ioc, edpt_hdl.index) : BIT_CLR_(dcd_data.next_ioc, edpt_hdl.index);
}else
// if( dcd_edpt_busy(ep_addr) || dcd_edpt_stalled(ep_addr) )
// { // save this transfer data to next td if pipe is busy or already been stalled
// dcd_data.next_td[ep_id].buff_addr_offset = addr_offset(buffer);
// dcd_data.next_td[ep_id].total_bytes = total_bytes;
//
// dcd_data.next_ioc = BIT_SET_(dcd_data.next_ioc, ep_id);
// }else
{
dcd_data.current_ioc = int_on_complete ? BIT_SET_(dcd_data.current_ioc, edpt_hdl.index) : BIT_CLR_(dcd_data.current_ioc, edpt_hdl.index);
dcd_data.current_ioc = BIT_SET_(dcd_data.current_ioc, ep_id);
pipe_queue_xfer(edpt_hdl.index, addr_offset(buffer), total_bytes);
pipe_queue_xfer(ep_id, addr_offset(buffer), total_bytes);
}
return TUSB_ERROR_NONE;
return true;
}
void tusb_hal_int_enable(uint8_t rhport)
{
(void) rhport; // discard compiler's warning
NVIC_EnableIRQ(USB0_IRQn);
}
void tusb_hal_int_disable(uint8_t rhport)
{
(void) rhport; // discard compiler's warning
NVIC_DisableIRQ(USB0_IRQn);
}
bool tusb_hal_init(void)
{
#if 0 // FIXME
// TODO remove magic number
LPC_SYSCON->SYSAHBCLKCTRL |= ((0x1<<14) | (0x1<<27)); /* Enable AHB clock to the USB block and USB RAM. */
LPC_SYSCON->PDRUNCFG &= ~( BIT_(8) | BIT_(10) ); // enable USB PLL & USB transceiver
/* Pull-down is needed, or internally, VBUS will be floating. This is to
address the wrong status in VBUSDebouncing bit in CmdStatus register. */
// set PIO0_3 as USB_VBUS
LPC_IOCON->PIO0_3 &= ~0x1F;
LPC_IOCON->PIO0_3 |= (0x01<<0) | (1 << 3); /* Secondary function VBUS */
// set PIO0_6 as usb connect
LPC_IOCON->PIO0_6 &= ~0x07;
LPC_IOCON->PIO0_6 |= (0x01<<0); /* Secondary function SoftConn */
#endif
return true;
}
void USB_IRQHandler(void)
{
uint32_t const int_enable = LPC_USB->INTEN;
uint32_t const int_status = LPC_USB->INTSTAT & int_enable;
LPC_USB->INTSTAT = int_status; // Acknowledge handled interrupt
if (int_status == 0) return;
uint32_t const dev_cmd_stat = LPC_USB->DEVCMDSTAT;
//------------- Device Status -------------//
if ( int_status & INT_MASK_DEVICE_STATUS )
{
LPC_USB->DEVCMDSTAT |= CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
if ( dev_cmd_stat & CMDSTAT_RESET_CHANGE_MASK) // bus reset
{
bus_reset();
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
}
if (dev_cmd_stat & CMDSTAT_CONNECT_CHANGE_MASK)
{
// device disconnect
if (dev_cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
{
// debouncing as this can be set when device is powering
dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
}
}
// TODO support suspend & resume
if (dev_cmd_stat & CMDSTAT_SUSPEND_CHANGE_MASK)
{
if (dev_cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK)
{ // suspend signal, bus idle for more than 3ms
// Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
if (dev_cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
{
dcd_event_bus_signal(0, DCD_EVENT_SUSPENDED, true);
}
}
}
// else
// { // resume signal
// dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
// }
// }
}
//------------- Setup Received -------------//
if ( BIT_TEST_(int_status, 0) && (dev_cmd_stat & CMDSTAT_SETUP_RECEIVED_MASK) )
{
// received control request from host
// copy setup request & acknowledge so that the next setup can be received by hw
dcd_event_setup_received(0, (uint8_t*) &dcd_data.setup_request, true);
// NXP control flowchart clear Active & Stall on both Control IN/OUT endpoints
dcd_data.qhd[0][0].stall = dcd_data.qhd[1][0].stall = 0;
LPC_USB->DEVCMDSTAT |= CMDSTAT_SETUP_RECEIVED_MASK;
dcd_data.qhd[0][1].buff_addr_offset = addr_offset(&dcd_data.setup_request);
}
//------------- Control Endpoint -------------//
else if ( int_status & 0x03 )
{
endpoint_control_isr(int_status);
}
//------------- Non-Control Endpoints -------------//
if( int_status & ~(0x03UL) )
{
endpoint_non_control_isr(int_status);
}
}
#endif