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

Reduce time between SPI transfers

Dear all,

I am using a DK with the NRF52832 to drive a 32-bit DAC through SPI @ 8 MHz. I use a solution based on the peripheral/spi example using the SDK15.

My goal is to change the DAC value every (say) 5 us. This is theoretically possible since 32-bit/ 8 MHz = 4 us. The application also uses the SoftDevice, as well as Timer2 (for pulse diuration purposes)

Using the "nrf_drv_spi_transfer()" function in an infinite loop, it yields a delay between transfers of around 60 us. That is, I measure the 32 clock pulses of an SPI transfer in a row, but until the next call of "nrf_drv_spi_transfer()" there is a delay of 60 us.

1) I would firstly like to ask for reference of the origin of this delay. I know it has to do with the SoftDevice mainly, and of course the rest of the executing code, but I could not find a reference guide about it.

2) I would need to minimize the inter-transfer delay to ideally 0. Any strategies on how to do this, and which would be roughly the theoretical minimum of this delay? Is any continuous-transfer (zero inter-delay) implementation possible?

Thank you for your kindness,

Fran89

Parents
  • Hi,

    I think we will need some more details in order to answer your questions. How have you configured the SPI driver? (non-blocking/blocking mode, SS signal being used, etc).

    Do you need to update the data that is being transferred every time you call the nrf_drv_spi_transfer? If this is static, you can use the "advanced usage" features of the driver to setup a transfer and start it through PPI directly from a TIMER. This will minimize the time between transfers.

    If you need to change the content of the buffer, and are running BLE activity simultaneously, there is no way to guarantee the completion of the transfer in this short time, since the softdevice will always have the highest priority and will preempt the SPI transfer.

    Best regards,
    Jørgen

  • Thank you very much for the prompt answer. I will test it out as soon as possible and let you know the results.

    For now I add a picture for future reference and clarification of what my problem is:

    The code is the one for the SPI example, with the delays removed. This doesn't use SoftDevice or any other interrupts, and yet there is a delay of around 30 us. The idea would be to minimize this delay.

    #define SPI_INSTANCE  0 /**< SPI instance index. */
    static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
    static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    
    #define TEST_STRING "Nordic"
    static uint8_t       m_tx_buf[] = TEST_STRING;           /**< TX buffer. */
    static uint8_t       m_rx_buf[sizeof(TEST_STRING) + 1];    /**< RX buffer. */
    static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */
    
    /**
     * @brief SPI user event handler.
     * @param event
     */
    void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
                           void *                    p_context)
    {
        spi_xfer_done = true;
        NRF_LOG_INFO("Transfer completed.");
        if (m_rx_buf[0] != 0)
        {
            NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
        }
    }
    
    int main(void)
    {
        //bsp_board_init(BSP_INIT_LEDS);
    
        //APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        //NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
        spi_config.ss_pin   = SPI_SS_PIN;
        spi_config.miso_pin = SPI_MISO_PIN;
        spi_config.mosi_pin = SPI_MOSI_PIN;
        spi_config.sck_pin  = SPI_SCK_PIN;
        APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
    
        NRF_LOG_INFO("SPI example started.");
    
        while (1)
        {
            // Reset rx buffer and transfer done flag
            memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
    
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, m_length, m_rx_buf, m_length));
    
            while (!spi_xfer_done)
            {
                __WFE();
            }
    
            //NRF_LOG_FLUSH();
    
            //bsp_board_led_invert(BSP_BOARD_LED_0);
            //nrf_delay_ms(200);
        }
    }
    

    Thanks again, and I will report back asap.

    Fran89

Reply
  • Thank you very much for the prompt answer. I will test it out as soon as possible and let you know the results.

    For now I add a picture for future reference and clarification of what my problem is:

    The code is the one for the SPI example, with the delays removed. This doesn't use SoftDevice or any other interrupts, and yet there is a delay of around 30 us. The idea would be to minimize this delay.

    #define SPI_INSTANCE  0 /**< SPI instance index. */
    static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
    static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    
    #define TEST_STRING "Nordic"
    static uint8_t       m_tx_buf[] = TEST_STRING;           /**< TX buffer. */
    static uint8_t       m_rx_buf[sizeof(TEST_STRING) + 1];    /**< RX buffer. */
    static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */
    
    /**
     * @brief SPI user event handler.
     * @param event
     */
    void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
                           void *                    p_context)
    {
        spi_xfer_done = true;
        NRF_LOG_INFO("Transfer completed.");
        if (m_rx_buf[0] != 0)
        {
            NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
        }
    }
    
    int main(void)
    {
        //bsp_board_init(BSP_INIT_LEDS);
    
        //APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        //NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
        spi_config.ss_pin   = SPI_SS_PIN;
        spi_config.miso_pin = SPI_MISO_PIN;
        spi_config.mosi_pin = SPI_MOSI_PIN;
        spi_config.sck_pin  = SPI_SCK_PIN;
        APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
    
        NRF_LOG_INFO("SPI example started.");
    
        while (1)
        {
            // Reset rx buffer and transfer done flag
            memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
    
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, m_length, m_rx_buf, m_length));
    
            while (!spi_xfer_done)
            {
                __WFE();
            }
    
            //NRF_LOG_FLUSH();
    
            //bsp_board_led_invert(BSP_BOARD_LED_0);
            //nrf_delay_ms(200);
        }
    }
    

    Thanks again, and I will report back asap.

    Fran89

Children
No Data
Related