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.

Parents Reply Children
  • 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

Related