diff --git a/TESTS/usb_device/msd/main.cpp b/TESTS/usb_device/msd/main.cpp index 5624fcd298..65297f86cd 100644 --- a/TESTS/usb_device/msd/main.cpp +++ b/TESTS/usb_device/msd/main.cpp @@ -33,8 +33,8 @@ #include "HeapBlockDevice.h" #include "FATFileSystem.h" - -#if !defined(DEVICE_USBDEVICE) || !DEVICE_USBDEVICE +// TARGET_NANO100 SRAM 16KB can't afford mass-storage-disk test, so skip usb_msd_test. +#if !defined(DEVICE_USBDEVICE) || !DEVICE_USBDEVICE || TARGET_NANO100 #error [NOT_SUPPORTED] USB Device not supported for this target #else diff --git a/drivers/source/usb/USBCDC.cpp b/drivers/source/usb/USBCDC.cpp index 501c60a1b5..a5a55d5d30 100644 --- a/drivers/source/usb/USBCDC.cpp +++ b/drivers/source/usb/USBCDC.cpp @@ -464,8 +464,8 @@ void USBCDC::_receive_isr_start() { if ((_rx_size == 0) && !_rx_in_progress) { // Refill the buffer - read_start(_bulk_out, _rx_buffer, sizeof(_rx_buffer)); _rx_in_progress = true; + read_start(_bulk_out, _rx_buffer, sizeof(_rx_buffer)); } } diff --git a/targets/TARGET_NUVOTON/TARGET_M2351/device/StdDriver/m2351_clk.h b/targets/TARGET_NUVOTON/TARGET_M2351/device/StdDriver/m2351_clk.h index 331aff4ce0..3477e08fec 100644 --- a/targets/TARGET_NUVOTON/TARGET_M2351/device/StdDriver/m2351_clk.h +++ b/targets/TARGET_NUVOTON/TARGET_M2351/device/StdDriver/m2351_clk.h @@ -64,6 +64,7 @@ extern "C" #define CLK_CLKSEL0_SDH0SEL_HCLK (0x02UL<USBPHY = SYS_USBPHY_LDO33EN_Msk; + +#elif defined(TARGET_M480) +#if (MBED_CONF_TARGET_USB_DEVICE_HSUSBD == 0) + /* Configure USB to Device mode */ + SYS->USBPHY = (SYS->USBPHY & ~SYS_USBPHY_USBROLE_Msk) | SYS_USBPHY_USBROLE_STD_USBD; + + /* Enable USB PHY */ + SYS->USBPHY |= SYS_USBPHY_USBEN_Msk | SYS_USBPHY_SBO_Msk; + + /* Select IP clock source */ + CLK->CLKDIV0 = (CLK->CLKDIV0 & ~CLK_CLKDIV0_USBDIV_Msk) | CLK_CLKDIV0_USB(4); + + /* Enable IP clock */ + CLK_EnableModuleClock(USBD_MODULE); + + /* Configure pins for USB 1.1 port: VBUS/D+/D-/ID */ + pin_function(PA_12, SYS_GPA_MFPH_PA12MFP_USB_VBUS); + pin_function(PA_13, SYS_GPA_MFPH_PA13MFP_USB_D_N); + pin_function(PA_14, SYS_GPA_MFPH_PA14MFP_USB_D_P); + pin_function(PA_15, (int) SYS_GPA_MFPH_PA15MFP_USB_OTG_ID); +#else + /* Configure HSUSB to Device mode */ + SYS->USBPHY = (SYS->USBPHY & ~SYS_USBPHY_HSUSBROLE_Msk) | SYS_USBPHY_HSUSBROLE_STD_USBD; + /* Enable HSUSB PHY */ + SYS->USBPHY = (SYS->USBPHY & ~(SYS_USBPHY_HSUSBEN_Msk | SYS_USBPHY_HSUSBACT_Msk)) | SYS_USBPHY_HSUSBEN_Msk; + /* Delay >10 us and then switch HSUSB PHY from reset state to active state */ + wait_us(10); + SYS->USBPHY |= SYS_USBPHY_HSUSBACT_Msk; + + /* Enable USBD module clock */ + CLK_EnableModuleClock(HSUSBD_MODULE); +#endif + +#elif defined (TARGET_M2351) || defined(TARGET_M261) + + /* Select USBD */ + SYS->USBPHY = (SYS->USBPHY & ~SYS_USBPHY_USBROLE_Msk) | SYS_USBPHY_OTGPHYEN_Msk | SYS_USBPHY_SBO_Msk; + + /* Enable IP clock */ + CLK_EnableModuleClock(USBD_MODULE); + + /* Select IP clock source */ + CLK_SetModuleClock(USBD_MODULE, CLK_CLKSEL0_USBSEL_HIRC48, CLK_CLKDIV0_USB(1)); + + /* USBD multi-function pins for VBUS, D+, D-, and ID pins */ + SYS->GPA_MFPH &= ~(SYS_GPA_MFPH_PA12MFP_Msk | SYS_GPA_MFPH_PA13MFP_Msk | SYS_GPA_MFPH_PA14MFP_Msk | SYS_GPA_MFPH_PA15MFP_Msk); + SYS->GPA_MFPH |= (SYS_GPA_MFPH_PA12MFP_USB_VBUS | SYS_GPA_MFPH_PA13MFP_USB_D_N | SYS_GPA_MFPH_PA14MFP_USB_D_P | SYS_GPA_MFPH_PA15MFP_USB_OTG_ID); + + +#elif defined (TARGET_NANO100) + + /* Select IP clock source */ + CLK_SetModuleClock(USBD_MODULE, 0, CLK_USB_CLK_DIVIDER(2)); + /* Enable IP clock */ + CLK_EnableModuleClock(USBD_MODULE); + +#elif defined (TARGET_NUC472) + + /* Enable USBD module clock */ + CLK_EnableModuleClock(USBD_MODULE); + + /* Enable USB PHY's LDO33. Run as USB device. */ + SYS->USBPHY = SYS_USBPHY_USBROLE_OTG_V33_EN | SYS_USBPHY_USBROLE_STD_USBD; + +#endif +} + +#if (MBED_CONF_TARGET_USB_DEVICE_HSUSBD == 0) + +// Conversion macros +#define DESC_TO_LOG(endpoint) ((endpoint) & 0xF) +#define NU_EPH2EPL(ep) ep +#define NU_EPL2EPH(ep) ep +#define HW_TO_DESC(endpoint) (endpoint|(((endpoint&1)?0x0:0x80))) + +/* Global variables for Control Pipe */ +#if defined(TARGET_M261) +extern uint8_t g_USBD_au8SetupPacket[]; /*!< Setup packet buffer */ +uint8_t* g_usbd_SetupPacket=g_USBD_au8SetupPacket; +#else +extern uint8_t g_usbd_SetupPacket[]; /*!< Setup packet buffer */ +#endif + +#define CEP_BUF_BASE 8 +#define MAX_CEP_SIZE 64 + +static volatile uint32_t s_ep_compl = 0; +static volatile uint32_t s_ep_buf_ind = 8; +static volatile uint32_t s_ep0_max_packet_size = MAX_CEP_SIZE; +static volatile uint8_t s_usb_addr = 0; +static volatile uint8_t s_ep_data_bit[NUMBER_OF_PHYSICAL_ENDPOINTS] = {1}; +static volatile uint8_t s_ep_mxp[NUMBER_OF_PHYSICAL_ENDPOINTS] = {0}; +volatile uint8_t s_ep_valid[NUMBER_OF_PHYSICAL_ENDPOINTS] = {0}; +extern volatile uint8_t *g_usbd_CtrlInPointer; +extern volatile uint32_t g_usbd_CtrlInSize; +extern volatile uint8_t *g_usbd_CtrlOutPointer; +extern volatile uint32_t g_usbd_CtrlOutSize; +extern volatile uint32_t g_usbd_CtrlOutSizeLimit; +extern volatile uint32_t g_usbd_UsbConfig; +extern volatile uint32_t g_usbd_CtrlMaxPktSize; +extern volatile uint32_t g_usbd_UsbAltInterface; +volatile uint32_t g_usbd_CepTransferLen = 0; +volatile uint32_t frame_cnt = 0; + + +USBPhy *get_usb_phy() +{ + static USBPhyHw usbphy; + return &usbphy; +} + +USBPhyHw::USBPhyHw(): events(NULL) +{ + +} + +USBPhyHw::~USBPhyHw() +{ + +} + +/* + Initialize this USBPhy instance. + This function must be called before calling any other functions of this class, unless specifically noted. +*/ +void USBPhyHw::init(USBPhyEvents *events) +{ + if (this->events == NULL) { + sleep_manager_lock_deep_sleep(); + } + this->events = events; + + SYS_UnlockReg(); + + s_ep_buf_ind = 0; + + chip_config(); + + /* Initial USB engine */ +#if defined (TARGET_NANO100) + USBD->CTL = 0x29f; + USBD->PDMA |= USBD_PDMA_BYTEM_Msk; +#else + USBD->ATTR = 0x7D0; +#endif + /* Set SE0 (disconnect) */ + USBD_SET_SE0(); + + NVIC_SetVector(USBD_IRQn, (uint32_t) &USBD_IRQHandler); + NVIC_EnableIRQ(USBD_IRQn); + + instance = this; +} + +void USBPhyHw::deinit() +{ + NVIC_DisableIRQ(USBD_IRQn); + USBD_SET_SE0(); + USBD_DISABLE_PHY(); + + if (events != NULL) + { + sleep_manager_unlock_deep_sleep(); + } + events = NULL; +} + +/* + Check if USB power is present. + Devices which don't support checking the USB power state must always return true. +*/ +bool USBPhyHw::powered() +{ + return true; +} + +void EpInit(void); + +void USBPhyHw::connect() +{ + int volatile i = 0; + memset(read_buffers, 0, sizeof(read_buffers)); + memset(read_sizes, 0, sizeof(read_sizes)); + + s_ep_compl = 0; + + EpInit(); + /* Disable software-disconnect function */ + USBD_CLR_SE0(); + + /* Clear USB-related interrupts before enable interrupt */ + USBD_CLR_INT_FLAG(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP); + + /* Enable USB-related interrupts. */ + USBD_ENABLE_INT(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP); +} + +/* Make the USB phy visible to the USB host. + Enable either the D+ or D- pullup so the host can detect the presence of this device. */ +void USBPhyHw::disconnect() +{ + uint32_t volatile i = 0; +#if 1 +#if defined (TARGET_NANO100) + SYS->IPRST_CTL2 = SYS_IPRST_CTL2_USBD_RST_Msk; +#else + SYS->IPRST1 = SYS_IPRST1_USBDRST_Msk; +#endif + for(i=0;i<1000;i++) + ; + +#if defined (TARGET_NANO100) + SYS->IPRST_CTL2 = 0; +#else + SYS->IPRST1 = 0; +#endif + + s_ep_buf_ind = 0; + + /* Initial USB engine */ +#if defined (TARGET_NANO100) + USBD->CTL = 0x29f; + USBD->PDMA |= USBD_PDMA_BYTEM_Msk; +#else + USBD->ATTR = 0x7D0; +#endif +#endif + /* Set SE0 (disconnect) */ + USBD_SET_SE0(); + + memset(read_buffers, 0, sizeof(read_buffers)); + memset(read_sizes, 0, sizeof(read_sizes)); + + frame_cnt = 0; + + EpInit(); + + /* Clear USB-related interrupts before disable interrupt */ + USBD_CLR_INT_FLAG(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP); + + /* Disable USB-related interrupts. */ + USBD->INTEN = 0; +} + + +void EpInit(void) +{ + uint32_t volatile i = 0; + +#if defined (TARGET_NANO100) + USBD->BUFSEG = 0; +#else + USBD->STBUFSEG = 0; +#endif + + memset((void *)s_ep_valid, 0, sizeof(s_ep_valid)); + + /* EP0 ==> control IN endpoint, address 0 */ + USBD_CONFIG_EP(EP0, USBD_CFG_CSTALL | USBD_CFG_EPMODE_IN | 0); + + /* Buffer range for EP0 */ + USBD_SET_EP_BUF_ADDR(EP0, CEP_BUF_BASE); + + /* EP1 ==> control OUT endpoint, address 0 */ + USBD_CONFIG_EP(EP1, USBD_CFG_CSTALL | USBD_CFG_EPMODE_OUT | 0); + + /* Buffer range for EP1 */ + USBD_SET_EP_BUF_ADDR(EP1, CEP_BUF_BASE); + + s_ep_buf_ind = CEP_BUF_BASE + MAX_CEP_SIZE; + + for(i=2;iCTL |= USBD_CTL_RWAKEUP_Msk; +#else + USBD->ATTR |= USBD_ATTR_RWAKEUP_Msk; +#endif +} + +/* + Get the endpoint table. + This function returns a table which describes the endpoints can be used, the functionality of those endpoints and the resource cost. +*/ +const usb_ep_table_t *USBPhyHw::endpoint_table() +{ + static const usb_ep_table_t endpoint_table = { + 1, // No cost per endpoint - everything allocated up front + { + {USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, +#if (!TARGET_M451) + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_OUT, 0, 0}, +#endif + } + }; + return &endpoint_table; +} +/* + Set wMaxPacketSize of endpoint 0. + */ +uint32_t USBPhyHw::ep0_set_max_packet(uint32_t max_packet) +{ + s_ep0_max_packet_size = max_packet; + return s_ep0_max_packet_size; +} + +/* Read the contents of the SETUP packet. */ +void USBPhyHw::ep0_setup_read_result(uint8_t *buffer, uint32_t size) +{ + USBD_MemCopy(g_usbd_SetupPacket, (uint8_t *)USBD_BUF_BASE, 8); + if (buffer) + USBD_MemCopy(buffer, g_usbd_SetupPacket, 8); + USBD_SET_PAYLOAD_LEN(EP1, s_ep0_max_packet_size); +} + +/* + Start receiving a packet of up to wMaxPacketSize on endpoint 0. +*/ +void USBPhyHw::ep0_read(uint8_t *data, uint32_t size) +{ + read_buffers[0] = data; + read_sizes[0] = size; +} +/* + Read the contents of a received packet. +*/ +uint32_t USBPhyHw::ep0_read_result() +{ + uint32_t i; + uint8_t *buf = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP1)); + uint8_t *buffer = read_buffers[0]; + uint32_t ceprxcnt = USBD_GET_PAYLOAD_LEN(EP1); + if(buffer) + { + for (i = 0; i < ceprxcnt; i ++) + buffer[i] = buf[i]; + } + USBD_SET_PAYLOAD_LEN(EP1, read_sizes[0]); + if(read_sizes[0] == 0) + ceprxcnt = 0; + read_buffers[0] = 0; + read_sizes[0] = 0; + return ceprxcnt; +} + +/* Write a packet on endpoint 0. */ +void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size) +{ + if (buffer && size) + { + if(s_ep_data_bit[0] & 1) + USBD_SET_DATA1(EP0); + else + USBD_SET_DATA0(EP0); + s_ep_data_bit[0]++; + USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), buffer, size); + USBD_SET_PAYLOAD_LEN(EP0, size); + if(size < s_ep0_max_packet_size) + s_ep_data_bit[0] = 1; + } + else + { + s_ep_data_bit[0] = 1; + USBD_SET_DATA1(EP0); + wait_us(500); + USBD_SET_PAYLOAD_LEN(EP0, 0); + + if((USBD->EPSTS & 0xF) == 0x00) /* NAK */ + USBD_SET_PAYLOAD_LEN(EP0, 0); + } +} + +void stallEndpoint(uint8_t endpoint) +{ + uint32_t ep_logic_index = DESC_TO_LOG(endpoint); + if (ep_logic_index >= NUMBER_OF_LOGICAL_ENDPOINTS) + return; + + USBD_SetStall(ep_logic_index); +} + +/* Protocol stall on endpoint 0. + Stall all IN and OUT packets on endpoint 0 until a setup packet is received. + Note The stall is cleared automatically when a setup packet is received +*/ +void USBPhyHw::ep0_stall() +{ + stallEndpoint(0); + stallEndpoint(1); +} + +/* Configure and enable an endpoint. */ +/* + endpoint Endpoint to configure and enable + max_packet The maximum packet size that can be sent or received + type The type of endpoint this should be configured as - USB_EP_TYPE_BULK, USB_EP_TYPE_INT or USB_EP_TYPE_ISO + This function cannot be used to configure endpoint 0. That must be done with ep0_set_max_packet +*/ +bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type) +{ + uint32_t ep_type = 0; + uint32_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t ep_hw_index = NU_EPL2EPH(ep_logic_index); + uint32_t ep_dir = (endpoint & 0x80) ? USBD_CFG_EPMODE_IN : USBD_CFG_EPMODE_OUT; + + if(type == USB_EP_TYPE_ISO) + ep_type = USBD_CFG_TYPE_ISO; + + USBD_CONFIG_EP(ep_hw_index, ep_dir | ep_type | ep_logic_index); + + /* Buffer range */ +// USBD_SET_EP_BUF_ADDR(ep_hw_index, s_ep_buf_ind); + + s_ep_mxp[ep_logic_index] = max_packet; +// s_ep_buf_ind += max_packet; + s_ep_valid[ep_logic_index] = 1; + return true; +} + +void USBPhyHw::endpoint_remove(usb_ep_t endpoint) +{ + +} + +/* + Perform a functional stall on the given endpoint. + Set the HALT feature for this endpoint so that all further communication is aborted. +*/ +void USBPhyHw::endpoint_stall(usb_ep_t endpoint) +{ + USBD_SetStall(DESC_TO_LOG(endpoint)); +} + +/* + Unstall the endpoint. + Clear the HALT feature on this endpoint so communication can resume. + */ +void USBPhyHw::endpoint_unstall(usb_ep_t endpoint) +{ + uint32_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t ep_hw_index = NU_EPL2EPH(ep_logic_index); + if (ep_logic_index >= NUMBER_OF_LOGICAL_ENDPOINTS) + return; + USBD_ClearStall(ep_logic_index); + USBD_SET_DATA0(ep_hw_index); + s_ep_compl &= ~(1 << ep_logic_index); + s_ep_valid[ep_logic_index] = 1; +} + +/* Start a read on the given endpoint. */ +bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size) +{ + /* Store the buffer address & length */ + uint32_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t ep_hw_index = NU_EPL2EPH(ep_logic_index); + USBD_SET_PAYLOAD_LEN(ep_hw_index,s_ep_mxp[ep_logic_index]); + read_buffers[ep_logic_index] = data; + read_sizes[ep_logic_index] = size; + return true; +} + +/* + Finish a read on the given endpoint + Returns The number of bytes received +*/ +uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint) +{ + uint8_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t bytes_read = 0; + endpoint_read_result_core(endpoint, read_buffers[ep_logic_index], read_sizes[ep_logic_index], &bytes_read); + read_buffers[ep_logic_index] = NULL; + read_sizes[ep_logic_index] = 0; + return bytes_read; +} + +bool USBPhyHw::endpoint_read_result_core(usb_ep_t endpoint, uint8_t *data, uint32_t size, uint32_t *bytes_read) +{ + uint32_t i; + uint8_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t ep_hw_index = NU_EPL2EPH(ep_logic_index); + uint8_t *buf = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(ep_hw_index)); + uint32_t eprxcnt = USBD_GET_PAYLOAD_LEN(ep_hw_index); + for (i = 0; i < eprxcnt; i ++) + data[i] = buf[i]; + *bytes_read = eprxcnt; + return true; +} + +/* + Start a write on the given endpoint. + true if the data was prepared for transmit, false otherwise +*/ +bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size) +{ + uint32_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t ep_hw_index = NU_EPL2EPH(ep_logic_index); + + if(ep_logic_index == 0) + return false; + else + { + uint8_t *buf; + uint32_t i=0; + if(s_ep_compl & (1 << ep_logic_index)) + return false; + + s_ep_compl |= (1 << ep_logic_index); + + buf = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(ep_hw_index)); + + for(i=0; ireset(); + } + +#if defined (TARGET_NANO100) + if(u32State & USBD_BUSSTS_SUSPEND_Msk) +#else + if(u32State & USBD_ATTR_SUSPEND_Msk) +#endif + { + /* Enable USB but disable PHY */ + USBD_DISABLE_PHY(); + } +#if defined (TARGET_NANO100) + if(u32State & USBD_BUSSTS_RESUME_Msk) +#else + if(u32State & USBD_ATTR_RESUME_Msk) +#endif + { + /* Enable USB and enable PHY */ + USBD_ENABLE_USB(); + } + } + +#if defined (TARGET_NANO100) + if(u32IntSts & USBD_INTSTS_USB_STS_Msk) +#else + if(u32IntSts & USBD_INTSTS_USBIF_Msk) +#endif + { + /* USB event */ + if(u32IntSts & USBD_INTSTS_SETUP_Msk) + { + /* Setup packet */ + /* Clear event flag */ + USBD_CLR_INT_FLAG(USBD_INTSTS_SETUP_Msk); + /* Clear the data IN/OUT ready flag of control end-points */ + USBD_STOP_TRANSACTION(EP0); + USBD_STOP_TRANSACTION(EP1); + events->ep0_setup(); + } + + /* EP events */ + if(u32IntSts & USBD_INTSTS_EP0) + { + /* Clear event flag */ + USBD_CLR_INT_FLAG(USBD_INTSTS_EP0); + /* Control IN */ + events->ep0_in(); + /* In ACK for Set address */ +#if defined(TARGET_M480) || defined(TARGET_M451) + if((g_usbd_SetupPacket[0] == REQ_STANDARD) && (g_usbd_SetupPacket[1] == USBD_SET_ADDRESS)) +#else + if((g_usbd_SetupPacket[0] == REQ_STANDARD) && (g_usbd_SetupPacket[1] == SET_ADDRESS)) +#endif + { + if((USBD_GET_ADDR() != s_usb_addr) && (USBD_GET_ADDR() == 0)) + { + USBD_SET_ADDR(s_usb_addr); + } + } + } + if(u32IntSts & USBD_INTSTS_EP1) + { + /* Clear event flag */ + USBD_CLR_INT_FLAG(USBD_INTSTS_EP1); + + /* Control OUT */ + events->ep0_out(); + } + + uint32_t gintsts_epx = (u32IntSts >> 18) & 0x3F; + uint32_t ep_hw_index = 2; + while (gintsts_epx) + { + if(gintsts_epx & 0x01) + { + uint32_t ep_status; +#if defined(TARGET_M451) + ep_status = (USBD->EPSTS >> (ep_hw_index * 3 + 8)) & 0x7; +#elif defined(TARGET_NANO100) + if(ep_hw_index < 6) + ep_status = (USBD->EPSTS >> (ep_hw_index * 4 + 8)) & 0xF; + else + ep_status = (USBD->EPSTS2 >> ((ep_hw_index - 6) * 4)) & 0x7; +#elif defined(TARGET_M480) || defined(TARGET_M2351) || defined(TARGET_M261) + if(ep_hw_index < 8) + ep_status = (USBD->EPSTS0 >> (ep_hw_index * 4)) & 0xF; + else + ep_status = (USBD->EPSTS1 >> ((ep_hw_index - 8) * 4)) & 0xF; +#endif + /* Clear event flag */ + USBD_CLR_INT_FLAG(1 << (ep_hw_index + 16)); + + if(ep_status == 0x02 || ep_status == 0x06 || (ep_status == 0x07 && (ep_hw_index & 0x01) == 1)) + { /* RX */ + s_ep_compl &= ~(1 << (NU_EPH2EPL(ep_hw_index))); + if(s_ep_valid[NU_EPH2EPL(ep_hw_index)]) + events->out(HW_TO_DESC(ep_hw_index)); + s_ep_valid[NU_EPH2EPL(ep_hw_index)] = 1; + } + else if(ep_status == 0x00 || ep_status == 0x07) + { /* TX */ + s_ep_compl &= ~(1 << (NU_EPH2EPL(ep_hw_index))); + if(s_ep_valid[NU_EPH2EPL(ep_hw_index)]) + events->in(HW_TO_DESC(ep_hw_index)); + s_ep_valid[NU_EPH2EPL(ep_hw_index)] = 1; + } + } + gintsts_epx = gintsts_epx >> 1; + ep_hw_index++; + } + } +} + +extern "C" void USBD_IRQHandler(void) +{ + instance->events->start_process(); +} +#else +/* USB 2.0 Engine */ +static volatile int epComplete = 0; + +// Conversion macros +#define DESC_TO_LOG(endpoint) ((endpoint) & 0xF) +#define NU_EPH2EPL(ep) ((ep) + 1) +#define NU_EPL2EPH(ep) (ep - 1) + +#define EP_DIR_Msk 0x80 +#define EP_DIR_OUT 0x00 +#define EP_DIR_IN 0x80 + +#if defined (TARGET_M480) +#define HSUSBD_GET_EP_MAX_PAYLOAD(ep) HSUSBD->EP[ep].EPMPS +#define HSUSBD_GET_EP_DATA_COUNT(ep) (HSUSBD->EP[ep].EPDATCNT & 0xFFFFF) +#define HSUSBD_SET_EP_SHORT_PACKET(ep) HSUSBD->EP[ep].EPRSPCTL = ((HSUSBD->EP[ep].EPRSPCTL & 0x10) | 0x40) +#define HSUSBD_GET_EP_INT_EN(ep) HSUSBD->EP[ep].EPINTEN +#elif defined (TARGET_NUC472) +#define USBD_GET_EP_MAX_PAYLOAD(ep) *((__IO uint32_t *) ((uint32_t)&USBD->EPAMPS + (uint32_t)(ep*0x28))) +#define USBD_GET_EP_DATA_COUNT(ep) *((__IO uint32_t *) ((uint32_t)&USBD->EPADATCNT + (uint32_t)(ep*0x28))) +#define USBD_SET_EP_SHORT_PACKET(ep) *((__IO uint32_t *) ((uint32_t)&USBD->EPARSPCTL + (uint32_t)(ep*0x28))) = ((*((__IO uint32_t *)((uint32_t)&USBD->EPARSPCTL+(uint32_t)(ep*0x28))) & 0x10) | 0x40) +#define USBD_SET_EP_BUF_FLUSH(ep) *((__IO uint32_t *) ((uint32_t)&USBD->EPARSPCTL + (uint32_t)(ep*0x28))) = USBD_EPRSPCTL_FLUSH_Msk +#define USBD_GET_EP_INT_EN(ep) *((__IO uint32_t *) ((uint32_t)&USBD->EPAINTEN + (uint32_t)(ep*0x28))) +#define USBD_GET_EP_INT(ep) *((__IO uint32_t *) ((uint32_t)&USBD->EPAINTSTS + (uint32_t)(ep*0x28))) +#define USBD_CLR_EP_INT(ep, intr) (*((__IO uint32_t *) ((uint32_t)&USBD->EPAINTSTS + (uint32_t)(ep*0x28))) = (intr)) /*!= g_usbd_CtrlMaxPktSize) + { + for (i=0; iCEPDAT_BYTE = *(uint8_t *)(g_usbd_CtrlInPointer++); + USBD->CEPTXCNT = g_usbd_CtrlMaxPktSize; + g_usb_CtrlInSize -= g_usbd_CtrlMaxPktSize; + } + else + { + for (i=0; iCEPDAT_BYTE = *(uint8_t *)(g_usbd_CtrlInPointer++); + USBD->CEPTXCNT = g_usb_CtrlInSize; + g_usbd_CtrlInPointer = 0; + g_usb_CtrlInSize = 0; + } +} +#elif defined (TARGET_M480) +void HSUSBD_CtrlInput(void) +{ + unsigned volatile i; + uint32_t volatile count; + + /*************************** Enable Buffer ***************************/ + HSUSBD_SetEpBufAddr(CEP, 0, s_ep0_max_packet_size); + if(g_usb_CtrlInSize >= g_usbd_CtrlMaxPktSize) + { + for (i=0; iCEPDAT_BYTE = *(uint8_t *)(g_usbd_CtrlInPointer++); + HSUSBD->CEPTXCNT = g_usbd_CtrlMaxPktSize; + g_usb_CtrlInSize -= g_usbd_CtrlMaxPktSize; + } + else + { + for (i=0; iCEPDAT_BYTE = *(uint8_t *)(g_usbd_CtrlInPointer++); + HSUSBD->CEPTXCNT = g_usb_CtrlInSize; + g_usbd_CtrlInPointer = 0; + g_usb_CtrlInSize = 0; + } +} +#endif + +USBPhy *get_usb_phy() +{ + static USBPhyHw usbphy; + return &usbphy; +} + + +USBPhyHw::USBPhyHw(): events(NULL) +{ +} + +USBPhyHw::~USBPhyHw() +{ +} + +/* + Initialize this USBPhy instance. + This function must be called before calling any other functions of this class, unless specifically noted. +*/ +void USBPhyHw::init(USBPhyEvents *events) +{ + if (this->events == NULL) + sleep_manager_lock_deep_sleep(); + + this->events = events; + + SYS_UnlockReg(); + + s_ep_buf_ind = 0; + + chip_config(); + +#if defined (TARGET_NUC472) + + USBD_ENABLE_PHY(); + + while (1) + { + USBD->EPAMPS = 0x20; + if (USBD->EPAMPS == 0x20) + break; + } + + /* Set SE0 (disconnect) */ + USBD_SET_SE0(); + + NVIC_SetVector(USBD_IRQn, (uint32_t) &USBD_IRQHandler); + NVIC_EnableIRQ(USBD_IRQn); + +#elif defined (TARGET_M480) + HSUSBD_ENABLE_PHY(); + + while (1) + { + HSUSBD->EP[0].EPMPS = 0x20; + if (HSUSBD->EP[0].EPMPS == 0x20) + break; + } + + /* Set SE0 (disconnect) */ + HSUSBD_SET_SE0(); + + NVIC_SetVector(USBD20_IRQn, (uint32_t) &USBD_IRQHandler); + NVIC_EnableIRQ(USBD20_IRQn); +#endif + + instance = this; +} + +void USBPhyHw::deinit() +{ + disconnect(); + +#if defined (TARGET_NUC472) + + NVIC_DisableIRQ(USBD_IRQn); + + USBD_SET_SE0(); + USBD_DISABLE_PHY(); + +#elif defined (TARGET_M480) + + NVIC_DisableIRQ(USBD20_IRQn); + + HSUSBD_SET_SE0(); + HSUSBD_DISABLE_PHY(); + +#endif + + if (events != NULL) + { + sleep_manager_unlock_deep_sleep(); + } + events = NULL; +} + +/* + Check if USB power is present. + Devices which don't support checking the USB power state must always return true. +*/ +bool USBPhyHw::powered() +{ + return true; +} + +void USBPhyHw::connect() +{ + memset(read_buffers, 0, sizeof(read_buffers)); + memset(read_sizes, 0, sizeof(read_sizes)); + +#if defined (TARGET_NUC472) + USBD_ResetDMA(); + USBD_SET_ADDR(0); + + /** + * Control Transfer Packet Size Constraints + * low-speed: 8 + * full-speed: 8, 16, 32, 64 + * high-speed: 64 + */ + /* Control endpoint */ + USBD_SetEpBufAddr(CEP, 0, s_ep0_max_packet_size); + s_ep_buf_ind = s_ep0_max_packet_size; + + /* Enable USB/CEP interrupt */ + USBD_ENABLE_USB_INT(USBD_GINTEN_USBIE_Msk | USBD_GINTEN_CEPIE_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk| USBD_CEPINTEN_STSDONEIEN_Msk); + + /* Enable BUS interrupt */ + USBD_ENABLE_BUS_INT( + USBD_BUSINTEN_RESUMEIEN_Msk | + USBD_BUSINTEN_RSTIEN_Msk | + USBD_BUSINTEN_VBUSDETIEN_Msk + ); + + /* Clear SE0 (connect) */ + USBD_CLR_SE0(); + +#elif defined (TARGET_M480) + HSUSBD_ResetDMA(); + HSUSBD_SET_ADDR(0); + + /** + * Control Transfer Packet Size Constraints + * low-speed: 8 + * full-speed: 8, 16, 32, 64 + * high-speed: 64 + */ + /* Control endpoint */ + /*************************** Disable Buffer ***************************/ + HSUSBD_SetEpBufAddr(CEP, 0, 1); + s_ep_buf_ind = s_ep0_max_packet_size; + + /* Enable USB/CEP interrupt */ + HSUSBD_ENABLE_USB_INT(HSUSBD_GINTEN_USBIEN_Msk | HSUSBD_GINTEN_CEPIEN_Msk); + HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_SETUPTKIEN_Msk|HSUSBD_CEPINTEN_SETUPPKIEN_Msk|HSUSBD_CEPINTEN_STSDONEIEN_Msk); + + /* Enable BUS interrupt */ + HSUSBD_ENABLE_BUS_INT( + HSUSBD_BUSINTEN_RESUMEIEN_Msk | + HSUSBD_BUSINTEN_RSTIEN_Msk | + HSUSBD_BUSINTEN_VBUSDETIEN_Msk + ); + + /* Clear SE0 (connect) */ + HSUSBD_CLR_SE0(); +#endif +} + +/* Make the USB phy visible to the USB host. + Enable either the D+ or D- pullup so the host can detect the presence of this device. */ +void USBPhyHw::disconnect() +{ + /* Set SE0 (disconnect) */ +#if defined (TARGET_NUC472) + USBD_SET_SE0(); +#elif defined (TARGET_M480) + HSUSBD_SET_SE0(); +#endif +} + +/* Set this device to the configured state. + Enable added endpoints if they are not enabled already. */ +void USBPhyHw::configure() +{ + // not needed +} + +/* + Leave the configured state. + This is a notification to the USBPhy indicating that the device is leaving the configured state. The USBPhy can disable all endpoints other than endpoint 0. +*/ +void USBPhyHw::unconfigure() +{ + s_ep_buf_ind = s_ep0_max_packet_size; +} + +/* Enable the start of frame interrupt. */ +void USBPhyHw::sof_enable() +{ +#if defined (TARGET_NUC472) + USBD->BUSINTEN |= USBD_BUSINTEN_SOFIEN_Msk; +#elif defined (TARGET_M480) + HSUSBD->BUSINTEN |= HSUSBD_BUSINTEN_SOFIEN_Msk; +#endif +} + +/* Disable the start of frame interrupt. */ +void USBPhyHw::sof_disable() +{ +#if defined (TARGET_NUC472) + USBD->BUSINTEN &= ~USBD_BUSINTEN_SOFIEN_Msk; +#elif defined (TARGET_M480) + HSUSBD->BUSINTEN &= ~HSUSBD_BUSINTEN_SOFIEN_Msk; +#endif +} + +/* Set the USBPhy's address. */ +void USBPhyHw::set_address(uint8_t address) +{ + s_usb_addr = address; +} + +/* Wake upstream devices */ +void USBPhyHw::remote_wakeup() +{ +#if defined (TARGET_NUC472) + USBD->OPER |= USBD_OPER_RESUMEEN_Msk; +#elif defined (TARGET_M480) + HSUSBD->OPER |= HSUSBD_OPER_RESUMEEN_Msk; +#endif +} + +/* + Get the endpoint table. + This function returns a table which describes the endpoints can be used, the functionality of those endpoints and the resource cost. +*/ +const usb_ep_table_t *USBPhyHw::endpoint_table() +{ + static const usb_ep_table_t endpoint_table = { + 1, // No cost per endpoint - everything allocated up front + { + {USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_IN , 0, 0}, + {ALLOW_ALL_EXCEPT_CRTL | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN, 0, 0} + } + }; + return &endpoint_table; +} +/* + Set wMaxPacketSize of endpoint 0. + */ +uint32_t USBPhyHw::ep0_set_max_packet(uint32_t max_packet) +{ + s_ep0_max_packet_size = max_packet; + return s_ep0_max_packet_size; +} + +/* Read the contents of the SETUP packet. */ +void USBPhyHw::ep0_setup_read_result(uint8_t *buffer, uint32_t size) +{ +#if defined (TARGET_NUC472) + *((uint16_t *) (buffer + 0)) = (uint16_t) USBD->SETUP1_0; + *((uint16_t *) (buffer + 2)) = (uint16_t) USBD->SETUP3_2; + *((uint16_t *) (buffer + 4)) = (uint16_t) USBD->SETUP5_4; + *((uint16_t *) (buffer + 6)) = (uint16_t) USBD->SETUP7_6; + + s_setup.bmRequestType = (uint8_t) (USBD->SETUP1_0 & 0xff); + s_setup.bRequest = (int8_t) (USBD->SETUP1_0 >> 8) & 0xff; + s_setup.wValue = (uint16_t) USBD->SETUP3_2; + s_setup.wIndex = (uint16_t) USBD->SETUP5_4; + s_setup.wLength = (uint16_t) USBD->SETUP7_6; +#elif defined (TARGET_M480) + *((uint16_t *) (buffer + 0)) = (uint16_t) HSUSBD->SETUP1_0; + *((uint16_t *) (buffer + 2)) = (uint16_t) HSUSBD->SETUP3_2; + *((uint16_t *) (buffer + 4)) = (uint16_t) HSUSBD->SETUP5_4; + *((uint16_t *) (buffer + 6)) = (uint16_t) HSUSBD->SETUP7_6; + + s_setup.bmRequestType = (uint8_t) (HSUSBD->SETUP1_0 & 0xff); + s_setup.bRequest = (int8_t) (HSUSBD->SETUP1_0 >> 8) & 0xff; + s_setup.wValue = (uint16_t) HSUSBD->SETUP3_2; + s_setup.wIndex = (uint16_t) HSUSBD->SETUP5_4; + s_setup.wLength = (uint16_t) HSUSBD->SETUP7_6; +#endif +} + +/* + Start receiving a packet of up to wMaxPacketSize on endpoint 0. +*/ +void USBPhyHw::ep0_read(uint8_t *data, uint32_t size) +{ +#if defined (TARGET_NUC472) + if (s_setup.wLength && ! (s_setup.bmRequestType & 0x80)) + { + /* Control OUT */ + read_buffers[0] = data; + read_sizes[0] = size; + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk | USBD_CEPINTEN_RXPKIEN_Msk); + } + else + { + /* Status stage */ + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk); + USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_STSDONEIEN_Msk|USBD_CEPINTEN_INTKIEN_Msk); + } +#elif defined (TARGET_M480) + if (s_setup.wLength && ! (s_setup.bmRequestType & 0x80)) + { + /* Control OUT */ + read_buffers[0] = data; + read_sizes[0] = size; + HSUSBD->CEPINTSTS = HSUSBD_CEPINTSTS_NAKIF_Msk; + HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_SETUPTKIEN_Msk|HSUSBD_CEPINTEN_SETUPPKIEN_Msk | HSUSBD_CEPINTEN_RXPKIEN_Msk | HSUSBD_CEPINTEN_NAKIEN_Msk); + } + else + { + /* Status stage */ + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_STSDONEIF_Msk); + HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_NAKCLR); + HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_STSDONEIEN_Msk|HSUSBD_CEPINTEN_INTKIEN_Msk); + /*************************** Disable Buffer ***************************/ + HSUSBD_SetEpBufAddr(CEP, 0, 1); + } +#endif +} +/* + Read the contents of a received packet. +*/ +uint32_t USBPhyHw::ep0_read_result() +{ + uint32_t i; + uint8_t *ep0_data = read_buffers[0]; +#if defined (TARGET_NUC472) + uint32_t ceprxcnt = USBD->CEPRXCNT; + + for (i = 0; i < ceprxcnt; i ++) + ep0_data[i] = USBD->CEPDAT_BYTE; +#elif defined (TARGET_M480) + uint32_t ceprxcnt = HSUSBD->CEPRXCNT; + + for (i = 0; i < ceprxcnt; i ++) + ep0_data[i] = HSUSBD->CEPDAT_BYTE; +#endif + return ceprxcnt; +} + +/* Write a packet on endpoint 0. */ +void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size) +{ +#if defined (TARGET_NUC472) + if (buffer && size) + { + g_usbd_CtrlInPointer = buffer; + g_usb_CtrlInSize = size; + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_INTKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_INTKIEN_Msk); + } + else + { + /* Status stage */ + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk); + USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_STSDONEIEN_Msk); + } +#elif defined (TARGET_M480) + if (buffer && size) + { + g_usbd_CtrlInPointer = buffer; + g_usb_CtrlInSize = size; + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_INTKIF_Msk); + HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_INTKIEN_Msk); + } + else + { + /* Status stage */ + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_STSDONEIF_Msk); + HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_NAKCLR); + HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_STSDONEIEN_Msk); + } +#endif +} + +void stallEndpoint(uint8_t endpoint) +{ + uint32_t ep_hw_index = NU_EPL2EPH(endpoint); + if (ep_hw_index >= NUMBER_OF_PHYSICAL_ENDPOINTS) + return; +#if defined (TARGET_NUC472) + USBD_SetStall(ep_hw_index); +#elif defined (TARGET_M480) + HSUSBD_SetStall(ep_hw_index); +#endif +} + +/* Protocol stall on endpoint 0. + Stall all IN and OUT packets on endpoint 0 until a setup packet is received. + Note The stall is cleared automatically when a setup packet is received +*/ +void USBPhyHw::ep0_stall() +{ +#if defined (TARGET_NUC472) + USBD_SetStall(0); +#elif defined (TARGET_M480) + HSUSBD_SetStall(0); +#endif +} + +/* Configure and enable an endpoint. */ +/* + endpoint Endpoint to configure and enable + max_packet The maximum packet size that can be sent or received + type The type of endpoint this should be configured as - USB_EP_TYPE_BULK, USB_EP_TYPE_INT or USB_EP_TYPE_ISO + This function cannot be used to configure endpoint 0. That must be done with ep0_set_max_packet +*/ +bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type) +{ + uint32_t ep_type; + uint32_t ep_hw_index = NU_EPL2EPH(DESC_TO_LOG(endpoint)); + +#if defined (TARGET_NUC472) + USBD_SetEpBufAddr(ep_hw_index, s_ep_buf_ind, max_packet); + s_ep_buf_ind += max_packet; + USBD_SET_MAX_PAYLOAD(ep_hw_index, max_packet); + switch (type) + { + case USB_EP_TYPE_INT: + ep_type = USB_EP_CFG_TYPE_INT; + break; + + case USB_EP_TYPE_ISO: + ep_type = USB_EP_CFG_TYPE_ISO; + break; + + default: + ep_type = USB_EP_CFG_TYPE_BULK; + } + + uint32_t ep_dir = ((endpoint & EP_DIR_Msk) == EP_DIR_IN) ? USB_EP_CFG_DIR_IN : USB_EP_CFG_DIR_OUT; + USBD_ConfigEp(ep_hw_index, DESC_TO_LOG(endpoint), ep_type, ep_dir); + + /* Enable USB/EPX interrupt */ + // NOTE: Require USBD_GINTEN_EPAIE_Pos, USBD_GINTEN_EPBIE_Pos, ... USBD_GINTEN_EPLIE_Pos to be consecutive. + USBD_ENABLE_USB_INT(USBD->GINTEN | USBD_GINTEN_USBIE_Msk | + USBD_GINTEN_CEPIE_Msk | + 1 << (ep_hw_index + USBD_GINTEN_EPAIE_Pos)); + + if (ep_dir != 0) + USBD_ENABLE_EP_INT(ep_hw_index, USBD_EPINTEN_TXPKIEN_Msk); +#elif defined (TARGET_M480) + HSUSBD_SetEpBufAddr(ep_hw_index, s_ep_buf_ind, max_packet); + s_ep_buf_ind += max_packet; + HSUSBD_SET_MAX_PAYLOAD(ep_hw_index, max_packet); + switch (type) + { + case USB_EP_TYPE_INT: + ep_type = HSUSBD_EP_CFG_TYPE_INT; + break; + + case USB_EP_TYPE_ISO: + ep_type = HSUSBD_EP_CFG_TYPE_ISO; + break; + + default: + ep_type = HSUSBD_EP_CFG_TYPE_BULK; + } + + uint32_t ep_dir = ((endpoint & EP_DIR_Msk) == EP_DIR_IN) ? HSUSBD_EP_CFG_DIR_IN : HSUSBD_EP_CFG_DIR_OUT; + HSUSBD_ConfigEp(ep_hw_index, DESC_TO_LOG(endpoint), ep_type, ep_dir); + + /* Enable USB/EPX interrupt */ + // NOTE: Require USBD_GINTEN_EPAIE_Pos, USBD_GINTEN_EPBIE_Pos, ... USBD_GINTEN_EPLIE_Pos to be consecutive. + HSUSBD_ENABLE_USB_INT(HSUSBD->GINTEN | HSUSBD_GINTEN_USBIEN_Msk | + HSUSBD_GINTEN_CEPIEN_Msk | + 1 << (ep_hw_index + HSUSBD_GINTEN_EPAIEN_Pos)); +#endif + return true; +} + +void USBPhyHw::endpoint_remove(usb_ep_t endpoint) +{ + uint32_t ep_hw_index = NU_EPL2EPH(DESC_TO_LOG(endpoint)); +#if defined (TARGET_NUC472) + *((__IO uint32_t *) ((uint32_t)&USBD->EPACFG + (uint32_t)(ep_hw_index*0x28))) = (*((__IO uint32_t *)((uint32_t)&USBD->EPACFG+(uint32_t)(ep_hw_index*0x28))) & ~USB_EP_CFG_VALID); +#elif defined (TARGET_M480) + HSUSBD->EP[ep_hw_index].EPCFG = HSUSBD->EP[ep_hw_index].EPCFG & ~HSUSBD_EP_CFG_VALID; +#endif +} + +/* + Perform a functional stall on the given endpoint. + Set the HALT feature for this endpoint so that all further communication is aborted. +*/ +void USBPhyHw::endpoint_stall(usb_ep_t endpoint) +{ + uint8_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t ep_hw_index = NU_EPL2EPH(ep_logic_index); +#if defined (TARGET_NUC472) + if(ep_logic_index == 0) + USBD_SetStall(0); + else + USBD_SetStall(ep_logic_index); +#elif defined (TARGET_M480) + if(ep_logic_index == 0) + HSUSBD_SetEpStall(CEP); + else + HSUSBD_SetEpStall(ep_hw_index); +#endif +} + +/* + Unstall the endpoint. + Clear the HALT feature on this endpoint so communication can resume. + */ +void USBPhyHw::endpoint_unstall(usb_ep_t endpoint) +{ + uint8_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t ep_hw_index = NU_EPL2EPH(ep_logic_index); +#if defined (TARGET_NUC472) + if(ep_logic_index != 0) + USBD_ClearStall(ep_logic_index); +#elif defined (TARGET_M480) + if(ep_logic_index != 0) + HSUSBD_ClearEpStall(ep_hw_index); +#endif +} + +/* Start a read on the given endpoint. */ +bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size) +{ +/* Store the buffer address & length */ + uint8_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t ep_hw_index = NU_EPL2EPH(ep_logic_index); + read_buffers[ep_logic_index] = data; + read_sizes[ep_logic_index] = size; +#if defined (TARGET_NUC472) + USBD_ENABLE_EP_INT(ep_hw_index, USBD_GET_EP_INT_EN(ep_hw_index) | USBD_EPINTEN_RXPKIEN_Msk); +#elif defined (TARGET_M480) + HSUSBD->EP[ep_hw_index].EPINTEN |= HSUSBD_EPINTEN_RXPKIEN_Msk; +#endif + return true; +} + +/* + Finish a read on the given endpoint + Returns The number of bytes received +*/ +uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint) +{ + uint32_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t bytes_read = 0; + endpoint_read_result_core(endpoint, read_buffers[ep_logic_index], read_sizes[ep_logic_index], &bytes_read); + read_buffers[ep_logic_index] = 0; + read_sizes[ep_logic_index] = 0; + return bytes_read; +} + +bool USBPhyHw::endpoint_read_result_core(usb_ep_t endpoint, uint8_t *data, uint32_t size, uint32_t *bytes_read) +{ + uint32_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t ep_hw_index = NU_EPL2EPH(ep_logic_index); + uint8_t __attribute__((aligned(4))) tmp_buffer[4]; + uint32_t volatile buffer, len, i; +#if defined (TARGET_NUC472) + uint32_t mps = USBD_GET_EP_MAX_PAYLOAD(ep_hw_index); + + gEpReadCnt = USBD_GET_EP_DATA_COUNT(ep_hw_index); +#elif defined (TARGET_M480) + uint32_t mps = HSUSBD_GET_EP_MAX_PAYLOAD(ep_hw_index); + + gEpReadCnt = HSUSBD_GET_EP_DATA_COUNT(ep_hw_index); +#endif + + if(gEpReadCnt == 0) + { + *bytes_read = 0; + return true; + } + + buffer = (uint32_t)data; + + if(buffer % 4) + { + len = 4 - (buffer % 4); + if(gEpReadCnt <= len) + len = gEpReadCnt; + + while(1) + { +#if defined (TARGET_NUC472) + if (!(USBD->DMACTL & USBD_DMACTL_DMAEN_Msk)) + break; + else if (!USBD_IS_ATTACHED()) + break; +#elif defined (TARGET_M480) + if (!(HSUSBD->DMACTL & HSUSBD_DMACTL_DMAEN_Msk)) + break; + else if (!HSUSBD_IS_ATTACHED()) + break; +#endif + } +#if defined (TARGET_NUC472) + USBD_SET_DMA_LEN(len); + USBD_SET_DMA_ADDR((uint32_t)tmp_buffer); + USBD_SET_DMA_WRITE(ep_logic_index); + USBD_ENABLE_DMA(); +#elif defined (TARGET_M480) + HSUSBD_SET_DMA_LEN(len); + HSUSBD_SET_DMA_ADDR((uint32_t)tmp_buffer); + HSUSBD_SET_DMA_WRITE(ep_logic_index); + HSUSBD_ENABLE_DMA(); +#endif + + while(1) + { +#if defined (TARGET_NUC472) + if (!(USBD->DMACTL & USBD_DMACTL_DMAEN_Msk)) + break; + else if (!USBD_IS_ATTACHED()) + break; +#elif defined (TARGET_M480) + if (!(HSUSBD->DMACTL & HSUSBD_DMACTL_DMAEN_Msk)) + break; + else if (!HSUSBD_IS_ATTACHED()) + break; +#endif + } + for(i=0;iDMACTL & USBD_DMACTL_DMAEN_Msk)) + break; + else if (!USBD_IS_ATTACHED()) + break; + } +#elif defined (TARGET_M480) + HSUSBD_SET_DMA_LEN(len); + HSUSBD_SET_DMA_ADDR(buffer); + HSUSBD_SET_DMA_WRITE(ep_logic_index); + HSUSBD_ENABLE_DMA(); + while(1) + { + if (!(HSUSBD->DMACTL & HSUSBD_DMACTL_DMAEN_Msk)) + break; + else if (!HSUSBD_IS_ATTACHED()) + break; + } +#endif + + } + *bytes_read = gEpReadCnt; + return true; +} + +/* + Start a write on the given endpoint. + true if the data was prepared for transmit, false otherwise +*/ +bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size) +{ + uint32_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t ep_hw_index = NU_EPL2EPH(ep_logic_index); + uint8_t __attribute__((aligned(4))) tmp_buffer[4]; + + if(ep_logic_index == 0) + return false; + else + { +#if defined (TARGET_NUC472) + uint32_t mps = USBD_GET_EP_MAX_PAYLOAD(ep_hw_index); +#elif defined (TARGET_M480) + uint32_t mps = HSUSBD_GET_EP_MAX_PAYLOAD(ep_hw_index); +#endif + + uint32_t buffer, len, i; + if (size > mps) + return false; + +#if defined (TARGET_NUC472) + if(USBD_GET_EP_DATA_COUNT(ep_hw_index) & 0xFFFF) + { + USBD_SET_EP_SHORT_PACKET(ep_hw_index); + return false; + } +#elif defined (TARGET_M480) + if(HSUSBD->EP[ep_hw_index].EPDATCNT & 0xFFFF) + { + HSUSBD_SET_EP_SHORT_PACKET(ep_hw_index); + return false; + } +#endif + + if(size < mps) + g_usb_ShortPacket = 1; + + while(1) + { +#if defined (TARGET_NUC472) + if (!(USBD->DMACTL & USBD_DMACTL_DMAEN_Msk)) + break; + else if (!USBD_IS_ATTACHED()) + break; +#elif defined (TARGET_M480) + if (!(HSUSBD->DMACTL & HSUSBD_DMACTL_DMAEN_Msk)) + break; + else if (!HSUSBD_IS_ATTACHED()) + break; +#endif + } + buffer = (uint32_t)data; + if(buffer % 4) + { + len = 4 - (buffer % 4); + if(size <= len) + len = size; + + for(i=0;iDMACTL & USBD_DMACTL_DMAEN_Msk)) + break; + else if (!USBD_IS_ATTACHED()) + break; + } +#elif defined (TARGET_M480) + HSUSBD_SET_DMA_LEN(len); + HSUSBD_SET_DMA_ADDR((uint32_t)tmp_buffer); + HSUSBD_SET_DMA_READ(ep_logic_index); + HSUSBD_ENABLE_DMA(); + while(1) + { + if (!(HSUSBD->DMACTL & HSUSBD_DMACTL_DMAEN_Msk)) + break; + else if (!HSUSBD_IS_ATTACHED()) + break; + } +#endif + buffer = buffer + len; + len = size - len; + } + else + len = size; + + if(len) + { +#if defined (TARGET_NUC472) + USBD_SET_DMA_LEN(len); + USBD_SET_DMA_ADDR((uint32_t)buffer); + USBD_SET_DMA_READ(ep_logic_index); + USBD_ENABLE_DMA(); + while(1) + { + if (!(USBD->DMACTL & USBD_DMACTL_DMAEN_Msk)) + break; + else if (!USBD_IS_ATTACHED()) + break; + } +#elif defined (TARGET_M480) + HSUSBD_SET_DMA_LEN(len); + HSUSBD_SET_DMA_ADDR((uint32_t)buffer); + HSUSBD_SET_DMA_READ(ep_logic_index); + HSUSBD_ENABLE_DMA(); + while(1) + { + if (!(HSUSBD->DMACTL & HSUSBD_DMACTL_DMAEN_Msk)) + break; + else if (!HSUSBD_IS_ATTACHED()) + break; + } +#endif + } + +#if defined (TARGET_NUC472) + if(g_usb_ShortPacket) + USBD_SET_EP_SHORT_PACKET(ep_hw_index); + USBD_ENABLE_EP_INT(ep_hw_index, USBD_GET_EP_INT_EN(ep_hw_index) | USBD_EPINTEN_TXPKIEN_Msk); +#elif defined (TARGET_M480) + if(g_usb_ShortPacket) + HSUSBD_SET_EP_SHORT_PACKET(ep_hw_index); + HSUSBD->EP[ep_hw_index].EPINTEN |= HSUSBD_EPINTEN_TXPKIEN_Msk; +#endif + } + return true; +} + +/* Abort the current transfer if it has not yet been sent. */ +void USBPhyHw::endpoint_abort(usb_ep_t endpoint) +{ + uint32_t ep_logic_index = DESC_TO_LOG(endpoint); + uint32_t ep_hw_index = NU_EPL2EPH(ep_logic_index); +#if defined (TARGET_NUC472) + USBD_CLR_EP_INT(ep_hw_index, USBD_GET_EP_INT(ep_hw_index)); + USBD_ENABLE_EP_INT(ep_hw_index, 0); + USBD_SET_EP_BUF_FLUSH(ep_hw_index); +#elif defined (TARGET_M480) + HSUSBD->EP[ep_hw_index].EPINTEN = 0; + HSUSBD->EP[ep_hw_index].EPINTSTS = HSUSBD->EP[ep_hw_index].EPINTSTS; + HSUSBD->EP[ep_hw_index].EPRSPCTL = HSUSBD_EPRSPCTL_FLUSH_Msk; +#endif +} + +/* + Callback used for performing USB processing. + USBPhy processing should be triggered by calling USBPhyEvents::start_process and done inside process. All USBPhyEvents callbacks aside from USBPhyEvents::start_process must be called in the context of process +*/ +void USBPhyHw::process() +{ +#if defined (TARGET_NUC472) + uint32_t gintsts = USBD->GINTSTS & USBD->GINTEN; + uint32_t gintsts_epx = gintsts >> 2; /* EPA, EPB, EPC, ... EPL interrupts */ + uint32_t ep_hw_index = 0; + uint32_t ep_logic_index = 0,i; + + if (! gintsts) + return; + + if (gintsts & USBD_GINTSTS_USBIF_Msk) + { + uint32_t busintsts = USBD->BUSINTSTS & USBD->BUSINTEN; + + /* SOF */ + if (busintsts & USBD_BUSINTSTS_SOFIF_Msk) + { + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_SOFIF_Msk); + + events->sof(USBD->FRAMECNT >> 3); + } + + /* Reset */ + if (busintsts & USBD_BUSINTSTS_RSTIF_Msk) + { + connect(); + events->reset(); + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_RSTIF_Msk); + USBD_CLR_CEP_INT_FLAG(0x1ffc); + } + + /* Resume */ + if (busintsts & USBD_BUSINTSTS_RESUMEIF_Msk) + { + USBD_ENABLE_BUS_INT(USBD_BUSINTEN_RSTIEN_Msk | USBD_BUSINTEN_SUSPENDIEN_Msk); + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_RESUMEIF_Msk); +// events->suspend(false); + } + + /* Suspend */ + if (busintsts & USBD_BUSINTSTS_SUSPENDIF_Msk) + { + USBD_ENABLE_BUS_INT(USBD_BUSINTEN_RSTIEN_Msk | USBD_BUSINTEN_RESUMEIEN_Msk); + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_SUSPENDIF_Msk); + } + + /* High-speed */ + if (busintsts & USBD_BUSINTSTS_HISPDIF_Msk) + { + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk); + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_HISPDIF_Msk); + } + + /* DMA */ + if (busintsts & USBD_BUSINTSTS_DMADONEIF_Msk) + { + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_DMADONEIF_Msk); + } + + /* PHY clock available */ + if (busintsts & USBD_BUSINTSTS_PHYCLKVLDIF_Msk) + { + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_PHYCLKVLDIF_Msk); + } + + /* VBUS plug-in */ + if (busintsts & USBD_BUSINTSTS_VBUSDETIF_Msk) + { + if (USBD_IS_ATTACHED()) + { + /* USB plug-in */ + USBD_ENABLE_USB(); + } + else + { + /* USB unplug-out */ + USBD_DISABLE_USB(); + } + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_VBUSDETIF_Msk); + } + } + + /* CEP interrupts */ + if (gintsts & USBD_GINTSTS_CEPIF_Msk) + { + uint32_t cepintsts = USBD->CEPINTSTS & USBD->CEPINTEN; + + /* SETUP token packet */ + if (cepintsts & USBD_CEPINTSTS_SETUPTKIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_SETUPTKIF_Msk); + + return; + } + + /* SETUP transaction */ + if (cepintsts & USBD_CEPINTSTS_SETUPPKIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_SETUPPKIF_Msk); + events->ep0_setup(); + + return; + } + + /* OUT token packet */ + if (cepintsts & USBD_CEPINTSTS_OUTTKIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_OUTTKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_STSDONEIEN_Msk); + + return; + } + + /* IN token packet */ + if (cepintsts & USBD_CEPINTSTS_INTKIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_INTKIF_Msk); + if (!(cepintsts & USBD_CEPINTSTS_STSDONEIF_Msk)) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_TXPKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_TXPKIEN_Msk | USBD_CEPINTEN_SETUPPKIEN_Msk); + USBD_CtrlInput(); + } + else + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_TXPKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_TXPKIEN_Msk| USBD_CEPINTEN_STSDONEIEN_Msk); + } + + return; + } + + /* PING packet */ + if (cepintsts & USBD_CEPINTSTS_PINGIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_PINGIF_Msk); + + return; + } + + /* IN transaction */ + if (cepintsts & USBD_CEPINTSTS_TXPKIF_Msk) + { + events->ep0_in(); + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_TXPKIF_Msk); + + return; + } + + /* OUT transaction */ + if (cepintsts & USBD_CEPINTSTS_RXPKIF_Msk) + { + events->ep0_out(); + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_RXPKIF_Msk); + + return; + } + + /* NAK handshake packet */ + if (cepintsts & USBD_CEPINTSTS_NAKIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_NAKIF_Msk); + + return; + } + + /* STALL handshake packet */ + if (cepintsts & USBD_CEPINTSTS_STALLIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STALLIF_Msk); + + return; + } + + /* ERR special packet */ + if (cepintsts & USBD_CEPINTSTS_ERRIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_ERRIF_Msk); + + return; + } + + /* Status stage transaction */ + if (cepintsts & USBD_CEPINTSTS_STSDONEIF_Msk) + { + if (s_usb_addr) + { + USBD_SET_ADDR(s_usb_addr); + s_usb_addr = 0; + } + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk); + + return; + } + + /* Buffer Full */ + if (cepintsts & USBD_CEPINTSTS_BUFFULLIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_BUFFULLIF_Msk); + + return; + } + + /* Buffer Empty */ + if (cepintsts & USBD_CEPINTSTS_BUFEMPTYIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_BUFEMPTYIF_Msk); + + return; + } + } + + while (gintsts_epx) + { + if(gintsts_epx & 0x01) + { + uint32_t volatile epxintsts = USBD_GET_EP_INT_FLAG(ep_hw_index) & USBD_GET_EP_INT_EN(ep_hw_index); + + ep_logic_index = NU_EPH2EPL(ep_hw_index); + + USBD_CLR_EP_INT_FLAG(ep_hw_index, epxintsts); + + /* Buffer Full */ + if (epxintsts & USBD_EPINTSTS_BUFFULLIF_Msk) + { + } + + /* Buffer Empty */ + if (epxintsts & USBD_EPINTSTS_BUFEMPTYIF_Msk) + { + } + + /* Short Packet Transferred */ + if (epxintsts & USBD_EPINTSTS_SHORTTXIF_Msk) + { + } + + /* Data Packet Transmitted */ + if (epxintsts & USBD_EPINTSTS_TXPKIF_Msk) + { + USBD_ENABLE_EP_INT(ep_hw_index, USBD_GET_EP_INT_EN(ep_hw_index) & ~USBD_EPINTEN_TXPKIEN_Msk); + events->in(NU_EPH2EPL(ep_hw_index) | EP_DIR_Msk); + } + + /* Data Packet Received */ + if (epxintsts & USBD_EPINTSTS_RXPKIF_Msk) + { + USBD_ENABLE_EP_INT(ep_hw_index, USBD_GET_EP_INT_EN(ep_hw_index) & ~USBD_EPINTEN_RXPKIEN_Msk); + events->out(ep_logic_index); + } + + /* OUT token packet */ + if (epxintsts & USBD_EPINTSTS_OUTTKIF_Msk) + { + + } + + /* IN token packet */ + if (epxintsts & USBD_EPINTSTS_INTKIF_Msk) + { + } + + /* PING packet */ + if (epxintsts & USBD_EPINTSTS_PINGIF_Msk) + { + } + + /* NAK handshake packet sent to Host */ + if (epxintsts & USBD_EPINTSTS_NAKIF_Msk) + { + + } + + /* STALL handshake packet sent to Host */ + if (epxintsts & USBD_EPINTSTS_STALLIF_Msk) + { + + } + + /* NYET handshake packet sent to Host */ + if (epxintsts & USBD_EPINTSTS_NYETIF_Msk) + { + + } + + /* ERR packet sent to Host */ + if (epxintsts & USBD_EPINTSTS_ERRIF_Msk) + { + } + + /* Bulk Out Short Packet Received */ + if (epxintsts & USBD_EPINTSTS_SHORTRXIF_Msk) + { + } + } + gintsts_epx = gintsts_epx >> 1; + ep_hw_index++; + } +#elif defined (TARGET_M480) + uint32_t gintsts = HSUSBD->GINTSTS & HSUSBD->GINTEN; + uint32_t gintsts_epx = gintsts >> 2; /* EPA, EPB, EPC, ... EPL interrupts */ + uint32_t ep_hw_index = 0; + uint32_t ep_logic_index = 0,i; + + if (! gintsts) + return; + + if (gintsts & HSUSBD_GINTSTS_USBIF_Msk) + { + uint32_t busintsts = HSUSBD->BUSINTSTS & HSUSBD->BUSINTEN; + + /* SOF */ + if (busintsts & HSUSBD_BUSINTSTS_SOFIF_Msk) + { + HSUSBD_CLR_BUS_INT_FLAG(HSUSBD_BUSINTSTS_SOFIF_Msk); + + events->sof(HSUSBD->FRAMECNT >> 3); + } + + /* Reset */ + if (busintsts & HSUSBD_BUSINTSTS_RSTIF_Msk) + { + connect(); + events->reset(); + HSUSBD_CLR_BUS_INT_FLAG(HSUSBD_BUSINTSTS_RSTIF_Msk); + HSUSBD_CLR_CEP_INT_FLAG(0x1ffc); + } + + /* Resume */ + if (busintsts & HSUSBD_BUSINTSTS_RESUMEIF_Msk) + { + HSUSBD_ENABLE_BUS_INT(HSUSBD_BUSINTEN_RSTIEN_Msk | HSUSBD_BUSINTEN_SUSPENDIEN_Msk); + HSUSBD_CLR_BUS_INT_FLAG(HSUSBD_BUSINTSTS_RESUMEIF_Msk); +// events->suspend(false); + } + + /* Suspend */ + if (busintsts & HSUSBD_BUSINTSTS_SUSPENDIF_Msk) + { + HSUSBD_ENABLE_BUS_INT(HSUSBD_BUSINTEN_RSTIEN_Msk | HSUSBD_BUSINTEN_RESUMEIEN_Msk); + HSUSBD_CLR_BUS_INT_FLAG(HSUSBD_BUSINTSTS_SUSPENDIF_Msk); + } + + /* High-speed */ + if (busintsts & HSUSBD_BUSINTSTS_HISPDIF_Msk) + { + HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_SETUPTKIEN_Msk|HSUSBD_CEPINTEN_SETUPPKIEN_Msk); + HSUSBD_CLR_BUS_INT_FLAG(HSUSBD_BUSINTSTS_HISPDIF_Msk); + } + + /* DMA */ + if (busintsts & HSUSBD_BUSINTSTS_DMADONEIF_Msk) + { + HSUSBD_CLR_BUS_INT_FLAG(HSUSBD_BUSINTSTS_DMADONEIF_Msk); + } + + /* PHY clock available */ + if (busintsts & HSUSBD_BUSINTSTS_PHYCLKVLDIF_Msk) + { + HSUSBD_CLR_BUS_INT_FLAG(HSUSBD_BUSINTSTS_PHYCLKVLDIF_Msk); + } + + /* VBUS plug-in */ + if (busintsts & HSUSBD_BUSINTSTS_VBUSDETIF_Msk) + { + if (HSUSBD_IS_ATTACHED()) + { + /* USB plug-in */ + HSUSBD_ENABLE_USB(); + } + else + { + /* USB unplug-out */ + HSUSBD_DISABLE_USB(); + } + HSUSBD_CLR_BUS_INT_FLAG(HSUSBD_BUSINTSTS_VBUSDETIF_Msk); + } + } + + /* CEP interrupts */ + if (gintsts & HSUSBD_GINTSTS_CEPIF_Msk) + { + uint32_t cepintsts = HSUSBD->CEPINTSTS & HSUSBD->CEPINTEN; + + /* SETUP token packet */ + if (cepintsts & HSUSBD_CEPINTSTS_SETUPTKIF_Msk) + { + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_SETUPTKIF_Msk); + + /*************************** Disable Buffer ***************************/ + HSUSBD_SetEpBufAddr(CEP, 0, 1); + return; + } + + /* SETUP transaction */ + if (cepintsts & HSUSBD_CEPINTSTS_SETUPPKIF_Msk) + { + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_SETUPPKIF_Msk); + events->ep0_setup(); + return; + } + + /* OUT token packet */ + if (cepintsts & HSUSBD_CEPINTSTS_OUTTKIF_Msk) + { + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_OUTTKIF_Msk); + HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_STSDONEIEN_Msk); + + return; + } + + /* IN token packet */ + if (cepintsts & HSUSBD_CEPINTSTS_INTKIF_Msk) + { + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_INTKIF_Msk); + if (!(cepintsts & HSUSBD_CEPINTSTS_STSDONEIF_Msk)) + { + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_TXPKIF_Msk); + HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_SETUPTKIEN_Msk|HSUSBD_CEPINTEN_TXPKIEN_Msk | HSUSBD_CEPINTEN_SETUPPKIEN_Msk); + HSUSBD_CtrlInput(); + } + else + { + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_TXPKIF_Msk); + HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_TXPKIEN_Msk | HSUSBD_CEPINTEN_STSDONEIEN_Msk); + + /*************************** Disable Buffer ***************************/ + HSUSBD_SetEpBufAddr(CEP, 0, 1); + } + + return; + } + + /* PING packet */ + if (cepintsts & HSUSBD_CEPINTSTS_PINGIF_Msk) + { + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_PINGIF_Msk); + + return; + } + + /* IN transaction */ + if (cepintsts & HSUSBD_CEPINTSTS_TXPKIF_Msk) + { + events->ep0_in(); + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_TXPKIF_Msk); + return; + } + + /* OUT transaction */ + if (cepintsts & HSUSBD_CEPINTSTS_RXPKIF_Msk) + { + events->ep0_out(); + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_RXPKIF_Msk); + return; + } + + /* NAK handshake packet */ + if (cepintsts & HSUSBD_CEPINTSTS_NAKIF_Msk) + { + /*************************** Enable Buffer ***************************/ + HSUSBD_SetEpBufAddr(CEP, 0, s_ep0_max_packet_size); + HSUSBD->CEPINTEN = HSUSBD->CEPINTEN & ~HSUSBD_CEPINTEN_NAKIEN_Msk; + + if(((uint8_t) (HSUSBD->SETUP1_0 & 0xff)) == 0x00 && + ((uint8_t) (HSUSBD->SETUP1_0 >> 8) & 0xff) == 0x07 && + ((uint16_t) HSUSBD->SETUP3_2) == 0x0100 && + ((uint16_t) HSUSBD->SETUP5_4) == 0x0000 && + ((uint16_t) HSUSBD->SETUP7_6) == 0x0012) + HSUSBD_SetStall(0); + + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_NAKIF_Msk); + return; + } + + /* STALL handshake packet */ + if (cepintsts & HSUSBD_CEPINTSTS_STALLIF_Msk) + { + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_STALLIF_Msk); + + return; + } + + /* ERR special packet */ + if (cepintsts & HSUSBD_CEPINTSTS_ERRIF_Msk) + { + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_ERRIF_Msk); + + return; + } + + /* Status stage transaction */ + if (cepintsts & HSUSBD_CEPINTSTS_STSDONEIF_Msk) + { + if (s_usb_addr) + { + HSUSBD_SET_ADDR(s_usb_addr); + s_usb_addr = 0; + } + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_STSDONEIF_Msk); + HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_SETUPTKIEN_Msk|HSUSBD_CEPINTEN_SETUPPKIEN_Msk); + return; + } + + /* Buffer Full */ + if (cepintsts & HSUSBD_CEPINTSTS_BUFFULLIF_Msk) + { + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_BUFFULLIF_Msk); + + return; + } + + /* Buffer Empty */ + if (cepintsts & HSUSBD_CEPINTSTS_BUFEMPTYIF_Msk) + { + HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_BUFEMPTYIF_Msk); + + return; + } + } + + while (gintsts_epx) + { + if(gintsts_epx & 0x01) + { + uint32_t volatile epxintsts = HSUSBD_GET_EP_INT_FLAG(ep_hw_index) & HSUSBD_GET_EP_INT_EN(ep_hw_index); + + ep_logic_index = NU_EPH2EPL(ep_hw_index); + + HSUSBD_CLR_EP_INT_FLAG(ep_hw_index, epxintsts); + + /* Buffer Full */ + if (epxintsts & HSUSBD_EPINTSTS_BUFFULLIF_Msk) + { + } + + /* Buffer Empty */ + if (epxintsts & HSUSBD_EPINTSTS_BUFEMPTYIF_Msk) + { + } + + /* Short Packet Transferred */ + if (epxintsts & HSUSBD_EPINTSTS_SHORTTXIF_Msk) + { + } + + /* Data Packet Transmitted */ + if (epxintsts & HSUSBD_EPINTSTS_TXPKIF_Msk) + { + HSUSBD->EP[ep_hw_index].EPINTEN &= ~HSUSBD_EPINTEN_TXPKIEN_Msk; + events->in(NU_EPH2EPL(ep_hw_index) | EP_DIR_Msk); + } + + /* Data Packet Received */ + if (epxintsts & HSUSBD_EPINTSTS_RXPKIF_Msk) + { + HSUSBD->EP[ep_hw_index].EPINTEN &= ~HSUSBD_EPINTEN_RXPKIEN_Msk; + events->out(ep_logic_index); + } + + /* OUT token packet */ + if (epxintsts & HSUSBD_EPINTSTS_OUTTKIF_Msk) + { + + } + + /* IN token packet */ + if (epxintsts & HSUSBD_EPINTSTS_INTKIF_Msk) + { + } + + /* PING packet */ + if (epxintsts & HSUSBD_EPINTSTS_PINGIF_Msk) + { + } + + /* NAK handshake packet sent to Host */ + if (epxintsts & HSUSBD_EPINTSTS_NAKIF_Msk) + { + + } + + /* STALL handshake packet sent to Host */ + if (epxintsts & HSUSBD_EPINTSTS_STALLIF_Msk) + { + + } + + /* NYET handshake packet sent to Host */ + if (epxintsts & HSUSBD_EPINTSTS_NYETIF_Msk) + { + + } + + /* ERR packet sent to Host */ + if (epxintsts & HSUSBD_EPINTSTS_ERRIF_Msk) + { + } + + /* Bulk Out Short Packet Received */ + if (epxintsts & HSUSBD_EPINTSTS_SHORTRXIF_Msk) + { + } + } + gintsts_epx = gintsts_epx >> 1; + ep_hw_index++; + } +#endif +} + +extern "C" void USBD_IRQHandler(void) +{ +#if defined (TARGET_NUC472) + NVIC_DisableIRQ(USBD_IRQn); + + instance->events->start_process(); + + NVIC_ClearPendingIRQ(USBD_IRQn); + NVIC_EnableIRQ(USBD_IRQn); +#elif defined (TARGET_M480) + NVIC_DisableIRQ(USBD20_IRQn); + + instance->events->start_process(); + + NVIC_ClearPendingIRQ(USBD20_IRQn); + NVIC_EnableIRQ(USBD20_IRQn); +#endif +} + +#endif diff --git a/targets/TARGET_NUVOTON/USBEndpoints_Nuvoton.h b/targets/TARGET_NUVOTON/USBEndpoints_Nuvoton.h new file mode 100644 index 0000000000..9412a060df --- /dev/null +++ b/targets/TARGET_NUVOTON/USBEndpoints_Nuvoton.h @@ -0,0 +1,41 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019-2020 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined(TARGET_M451) +#define NUMBER_OF_LOGICAL_ENDPOINTS (8) +#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS) +#elif defined (TARGET_M480) +#if (MBED_CONF_TARGET_USB_DEVICE_HSUSBD == 0) +#define NUMBER_OF_LOGICAL_ENDPOINTS (12) +#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS) +#else +#define NUMBER_OF_LOGICAL_ENDPOINTS (12) +#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS) +#endif +#elif defined (TARGET_M2351) || defined(TARGET_M261) +#define NUMBER_OF_LOGICAL_ENDPOINTS (12) +#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS) +#elif defined (TARGET_NANO100) +#define NUMBER_OF_LOGICAL_ENDPOINTS (8) +#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS) +#elif defined (TARGET_NUC472) +#define NUMBER_OF_LOGICAL_ENDPOINTS (12) +#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS) +#endif + +#define ALLOW_ALL_EXCEPT_CRTL (USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_ALLOW_ISO) +#define ALLOW_NO_ENDPOINTS 0 diff --git a/targets/TARGET_NUVOTON/USBPhyHw.h b/targets/TARGET_NUVOTON/USBPhyHw.h new file mode 100644 index 0000000000..42cdc342be --- /dev/null +++ b/targets/TARGET_NUVOTON/USBPhyHw.h @@ -0,0 +1,71 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019-2020 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBPHYHW_H +#define USBPHYHW_H + +#include "mbed.h" +#include "USBPhy.h" + + +class USBPhyHw : public USBPhy { +public: + USBPhyHw(); + virtual ~USBPhyHw(); + virtual void init(USBPhyEvents *events); + virtual void deinit(); + virtual bool powered(); + virtual void connect(); + virtual void disconnect(); + virtual void configure(); + virtual void unconfigure(); + virtual void sof_enable(); + virtual void sof_disable(); + virtual void set_address(uint8_t address); + virtual void remote_wakeup(); + virtual const usb_ep_table_t *endpoint_table(); + + virtual uint32_t ep0_set_max_packet(uint32_t max_packet); + virtual void ep0_setup_read_result(uint8_t *buffer, uint32_t size); + virtual void ep0_read(uint8_t *data, uint32_t size); + virtual uint32_t ep0_read_result(); + virtual void ep0_write(uint8_t *buffer, uint32_t size); + virtual void ep0_stall(); + + virtual bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type); + virtual void endpoint_remove(usb_ep_t endpoint); + virtual void endpoint_stall(usb_ep_t endpoint); + virtual void endpoint_unstall(usb_ep_t endpoint); + + virtual bool endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size); + virtual uint32_t endpoint_read_result(usb_ep_t endpoint); + virtual bool endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size); + virtual void endpoint_abort(usb_ep_t endpoint); + + virtual void process(); + + USBPhyEvents *events; +private: + uint8_t *read_buffers[16]; + uint16_t read_sizes[16]; + + bool endpoint_read_core(usb_ep_t endpoint, uint32_t max_packet); + bool endpoint_read_result_core(usb_ep_t endpoint, uint8_t *data, uint32_t size, uint32_t *bytesRead); + +}; + +#endif diff --git a/targets/targets.json b/targets/targets.json index 45c0f0ea44..0c4201d9e6 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -7895,7 +7895,8 @@ "FLASH", "EMAC", "MPU", - "WATCHDOG" + "WATCHDOG", + "USBDEVICE" ], "release_versions": ["5"], "device_name": "NUC472HI8AE", @@ -8027,7 +8028,8 @@ "FLASH", "MPU", "WATCHDOG", - "RESET_REASON" + "RESET_REASON", + "USBDEVICE" ], "components_add": ["FLASHIAP"], "release_versions": ["2", "5"], @@ -8097,7 +8099,8 @@ "SPISLAVE", "SPI_ASYNCH", "WATCHDOG", - "RESET_REASON" + "RESET_REASON", + "USBDEVICE" ], "release_versions": ["5"], "device_name": "NANO130KE3BN", @@ -8514,7 +8517,7 @@ }, "usb-device-hsusbd": { "help": "Select high-speed USB device or not", - "value": 1 + "value": 0 } }, "inherits": ["Target"], @@ -8546,7 +8549,8 @@ "EMAC", "MPU", "WATCHDOG", - "RESET_REASON" + "RESET_REASON", + "USBDEVICE" ], "release_versions": ["5"], "bootloader_supported": true, @@ -8796,7 +8800,8 @@ "SPI_ASYNCH", "TRNG", "FLASH", - "MPU" + "MPU", + "USBDEVICE" ], "detect_code": ["1305"], "release_versions": ["5"], @@ -9774,7 +9779,8 @@ "SPI_ASYNCH", "TRNG", "FLASH", - "MPU" + "MPU", + "USBDEVICE" ], "components_add": ["FLASHIAP"], "detect_code": ["1310"],