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

What are memset() and nrf_driv_spis_buffers_set() doing in the spi_slave example?

I have two NRF52840 dev kits that are running what are essentially the spi master and spi slave examples. They both work and I've altered them slightly. I'm just kind of confused by this block of code in the spi slave example:


    while (1)
    {
        if (spis_xfer_done)
        {
        NRF_LOG_FLUSH();
        bsp_board_led_invert(BSP_BOARD_LED_1);
        memset(spi_rx_buf, 0, spi_length);
        spis_xfer_done = false;
        APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, spi_tx_buf, spi_length, spi_rx_buf, spi_length));
        }
    }

Why do I need to reset the rx_buf after each transaction? Why can't I have the master keep shifting in data without the slave running memset() and nrf_driv_spis_buffers_set()?

Also just to confirm my understanding of how this works,  when a spi transaction comes in, CS goes low, data gets shifted into some buffer in memory. Then CS goes high and an interrupt is triggered (in the slave). When this interrupt is triggered, a handler will read out the data and do whatever I tell it to do with it. Is this using the easyDMA?

Sorry if these are dumb questions, I appreciate all/any help someone can give me.

Parents
  • Hello,

    Sorry if these are dumb questions, I appreciate all/any help someone can give me.

    No need to apologize, these are not dumb questions at all! I am happy to help.

    Why do I need to reset the rx_buf after each transaction? Why can't I have the master keep shifting in data without the slave running memset() and nrf_driv_spis_buffers_set()?

    As you can see in the SPI Slave example documentation, it uses the SPIS Legacy driver. If we look at the nrf_drv_spis_buffers_set() function description in the API reference, you will see that it is a macro forwarding to the nrfx_spis_buffers_set() function. Reading the function documentation, we see that it prepares the SPIS for the next transfer.

    Also just to confirm my understanding of how this works,  when a spi transaction comes in, CS goes low, data gets shifted into some buffer in memory. Then CS goes high and an interrupt is triggered (in the slave). When this interrupt is triggered, a handler will read out the data and do whatever I tell it to do with it. Is this using the easyDMA?

    In this particular case, CS is active low. This is the usual case, and valid for nRF slave devices, but be aware that there also exists CS active high devices.
    You are correct in your understanding of an SPI transaction. I am not sure what you mean by handler will read out the data, but the important thing is that the data is handled during the interrupt service routine, in which you could do whatever you want with said data.
    You can read more about SPIS with easyDMA and its usage here and here.

    Do not hesitate to come back if you should have any more questions! :)

    Best regards,
    Karl

     

     

Reply
  • Hello,

    Sorry if these are dumb questions, I appreciate all/any help someone can give me.

    No need to apologize, these are not dumb questions at all! I am happy to help.

    Why do I need to reset the rx_buf after each transaction? Why can't I have the master keep shifting in data without the slave running memset() and nrf_driv_spis_buffers_set()?

    As you can see in the SPI Slave example documentation, it uses the SPIS Legacy driver. If we look at the nrf_drv_spis_buffers_set() function description in the API reference, you will see that it is a macro forwarding to the nrfx_spis_buffers_set() function. Reading the function documentation, we see that it prepares the SPIS for the next transfer.

    Also just to confirm my understanding of how this works,  when a spi transaction comes in, CS goes low, data gets shifted into some buffer in memory. Then CS goes high and an interrupt is triggered (in the slave). When this interrupt is triggered, a handler will read out the data and do whatever I tell it to do with it. Is this using the easyDMA?

    In this particular case, CS is active low. This is the usual case, and valid for nRF slave devices, but be aware that there also exists CS active high devices.
    You are correct in your understanding of an SPI transaction. I am not sure what you mean by handler will read out the data, but the important thing is that the data is handled during the interrupt service routine, in which you could do whatever you want with said data.
    You can read more about SPIS with easyDMA and its usage here and here.

    Do not hesitate to come back if you should have any more questions! :)

    Best regards,
    Karl

     

     

Children
  • Karl, thank you!!! Also thank you for the links, they are very helpful.

    I have another question now hahah. When I place memset() and nrf_driv_spis_buffers_set() inside the spi_event_handler, I properly reset the SPI buffers for the next transfer (the master will receive the proper data), but I also somehow delete the contents of the rx_buffer before I can read it out. My SPI event handler is below:

    void spis_event_handler(nrf_drv_spis_event_t event)
    {
        if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
        {
            spis_xfer_done = true;
            spi_packet_buffer = (uint32_t)m_rx_buf;
            NRF_LOG_INFO(" Transfer completed. Received: %s",spi_packet_buffer);
            bsp_board_led_invert(BSP_BOARD_LED_0);
    
            memset(m_rx_buf, 0, m_length);
            APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, m_tx_buf, m_length, m_rx_buf, m_length));
        }
    }

    The result is that the slave will print out an empty string over UART. 

    Kindest regards,

    Ryan

  • Hello Ryan,

    ryerye120 said:
    Karl, thank you!!! Also thank you for the links, they are very helpful.

    No problem at all, I am happy to help! :)

    Looking over your initial post, I see that I failed to explicitly explain memset(), which is good for you to know about.
    memset here is used to initialize the buffers to zero. memset directly accesses the specified memory addresses, and sets them to the given values.

    ryerye120 said:
    The result is that the slave will print out an empty string over UART. 

    By this, do you mean that the whole string is empty, or that just the section where spi_packet_buffer should have been is empty?
    Could you perhaps share your entire source code? or, is the code snippet you sent all the modifications that you have made to the example? If so, you do not need to share the source code.

    Best regards,
    Karl

  • Hi Karl,

    Sorry for not being clear!

    By this, do you mean that the whole string is empty, or that just the section where spi_packet_buffer should have been is empty?

    Just the section where spi_packet_buffer should have been is empty! Everything else I wanted to print was there.

    So I only made minor adjustments to the event handler and the main.c, copied below:

    void spis_event_handler(nrf_drv_spis_event_t event)
    {
        if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
        {
            spis_xfer_done = true;
            spi_packet_buffer = (uint32_t)m_rx_buf;
            NRF_LOG_INFO(" Transfer completed. Received: %s",spi_packet_buffer);
            bsp_board_led_invert(BSP_BOARD_LED_0);
    
            memset(m_rx_buf, 0, m_length);
            APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, m_tx_buf, m_length, m_rx_buf, m_length));
        }
    }

        while (1)
        {
            if (spis_xfer_done)
            {
            // If you're in this loop then that means spi interrupt was fired and flag has been set. We're okay to reset everything and wait for the next spi transfer
            NRF_LOG_FLUSH();
            bsp_board_led_invert(BSP_BOARD_LED_1);
            //memset(m_rx_buf, 0, m_length);
            spis_xfer_done = false;
           //APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, m_tx_buf, m_length, m_rx_buf, m_length));
            }
        }

    As always, thank you. I've really appreciated your help.

    Ryan

  • Hi Ryan,

    Looking at the SPI code you have provided I dont immediately see where it goes wrong.
    You are doing all the right things, but I suspect the order in which you do them is the cause of your problems. In particular, I think moving nrf_drv_spis_buffers_set to the event handler might be were it goes wrong, since the callback function can be called before returning from the function.
    Is there a particular reason why you would like to do this in your event handler?

    Here is the relevant exempt from the SPIS API Reference documentation:

    When either the memory buffer configuration or the SPI transaction has been completed, the event callback function will be called with the appropriate event nrfx_spis_evt_type_t. The callback function can be called before returning from this function, because it is called from the SPI slave interrupt context.

    Furthermore, I would advice you to use the __WFE() wait-for-event function, rather than wasting the full cycles in the while(1) loop. Using __WFE will give you considerably lower power consumption.

    ryerye120 said:
    As always, thank you. I've really appreciated your help.

    Thank you for saying that! It is no problem at all, I am happy to help! :)

    Best regards,
    Karl

  • So I was hoping to have all of the i/o handling organized neatly in the interrupts so that I wouldn't need to worry about timing issues while taking SPI packets and sending them over USB. Since I hope to build this into a wireless link (Peripheral<-SPI-> Dev kit <-BLE-> Dev kit <-USB-> host PC), I figured this interrupt-based organization would make my life a little easier. Unfortunately, it seems that may be a bad idea and that I'll have to leave nrf_drv_spis_buffers_set in the main inside the if(spi_transfer_done) scope.

    Furthermore, I would advice you to use the __WFE() wait-for-event function, rather than wasting the full cycles in the while(1) loop. Using __WFE will give you considerably lower power consumption.

    I didn't realize that! That will be very helpful for the future. Thank you!

Related