diff --git a/examples/device/cdc_msc_hid/ses/lpc175x_6x/lpc175x_6x.emProject b/examples/device/cdc_msc_hid/ses/lpc175x_6x/lpc175x_6x.emProject index f281415a6..e060f71ed 100644 --- a/examples/device/cdc_msc_hid/ses/lpc175x_6x/lpc175x_6x.emProject +++ b/examples/device/cdc_msc_hid/ses/lpc175x_6x/lpc175x_6x.emProject @@ -32,7 +32,7 @@ project_directory="" project_type="Executable" target_reset_script="Reset();" - target_script_file="$(ProjectDir)/LPC4300_Target.js" + target_script_file="$(ProjectDir)/LPC1700_Target.js" target_trace_initialize_script="EnableTrace("$(TraceInterfaceType)")" /> + diff --git a/hw/bsp/lpcxpresso1769/board_lpcxpresso1769.c b/hw/bsp/lpcxpresso1769/board_lpcxpresso1769.c index 4321a3f3c..dd2194894 100644 --- a/hw/bsp/lpcxpresso1769/board_lpcxpresso1769.c +++ b/hw/bsp/lpcxpresso1769/board_lpcxpresso1769.c @@ -36,10 +36,14 @@ */ /**************************************************************************/ -#include "../board.h" +#include "bsp/board.h" +#include "tusb.h" #ifdef BOARD_LPCXPRESSO1769 +#include "LPC17xx.h" +#include "lpc17xx_pinsel.h" + #define BOARD_LED_PORT (0) #define BOARD_LED_PIN (22) @@ -89,6 +93,7 @@ void board_init(void) //P0_21 instead of P2_9 as USB connect #endif +#if 0 //------------- UART -------------// PINSEL_CFG_Type PinCfg = { @@ -110,20 +115,43 @@ void board_init(void) UART_Init(BOARD_UART_PORT, &UARTConfigStruct); UART_TxCmd(BOARD_UART_PORT, ENABLE); // Enable UART Transmit +#endif } +/*------------------------------------------------------------------*/ +/* TUSB HAL MILLISECOND + *------------------------------------------------------------------*/ +#if CFG_TUSB_OS == OPT_OS_NONE + +volatile uint32_t system_ticks = 0; + +void SysTick_Handler (void) +{ + system_ticks++; +} + +uint32_t tusb_hal_millis(void) +{ + return board_tick2ms(system_ticks); +} + +#endif + //--------------------------------------------------------------------+ // LEDS //--------------------------------------------------------------------+ -void board_leds(uint32_t on_mask, uint32_t off_mask) +void board_led_control(uint32_t id, bool state) { - if (on_mask & BIT_(0)) + (void) id; + + if (state) { GPIO_SetValue(BOARD_LED_PORT, BIT_(BOARD_LED_PIN)); - }else if (off_mask & BIT_(0)) + }else { GPIO_ClearValue(BOARD_LED_PORT, BIT_(BOARD_LED_PIN)); } + } //--------------------------------------------------------------------+ @@ -148,12 +176,12 @@ uint32_t board_buttons(void) //--------------------------------------------------------------------+ void board_uart_putchar(uint8_t c) { - UART_Send(BOARD_UART_PORT, &c, 1, BLOCKING); +// UART_Send(BOARD_UART_PORT, &c, 1, BLOCKING); } uint8_t board_uart_getchar(void) { - return UART_ReceiveByte(BOARD_UART_PORT); +// return UART_ReceiveByte(BOARD_UART_PORT); } #endif diff --git a/hw/bsp/lpcxpresso1769/board_lpcxpresso1769.h b/hw/bsp/lpcxpresso1769/board_lpcxpresso1769.h index 06520e16b..9f2f94865 100644 --- a/hw/bsp/lpcxpresso1769/board_lpcxpresso1769.h +++ b/hw/bsp/lpcxpresso1769/board_lpcxpresso1769.h @@ -53,6 +53,9 @@ #define CFG_PRINTF_TARGET PRINTF_TARGET_UART //#define CFG_PRINTF_TARGET PRINTF_TARGET_SWO +#define BOARD_LED_NUM 1 +#define BOARD_LED0 0 + #ifdef __cplusplus } diff --git a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c b/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c index ce8362546..c5b5d6b46 100644 --- a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c +++ b/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c @@ -40,13 +40,9 @@ #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" //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF @@ -54,53 +50,119 @@ #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 +typedef struct ATTR_ALIGNED(4) +{ + //------------- Word 0 -------------// + uint32_t next; - uint8_t class_code[DCD_QHD_MAX]; + //------------- Word 1 -------------// + uint16_t mode : 2; // either 00 normal or 01 ATLE(auto length extraction) + uint16_t next_valid : 1; + uint16_t int_on_complete : 1; ///< make use of reserved bit + uint16_t isochronous : 1; // is an iso endpoint + uint16_t max_packet_size : 11; + volatile uint16_t buffer_length; - struct { + //------------- Word 2 -------------// + volatile uint32_t buffer_addr; + + //------------- 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_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 + +typedef struct +{ + // must be 128 byte aligned + volatile dcd_dma_descriptor_t* udca[DCD_QHD_MAX]; + + // each endpoints can have up to 2 DD queued at a time + // TODO DMA does not support control transfer (0-1 are not used, offset to reduce memory) + dcd_dma_descriptor_t dd[DCD_QTD_MAX][2]; + + struct + { uint8_t* p_data; uint16_t remaining_bytes; - uint8_t int_on_complete; - }control_dma; + bool out_received; // -}dcd_data_t; + uint8_t in_bytes; + } control_dma; -CFG_TUSB_MEM_SECTION ATTR_ALIGNED(128) STATIC_VAR dcd_data_t dcd_data; +} dcd_data_t; + +CFG_TUSB_MEM_SECTION ATTR_ALIGNED(128) static dcd_data_t dcd_data; + + +//--------------------------------------------------------------------+ +// 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); + + 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 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 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; +} //--------------------------------------------------------------------+ // 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); //--------------------------------------------------------------------+ // 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) +static inline uint8_t edpt_addr2phy(uint8_t ep_addr) { - return 2*(endpoint_addr & 0x0F) + ((endpoint_addr & TUSB_DIR_IN_MASK) ? 1 : 0); + return 2*(ep_addr & 0x0F) + ((ep_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 +{ + // follows example in 11.10.4.2 LPC_USB->USBReEp |= BIT_(ep_id); LPC_USB->USBEpInd = ep_id; // select index before setting packet size LPC_USB->USBMaxPSize = max_packet_size; -#ifndef _TEST_ while ((LPC_USB->USBDevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {} // TODO can be omitted LPC_USB->USBDevIntClr = DEV_INT_ENDPOINT_REALIZED_MASK; -#endif - } + //--------------------------------------------------------------------+ // USBD-DCD API //--------------------------------------------------------------------+ @@ -144,152 +206,6 @@ bool dcd_init(uint8_t rhport) return TUSB_ERROR_NONE; } -static void endpoint_non_control_isr(uint32_t eot_int) -{ - 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 - - // 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 - } - } - } - } -} - -static void endpoint_control_isr(void) -{ - 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 }; - - //------------- 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 - - event.event_id = DCD_EVENT_SETUP_RECEIVED; - pipe_control_read(&event.setup_received, 8); // TODO read before clear setup above - - dcd_event_handler(&event, true); - } - else if (endpoint_int_status & 0x03) - { - uint8_t const ep_id = ( endpoint_int_status & BIT_(0) ) ? 0 : 1; - - 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; - - // FIXME xferred_byte for control xfer is not needed now !!! - dcd_xfer_complete(edpt_hdl, 0, true); - } - } - } - - LPC_USB->USBEpIntClr = endpoint_int_status; // acknowledge interrupt TODO cannot immediately acknowledge setup packet -} - -void hal_dcd_isr(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 }; - - //------------- 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(); - - event.event_id = DCD_EVENT_BUS_RESET; - dcd_event_handler(&event, true); - } - - 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); - } - - 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) - { - endpoint_control_isr(); - } - - //------------- 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); - } - - 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); - } -} - //--------------------------------------------------------------------+ // USBD API - CONTROLLER //--------------------------------------------------------------------+ @@ -321,25 +237,25 @@ static inline uint16_t length_byte2dword(uint16_t length_in_bytes) return (length_in_bytes + 3) / 4; // length_in_dword } -static tusb_error_t pipe_control_xfer(uint8_t ep_id, uint8_t* p_buffer, uint16_t length) -{ - uint16_t const packet_len = tu_min16(length, CFG_TUD_ENDOINT0_SIZE); +//static tusb_error_t pipe_control_xfer(uint8_t ep_id, uint8_t* p_buffer, uint16_t length) +//{ +// 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; +//} - 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) +static void pipe_control_write(void const * buffer, uint16_t length) { uint32_t const * p_write_data = (uint32_t const *) buffer; @@ -357,17 +273,16 @@ static tusb_error_t pipe_control_write(void const * buffer, uint16_t length) // select control IN & validate the endpoint sie_write(SIE_CMDCODE_ENDPOINT_SELECT+1, 0, 0); sie_write(SIE_CMDCODE_BUFFER_VALIDATE , 0, 0); - - return TUSB_ERROR_NONE; } -static tusb_error_t pipe_control_read(void * buffer, uint16_t length) +static uint8_t pipe_control_read(void * buffer, uint16_t length) { 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++) { *p_read_data = LPC_USB->USBRxData; @@ -380,108 +295,80 @@ 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 actual_length; } //--------------------------------------------------------------------+ -// 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) ); - - // 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; - - dcd_data.control_dma.int_on_complete = int_on_complete ? BIT_(ep_status) : 0; - - //------------- Data Phase -------------// - if ( length ) - { - dcd_data.control_dma.p_data = (uint8_t*) p_buffer; - dcd_data.control_dma.remaining_bytes = length; - - // lpc17xx already received the first DATA OUT packet by now - TU_VERIFY_ERR ( pipe_control_xfer(ep_data, p_buffer, length), false ); - } - - //------------- 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 ); - } - - 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) -{ - (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 +// 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 = edpt_addr2phy( p_endpoint_desc->bEndpointAddress ); //------------- 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; //------------- 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)); - p_dd->is_isochronous = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) ? 1 : 0; + p_dd->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 + p_dd->retired = 1; // inactive at first dcd_data.udca[ ep_id ] = p_dd; // hook to UDCA sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, 0); // clear all endpoint status - return (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.udca[edpt_hdl.index] != NULL && !dcd_data.udca[edpt_hdl.index]->is_retired); + (void) rhport; + + uint8_t ep_id = edpt_addr2phy( ep_addr ); + return (dcd_data.udca[ep_id] != NULL && !dcd_data.udca[ep_id]->retired); } -void dcd_edpt_stall(edpt_hdl_t edpt_hdl) +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { - sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+edpt_hdl.index, 1, SIE_SET_ENDPOINT_STALLED_MASK); + (void) rhport; + + if ( ep_addr == 0) + { + sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+0, 1, SIE_SET_ENDPOINT_STALLED_MASK | SIE_SET_ENDPOINT_CONDITION_STALLED_MASK); +// 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 = edpt_addr2phy( 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) { - uint8_t ep_id = ep_addr2phy(ep_addr); + uint8_t ep_id = edpt_addr2phy(ep_addr); sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, 0); } +bool dcd_edpt_stalled (uint8_t rhport, uint8_t ep_addr) +{ + // TODO implement later + return false; +} + void dd_xfer_init(dcd_dma_descriptor_t* p_dd, void* buffer, uint16_t total_bytes) { p_dd->next = 0; - p_dd->is_next_valid = 0; + p_dd->next_valid = 0; p_dd->buffer_addr = (uint32_t) buffer; p_dd->buffer_length = total_bytes; p_dd->status = DD_STATUS_NOT_SERVICED; @@ -489,55 +376,222 @@ void dd_xfer_init(dcd_dma_descriptor_t* p_dd, void* buffer, uint16_t total_bytes p_dd->present_count = 0; } -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 +//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 +// +// dd_xfer_init(p_fixed_dd, buffer, total_bytes); +// p_fixed_dd->is_retired = 1; +// p_fixed_dd->int_on_complete = 0; +// +// return TUSB_ERROR_NONE; +//} - dd_xfer_init(p_fixed_dd, buffer, total_bytes); - p_fixed_dd->is_retired = 1; - p_fixed_dd->int_on_complete = 0; +bool dcd_control_xfer(uint8_t rhport, uint8_t dir, uint8_t * buffer, uint16_t len) +{ + (void) rhport; - return TUSB_ERROR_NONE; + uint8_t const ep_idx = (dir == TUSB_DIR_IN) ? 1 : 0; + + if ( dir ) + { + dcd_data.control_dma.in_bytes = len; + pipe_control_write(buffer, len); + }else + { + dcd_data.control_dma.p_data = buffer; + dcd_data.control_dma.remaining_bytes = len; + + // lpc17xx already received the first DATA OUT packet by now + pipe_control_read(buffer, len); + + dcd_event_xfer_complete(0, 0, len, XFER_RESULT_SUCCESS, true); + } + + return true; } -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) { - dcd_dma_descriptor_t* const p_first_dd = &dcd_data.dd[edpt_hdl.index][0]; + uint8_t const epnum = edpt_number(ep_addr); + uint8_t const dir = edpt_dir(ep_addr); + + // Control transfer is not DMA support, and must be done in slave mode + if ( epnum == 0 ) + { + return dcd_control_xfer(rhport, dir, buffer, total_bytes); + } + + uint8_t ep_id = edpt_addr2phy(ep_addr); + dcd_dma_descriptor_t* const p_first_dd = &dcd_data.dd[ep_id][0]; //------------- fixed DD is already queued a xfer -------------// if ( p_first_dd->buffer_length ) { // setup new dd - dcd_dma_descriptor_t* const p_dd = &dcd_data.dd[ edpt_hdl.index ][1]; + dcd_dma_descriptor_t* const p_dd = &dcd_data.dd[ ep_id ][1]; tu_memclr(p_dd, sizeof(dcd_dma_descriptor_t)); dd_xfer_init(p_dd, buffer, total_bytes); 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; + p_dd->isochronous = p_first_dd->isochronous; + p_dd->int_on_complete = true; // hook to fixed dd p_first_dd->next = (uint32_t) p_dd; - p_first_dd->is_next_valid = 1; + p_first_dd->next_valid = 1; } //------------- fixed DD is free -------------// else { dd_xfer_init(p_first_dd, buffer, total_bytes); - p_first_dd->int_on_complete = int_on_complete; + p_first_dd->int_on_complete = true; } - p_first_dd->is_retired = 0; // activate xfer - dcd_data.udca[edpt_hdl.index] = p_first_dd; - LPC_USB->USBEpDMAEn = BIT_(edpt_hdl.index); + p_first_dd->retired = 0; // activate xfer + dcd_data.udca[ep_id] = p_first_dd; + LPC_USB->USBEpDMAEn = BIT_(ep_id); - if ( edpt_hdl.index % 2 ) - { // endpoint IN need to actively raise DMA request - LPC_USB->USBDMARSet = BIT_(edpt_hdl.index); + if ( ep_id % 2 ) + { + // endpoint IN need to actively raise DMA request + LPC_USB->USBDMARSet = BIT_(ep_id); } - return TUSB_ERROR_NONE; + return true; +} + +//--------------------------------------------------------------------+ +// ISR +//--------------------------------------------------------------------+ +static void endpoint_non_control_isr(uint32_t eot_int) +{ + 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->next_valid ? 1 : 0); // Maximum is 2 QTD are queued in an endpoint + + // 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 ) + { + uint8_t result = (p_last_dd->status == DD_STATUS_NORMAL || p_last_dd->status == DD_STATUS_DATA_UNDERUN) ? XFER_RESULT_SUCCESS : XFER_RESULT_FAILED; + + // report only xferred bytes in the IOC qtd + uint8_t const ep_addr = (ep_id/2) | ( (ep_id & 0x01) ? TUSB_DIR_IN_MASK : 0 ); + dcd_event_xfer_complete(0, ep_addr, p_last_dd->present_count, result, true); + } + } + } + } +} + +static void endpoint_control_isr(void) +{ + 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 }; + + //------------- Setup Received-------------// + 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 + + uint8_t setup_packet[8]; + pipe_control_read(setup_packet, 8); // TODO read before clear setup above + + dcd_event_setup_received(0, setup_packet, true); + } + else if (endpoint_int_status & 0x03) + { + uint8_t const ep_id = ( endpoint_int_status & BIT_(0) ) ? 0 : 1; + + if ( ep_id ) + { + // Control In + dcd_event_xfer_complete(0, ep_id ? TUSB_DIR_IN_MASK : 0 , dcd_data.control_dma.in_bytes, XFER_RESULT_SUCCESS, true); + }else + { + // Control Out + dcd_data.control_dma.out_received = true; + } + } + + LPC_USB->USBEpIntClr = endpoint_int_status; // acknowledge interrupt TODO cannot immediately acknowledge setup packet +} + +void hal_dcd_isr(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 + + //------------- 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(); + dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true); + } + + if (dev_status_reg & 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_reg & SIE_DEV_STATUS_SUSPEND_CHANGE_MASK) + { + if (dev_status_reg & SIE_DEV_STATUS_SUSPEND_MASK) + { + dcd_event_bus_signal(rhport, DCD_EVENT_SUSPENDED, true); + } +// else +// { // resume signal +// dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); +// } +// } + } + } + + //------------- Control Endpoint (Slave Mode) -------------// + if (device_int_status & DEV_INT_ENDPOINT_SLOW_MASK) + { + endpoint_control_isr(); + } + + //------------- 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); + } + + 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); + } } #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 +#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..cfe392e46 100644 --- a/src/portable/nxp/lpc17xx/hal_lpc175x_6x.c +++ b/src/portable/nxp/lpc17xx/hal_lpc175x_6x.c @@ -37,9 +37,10 @@ /**************************************************************************/ #include "common/tusb_common.h" -#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X -#include "hal_usb.h" +#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X + +#include "LPC17xx.h" void tusb_hal_int_enable(uint8_t rhport) { @@ -102,6 +103,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 260cc3a45..66ca04b71 100644 --- a/src/portable/nxp/lpc43xx_lpc18xx/dcd_lpc43xx.c +++ b/src/portable/nxp/lpc43xx_lpc18xx/dcd_lpc43xx.c @@ -392,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 } }