SPI slave always returns -ETIMEDOUT

Hi,

I am working on SPI master-slave application, as in, on one BL653 I am running SPI master driver, I am able to observe the waveforms for clock and data transfer from master on USB logic analyzer.

But I am facing an issue with the BL653 board which is running SPI slave code, basically, for slave under main my code is as below:

	m_spi_cfg->operation |= SPI_WORD_SET(8);

	m_rx_bufs->buf = &data;
	m_rx_bufs->len = sizeof(data);

	m_rx_set_buff->buffers = m_rx_bufs;
	m_rx_set_buff->count = 1;

	if ((m_spi_dev) != nullptr)
	{
		l_nStatus = spi_read(m_spi_dev, m_spi_cfg, m_rx_set_buff);
		printk("Received data : %u : %d\n",data,l_nStatus);
		if (l_nStatus != SUCCESS)
		{
			return ERR;
		}
	}

Here spi_read always returns -116, that is  -ETIMEDOUT.

My device binding, spi slave configurations and wiring with spi master are in order.

But I do not understand why slave driver always returns -ETIMEDOUT.

I traced the flow of execution all the way to the source of the error and here is what I found

spi_read( ) -> transceive (in file "spi_nrfx_spis.c") -> spi_context_wait_for_completion( in file "spi_context.h") -> and the source of error is as attached in the below snap in #else part 

Without debug mode as well I am getting the same -ETIMEDOUT.

Kindly suggest on if I have missed out on configuring something.


Thanks,

Ubaid

Parents Reply Children
  • Hello Jørgen,

    Thank you so much, Master's signals I am able to observe on USB logic analyzer, CLK, MOSI & CS (all three),

    as in below snap, cs stays low for 26micro secs during which master board is sending data:


    Roughly below is my slave code Jørgen, running on another board:

    #define SPI_DEVICE_NAME_P1 DT_LABEL(DT_NODELABEL(spi1))
    const device *m_spi_dev;
    struct spi_config *m_spi_cfg = new spi_config();
    void main(void)
    {
    
    	uint8_t spi_channel = 1;
    	bool is_master;
    
    	uint8_t port = 0;
    	uint8_t pin = 23;
    	uint32_t flag = GPIO_ACTIVE_LOW;//GPIO_OUTPUT_ACTIVE;
    	
        m_spi_dev = device_get_binding(SPI_DEVICE_NAME_P1);
        
        m_spi_cfg->frequency =  4000000;
        m_spi_cfg->operation |= SPI_OP_MODE_SLAVE;
        m_spi_cfg->slave = 1;
        m_spi_cfg->operation |= SPI_WORD_SET(8);
        
        const struct device	*gpio_dev = device_get_binding("GPIO_0");
        uint8_t gpio_pin_t = 23;
        uint8_t gpio_dt_flags_t = GPIO_ACTIVE_LOW;
        
        gpio_pin_configure(gpio_dev, gpio_pin_t, GPIO_INPUT | gpio_dt_flags_t);
        
        static uint8_t rx_buffer[1];
        struct spi_buf rx_buf = {
    .buf = rx_buffer,
    .len = sizeof(rx_buffer),
    };	
    
    const struct spi_buf_set rx = {
    .buffers = &rx_buf,
    .count = 1
    };
        
        while(true)
        {
        	l_nStatus = spi_read(m_spi_dev, m_spi_cfg, &rx);
    		printk("RX recv: %u : %d \n", rx_buffer[0],l_nStatus);
    		if (l_nStatus != SUCCESS)
    		{
    			return ERR;
    		}
            
        }
        
        }
        
        

    prj.conf:

    #C++ support configs
    CONFIG_CPLUSPLUS=y
    CONFIG_NEWLIB_LIBC=y
    CONFIG_LIB_CPLUSPLUS=y
    CONFIG_HEAP_MEM_POOL_SIZE=16348
    CONFIG_OPENOCD_SUPPORT=n
    
    #SPI
    CONFIG_SPI=y
    CONFIG_SPI_SLAVE=y
    CONFIG_LOG=y
    #CONFIG_SPI_ASYNC=y

    overlay:

    &spi1 {
    	compatible = "nordic,nrf-spis";
    	status = "okay";
    	sck-pin = <41>;
    	mosi-pin = <40>;
    	miso-pin = <4>;
    	cs-gpios = <&gpio0 23 0>;
    	csn-pin = <23>;
        def-char = <0xFF>;
    };



    Now with this code I am getting prints for:

    -ETIMEDOUT

    or 

    -EIO

    Being generated from adc_context.h

  • Hello ,

    Are the CSN pin connected and toggling as expected?


    I have uploaded the code and csn pin states on a logic analyser in the case:

    https://devzone.nordicsemi.com/f/nordic-q-a/83616/using-spi_write-spi_read-not-behaving-the-same-as-spi_transceive-for-spi-data-in-provided-spi-sample

    Same problem yet, 

    I have tried everything, yet no progress, can you kindly help out on why I am unable to receive data on slave board.


    Thanks,

    Ubaid

  • Hello   ,

    Clearly master board it is doing, I think something with slave board or slave pin out config.


    Can you have a look at slave code, config and kindlu suggest, as in below.
     

    SLAVE:************************************

    I am using  second board to run as a Slave, an nrf52833_dk,
    It's project is as follows:

    Code:

    /*
     * Copyright (c) 2012-2014 Wind River Systems, Inc.
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    #include <string.h>
    #include <errno.h>
    #include <zephyr.h>
    #include <sys/printk.h>
    #include <device.h>
    #include <drivers/spi.h>
    
    
    /*---------------------------------------------------------------------------*/
    /*                                                                           */
    /*---------------------------------------------------------------------------*/
    
    #define SPI_SLAVE_BUS_NAME     			DT_INST_0_NORDIC_NRF_SPIS_LABEL
    #define SPI_SLAVE_GPIOS_NAME    		DT_ALIAS_GPIO_0_LABEL
    #define SPI_SLAVE_GPIO_IRQ_PIN  		DT_ALIAS_SPI_0_CSN_PIN
    
    #define STACKSIZE 1024
    #define PRIORITY 99
    
    /*---------------------------------------------------------------------------*/
    /*                                                                           */
    /*---------------------------------------------------------------------------*/
    void spi_slave_init(void);
    
    /*---------------------------------------------------------------------------*/
    /*                                                                           */
    /*---------------------------------------------------------------------------*/
    int spi_slave_write(struct device * spi, 
                        struct spi_config * spi_cfg,
                        uint16_t * data)
    {
        struct spi_buf bufs = {
                .buf = data,
                .len = 2
        };
        struct spi_buf_set tx = {
            .buffers = &bufs
        };
        
        tx.count = 1;
    
        return spi_write(spi, spi_cfg, &tx);
    }
    
    /*---------------------------------------------------------------------------*/
    /*                                                                           */
    /*---------------------------------------------------------------------------*/
    int spi_slave_read(struct device * spi, 
                       struct spi_config * spi_cfg,
                       uint16_t * data)
    {
        struct spi_buf bufs = {
                .buf = data,
                .len = 2
        };
        struct spi_buf_set rx = {
            .buffers = &bufs
        };
        
        rx.count = 1;
    
        return spi_read(spi, spi_cfg, &rx);
    }
    
    /*---------------------------------------------------------------------------*/
    /*                                                                           */
    /*---------------------------------------------------------------------------*/
    void spi_slave_init(void)
    {
        struct device * spi;
        struct spi_config spi_cfg;
    
        uint16_t tx_data = 0x5678;
        uint16_t rx_data = 0;
    
        printk("SPI Slave example application\n");
    
        printk("rx_data buffer at %p\n", &rx_data);
    
        spi = device_get_binding("SPI_0");
        if (!spi) {
            printk("Could not find SPI driver\n");
            return;
        }
    
        /*
         *  SPI controller configuration structure for the nRF52 series.
         *
         *  param frequency is the bus frequency in hertz
         *  param operation is a bit field with the following parts:
         *
         *     operational mode  [ 0 ]       - master or slave.
         *     mode              [ 1 : 3 ]   - Polarity, phase and loop mode.
         *     transfer          [ 4 ]       - LSB or MSB first.
         *     word_size         [ 5 : 10 ]  - Size of a data frame in bits.
         *     lines             [ 11 : 12 ] - MISO lines: Single/Dual/Quad/Octal.
         *     cs_hold           [ 13 ]      - Hold on the CS line if possible.
         *     lock_on           [ 14 ]      - Keep resource locked for the caller.
         *     cs_active_high    [ 15 ]      - Active high CS logic.
         *
         *  param slave is the slave number from 0 to host controller slave limit.
         *  param cs is a valid pointer on a struct spi_cs_control is CS line is
         *        emulated through a gpio line, or NULL otherwise.
         */
    
        /* Note: Implicid Mode-0; e.g. CPOL=0, CPHA=0 -- the only mode supported */
        /* Note: The nRF52 series doesn't support CS pin configuration */
    
        memset(&spi_cfg, 0, sizeof(spi_cfg));
    
        spi_cfg.operation = SPI_WORD_SET(8) | SPI_OP_MODE_SLAVE;
        spi_cfg.frequency = 1000000;
        spi_cfg.slave = 1;
    
        printk("%s: slave config @ %p:"
                " wordsize(%u), mode(%u/%u/%u)\n", __func__, &spi_cfg,
                SPI_WORD_SIZE_GET(spi_cfg.operation),
                (SPI_MODE_GET(spi_cfg.operation) & SPI_MODE_CPOL) ? 1 : 0,
                (SPI_MODE_GET(spi_cfg.operation) & SPI_MODE_CPHA) ? 1 : 0,
                (SPI_MODE_GET(spi_cfg.operation) & SPI_MODE_LOOP) ? 1 : 0);
    
        while (1) {
            spi_slave_read(spi, &spi_cfg, &rx_data);
    
            if (rx_data == 0x1234) {
                spi_slave_write(spi, &spi_cfg, &tx_data);
            }
            printk("Received: 0x%04X -- %s\n", rx_data,
                   (rx_data == 0x1234) ? "ok" : "wrong"); 
        }
    }
    
    
    /*---------------------------------------------------------------------------*/
    /*                                                                           */
    /*---------------------------------------------------------------------------*/
    void spi_slave_thread(void * id, void * unused1, void * unused2)
    {
        printk("%s\n", __func__);
    
        spi_slave_init();
    
        while (1) { /* spin */}
    }
    
    K_THREAD_DEFINE(spi_slave_id, STACKSIZE, spi_slave_thread, 
                    NULL, NULL, NULL, PRIORITY, 0, 0);

    nrf52833dk_nrf52833.overlay:

    /*
    * Copyright (c) 2019 Callender-Consulting, LLC
    *
    * SPDX-License-Identifier: Apache-2.0
    */
    &spi0 {
    compatible = "nordic,nrf-spis";
    status = "okay";
    sck-pin = <27>;
    mosi-pin = <26>;
    miso-pin = <29>;
    csn-pin = <1>;
    def-char = <0xFF>;
    };

    prj.conf:

    # nothing here
    CONFIG_DEBUG=y
    CONFIG_GPIO=y
    CONFIG_SPI=y
    CONFIG_SPI_SLAVE=y
    CONFIG_PRINTK=y

    Hardware connections:

    SCLK : M-41 : S-27
    MOSI : M-40 : S-26

    MISO : M-04 : S-29

    CS :     M-23 : S-1


    Kindly suggest where i can look for further, I have evaluated everything yet to no avail 

    Thanks

  • Hi,

    Can you try with a different CS pin? P0.01 is by default connected to the 32.768 kHz LF crystal on the nRF52833 DK. The LF clock is usually started by the RTOS, meaning the pin is already in use and cannot be used with the SPI(S) peripheral.

    Best regards,
    Jørgen

  • Hello  ,

    Thanks, for the suggestion 

    Can you try with a different CS pin?

    After cs configuration, I was facing an issue where spi_read( ) was returning  timeout everytime.


    With this patch:https://github.com/zephyrproject-rtos/zephyr/pull/39906/commits/dfcc77526163ce6973a5788b202d2a17e4f82d86

    I was able to solve this issue, receive & print data on slave board.

    But what i do not understand is I cannot have  spi_read( ) wait indefinitely, It is a bad application if so,

    Now how can i Optimize this in my application..?
    I mean i read data only when it is available & not keep on waiting until data becomes available.

    Kindly suggest  ,

    Thanks,

    Ubaid

Related