#include #include #include #include "usb_dc.h" #include "usbd_core.h" #include "./nrf5x_regs.h" #define __ISB() \ do \ { \ __schedule_barrier(); \ __isb(0xF); \ __schedule_barrier(); \ } while (0U) #define __DSB() \ do \ { \ __schedule_barrier(); \ __dsb(0xF); \ __schedule_barrier(); \ } while (0U) #ifndef USBD_IRQHandler #define USBD_IRQHandler USBD_IRQHandler /*!< use actual usb irq name instead */ #endif #ifndef USBD_CONFIG_ISO_IN_ZLP #define USBD_CONFIG_ISO_IN_ZLP 0 #endif /*!< ep dir in */ #define EP_DIR_IN 1 /*!< ep dir out */ #define EP_DIR_OUT 0 /*!< get ep id by epadd */ #define GET_EP_ID(ep_add) (uint8_t)(ep_add & 0x7f) /*!< get ep dir by epadd */ #define GET_EP_DIR(ep_add) (uint8_t)(ep_add & 0x80) /*!< ep nums */ #define EP_NUMS 9 /*!< ep mps */ #define EP_MPS 64 /*!< nrf5x special */ #define EP_ISO_NUM 8 /*!< Peripheral address base */ #define NRF_USBD_BASE 0x40027000UL #define NRF_USBD ((NRF_USBD_Type *)NRF_USBD_BASE) #ifndef EP_ISO_MPS #define EP_ISO_MPS 64 #endif __attribute__((aligned(4))) uint8_t ep_iso_tx[EP_ISO_MPS]; __attribute__((aligned(4))) uint8_t ep_iso_rx[EP_ISO_MPS + EP_ISO_MPS]; /** * @brief Endpoint information structure */ typedef struct _usbd_ep_info { uint8_t mps; /*!< Maximum packet length of endpoint */ uint8_t eptype; /*!< Endpoint Type */ uint8_t *ep_ram_addr; /*!< Endpoint buffer address */ /*!< Other endpoint parameters that may be used */ volatile uint8_t is_using_dma; } usbd_ep_info; /*!< nrf52840 usb */ struct _nrf52840_core_prvi { uint8_t address; /*!< address */ usbd_ep_info ep_in[EP_NUMS]; /*!< ep in */ usbd_ep_info ep_out[EP_NUMS]; /*!< ep out */ struct usb_setup_packet setup; /*!< Setup package that may be used in interrupt processing (outside the protocol stack) */ volatile uint8_t dma_running; int8_t in_count; volatile uint8_t iso_turn; volatile uint8_t iso_tx_is_ready; /** * For nrf5x, easydma will not move the setup packet into RAM. * We use a flag bit to judge whether the host sends setup, * and then notify usbd_ep_read to and from the register to read the setup package */ volatile uint8_t is_setup_packet; } usb_dc_cfg; __WEAK void usb_dc_low_level_init(void) { } __WEAK void usb_dc_low_level_deinit(void) { } static inline void nrf_usbd_enable(void) { /*!< Prepare for READY event receiving */ NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk; __ISB(); __DSB(); NRF_USBD->ENABLE = 0x01; while (0 == (USBD_EVENTCAUSE_READY_Msk & (NRF_USBD->EVENTCAUSE))) { /*!< Empty loop */ } NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk; __ISB(); __DSB(); NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN << USBD_ISOSPLIT_SPLIT_Pos; if (USBD_CONFIG_ISO_IN_ZLP) { NRF_USBD->ISOINCONFIG = ((uint32_t)USBD_ISOINCONFIG_RESPONSE_ZeroData) << USBD_ISOINCONFIG_RESPONSE_Pos; } else { NRF_USBD->ISOINCONFIG = ((uint32_t)USBD_ISOINCONFIG_RESPONSE_NoResp) << USBD_ISOINCONFIG_RESPONSE_Pos; } usb_dc_low_level_init(); } /** * @brief Get setup package * @pre None * @param[in] setup Pointer to the address where the setup package is stored * @retval None */ static inline void get_setup_packet(struct usb_setup_packet *setup) { setup->bmRequestType = (uint8_t)(NRF_USBD->BMREQUESTTYPE); setup->bRequest = (uint8_t)(NRF_USBD->BREQUEST); setup->wIndex = (uint16_t)(NRF_USBD->WINDEXL | ((NRF_USBD->WINDEXH) << 8)); setup->wLength = (uint16_t)(NRF_USBD->WLENGTHL | ((NRF_USBD->WLENGTHH) << 8)); setup->wValue = (uint16_t)(NRF_USBD->WVALUEL | ((NRF_USBD->WVALUEH) << 8)); } /** * @brief Set tx easydma * @pre None * @param[in] ep End point address * @param[in] ptr Data ram ptr * @param[in] maxcnt Max length * @retval None */ static void nrf_usbd_ep_easydma_set_tx(uint8_t ep, uint32_t ptr, uint32_t maxcnt) { uint8_t epid = GET_EP_ID(ep); if (epid == EP_ISO_NUM) { NRF_USBD->ISOIN.PTR = ptr; NRF_USBD->ISOIN.MAXCNT = maxcnt; return; } NRF_USBD->EPIN[epid].PTR = ptr; NRF_USBD->EPIN[epid].MAXCNT = maxcnt; } /** * @brief Set rx easydma * @pre None * @param[in] ep End point address * @param[in] ptr Data ram ptr * @param[in] maxcnt Max length * @retval None */ static void nrf_usbd_ep_easydma_set_rx(uint8_t ep, uint32_t ptr, uint32_t maxcnt) { uint8_t epid = GET_EP_ID(ep); if (epid == EP_ISO_NUM) { NRF_USBD->ISOOUT.PTR = ptr; NRF_USBD->ISOOUT.MAXCNT = maxcnt; return; } NRF_USBD->EPOUT[epid].PTR = ptr; NRF_USBD->EPOUT[epid].MAXCNT = maxcnt; } /** * @brief Set address * @pre None * @param[in] address 8-bit valid address * @retval >=0 success otherwise failure */ int usbd_set_address(const uint8_t address) { if (address == 0) { /*!< init 0 address */ } else { /*!< For non-0 addresses, write the address to the register in the state phase of setting the address */ } NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE; NRF_USBD->EVENTS_USBEVENT = 0; NRF_USBD->INTENSET = USBD_INTEN_USBEVENT_Msk; /*!< nothing to do, handled by hardware; but don't STALL */ usb_dc_cfg.address = address; return 0; } /** * @brief Open endpoint * @pre None * @param[in] ep_cfg : Endpoint configuration structure pointer * @retval >=0 success otherwise failure */ int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg) { /*!< ep id */ uint8_t epid = GET_EP_ID(ep_cfg->ep_addr); /*!< ep dir */ bool dir = GET_EP_DIR(ep_cfg->ep_addr); /*!< ep max packet length */ uint8_t mps = ep_cfg->ep_mps; if (dir == EP_DIR_IN) { /*!< In */ usb_dc_cfg.ep_in[epid].mps = mps; usb_dc_cfg.ep_in[epid].eptype = ep_cfg->ep_type; /*!< Open ep */ if (ep_cfg->ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) { /*!< Allocate memory to endpoints */ usb_dc_cfg.ep_in[epid].ep_ram_addr = (uint8_t *)malloc(usb_dc_cfg.ep_in[epid].mps); /*!< Enable endpoint interrupt */ NRF_USBD->INTENSET = (1 << (USBD_INTEN_ENDEPIN0_Pos + epid)); /*!< Enable the in endpoint host to respond when sending in token */ NRF_USBD->EPINEN |= (1 << (epid)); __ISB(); __DSB(); } else { /*!< Allocate memory to endpoints */ usb_dc_cfg.ep_in[EP_ISO_NUM].ep_ram_addr = ep_iso_tx; NRF_USBD->EVENTS_ENDISOIN = 0; /*!< SPLIT ISO buffer when ISO OUT endpoint is already opened. */ if (usb_dc_cfg.ep_out[EP_ISO_NUM].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN; /*!< Clear SOF event in case interrupt was not enabled yet. */ if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0; /*!< Enable SOF and ISOIN interrupts, and ISOIN endpoint. */ NRF_USBD->INTENSET = USBD_INTENSET_ENDISOIN_Msk | USBD_INTENSET_SOF_Msk; NRF_USBD->EPINEN |= USBD_EPINEN_ISOIN_Msk; } } else if (dir == EP_DIR_OUT) { /*!< Out */ usb_dc_cfg.ep_out[epid].mps = mps; usb_dc_cfg.ep_out[epid].eptype = ep_cfg->ep_type; /*!< Open ep */ if (ep_cfg->ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) { /*!< Allocate memory to endpoints */ usb_dc_cfg.ep_out[epid].ep_ram_addr = (uint8_t *)malloc(usb_dc_cfg.ep_out[epid].mps); NRF_USBD->INTENSET = (1 << (USBD_INTEN_ENDEPOUT0_Pos + epid)); NRF_USBD->EPOUTEN |= (1 << (epid)); __ISB(); __DSB(); /*!< Write any value to SIZE register will allow nRF to ACK/accept data */ NRF_USBD->SIZE.EPOUT[epid] = 0; } else { /*!< Allocate memory to endpoints */ usb_dc_cfg.ep_out[EP_ISO_NUM].ep_ram_addr = ep_iso_rx; /*!< SPLIT ISO buffer when ISO IN endpoint is already opened. */ if (usb_dc_cfg.ep_in[EP_ISO_NUM].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN; /*!< Clear old events */ NRF_USBD->EVENTS_ENDISOOUT = 0; /*!< Clear SOF event in case interrupt was not enabled yet. */ if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0; /*!< Enable SOF and ISOOUT interrupts, and ISOOUT endpoint. */ NRF_USBD->INTENSET = USBD_INTENSET_ENDISOOUT_Msk | USBD_INTENSET_SOF_Msk; NRF_USBD->EPOUTEN |= USBD_EPOUTEN_ISOOUT_Msk; } } /*!< Clear stall and reset DataToggle */ NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | (ep_cfg->ep_addr); NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | (ep_cfg->ep_addr); __ISB(); __DSB(); return 0; } /** * @brief Close endpoint * @pre None * @param[in] ep : Endpoint address * @retval >=0 success otherwise failure */ int usbd_ep_close(const uint8_t ep) { /*!< ep id */ uint8_t epid = GET_EP_ID(ep); /*!< ep dir */ bool dir = GET_EP_DIR(ep); if (epid != EP_ISO_NUM) { if (dir == EP_DIR_OUT) { free(usb_dc_cfg.ep_out[epid].ep_ram_addr); NRF_USBD->INTENCLR = (1 << (USBD_INTEN_ENDEPOUT0_Pos + epid)); NRF_USBD->EPOUTEN &= ~(1 << (epid)); } else { free(usb_dc_cfg.ep_in[epid].ep_ram_addr); NRF_USBD->INTENCLR = (1 << (USBD_INTEN_ENDEPIN0_Pos + epid)); NRF_USBD->EPINEN &= ~(1 << (epid)); } } else { /*!< ISO EP */ if (dir == EP_DIR_OUT) { usb_dc_cfg.ep_out[EP_ISO_NUM].mps = 0; NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOOUT_Msk; NRF_USBD->EPOUTEN &= ~USBD_EPOUTEN_ISOOUT_Msk; NRF_USBD->EVENTS_ENDISOOUT = 0; } else { usb_dc_cfg.ep_in[EP_ISO_NUM].mps = 0; NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOIN_Msk; NRF_USBD->EPINEN &= ~USBD_EPINEN_ISOIN_Msk; } /*!< One of the ISO endpoints closed, no need to split buffers any more. */ NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir; /*!< When both ISO endpoint are close there is no need for SOF any more. */ if (usb_dc_cfg.ep_in[EP_ISO_NUM].mps + usb_dc_cfg.ep_out[EP_ISO_NUM].mps == 0) { NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk; } } __ISB(); __DSB(); return 0; } /** * @brief Write send buffer * @pre None * @param[in] ep : Endpoint address * @param[in] data : First address of data buffer to be written * @param[in] data_len : Write total length * @param[in] ret_bytes : Length actually written * @retval >=0 success otherwise failure */ int usbd_ep_write(const uint8_t ep, const uint8_t *data, uint32_t data_len, uint32_t *ret_bytes) { /*!< ep id */ uint8_t epid = GET_EP_ID(ep); /*!< real write byte nums */ uint32_t real_wt_nums = 0; /*!< ep mps */ uint8_t ep_mps = usb_dc_cfg.ep_in[epid].mps; /*!< Analyze bytes actually written */ if (data == NULL && data_len > 0) { return -1; } if (data_len == 0) { /*!< write 0 len data */ memset(usb_dc_cfg.ep_in[epid].ep_ram_addr, 0, ep_mps); nrf_usbd_ep_easydma_set_tx(epid, (uint32_t)usb_dc_cfg.ep_in[epid].ep_ram_addr, 0); NRF_USBD->TASKS_STARTEPIN[epid] = 1; return 0; } if (data_len > ep_mps) { /*!< The data length is greater than the maximum packet length of the endpoint */ real_wt_nums = ep_mps; } else { real_wt_nums = data_len; } /*!< write buff start */ memcpy(usb_dc_cfg.ep_in[epid].ep_ram_addr, data, real_wt_nums); nrf_usbd_ep_easydma_set_tx(epid, (uint32_t)usb_dc_cfg.ep_in[epid].ep_ram_addr, real_wt_nums); /*!< write buff over */ /** * Note that starting DMA transmission is to transmit data to USB peripherals, * and then wait for the host to get it */ /*!< Start dma transfer */ if (epid != EP_ISO_NUM) { NRF_USBD->TASKS_STARTEPIN[epid] = 1; } else { // NRF_USBD->TASKS_STARTISOIN = 1; usb_dc_cfg.iso_tx_is_ready = 1; } if (ret_bytes != NULL) { *ret_bytes = real_wt_nums; } return 0; } /** * @brief Read receive buffer * @pre None * @param[in] ep : Endpoint address * @param[in] data : Read the first address of the buffer where the data is stored * @param[in] max_data_len : Maximum readout length * @param[in] read_bytes : Actual read length * @retval >=0 success otherwise failure */ int usbd_ep_read(const uint8_t ep, uint8_t *data, uint32_t max_data_len, uint32_t *read_bytes) { /*!< ep id */ uint8_t epid = GET_EP_ID(ep); /*!< real read byte nums */ uint32_t real_rd_nums = 0; /*!< ep mps */ uint8_t ep_mps = usb_dc_cfg.ep_out[epid].mps; if (data == NULL && max_data_len > 0) { return -1; } if (max_data_len == 0) { // if (epid != 0) NRF_USBD->SIZE.EPOUT[epid] = EP_MPS; return 0; } /*!< Nrf5x special place */ /*!< Start */ if ((usb_dc_cfg.is_setup_packet == 1) && (max_data_len == sizeof(struct usb_setup_packet))) { /*!< Read setup packet */ get_setup_packet((struct usb_setup_packet *)data); usb_dc_cfg.is_setup_packet = 0; if (read_bytes != NULL) { *read_bytes = real_rd_nums; } return 0; } /*!< Over */ if (max_data_len > ep_mps) max_data_len = ep_mps; real_rd_nums = NRF_USBD->SIZE.EPOUT[epid]; real_rd_nums = MIN(real_rd_nums, max_data_len); /*!< read buff start */ memcpy(data, (uint8_t *)usb_dc_cfg.ep_out[epid].ep_ram_addr, real_rd_nums); /** * The reason why DMA transmission is not started here is that when the endpoint receives data, the host sends an out token and then transmits the data. * Nrf5x after receiving the data and responding to the host ACK, an EPDATA event will be generated. * In that event, we query the flag bit to obtain which endpoint received the data successfully, * and then set the target address of easydma to move the data from the USB peripheral to ram. * Easydma will trigger an ENDEPOUT[epid] event after moving data, * in which EP in the protocol stack is called ep_out_handler.So When reading, the RAM buffer of the endpoint has received the data. * We only need to copy the data from the buffer. */ /*!< read buff over */ if (read_bytes != NULL) { *read_bytes = real_rd_nums; } return 0; } /** * @brief Endpoint setting pause * @pre None * @param[in] ep : Endpoint address * @retval >=0 success otherwise failure */ int usbd_ep_set_stall(const uint8_t ep) { /*!< ep id */ uint8_t epid = GET_EP_ID(ep); bool dir = GET_EP_DIR(ep); if (epid == 0) { NRF_USBD->TASKS_EP0STALL = 1; } else if (epid != EP_ISO_NUM) { NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_Stall << USBD_EPSTALL_STALL_Pos) | (ep); } __ISB(); __DSB(); return 0; } /** * @brief Endpoint clear pause * @pre None * @param[in] ep : Endpoint address * @retval >=0 success otherwise failure */ int usbd_ep_clear_stall(const uint8_t ep) { /*!< ep id */ uint8_t epid = GET_EP_ID(ep); uint8_t dir = GET_EP_DIR(ep); if (epid != 0 && epid != EP_ISO_NUM) { /** * reset data toggle to DATA0 * First write this register with VALUE=Nop to select the endpoint, then either read it to get the status from * VALUE, or write it again with VALUE=Data0 or Data1 */ NRF_USBD->DTOGGLE = ep; NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep; /*!< Clear stall */ NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep; /*!< Write any value to SIZE register will allow nRF to ACK/accept data */ if (dir == EP_DIR_OUT) NRF_USBD->SIZE.EPOUT[epid] = 0; __ISB(); __DSB(); } return 0; } /** * @brief Check endpoint status * @pre None * @param[in] ep : Endpoint address * @param[out] stalled : Outgoing endpoint status * @retval >=0 success otherwise failure */ int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled) { return 0; } /** * @brief USB initialization * @pre None * @param[in] None * @retval >=0 success otherwise failure */ int usb_dc_init(void) { /*!< dc init */ memset(&usb_dc_cfg, 0, sizeof(usb_dc_cfg)); /*!< Clear USB Event Interrupt */ NRF_USBD->EVENTS_USBEVENT = 0; NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE; /*!< Reset interrupt */ NRF_USBD->INTENCLR = NRF_USBD->INTEN; NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_USBEVENT_Msk | USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk | USBD_INTEN_STARTED_Msk; nrf_usbd_enable(); return 0; } /** * @brief USB interrupt processing function * @pre None * @param[in] None * @retval None */ void USBD_IRQHandler(void) { uint32_t const inten = NRF_USBD->INTEN; uint32_t int_status = 0; volatile uint32_t usb_event = 0; volatile uint32_t *regevt = &NRF_USBD->EVENTS_USBRESET; /*!< Traverse USB events */ for (uint8_t i = 0; i < USBD_INTEN_EPDATA_Pos + 1; i++) { if ((inten & (1 << i)) && regevt[i]) { int_status |= (1 << (i)); /*!< event clear */ regevt[i] = 0; __ISB(); __DSB(); } } /*!< bit 24 */ if (int_status & USBD_INTEN_EPDATA_Msk) { /*!< out ep */ for (uint8_t ep_out_ct = 1; ep_out_ct <= 7; ep_out_ct++) { if ((NRF_USBD->EPDATASTATUS) & (1 << (16 + ep_out_ct))) { NRF_USBD->EPDATASTATUS |= (1 << (16 + ep_out_ct)); nrf_usbd_ep_easydma_set_rx(ep_out_ct, (uint32_t)usb_dc_cfg.ep_out[ep_out_ct].ep_ram_addr, NRF_USBD->SIZE.EPOUT[ep_out_ct]); NRF_USBD->TASKS_STARTEPOUT[ep_out_ct] = 1; } } /*!< in ep */ for (uint8_t ep_in_ct = 1; ep_in_ct <= 7; ep_in_ct++) { if ((NRF_USBD->EPDATASTATUS) & (1 << (0 + ep_in_ct))) { /*!< in ep tranfer to host successfully */ NRF_USBD->EPDATASTATUS |= (1 << (0 + ep_in_ct)); usbd_event_notify_handler(USBD_EVENT_EP_IN_NOTIFY, (uint32_t *)((ep_in_ct) | 0x80)); } } } /*!< bit 23 */ if (int_status & USBD_INTEN_EP0SETUP_Msk) { /* Setup */ /*!< Storing this setup package will help the following procedures */ get_setup_packet(&(usb_dc_cfg.setup)); usb_dc_cfg.is_setup_packet = 1; usb_dc_cfg.in_count = usb_dc_cfg.setup.wLength / 64; /*!< Nrf52840 will set the address automatically by hardware, so the protocol stack of the address setting command sent by the host does not need to be processed */ if ((usb_dc_cfg.setup.bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_OUT && usb_dc_cfg.setup.wLength > 0) { NRF_USBD->TASKS_EP0RCVOUT = 1; nrf_usbd_ep_easydma_set_rx(0, (uint32_t)usb_dc_cfg.ep_out[0].ep_ram_addr, usb_dc_cfg.ep_out[0].mps); } if (usb_dc_cfg.setup.wLength == 0) { NRF_USBD->TASKS_EP0STATUS = 1; } if (usb_dc_cfg.setup.bRequest != USB_REQUEST_SET_ADDRESS) { usbd_event_notify_handler(USBD_EVENT_SETUP_NOTIFY, NULL); } } /*!< bit 22 */ if (int_status & USBD_INTEN_USBEVENT_Msk) { usb_event = NRF_USBD->EVENTCAUSE; NRF_USBD->EVENTCAUSE = usb_event; if (usb_event & USBD_EVENTCAUSE_SUSPEND_Msk) { NRF_USBD->LOWPOWER = 1; usbd_event_notify_handler(USBD_EVENT_SUSPEND, NULL); } if (usb_event & USBD_EVENTCAUSE_RESUME_Msk) { usbd_event_notify_handler(USBD_EVENT_RESUME, NULL); } if (usb_event & USBD_EVENTCAUSE_USBWUALLOWED_Msk) { NRF_USBD->DPDMVALUE = USBD_DPDMVALUE_STATE_Resume; NRF_USBD->TASKS_DPDMDRIVE = 1; /** * There is no Resume interrupt for remote wakeup, enable SOF for to report bus ready state * Clear SOF event in case interrupt was not enabled yet. */ if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0; NRF_USBD->INTENSET = USBD_INTENSET_SOF_Msk; } } /*!< bit 21 */ if (int_status & USBD_INTEN_SOF_Msk) { bool iso_enabled = false; /*!< ISOOUT: Transfer data gathered in previous frame from buffer to RAM */ if (NRF_USBD->EPOUTEN & USBD_EPOUTEN_ISOOUT_Msk) { iso_enabled = true; /*!< If ZERO bit is set, ignore ISOOUT length */ if (usb_dc_cfg.iso_turn < 2) { usb_dc_cfg.iso_turn++; if ((NRF_USBD->SIZE.ISOOUT) & USBD_SIZE_ISOOUT_ZERO_Msk) { /*!< */ } else { /*!< Prepare */ NRF_USBD->ISOOUT.PTR = (uint32_t)usb_dc_cfg.ep_out[EP_ISO_NUM].ep_ram_addr; NRF_USBD->ISOOUT.MAXCNT = NRF_USBD->SIZE.ISOOUT; } } if (usb_dc_cfg.iso_turn == 2) { NRF_USBD->ISOOUT.PTR = (uint32_t)usb_dc_cfg.ep_out[EP_ISO_NUM].ep_ram_addr; NRF_USBD->ISOOUT.MAXCNT = NRF_USBD->SIZE.ISOOUT; NRF_USBD->TASKS_STARTISOOUT = 1; /*!< EP_ISO_NUM out using dma */ usb_dc_cfg.ep_out[EP_ISO_NUM].is_using_dma = 1; } } /*!< ISOIN: Notify client that data was transferred */ if (NRF_USBD->EPINEN & USBD_EPINEN_ISOIN_Msk) { iso_enabled = true; if (usb_dc_cfg.iso_tx_is_ready == 1) { usb_dc_cfg.iso_tx_is_ready = 0; NRF_USBD->TASKS_STARTISOIN = 1; } } if (!iso_enabled) { /** * ISO endpoint is not used, SOF is only enabled one-time for remote wakeup * so we disable it now */ NRF_USBD->INTENCLR = USBD_INTENSET_SOF_Msk; } } /*!< bit 20 */ if (int_status & USBD_INTEN_ENDISOOUT_Msk) { if (usb_dc_cfg.ep_out[EP_ISO_NUM].is_using_dma == 1) { usb_dc_cfg.ep_out[EP_ISO_NUM].is_using_dma = 0; usbd_event_notify_handler(USBD_EVENT_EP_OUT_NOTIFY, (uint32_t *)(EP_ISO_NUM | 0x00)); } } /** * Traverse ordinary out endpoint events, starting from endpoint 1 to endpoint 7, * and end 0 for special processing */ for (uint8_t offset = 0; offset < 7; offset++) { if (int_status & (USBD_INTEN_ENDEPOUT1_Msk << offset)) { /*!< Out 'offset' transfer complete */ usbd_event_notify_handler(USBD_EVENT_EP_OUT_NOTIFY, (uint32_t *)((offset + 1) & 0x7f)); } } /*!< bit 12 */ if (int_status & USBD_INTEN_ENDEPOUT0_Msk) { if (NRF_USBD->SIZE.EPOUT[0] == 64) { /*!< Enable the data phase of the endpoint */ NRF_USBD->TASKS_EP0RCVOUT = 1; } else { /*!< Enable the state phase of endpoint 0 */ NRF_USBD->TASKS_EP0STATUS = 1; } usbd_event_notify_handler(USBD_EVENT_EP0_OUT_NOTIFY, NULL); } /*!< bit 11 */ if (int_status & USBD_INTEN_ENDISOIN_Msk) { } /*!< bit 10 */ if (int_status & USBD_INTEN_EP0DATADONE_Msk) { switch (usb_dc_cfg.setup.bmRequestType >> USB_REQUEST_DIR_SHIFT) { case 1: /*!< IN */ if ((usb_dc_cfg.setup.wLength == 64 && usb_dc_cfg.setup.bRequest == 0x06 && (usb_dc_cfg.setup.wValue >> 8) == 1) || /*!< Get device descriptor for the first time */ (usb_dc_cfg.setup.wLength == 0xff && usb_dc_cfg.setup.bRequest == 0x06 && (usb_dc_cfg.setup.wValue >> 8) == 2) || /*!< Get configuration descriptor for the first time */ (usb_dc_cfg.setup.wLength == 0xff && usb_dc_cfg.setup.bRequest == 0x06 && (usb_dc_cfg.setup.wValue >> 8) == 3) || /*!< Get string descriptor for the first time */ (usb_dc_cfg.setup.wLength == 64)) { usbd_event_notify_handler(USBD_EVENT_EP0_IN_NOTIFY, NULL); NRF_USBD->TASKS_EP0STATUS = 1; } else if (usb_dc_cfg.setup.wLength > 64) { usb_dc_cfg.in_count--; usbd_event_notify_handler(USBD_EVENT_EP0_IN_NOTIFY, NULL); if (usb_dc_cfg.in_count == -1) { NRF_USBD->TASKS_EP0STATUS = 1; } } else { usbd_event_notify_handler(USBD_EVENT_EP0_IN_NOTIFY, NULL); NRF_USBD->TASKS_EP0STATUS = 1; } break; case 0: if (usb_dc_cfg.setup.bRequest != USB_REQUEST_SET_ADDRESS) { NRF_USBD->TASKS_STARTEPOUT[0] = 1; } break; } } /** * Traversing ordinary in endpoint events, starting from endpoint 1 to endpoint 7, * endpoint 0 special processing */ for (uint8_t offset = 0; offset < 7; offset++) { if (int_status & (USBD_INTEN_ENDEPIN1_Msk << offset)) { /*!< DMA move data completed */ } } /*!< bit 2 */ if (int_status & USBD_INTEN_ENDEPIN0_Msk) { } /*!< bit 1 */ if (int_status & USBD_INTEN_STARTED_Msk) { if (usb_dc_cfg.ep_out[EP_ISO_NUM].is_using_dma == 1) { NRF_USBD->ISOOUT.PTR = (uint32_t)usb_dc_cfg.ep_out[EP_ISO_NUM].ep_ram_addr + EP_NUMS; NRF_USBD->ISOOUT.MAXCNT = NRF_USBD->SIZE.ISOOUT; } } /*!< bit 0 */ if (int_status & USBD_INTEN_USBRESET_Msk) { NRF_USBD->EPOUTEN = 1UL; NRF_USBD->EPINEN = 1UL; for (int i = 0; i < 8; i++) { NRF_USBD->TASKS_STARTEPIN[i] = 0; NRF_USBD->TASKS_STARTEPOUT[i] = 0; } NRF_USBD->TASKS_STARTISOIN = 0; NRF_USBD->TASKS_STARTISOOUT = 0; /*!< Clear USB Event Interrupt */ NRF_USBD->EVENTS_USBEVENT = 0; NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE; /*!< Reset interrupt */ NRF_USBD->INTENCLR = NRF_USBD->INTEN; NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_USBEVENT_Msk | USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk | USBD_INTEN_STARTED_Msk; usbd_event_notify_handler(USBD_EVENT_RESET, NULL); } }