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

SPIM & easyDMA: understanding Soft Device interrupts and timing

I have another longer question regarding an SPI led driver I’m working with that has some strict timings, but I wanted to ask a more succinct question here since I think I may not be entirely clear on how the EasyDMA works with SPIM and an answer here may save me a lot of head scratching.

I'd like to know if there is any way to send data via SPIM and to ensure that the soft device won’t interrupt and hold the clock for longer than 10us or so? In the end I really only need to be able to send two bytes with an assurance that I won’t have them interrupted and a delay added between since that times out the peripheral.

Some points/questions

  • Ive been told this is exactly what EasyDMA does, schedules a transfer that won’t be interrupted up to 255 bytes. I’ve tried with EasyDMA enabled though and I still occasionally see the clock hang for close to 30us

• I also tried sending only two bytes at a time using the nrf_drv_spi_transfer() method and then sending the next pair of bytes when I get the return event. This seemed to work great since the first two bytes sent together because of the double buffer, but then on the rare occasion I would see the bytes split again by 10us+

• Question: Would moving these transfers to the main context either via a flag or the app scheduler prevent the soft device from breaking in?

  • Question: Is there simply no way to guarantee the soft device won’t break in, even for as little as two bytes?

  • Question: if this should be working via EasyDMA, can someone point me to a clear way to test if easyDMA is enabled (I’m in segger embedded) but a simple way to check the DMA status at runtime and log it works too!

-I've attached a logic capture showing the breaks though prob not necessary since this is ideally cut and dry and I can either reliable block the soft device or I can't, hopefully a nordic employee can put this to rest relatively easily. !

Logic probe showing breaks in clock

  • Ive been told this is exactly what EasyDMA does, schedules a transfer that won’t be interrupted up to 255 bytes. I’ve tried with EasyDMA enabled though and I still occasionally see the clock hang for close to 30us.

    An initiated transfer shouldn't be interrupted, but the SPI interrupt can be delayed if the SoftDevice is active in a higher interrupt context. The SoftDevice can also interrupt the initiation of the next transfer.

    I also tried sending only two bytes at a time using the nrf_drv_spi_transfer() method and then sending the next pair of bytes when I get the return event. This seemed to work great since the first two bytes sent together because of the double buffer, but then on the rare occasion I would see the bytes split again by 10us+

    Sounds like you are saying that you are interrupted in a middle of a 2 byte transfer, that shouldn't happen.

    Question: Would moving these transfers to the main context either via a flag or the app scheduler prevent the soft device from breaking in?

    Main context has the lowest priority, so that wouldn't protect you against interrupts at all.

    Question: Is there simply no way to guarantee the soft device won’t break in, even for as little as two bytes?

    An initiated 2 byte transfer shouldn't be interrupted.

    Question: if this should be working via EasyDMA, can someone point me to a clear way to test if easyDMA is enabled (I’m in segger embedded) but a simple way to check the DMA status at runtime and log it works too!

    You can check the use_easy_dma in the driver instance:

    typedef struct
    {
        void *    p_registers;  ///< Pointer to the structure with SPI/SPIM peripheral instance registers.
        IRQn_Type irq;          ///< SPI/SPIM peripheral instance IRQ number.
        uint8_t   drv_inst_idx; ///< Driver instance index.
        bool      use_easy_dma; ///< True if the peripheral with EasyDMA (SPIM) shall be used.
    } nrf_drv_spi_t;
    

    You should have the following in sdk_config.h

    #ifndef SPI0_ENABLED
    #define SPI0_ENABLED 1
    #endif
    #if  SPI0_ENABLED
    // <q> SPI0_USE_EASY_DMA  - Use EasyDMA
     
    
    #ifndef SPI0_USE_EASY_DMA
    #define SPI0_USE_EASY_DMA 1
    #endif
    

    -I've attached a logic capture showing the breaks though prob not necessary since this is ideally cut and dry and I can either reliable block the soft device or I can't, hopefully a nordic employee can put this to rest relatively easily. !

    Can you please attach the actual capture (not picture) so I can look at it?

  • Thank you for the reply and information, Ill grab a full logic capture Monday. To a few of your points:

    • The two byte transfer I saw interrupted was when I moved to sending all 52 bytes in two byte packets with the spi_handler setting up the next transfer after each was done. I saw all the data go over in nice tight two byte packets until very rarely those two bytes had extra time between them. I assumed that maybe I was sending too fast for the spi call to fill the double buffer but Im not sure if thats possible. This might be harder to grab a logic capture for since it was rare and I moved away from that solution.

    • When you say the SPI interrupt can be delayed do you mean the interrupt that sends the next byte thus causing more time between bytes occasionally or do you mean the entire spi transfer can be delayed but that with easydma the transfer wont gap once started?

  • • I also do have easy dma enabled in the config and I confirmed it was on via segger for one of the spi instances but for the one in question I couldnt find the driver instance structure during debug, but Ill log its status to double check easy dma is getting enabled.

    • Lastly I realized that I was on SDK 12.1, but today I updated to 12.3, not sure if that should make any difference.

    • Finally I did sort a work around to all this by wiggling my data a bit and making sure my most important two bytes are always sent as the head of an spi write so they now always seem to go together but it would still be nice to know why Im seeing breaks in my spi write even while supposedly using easy dma.

    Ill report back when I get a chance to do some more debugging monday.

  • Please confirm if a initiated 2 byte transfer has a delay between the two bytes, or if two 2 byte transfers have delay between them. If you want to send 52 bytes just call nrf_drv_spi_transfer() with a pointer to the 52 byte buffer.

    I mean that the entire SPI transfer can be delayed but that with EasyDMA the transfer wont gap once started.

    The SDK version shouldn't matter, but if you want me to try to reproduce we should have similar setups.

Related