This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

USB DMA

when I use usb to transfer, i fine many datas are lost.Is it because the DMA size is too small?Where can i see the dma size?(In nrf52833/examples/peripheral/usb_cdc_acm ).Thanks.

  • I think you should look at the return codes of app_usbd_cdc_acm_write() and app_usbd_cdc_acm_read(). I suspect data is lost because error codes are ignored or not handled (e.g. you should buffer data and retry if the return code is not success).

    Also check out the documentation and another devzone case below:

    https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.0.2/lib_usbd_class_cdc.html 

    https://devzone.nordicsemi.com/f/nordic-q-a/23265/max-frame-size-usb-bulk-transmision-increase-speed 

    Best regards,
    Kenneth

  • When I use Putty to send data to the NRF52833 through usb,it keeps reminding "

    USB DMA process - EasyDMA busy",Is this related to missing datas?
    static void usbd_dmareq_process(void)
    {
        if (!m_dma_pending)
        {
            uint32_t req;
            while (0 != (req = m_ep_dma_waiting & m_ep_ready))
            {
                uint8_t pos;
                if (NRFX_USBD_CONFIG_DMASCHEDULER_ISO_BOOST && ((req & USBD_EPISO_BIT_MASK) != 0))
                {
                    pos = usbd_dma_scheduler_algorithm(req & USBD_EPISO_BIT_MASK);
                }
                else
                {
                    pos = usbd_dma_scheduler_algorithm(req);
                }
                nrfx_usbd_ep_t ep = bit2ep(pos);
                usbd_ep_state_t * p_state = ep_state_access(ep);
    
                nrfx_usbd_ep_transfer_t transfer;
                bool continue_transfer;
    
                NRFX_STATIC_ASSERT(offsetof(usbd_ep_state_t, handler.feeder) ==
                    offsetof(usbd_ep_state_t, handler.consumer));
                NRFX_ASSERT((p_state->handler.feeder) != NULL);
    
                if (NRF_USBD_EPIN_CHECK(ep))
                {
                    /* Device -> Host */
                    continue_transfer = p_state->handler.feeder(
                        &transfer,
                        p_state->p_context,
                        p_state->max_packet_size);
    
                    if (!continue_transfer)
                    {
                        p_state->handler.feeder = NULL;
                    }
                }
                else
                {
                    /* Host -> Device */
                    const size_t rx_size = nrfx_usbd_epout_size_get(ep);
                    continue_transfer = p_state->handler.consumer(
                        &transfer,
                        p_state->p_context,
                        p_state->max_packet_size,
                        rx_size);
    
                    if (transfer.p_data.rx == NULL)
                    {
                        /* Dropping transfer - allow processing */
                        NRFX_ASSERT(transfer.size == 0);
                    }
                    else if (transfer.size < rx_size)
                    {
                        NRFX_LOG_DEBUG("Endpoint %x overload (r: %u, e: %u)", ep, rx_size, transfer.size);
                        p_state->status = NRFX_USBD_EP_OVERLOAD;
                        (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << pos)));
                        NRFX_USBD_EP_TRANSFER_EVENT(evt, ep, NRFX_USBD_EP_OVERLOAD);
                        m_event_handler(&evt);
                        /* This endpoint will not be transmitted now, repeat the loop */
                        continue;
                    }
                    else
                    {
                        /* Nothing to do - only check integrity if assertions are enabled */
                        NRFX_ASSERT(transfer.size == rx_size);
                    }
    
                    if (!continue_transfer)
                    {
                        p_state->handler.consumer = NULL;
                    }
                }
    
                usbd_dma_pending_set();
                m_ep_ready &= ~(1U << pos);
                if (NRFX_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep)))
                {
                    NRFX_LOG_DEBUG(
                        "USB DMA process: Starting transfer on EP: %x, size: %u",
                        ep,
                        transfer.size);
                }
                /* Update number of currently transferred bytes */
                p_state->transfer_cnt += transfer.size;
                /* Start transfer to the endpoint buffer */
                nrf_usbd_ep_easydma_set(ep, transfer.p_data.addr, (uint32_t)transfer.size);
    
                if (nrfx_usbd_errata_104())
                {
                    uint32_t cnt_end = (uint32_t)(-1);
                    do
                    {
                        uint32_t cnt = (uint32_t)(-1);
                        do
                        {
                            nrf_usbd_event_clear(NRF_USBD_EVENT_STARTED);
                            usbd_dma_start(ep);
                            nrfx_systick_delay_us(2);
                            ++cnt;
                        }while (!nrf_usbd_event_check(NRF_USBD_EVENT_STARTED));
                        if (cnt)
                        {
                            NRFX_USBD_LOG_PROTO1_FIX_PRINTF("   DMA restarted: %u times", cnt);
                        }
    
                        nrfx_systick_delay_us(30);
                        while (0 == (0x20 & *((volatile uint32_t *)(NRF_USBD_BASE + 0x474))))
                        {
                            nrfx_systick_delay_us(2);
                        }
                        nrfx_systick_delay_us(1);
    
                        ++cnt_end;
                    } while (!nrf_usbd_event_check(nrfx_usbd_ep_to_endevent(ep)));
                    if (cnt_end)
                    {
                        NRFX_USBD_LOG_PROTO1_FIX_PRINTF("   DMA fully restarted: %u times", cnt_end);
                    }
                }
                else
                {
                    usbd_dma_start(ep);
                    /* There is a lot of USBD registers that cannot be accessed during EasyDMA transfer.
                     * This is quick fix to maintain stability of the stack.
                     * It cost some performance but makes stack stable. */
                    while (!nrf_usbd_event_check(nrfx_usbd_ep_to_endevent(ep)) &&
                           !nrf_usbd_event_check(NRF_USBD_EVENT_USBRESET))
                    {
                        /* Empty */
                    }
                }
    
                if (NRFX_USBD_DMAREQ_PROCESS_DEBUG)
                {
                    NRFX_LOG_DEBUG("USB DMA process - finishing");
                }
                /* Transfer started - exit the loop */
                break;
            }
        }
        else
        {
            if (NRFX_USBD_DMAREQ_PROCESS_DEBUG)
            {
                NRFX_LOG_DEBUG("USB DMA process - EasyDMA busy");
            }
        }
    }
  • Please see my comments on how to use the high level api to buffer and send/receive data. I do not think it is a good idea to start modify or play around with the low level usb drivers.

    I can see that the code you refer to have the following define:

    #ifndef NRFX_USBD_EARLY_DMA_PROCESS
    /* Try to process DMA request when endpoint transmission has been detected
     * and just after last EasyDMA has been processed.
     * It speeds up the transmission a little (about 10% measured)
     * with a cost of more CPU power used.
     */
    #define NRFX_USBD_EARLY_DMA_PROCESS 1
    #endif

  • Thank you for your reply,There is another question:How do I know that the DMA transfer is over,Is there a transmission end flag and where

  • I assume that is handled in nrfx_usbd_irq_handler():

    /** @brief USBD events. */
    typedef enum
    {
        NRF_USBD_EVENT_USBRESET      = offsetof(NRF_USBD_Type, EVENTS_USBRESET   ), /**< Signals that a USB reset condition is detected on the USB lines. */
        NRF_USBD_EVENT_STARTED       = offsetof(NRF_USBD_Type, EVENTS_STARTED    ), /**< Confirms that the EPIN[n].PTR, EPIN[n].MAXCNT, EPIN[n].CONFIG, or EPOUT[n].PTR, EPOUT[n].MAXCNT, and EPOUT[n].CONFIG registers have been captured on all endpoints reported in the EPSTATUS register. */
        NRF_USBD_EVENT_ENDEPIN0      = offsetof(NRF_USBD_Type, EVENTS_ENDEPIN[0] ), /**< The whole EPIN[0] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPIN1      = offsetof(NRF_USBD_Type, EVENTS_ENDEPIN[1] ), /**< The whole EPIN[1] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPIN2      = offsetof(NRF_USBD_Type, EVENTS_ENDEPIN[2] ), /**< The whole EPIN[2] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPIN3      = offsetof(NRF_USBD_Type, EVENTS_ENDEPIN[3] ), /**< The whole EPIN[3] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPIN4      = offsetof(NRF_USBD_Type, EVENTS_ENDEPIN[4] ), /**< The whole EPIN[4] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPIN5      = offsetof(NRF_USBD_Type, EVENTS_ENDEPIN[5] ), /**< The whole EPIN[5] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPIN6      = offsetof(NRF_USBD_Type, EVENTS_ENDEPIN[6] ), /**< The whole EPIN[6] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPIN7      = offsetof(NRF_USBD_Type, EVENTS_ENDEPIN[7] ), /**< The whole EPIN[7] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_EP0DATADONE   = offsetof(NRF_USBD_Type, EVENTS_EP0DATADONE), /**< An acknowledged data transfer has taken place on the control endpoint. */
        NRF_USBD_EVENT_ENDISOIN0     = offsetof(NRF_USBD_Type, EVENTS_ENDISOIN   ), /**< The whole ISOIN buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPOUT0     = offsetof(NRF_USBD_Type, EVENTS_ENDEPOUT[0]), /**< The whole EPOUT[0] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPOUT1     = offsetof(NRF_USBD_Type, EVENTS_ENDEPOUT[1]), /**< The whole EPOUT[1] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPOUT2     = offsetof(NRF_USBD_Type, EVENTS_ENDEPOUT[2]), /**< The whole EPOUT[2] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPOUT3     = offsetof(NRF_USBD_Type, EVENTS_ENDEPOUT[3]), /**< The whole EPOUT[3] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPOUT4     = offsetof(NRF_USBD_Type, EVENTS_ENDEPOUT[4]), /**< The whole EPOUT[4] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPOUT5     = offsetof(NRF_USBD_Type, EVENTS_ENDEPOUT[5]), /**< The whole EPOUT[5] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPOUT6     = offsetof(NRF_USBD_Type, EVENTS_ENDEPOUT[6]), /**< The whole EPOUT[6] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDEPOUT7     = offsetof(NRF_USBD_Type, EVENTS_ENDEPOUT[7]), /**< The whole EPOUT[7] buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_ENDISOOUT0    = offsetof(NRF_USBD_Type, EVENTS_ENDISOOUT  ), /**< The whole ISOOUT buffer has been consumed. The RAM buffer can be accessed safely by software. */
        NRF_USBD_EVENT_SOF           = offsetof(NRF_USBD_Type, EVENTS_SOF        ), /**< Signals that a SOF (start of frame) condition has been detected on the USB lines. */
        NRF_USBD_EVENT_USBEVENT      = offsetof(NRF_USBD_Type, EVENTS_USBEVENT   ), /**< An event or an error not covered by the specified events has occurred, check EVENTCAUSE register to find the cause. */
        NRF_USBD_EVENT_EP0SETUP      = offsetof(NRF_USBD_Type, EVENTS_EP0SETUP   ), /**< A valid SETUP token has been received (and acknowledged) on the control endpoint. */
        NRF_USBD_EVENT_DATAEP        = offsetof(NRF_USBD_Type, EVENTS_EPDATA     ), /**< A data transfer has occurred on a data endpoint, indicated by the EPDATASTATUS register. */
    }nrf_usbd_event_t;

Related