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..?

  • 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

  • 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

Related