Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Burstiness of nRF 52840 Dev Kit USB CDC ADM code on Mac OS

We're using a combination of the ESB library/example code and the USB CDC ADM example code to transfer data from one 52840 dev kit to another system via a 2nd 52840 dev kit, via this setup:

  1. The transmitting 52840 send 128 bytes of data every millisecond via nrf_esb_write_payload().
  2. The receiving 52840 receives the 128 byte packet and immediately does an app_usbd_cdc_acm_write() with the data.  
  3. The system reads the data by polling /dev/tty.usbmodemxyz waiting for a complete 128 byte packet.  This is done via either a C++ program or a python3 script.

This all seems to work fine.  By looking at time stamps that are included in the data, we can tell the receive side is getting packets as expected once a millisecond.  But the problem is the reads of the data from the USB are bursty - the first read takes about 4 ms, then we'll get the next 3 or so almost immediately.  Then 4 ms to the next packet, then 3 to 4 more, etc.

I'm seeing this both with an C program (Xcode, Open Framework C++ app) and with python3 script.  I've tried various flags on the device open like O_NDELAY, but nothing I've done really changes the behavior.  Mac OS does not support the N_DIRECT flag.  

Is there a way to eliminate this bursty type of USB read with the CDC ADM example code?  Is there a better Nordic USB device/example code to use?  Any ideas are appreciated, it is important that the data arrive as consistently as is possible (given a non-real time OS like Mac OS).

nRF SDK 15, Mac OS 10.13.4, Xcode 9.3, Python 3.6.2

Thanks

Ed

Parents
  • Any ideas here?   Is there a different USB example/code base we could use to smooth out the transactions.  ESB does us no good if we can't get the data across USB in a timely manner.

    Ed

  • Either dont't send an integer multiple of 64 byte or send a "zero" packet after sending such a packet.And yes, USB bulk should allow sending a packet that contains no data bytes.

    Reason behind this is bulk endpoint handling in the USB spec, that assumes "full" endpoint packets belong to the same transaction. This delays delivery to your application until the transaction is finished.

  • Thanks TJ.  A zero byte packet did not work, but a combination of a 96 byte packet and a 32 byte packet fixes the problem.  112/16 did not work, gave me the same burst timing.  Don't know what's magic about 32 bytes.

    Thanks for all the help.

    Ed

  • Hi Ed,

    Can you see if this change improves anything ?

    ret_code_t app_usbd_cdc_acm_write(app_usbd_cdc_acm_t const * p_cdc_acm,
                                      const void *               p_buf,
                                      size_t                     length)
    {
        app_usbd_class_inst_t const * p_inst = app_usbd_cdc_acm_class_inst_get(p_cdc_acm);
        app_usbd_cdc_acm_ctx_t * p_cdc_acm_ctx = cdc_acm_ctx_get(p_cdc_acm);
    
        bool dtr_state = (p_cdc_acm_ctx->line_state & APP_USBD_CDC_ACM_LINE_STATE_DTR) ?
                          true : false;
        if (!dtr_state)
        {
            /*Port is not opened*/
            return NRF_ERROR_INVALID_STATE;
        }
        
        nrf_drv_usbd_ep_t ep = data_ep_in_addr_get(p_inst);
        
        if ((length % NRF_DRV_USBD_EPSIZE) == 0)
        {
            NRF_DRV_USBD_TRANSFER_IN_ZLP(transfer, p_buf, length);
            return app_usbd_ep_transfer(ep, &transfer);
        }
        else
        {
            NRF_DRV_USBD_TRANSFER_IN(transfer, p_buf, length);
            return app_usbd_ep_transfer(ep, &transfer);
        }
    }

    Edit: The idea here is to use NRF_DRV_USBD_TRANSFER_IN_ZLP() when you don't have a full packet to send. A Zero Length Packet will be generated on the end of the transfer when using NRF_DRV_USBD_TRANSFER_IN_ZLP(), and it should therefore end the transaction.

  • Thanks for the quick response Sigurd,

    This does appear to eliminate the problem, I’m able to move 128 byte packets (i.e. single app_usbd_cdc_acm_write) at a 1 KHz rate with minimum jitter and *NO* 4 ms bursts.  
    I thought we had fixed this before with the double write, so I’d like to test for a few days to ensure the problem doesn’t reappear.  I also want to test on Windows, which I won’t get to until this weekend, so I’ll update everyone on the state of things this weekend once I’m done testing.
    Ed
  • I've been testing all weekend and have not seen any burst problems, I think we can declare victory at this point.  

    Will your changes be rolled into the SDK at some point?  I'll make sure our code includes the changes.

    Thanks for your help.

    Ed

Reply Children
Related