This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

using spi_write() & spi_read() not behaving the same as spi_transceive() for spi data in provided spi sample

Hi,

I tried running an spi sample program with code as in below, shorted the MOSI and MISO pins and data was visibly received in print statement:

#include <zephyr.h>

#include <sys/printk.h>
#include <drivers/spi.h>
#include <drivers/gpio.h>



uint32_t freq = 4000000;
static const struct spi_config spi_cfg = {freq,(SPI_WORD_SET(8) | SPI_TRANSFER_MSB),0,nullptr};




const device * spi_dev;



static void spi_init(void)
{
const char* spiName = "SPI_1";
//const char* const spiName = "spi1";
spi_dev = device_get_binding(spiName);



if (spi_dev == NULL) {
printk("Could not get %s device\n", spiName);
return;
}
}



void spi_test_send(void)
{
int err;
static uint32_t tx_buffer[1]={0x05};
//static uint8_t tx_buffer = 128;
//static char tx_buffer[3]={'D','s','s'};
static uint32_t rx_buffer[1];
//static uint8_t rx_buffer;



const struct spi_buf tx_buf = {
.buf = tx_buffer,
.len = sizeof(tx_buffer)
};
const struct spi_buf_set tx = {
.buffers = &tx_buf,
.count = 1
};



struct spi_buf rx_buf = {
.buf = rx_buffer,
.len = sizeof(rx_buffer),
};
const struct spi_buf_set rx = {
.buffers = &rx_buf,
.count = 1
};


err = spi_transceive(spi_dev, &spi_cfg, &tx, &rx);

if (err) {
printk("SPI error: %d\n", err);
} else {
/* Connect MISO to MOSI for loopback */
printk("TX sent: %d\n", tx_buffer[0]);
printk("RX recv: %d\n", rx_buffer[0]);

}
}



void main(void)
{
printk("SPIM Example\n");
spi_init();



while (1) {
spi_test_send();
k_sleep(K_SECONDS(1));
}
}

While in the same code if i use spi_write( ) & spi_read( ) apis, which inturn call spi transceive, I am not receiving any data, code as in below:

#include <zephyr.h>

#include <sys/printk.h>
#include <drivers/spi.h>
#include <drivers/gpio.h>



uint32_t freq = 4000000;
static const struct spi_config spi_cfg = {freq,(SPI_WORD_SET(8) | SPI_TRANSFER_MSB),0,nullptr};




const device * spi_dev;



static void spi_init(void)
{
const char* spiName = "SPI_1";
//const char* const spiName = "spi1";
spi_dev = device_get_binding(spiName);



if (spi_dev == NULL) {
printk("Could not get %s device\n", spiName);
return;
}
}



void spi_test_send(void)
{
int err;
static uint32_t tx_buffer[1]={0x05};
//static uint8_t tx_buffer = 128;
//static char tx_buffer[3]={'D','s','s'};
static uint32_t rx_buffer[1];
//static uint8_t rx_buffer;



const struct spi_buf tx_buf = {
.buf = tx_buffer,
.len = sizeof(tx_buffer)
};
const struct spi_buf_set tx = {
.buffers = &tx_buf,
.count = 1
};



struct spi_buf rx_buf = {
.buf = rx_buffer,
.len = sizeof(rx_buffer),
};
const struct spi_buf_set rx = {
.buffers = &rx_buf,
.count = 1
};



err = spi_write(spi_dev, &spi_cfg, &tx);
err = spi_read(spi_dev, &spi_cfg, &rx);

if (err) {
printk("SPI error: %d\n", err);
} else {
/* Connect MISO to MOSI for loopback */
printk("TX sent: %d\n", tx_buffer[0]);
printk("RX recv: %d\n", rx_buffer[0]);

}
}



void main(void)
{
printk("SPIM Example\n");
spi_init();



while (1) {
spi_test_send();
k_sleep(K_SECONDS(1));
}
}

I am getting just -1 in receive buffer.

Kindly suggest what i can do to make spi_write & spi_read work..?

Parents
  • Hi,

     

    P0.01 is default setup to be one of the inputs of the external 32k crystal:

    https://infocenter.nordicsemi.com/topic/ps_nrf52833/pin.html?cp=4_1_0_6_0_1#wlcsp

     

    I would recommend that you choose another GPIO for the CSN pin.

     

    There's a couple of samples available here with both SPIM and SPIS:

    https://github.com/sigurdnev/ncs-playground/tree/master/samples

     

    Kind regards,

    Håkon

  • Hello ,


    There's a couple of samples available here with both SPIM and SPIS:

    https://github.com/sigurdnev/ncs-playground/tree/master/samples

    This does not suffice my requirement as everywhere here only spi_transceive is being used, while I am supposed to evaluate spi_read & spi_write.

    And

    P0.01 is default setup to be one of the inputs of the external 32k crystal:

    Thank you for the kind suggestion, I used P0.11 and after a couple of resets I was able to print 0x1234(data sent via master)

    on slave as in below:

    Need your help in understanding why the -116 (-ETIMEOUT) error is still persistent with the call to SPI_Read( ).
    I need to eliminate this error.

    For your kind reference, attaching the master board code & slave board code with configs.

    Master (BL653):

    prj.conf:

    CONFIG_DEBUG=y
    
    CONFIG_GPIO=y
    
    CONFIG_SPI=y
    #CONFIG_SPI_1=y
    
    CONFIG_PRINTK=y
    
    CONFIG_POLL=y

    bl653_dvk.overlay:

    /*
     * Copyright (c) 2019 Callender-Consulting, LLC
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    &spi1 {
    	compatible = "nordic,nrf-spi";
    	status = "okay";
    	sck-pin = <41>;
    	mosi-pin = <40>;
    	miso-pin = <4>;
    	cs-gpios = <&gpio0 23 0>;
    };

    main.c:

    /**
     * Copyright (c) 2019 - Callender-Consulting. LLC
     *
     *   You should have received a copy of the GNU General Public License.
     *   see <https://www.gnu.org/licenses/>.
     * 
     */
    #include <string.h>
    #include <errno.h>
    #include <zephyr.h>
    #include <sys/printk.h>
    #include <device.h>
    #include <drivers/spi.h>
    
    #define STACKSIZE 1024
    #define PRIORITY 99
    
    /*---------------------------------------------------------------------------*/
    /*                                                                           */
    /*---------------------------------------------------------------------------*/
    
    #define SPI_MASTER_BUS_NAME     		DT_INST_0_NORDIC_NRF_SPI_LABEL
    #define SPI_MASTER_GPIOS_NAME    		DT_ALIAS_GPIO_0_LABEL
    #define SPI_MASTER_GPIO_IRQ_PIN  		DT_ALIAS_SPI_0_CSN_PIN
    
    /* Needs to be aligned with the SPI master buffer size */
    #define SPI_MAX_MSG_LEN         255
    
    typedef struct spi_master_msg {
    	uint32_t       length;
        uint8_t        data [SPI_MAX_MSG_LEN];
    } spi_master_msg_t;
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /*---------------------------------------------------------------------------*/
    /*                                                                           */
    /*---------------------------------------------------------------------------*/
    int spi_master_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_master_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_master_init(void)
    {
        struct device * spi;
        struct spi_config spi_cfg;
        struct spi_cs_control cs_ctrl;
    
        uint16_t tx_data = 0x1234;
        uint16_t rx_data = 0;
    
        printk("SPI Master example application\n");
    
        printk("rx_data buffer at %p\n", &rx_data);
    
        spi = device_get_binding("SPI_1");
        if (!spi) {
            printk("Could not find SPI driver\n");
            return;
        }
    
        cs_ctrl.gpio_dev = device_get_binding("GPIO_0");
        cs_ctrl.gpio_pin = 23;
        cs_ctrl.delay = 0;
    
        /*
         *  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 master is the master number from 0 to host controller master 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_MASTER 
        //                    | SPI_MODE_CPOL | SPI_MODE_CPHA 
                            | SPI_LINES_SINGLE; 
        spi_cfg.frequency = 1000000;
        spi_cfg.cs = &cs_ctrl;
    
        printk("%s: master 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)  { //for (int i=0; i < 2; i++) {
    
            spi_master_write(spi, &spi_cfg, &tx_data);
    
            printk("Sent: 0x%02X\n", tx_data);
    
            spi_master_read(spi, &spi_cfg, &rx_data);
    
            printk("Received: 0x%02X\n", rx_data);
    
            printk("Response is %s\n",  (rx_data == 0x5678) ? "correct" : "incorrect");
    
            k_sleep(K_SECONDS(2));
        }
        printk("done\n");
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    
    /*---------------------------------------------------------------------------*/
    /*                                                                           */
    /*---------------------------------------------------------------------------*/
    void spi_master_thread(void * id, void * unused1, void * unused2)
    {
        printk("%s\n", __func__);
    
        spi_master_init();
    
        while(1) { /* spin */}
    }
    
    K_THREAD_DEFINE(spi_master_id, STACKSIZE, spi_master_thread,NULL, NULL, NULL, PRIORITY, 0, 0);
    

    Slave (nRF52833_dk):

    prj.conf:

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

    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 = <11>;
    def-char = <0xFF>;
    };

    main.c:

    /*
     * 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) {
            int err = spi_slave_read(spi, &spi_cfg, &rx_data);
    
            if (rx_data == 0x1234) {
                spi_slave_write(spi, &spi_cfg, &tx_data);
            }
            printk("err: %d ,Received: 0x%04X -- %s \n",err, 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);
    

    And also the master's captured waveforms:

    Kindly suggest,

    Thanks,

  • Ubaid_M said:
    This does not suffice my requirement as everywhere here only spi_transceive is being used, while I am supposed to evaluate spi_read & spi_write.

    Could you please test those examples for SPIM + SPIS to see if they work?

     

    Kind regards,

    Håkon

  • Hello Hakan,

    Could you please test those examples for SPIM + SPIS to see if they work?

    I mean to say, no where in those examples spi_read( ) & spi_write( ) are being used.

    And i need to work with spi_read( ) & spi_write( ), which I am able to currently with these example,

    Master (BL653):

    &

    Slave (nRF52833_dk):

    Except for this, towards which I need your help:

    Need your help in understanding why the -116 (-ETIMEOUT) error is still persistent with the call to SPI_Read( ).
    I need to eliminate this error.

    Do you suggest i lower the frequency and check again..?

    Thanks

     

  • Hi,

     

    There is a timeout on the spi_read() command that causes the ETIMEDOUT return. Could you try manually applying this patch and see if this is fixed?

    https://github.com/zephyrproject-rtos/zephyr/pull/39906

     

    Kind regards,

    Håkon

  • Hello ,


    There is a timeout on the spi_read() command that causes the ETIMEDOUT return. Could you try manually applying this patch and see if this is fixed?

    Thank you for the suggestion, It worked.

    But in my application I cannot have spi_read( ) waiting infinitely for data to become available.
    How can I make it such that I call spi_read( ) only when data is available in the buffer.

    Thanks,

    Ubaid

  • Hi,

     

    I am glad to hear that the PR worked for you. 

    Ubaid_M said:
    But in my application I cannot have spi_read( ) waiting infinitely for data to become available.
    How can I make it such that I call spi_read( ) only when data is available in the buffer.

    Yes, this is true. When this function is waiting, it is putting the thread to sleep.

    The easiest implementation is to run this in a dedicated thread:

    https://docs.zephyrproject.org/latest/reference/kernel/threads/index.html#implementation

     

    Kind regards,

    Håkon

Reply Children
  • Hello ,

    es, this is true. When this function is waiting, it is putting the thread to sleep.

    Thank you for the confirmation, I need to know on how to get an interrupt when data is available in RX buffer so that based on that interrupt I can call spi_read( ).
    I will open a new ticket for that i suppose.

    Meanwhile can you please confirm if this spi patch will be available in future releases of nCS..?

    Could you try manually applying this patch

    Thanks,

  • Hi,

     

    Ubaid_M said:

    Meanwhile can you please confirm if this spi patch will be available in future releases of nCS..?

    Yes, this will be present in the next version of NCS.

    Ubaid_M said:
    Thank you for the confirmation, I need to know on how to get an interrupt when data is available in RX buffer so that based on that interrupt I can call spi_read( ).

    This is effectively what happens in the background when calling spi_read. It goes into sleep until data is available.

    If you setup your SPI transactions within one thread, it will allow other threads to run properly while your thread waits for SPI transfers.

     

    If this is problematic, you can use the NRFX_SPIM driver directly.

     

    Kind regards,

    Håkon

  • Hello ,

    Thank you so much for the confirmation

    Yes, this will be present in the next version of NCS.

    Request one more information from you, on SPI interrupts,
    Is "NRFX_SPIM" built on SPI interrupts..?

    If not, Can I use spi_read( ) & spi_write( ) with explicit SPI interrupts (have not decided on which interrupts, assuming TX, RX buffer interrupts)..?

    Or it will not serve the purpose of interrupts..?

    Thanks,

    Ubaid

  • Hi,

     

    Ubaid_M said:
    Request one more information from you, on SPI interrupts,
    Is "NRFX_SPIM" built on SPI interrupts..?

    Yes, you can get a direct callback when an event occurs when using the nrfx driver directly.

     

    Ubaid_M said:

    If not, Can I use spi_read( ) & spi_write( ) with explicit SPI interrupts (have not decided on which interrupts, assuming TX, RX buffer interrupts)..?

    Or it will not serve the purpose of interrupts..?

    both spi_read and spi_write will wait for the transaction to complete, by waiting for the respective event to occur.

     

    Kind regards,

    Håkon

  • Yes, you can get a direct callback when an event occurs when using the nrfx driver directly.

    Thank you for the confirmation .

    Marking this thread as solved.

Related