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

nRF52810 SPI and duration of CS after last byte transferred

In my attempt of learning the nRF52 "eco system" (nRF52 DK, nRF15.3 SDK, SES and pca10040e project  for nRF52810), I have combined the GATT_C, GPIO and SPI examples to make an application for streaming CAN data over BLE. CAN is a mcp2515 chip with SPI, and I use SPI with DMA to transfer data to and from the mcp2515.

Everything works fine wrt SPI. However, it seems to me that the CS goes systematically high (or with other words, the SoftDevice releases the SPI) ~15 us after last byte is transferred over the SPI bus.  

My question is if there is a way to reduce the time from the SPI SCK goes inactive to the CS goes high (CS is active low on the mcp2515)? 



In the picture the red is the CS and the blue is the SPI SCK.

  • For controlling the CS there are two options: either this is done automatically by SoftDevice or you could control the CS pin yourself. This can be done by setting the ss_pin of the nrf_drv_spi_config_t struct to NRF_DRV_SPI_PIN_NOT_USED. In my projects I always control the CS (or Slave Select as it is called here) myself.

  • Thanks for the advice. I tested it, but it had little to no impact in my application

    I guess I also have to do some more clever stuff than only controlling  SS/CS myself?

    I have an spi_eventhandler():

    void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
                           void *                    p_context)
    {
          spi_xfer_done = true;
    }

    and typically my SPI functions looks like this:

    uint8_t mcp2515_readRegister( uint8_t address)                                                                     
    {
        uint8_t ret;
        ret_code_t err_code;
    
        uint8_t m_tx_buf[] = {MCP_READ, address};
        uint8_t m_rx_buf[] = {0, 0, 0};
    
        //mcp2515_select();
        err_code = nrf_drv_spi_transfer(&spi, m_tx_buf, 2, m_rx_buf, 3);
        APP_ERROR_CHECK(err_code);
        
        while (!spi_xfer_done) { __WFE(); }
        spi_xfer_done = false;
        //mcp2515_unselect();
    
        return m_rx_buf[2];
    }


    In the case of controlling CS/SS myself: The reason why it have little impact in my code is probably that before I can set CS high, I wait for __WFE, which triggers my SPI_eventhandler, which set the flag to terminate the wait loop. 

    On other controllers I usually handle all these things in interrupt service routines (ISR), but I am not there yet that I know how to deal with ISRs on the nRF-platform using the SoftDevice for BLE...

  • Did you try adding your mcp2515_unselect() in the spi_event_handler()? That's effectively doing it in an ISR.

  • Yes, tested that as well, but it had no impact. Can it be that the  __WFE need some time to  discover that the bytes are transmitted... ?

  • Hi,

    The SPIM peripheral in the nRF52810 does not implement chip select, so this is handled by the driver by controlling a GPIO pin. Looking at the implementation in nrfx (modules\nrfx\drivers\src\nrfx_spim.c) you can see that it is cleared by the finish_transfer() function, which is called as the last thing when handling the NRF_SPIM_EVENT_END. If you use on-deferred logging you might be able to save a bit of time by moving the call to finish_transfer()  before the log line, but other than that there is not much optimization to be done as far as I can see.

Related