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

SPI/USB will drop large multiple of packets in a row. Can't keep up with 1 Mbps on nrf52840 dk?

Hi,

I'm using an nrf52840 dk to query another device over spi and then pipe the response back USB to a host PC. Ideally, we're piping data at 1 Mbps (which should be very much doable for USB) and for a little bit, it will work perfectly. Then randomly we'll miss 4 kB worth of packets. After plotting the data stream it's become apparent that it's quite bad. We consistently lose at least a 3rd of our packets. Furthermore, the lost data is lost in chunks. Here's an example of a 'noisy' sine wave that we sent through the serial link.

I don't believe it's an issue with the spi because I've tied an oscope to the spi pins and observed perfect spi packets being transmitted at a rate of 1 Mbps (but I could only observe maybe 20 packets at a time and didn't decode them so ...). Given that we're missing consecutive packets, and it seems to happen more or less regularly, I think this might have to do with a USB overhead issue.  

Is there something I'm missing about USB? Is there an ideal packet size that I should send over the USB at a given moment? I've played with the following settings but they've seem to make no difference:

  • APP_USBD_CONFIG_SOF_HANDLING_MODE (tried both normal and compress queue)
  • APP_USBD_CONFIG_EVENT_QUEUE_SIZE (Tried setting this to the max, 64, in case I was trying to send packets too frequently and they needed a larger queue)

I'm pretty new with USB communication so any help would be amazing! 

EDIT: I've started saving the data to a buffer on the dev kit and reading it all out at once (ideally this decouples the SPI and USB). While I'm missing significantly fewer packets, I am still missing a few. Now I'm getting 75%-85% of all my packets. So I guess this means there is some function that's interrupting the SPI's interrupt, possibly? I've tried bumping the SPI interrupts priority but it doesn't seem to have changed anything. I'm completely out of ideas so any pointers would be a huge help.

Thanks,

Ryan

Parents
  • Hi,

     

    Is the SPIM or SPIS running on the nRF?

    If logging is an issue, you could use RTT instead of UART as the logger backend (see sdk_config.h::NRF_LOG_BACKEND_RTT_ENABLED and clearing NRF_LOG_BACKEND_UART_ENABLED) to see if something is caught and printed.

     

    How large are the USB packets and how often do you send? How does your device enumerate, HID, CDC, libusb, winusb?

    Note that HID is limited to 64 byte per 1 ms frame.

     

    Kind regards,

    Håkon

Reply
  • Hi,

     

    Is the SPIM or SPIS running on the nRF?

    If logging is an issue, you could use RTT instead of UART as the logger backend (see sdk_config.h::NRF_LOG_BACKEND_RTT_ENABLED and clearing NRF_LOG_BACKEND_UART_ENABLED) to see if something is caught and printed.

     

    How large are the USB packets and how often do you send? How does your device enumerate, HID, CDC, libusb, winusb?

    Note that HID is limited to 64 byte per 1 ms frame.

     

    Kind regards,

    Håkon

Children
  • The SPIM is running on the nRF.

    I can try with RTT to see if the chip select issue continues (you're right in that I was using UART debugging) - and if not, I can look into debugging with that.

    I send 520 bits every 500 us (so throughput is slightly higher than 1 Mbps). The software will send/receive 520 bits over SPI, then after a flag (spi_xfr_complete flag) is tripped in the main() body. After this flag is tripped, the data is processed (minorly) and then sent via USB to the host pc.

    I've built this off the CDC example so it enumerates as CDC with whatever settings were in the usb_CDC example. Does CDC have a similar limit?

    Thank you for the help!

  • Hi Ryan,

     

    ryerye120 said:
    Does CDC have a similar limit?

    No, that should be able to push more data through the link.

     

    ryerye120 said:
    I send 520 bits every 500 ms

     65 bytes will trigger a 64 byte + 1 byte transaction over USB, as your EP size is 64. Sending that every 500 milliseconds should be plenty time, or do you mean every 500 us?

    Which SDK version are you using? What else than SPIM and USBD is running in your application? Do you have any BLE links active?

     

    Kind regards,

    Håkon 

  • Sorry I did mean 500us. That was a silly mistake on my part. 512 bits every 500 us.

    I'm using v16.0.0 of the SDK (which I believe is the latest). In this setup, it's purely SPIM and USBD. At least, those are the only things that I'm making calls to.

  • The SPI clock? I set it to 4MHz because I was getting set up errors at 8MHz. 

    I should note that I found a bug in my code. Now if I save all the SPI codes and send them over USB *after* the fact, I don't drop any packets. So is there a recommended way of transferring data from SPI to USB on a packet-per-packet basis? 

    Earlier I had a naive nested conditional:

    app_usbd_event_queue_process();
    if (spi_xfer_done)
    {
        spis_xfer_done = 0;
        if (usb_xfer_done)
        {
            size = sprintf(some data);
            app_usbd_cdc_acm_write(some data, size);
            usb_xfer_done = 0;
        }
    }

    Where spi_xfer_done is set to 1 by the spi_event_handler & usb_xfer_done is set to 1 by a handler looking out for the APP_USBD_CDC_ACM_USER_EVT_TX_DONE event.

    This assumes that the USB driver is much faster than the SPI driver and will finish before the next SPI transaction is fired off/complete. Unfortunately, I must be missing something because experimentally speaking, this doesn't work. 

Related