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

SPI with multiple chip selects

As I understand the SPI HW driver documentation, it appears to be at least biased for using a single chip select (slave select in the API). I have an application where I have 5 devices on the SPI bus.

Should I create an SPI master configuration structure for each of the 5 devices? Only the SPI_Pin_SS would be different in each of them, and I think I would need to close and open SPI to switch between the devices.

Or can I use a single structure with spi configuration function to configure the SPI pins (CLK, MOSI, MISO) and manually configure the chip selects? And then when I want to change device I want, just change the SPI_Pin_SS?

Another way? After reading RK's answer, began to wonder if could use GPIOTE to handle the multiple chip selects. Would it work to assign SPI_Pin_SS to an "unused" pin, and cofigure GPIOTE task to toggle desired CS when SPI toggles _SS ? I haven't explored GPIOTE at all yet so this may be a naive idea.

Parents
  • I discovered that the chip select can be changed in the spi_master_instance that is created when SPI is opened. I wrote this function to do it:

    void spi_master_change_cs(spi_master_hw_instance_t spi_master_hw_instance, uint32_t cs_pin)
    {		
      volatile spi_master_instance_t * p_spi_instance = spi_master_get_instance(spi_master_hw_instance);
      p_spi_instance->pin_slave_select = cs_pin;
      //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_spi_instance->pin_slave_select);
      nrf_gpio_cfg_output(p_spi_instance->pin_slave_select);
      nrf_gpio_pin_set(p_spi_instance->pin_slave_select);
    }	
    

    and called like this

    spi_master_init(SPI_MASTER_0, spi_master_0_event_handler, true);
    
    for (;; )
    {
    		spi_send_recv(SPI_MASTER_0, m_tx_data_spi, m_rx_data_spi, TX_RX_MSG_LENGTH);
    		nrf_delay_ms(1);
    		spi_master_change_cs(SPI_MASTER_0,5);
    		spi_send_recv(SPI_MASTER_0, m_tx_data_spi, m_rx_data_spi, TX_RX_MSG_LENGTH);
    		nrf_delay_ms(1);
    		spi_master_change_cs(SPI_MASTER_0,6);
    		spi_send_recv(SPI_MASTER_0, m_tx_data_spi, m_rx_data_spi, TX_RX_MSG_LENGTH);
    		nrf_delay_ms(10);
    		spi_master_change_cs(SPI_MASTER_0,2);
    }
    

    image description

    Not perfect, still have to wait until SPI finishes previous transmission before changing hence the delays.

Reply
  • I discovered that the chip select can be changed in the spi_master_instance that is created when SPI is opened. I wrote this function to do it:

    void spi_master_change_cs(spi_master_hw_instance_t spi_master_hw_instance, uint32_t cs_pin)
    {		
      volatile spi_master_instance_t * p_spi_instance = spi_master_get_instance(spi_master_hw_instance);
      p_spi_instance->pin_slave_select = cs_pin;
      //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_spi_instance->pin_slave_select);
      nrf_gpio_cfg_output(p_spi_instance->pin_slave_select);
      nrf_gpio_pin_set(p_spi_instance->pin_slave_select);
    }	
    

    and called like this

    spi_master_init(SPI_MASTER_0, spi_master_0_event_handler, true);
    
    for (;; )
    {
    		spi_send_recv(SPI_MASTER_0, m_tx_data_spi, m_rx_data_spi, TX_RX_MSG_LENGTH);
    		nrf_delay_ms(1);
    		spi_master_change_cs(SPI_MASTER_0,5);
    		spi_send_recv(SPI_MASTER_0, m_tx_data_spi, m_rx_data_spi, TX_RX_MSG_LENGTH);
    		nrf_delay_ms(1);
    		spi_master_change_cs(SPI_MASTER_0,6);
    		spi_send_recv(SPI_MASTER_0, m_tx_data_spi, m_rx_data_spi, TX_RX_MSG_LENGTH);
    		nrf_delay_ms(10);
    		spi_master_change_cs(SPI_MASTER_0,2);
    }
    

    image description

    Not perfect, still have to wait until SPI finishes previous transmission before changing hence the delays.

Children
Related