Delay between read and write SPI operation

Hello, 

We are using Zephyr OS and SDK v2.5.0 on nrf52840 chip. We have noticed some delay between spi_write and spi_read of 29µs,which is critical for our goal. Comparing to the bare metal version this delay is reduced to around 4µs. We wanted to know is there a way to reduce this delay in the Zephyr version? 

The following is our SPI configuration and the line of code: 

&spi2 {
		compatible = "nordic,nrf-spim";
		status = "okay";
		pinctrl-0 = <&spi2_primary_default>;
		pinctrl-1 = <&spi2_primary_sleep>;
		pinctrl-names = "default", "sleep";
		/*cs-gpios   = <&gpio0 24 GPIO_ACTIVE_LOW>;*/
		shuttle_spi: device_ex@0 {
			compatible = "manuf_ex,device_ex";
			reg = <0>;
			spi-max-frequency = <8000000>;
			status = "okay";
		};
	};

    /*private api to set pin conf*/
    set_pin_config(CS_PIN,PIN_DIRECTION_OUT,PIN_VALUE_LOW);
	rc |= spi_write(spi_spec->bus, &spi_spec->config,&tx); //Zephyr SPI write API
	rc |= spi_read(spi_spec->bus, &spi_spec->config,&rx); //Zephyr SPI read API
	set_pin_config(CS_PIN,PIN_DIRECTION_OUT,PIN_VALUE_HIGH);

Regarding the CS line, we commented it from the SPI node def because we want to control it manually from our side since we are using some sensors which provide both SPI and I2C and the bus selection is set by toggling this CS line. 

This is a screenshot of baremetal version measurements: 


This is a screenshot of Zephyr version measurements:

Thanks! 

  • Have you tried with spi transceive function rather than a separate write and read? 

    Otherwise, you could use nrfx as the delay might be unavoidable due to zephyr layer.

  • Thank you for your reply. 

    I have tried with spi transceive and I got a wrong rx data but the timing is better:

    rc |= spi_transceive(spi_spec->bus, &spi_spec->config, &tx, &rx);




    I also tried 2 spi transceive like the following, and I got the same result as separate write and read which is obvious since the spi write and read are based on the spi transceive.
        rc |= spi_transceive(spi_spec->bus, &spi_spec->config, &tx, NULL);
        rc |= spi_transceive(spi_spec->bus, &spi_spec->config, NULL, &rx);
      


    I'm trying to implement nrfx in my project, I'll post update once done.

    Thanks

  •     
        const struct spi_buf tx_buf = {
    		.buf = &reg_addr,
    		.len = 1,
    	};
    	const struct spi_buf_set tx = {
    		.buffers = &tx_buf,
    		.count = 1,
    	};
        struct spi_buf rx_buf = {
            .buf = reg_data,
            .len = 2,
    	};
    
    	const struct spi_buf_set rx = {
    		.buffers = &rx_buf,
    		.count = 1,
    	};

  • You are reading 2 bytes, right? If there should come 2 actual bytes on MISO from the sensor then you can configure buffers like this and test again: (please review the code and modify accordingly if you are receiving different amount of data)

    uint8_t regs[3];
    regs[0] = reg_addr;
    regs[1] = 0xFF;
    regs[2] = 0xFF;
    uint8_t readbuf[3];		//3 is used as you are to receive 2 bytes
                            //1st byte received will be dummy byte
    
    struct spi_buf 	tx_spi_buf 		    = {.buf = (void *)&regs, .len = sizeof(regs)};
    struct spi_buf_set tx_spi_buf_set	= {.buffers = &tx_spi_buf, .count = 1};
    struct spi_buf 	rx_spi_bufs		    = {.buf = readbuf, .len = sizeof(regs)};
    struct spi_buf_set rx_spi_buffer_set	= {.buffers = &rx_spi_bufs, .count = 1};
    
    //use spi-transceive or spi-transceive-dt as per your overall code setup
    err = spi_transceive_dt(&spispec, &tx_spi_buf_set, &rx_spi_buffer_set);
    if (err < 0) {
    	LOG_ERR("spi_transceive_dt() failed, err: %d", err);
    	return err;
    }

Related