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

nRF52 SPI master controlling multiple slaves using hardware chipselect

So, time to give back...

Updating this post (https://devzone.nordicsemi.com/f/nordic-q-a/23488/a-nrf52-function-mapping-to-nrf51/124863?focus=true#92262) which outlines how to switch a Chip Select line for the SPI perhiperal when you have multiple slave devices on the same bus. The above post worked until SDK 14.2, but Nordic reorganized some of the perhiperal drivers, thus its implementation was a touch more complicated.

I was a bit ham-fisted in making it work, but it works and so I hope it will help you too. My setup is SDK15.0, nRF52832, Eclipse Oxygen v1a, GCC. 

You will have to modify several files, starting with nrf_drv_spi.h, below the inline function "nrf_drv_spi_abort(...)", you will need to add the following code:

__STATIC_INLINE
void nrf_drv_spi_switch_chips(nrf_drv_spi_t const * p_instance, uint32_t chip_select)
{
	if (NRF_DRV_SPI_USE_SPIM)
    {
       nrfx_spim_switch_chips(&p_instance->u.spim, chip_select);
    }
    else if (NRF_DRV_SPI_USE_SPI)
    {
       nrfx_spi_switch_chips(&p_instance->u.spi, chip_select);
    }
}
 

Then in nrfx_spim.h add the code directly below "void nrfx_spim_uninit(...)"

void nrfx_spim_switch_chips( nrfx_spim_t const * const p_instance, uint32_t chip_select );

Then in nrfx_spim.c add the code directly below the end of the function "void nrfx_spim_uninit(...)"

void nrfx_spim_switch_chips( nrfx_spim_t const * const p_instance,
                               uint32_t                    chip_select )
{
    spim_control_block_t * p_cb  = &m_cb[p_instance->drv_inst_idx];
    p_cb->ss_pin = chip_select;

    //A Slave select must be set as high before setting it as output,
    //because during connect it to the pin it causes glitches.
    nrf_gpio_pin_set(p_cb->ss_pin);
    nrf_gpio_cfg_output(p_cb->ss_pin);
    nrf_gpio_pin_set(p_cb->ss_pin);
}

Like I said, I was a bit ham-fisted when adding code, so to make the statement in nrf_drv_spi.h happy, I included very similar code to the nrfx_spi.h/c code as well, being careful to modify the specific types for that file.

so in nrfx_spi.h add the following code just below "void nrfx_spi_uninit(...);" 

void nrfx_spi_switch_chips( nrfx_spi_t const * const p_instance,uint32_t chip_select );

And in nrfx_spi.c, add the following code just below the end of the function "void nrfx_spim_uninit(...)"

void nrfx_spi_switch_chips( nrfx_spi_t const * const p_instance,
                               uint32_t                    chip_select )
{
    spi_control_block_t * p_cb  = &m_cb[p_instance->drv_inst_idx];
    p_cb->ss_pin = chip_select;

    //A Slave select must be set as high before setting it as output,
    //because during connect it to the pin it causes glitches.
    nrf_gpio_pin_set(p_cb->ss_pin);
    nrf_gpio_cfg_output(p_cb->ss_pin);
    nrf_gpio_pin_set(p_cb->ss_pin);
}

Finally, you need the instance of the spi bus so that the switch_chips function changes the correct I/O line.  So the pseudocode for that would be the following:

#define SPI_INSTANCE 0  
#define CS_SENSOR1  21
#define CS_SENSOR2  19
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);


int main()
{

uint8_t m_tx_buf[] = "DataAndStuff";
uint8_t m_spi_tx_count = 12; // quantity of characters between the quotes in above m_tx_buf[]

//setup the SPI

    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
    spi_config.ss_pin   = CS_SENSOR1;
    spi_config.miso_pin = 12;
    spi_config.mosi_pin = 13;
    spi_config.sck_pin  = 14;
    spi_config.frequency = NRF_SPI_FREQ_1M;
    spi_config.bit_order = NRF_SPI_BIT_ORDER_LSB_FIRST;
    
    nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL);

//change CS line
        nrf_drv_spi_switch_chips(&spi, CS_SENSOR1);
//Send data to the SENSOR1        
        nrf_drv_spi_transfer(&spi, m_tx_buf, m_spi_tx_count, NULL, 0);

//change CS line
        nrf_drv_spi_switch_chips(&spi, CS_SENSOR2);
//Send data to the SENSOR2        
        nrf_drv_spi_transfer(&spi, m_tx_buf, m_spi_tx_count, NULL, 0);

...
// the rest of your code

return 0;
}

As a reminder, be sure to include  "nrf_drv_spi.h" anywhere you use the switch_chips function. I tended to use it all in one file, so I just needed to include it once.

Any Nordic pros like to validate this? It worked on my setup.

Cheers, and happy bit flipping!

Parents Reply Children
Related