From 5f731a8d6a31d98d4a03dc39911c365f86c60fd5 Mon Sep 17 00:00:00 2001 From: George Beckstein Date: Wed, 5 Dec 2018 20:59:28 -0500 Subject: [PATCH] Added in triggers to synchronize control transfer stages with what the hardware expects. First working example! --- .../TARGET_MCU_NRF52840/USBPhyHw.h | 19 ---- .../TARGET_MCU_NRF52840/USBPhy_Nordic.cpp | 101 +++++++----------- 2 files changed, 38 insertions(+), 82 deletions(-) diff --git a/usb/device/targets/TARGET_NORDIC/TARGET_MCU_NRF52840/USBPhyHw.h b/usb/device/targets/TARGET_NORDIC/TARGET_MCU_NRF52840/USBPhyHw.h index cbaf0b068e..c9e58e9591 100644 --- a/usb/device/targets/TARGET_NORDIC/TARGET_MCU_NRF52840/USBPhyHw.h +++ b/usb/device/targets/TARGET_NORDIC/TARGET_MCU_NRF52840/USBPhyHw.h @@ -27,15 +27,6 @@ extern "C" { class USBPhyHw : public USBPhy { -public: - - // Keep track of setup transaction stages - typedef enum transaction_state_t { - SetupStage, - DataStage, - StatusStage - } transaction_state_t; - public: USBPhyHw(); virtual ~USBPhyHw(); @@ -74,10 +65,6 @@ public: static void _usb_event_handler(nrf_drv_usbd_evt_t const * const p_event); static void _usb_power_event_handler(nrf_drv_power_usb_evt_t event); - bool setup_feeder(nrf_drv_usbd_ep_transfer_t * p_next, - void * p_context, - size_t ep_size); - private: USBPhyEvents *events; @@ -102,15 +89,9 @@ private: // Buffer to hold setup packet nrf_drv_usbd_setup_t setup_buf; - // State of the setup transaction - transaction_state_t setup_state; - // Setup bytes remaining uint32_t setup_remaining; - // EP0 IN feeder - nrf_drv_usbd_handler_desc_t ep0_in_handler; - // Nordic transfer structures for each in/out endpoint nrf_drv_usbd_transfer_t transfer_buf[18]; diff --git a/usb/device/targets/TARGET_NORDIC/TARGET_MCU_NRF52840/USBPhy_Nordic.cpp b/usb/device/targets/TARGET_NORDIC/TARGET_MCU_NRF52840/USBPhy_Nordic.cpp index 45a07fcd6a..ad8cdd31b4 100644 --- a/usb/device/targets/TARGET_NORDIC/TARGET_MCU_NRF52840/USBPhy_Nordic.cpp +++ b/usb/device/targets/TARGET_NORDIC/TARGET_MCU_NRF52840/USBPhy_Nordic.cpp @@ -26,6 +26,11 @@ #define IS_IN_EP(ep) (ep & 0x80) // Checks if the given endpoint is an IN endpoint (MSB set) #define IS_OUT_EP(ep) (ep & ~0x80) // Checks if the given endpoint is an OUT endpoint (MSB clear) +// If this bit is set in setup.bmRequestType, the setup transfer +// is DEVICE->HOST (IN transfer) +// if it is clear, the transfer is HOST->DEVICE (OUT transfer) +#define SETUP_TRANSFER_DIR_MASK 0x80 + // Debugging flag for tracking USB events #define USBD_DEBUG 0 @@ -235,35 +240,30 @@ uint32_t USBPhyHw::ep0_read_result() { void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size) { - // First transaction chunk, transition to data stage - if(setup_state == USBPhyHw::SetupStage) + nrf_drv_usbd_transfer_t* transfer = get_transfer_buffer(NRF_DRV_USBD_EPIN0); + memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t)); + transfer->p_data.tx = buffer; + transfer->size = size; + + // If this is a zero-length-packet (ZLP) + // Set the ZLP flag + if(size == 0) + transfer->flags |= NRF_DRV_USBD_TRANSFER_ZLP_FLAG; + + // Update the number of bytes remaining in the setup data stage + setup_remaining -= size; + + // Check if this is the last chunk, conditions: + // 1: the remaining bytes will be 0 + // OR 2: the transfer size is < ep max size (including 0, short packet) + size_t ep_size = nrf_drv_usbd_ep_max_packet_size_get(NRF_DRV_USBD_EPIN0); + if((setup_remaining == 0) || (size < ep_size)) { - setup_state = USBPhyHw::DataStage; - - // Give the feeder function information to pass on thru DMA - setup_remaining = setup_buf.wLength; - nrf_drv_usbd_transfer_t* transfer = get_transfer_buffer((usb_ep_t)(NRF_DRV_USBD_EPIN0)); - memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t)); - transfer->p_data.tx = buffer; - transfer->size = size; - - // Setup the handler - ep0_in_handler.handler.feeder = mbed_nrf_feeder_ep0; - ep0_in_handler.p_context = NULL; - - // Initiate the transfer - nrf_drv_usbd_ep_handled_transfer(NRF_DRV_USBD_EPIN0, - &ep0_in_handler); - } - else if(setup_state == USBPhyHw::DataStage) - { - // Just subtract from the remaining and setup the transfer - //setup_remaining -= size; - nrf_drv_usbd_transfer_t* transfer = get_transfer_buffer((usb_ep_t)(NRF_DRV_USBD_EPIN0)); - memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t)); - transfer->p_data.tx = buffer; - transfer->size = size; + // Enter status stage after next DMA transfer completes + nrf_usbd_shorts_enable(NRF_USBD_SHORT_EP0DATADONE_EP0STATUS_MASK); } + + nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, transfer); } void USBPhyHw::ep0_stall() { @@ -389,8 +389,17 @@ void USBPhyHw::process() { // Copy the setup packet into the internal buffer nrf_drv_usbd_setup_get(&setup_buf); - // Prepare the transfer context for the data stage - setup_state = USBPhyHw::SetupStage; + // Reset the remaining setup data length + setup_remaining = setup_buf.wLength; + + // Skip data stage, go straight to status stage + if(setup_buf.wLength == 0) { + nrf_drv_usbd_setup_clear(); + } + else if((setup_buf.bmRequestType & SETUP_TRANSFER_DIR_MASK) == 0) { + // HOST->DEVICE transfer, need to notify hardware of Data OUT stage + nrf_usbd_task_trigger(NRF_USBD_TASK_EP0RCVOUT); + } // Notify the Mbed stack events->ep0_setup(); @@ -490,22 +499,6 @@ void USBPhyHw::disable_usb_interrupts(void) { NRF_POWER_INT_USBPWRRDY_MASK); } -bool USBPhyHw::setup_feeder(nrf_drv_usbd_ep_transfer_t* p_next, void* p_context, size_t ep_size) -{ - // Set up the next DMA transfer - nrf_drv_usbd_transfer_t* transfer = get_transfer_buffer((usb_ep_t)(NRF_DRV_USBD_EPIN0)); - p_next->p_data.tx = transfer->p_data.tx; - p_next->size = transfer->size; - - setup_remaining -= p_next->size; - - // Check if transfer should continue after this, false if: - // 1: the remaining bytes will be 0 - // OR 2: the transfer size is < ep max size (including 0) - return !((setup_remaining == 0) || - (p_next->size < ep_size)); -} - static void power_usb_event_handler(nrf_drv_power_usb_evt_t event) { if(instance) { // Pass the event on to the USBPhyHW instance @@ -520,21 +513,3 @@ static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event) { instance->_usb_event_handler(p_event); } } - -/** - * @brief Feeder passing data between mbed and nordic USB stacks - * - * @param[out] p_next See @ref nrf_drv_usbd_feeder_t documentation. - * @param[in,out] p_context See @ref nrf_drv_usbd_feeder_t documentation. - * @param[in] ep_size See @ref nrf_drv_usbd_feeder_t documentation. - * - * @retval true Continue transfer. - * @retval false This was the last transfer. - */ -bool mbed_nrf_feeder_ep0(nrf_drv_usbd_ep_transfer_t * p_next, - void * p_context, - size_t ep_size) -{ - MBED_ASSERT(instance != NULL); - return instance->setup_feeder(p_next, p_context, ep_size); -}