Issues with SPI and nrf52dk

Hello Nordic Forums.

I have been struggling for the past couple of days to try to get the SPI working. I never thought that something this easy could have become such a nightmare.
I tried compiling and running sample test from Lesson 5 of the Intermediate course (SPI). The problem with the sample is that I always get back 0xFF when I read back from the registry.
I have a bmp390 and I'd be very happy to read back a nice 0x60 value from chip id (registry 0x00), but so far all I was able to read is 0xFF, as you can see from the trace below.

This video shows something very similar to the sample files
https://www.youtube.com/watch?v=zStXcr2Fi44

I tried to write the same code and still get 0xFF. I tried to send a read 0x80 after the registry but nothing worked.
During this painful investigation, I found that for some reasons i am not even able to control some pins (ie pin 9) on the dk.

From the board configuration:

spi1_default: spi1_default {
 group1 {
     psels = <NRF_PSEL(SPIM_SCK, 0, 31)>,
             <NRF_PSEL(SPIM_MOSI, 0, 30)>,
             <NRF_PSEL(SPIM_MISO, 0, 29)>;
 };
};

While my overlay files is:

&gpio0 {
 status = "okay";
};

&gpiote0 {
 status = "okay";
};

&spi1 {
 compatible = "nordic,nrf-spi";
 status = "okay";
};

/ {
 cs_one_pin: cs-one-pin {
 compatible = "nordic,gpio-pins";
 gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
 status = "okay";
 };
};

Here is my main.c file

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>

#define SLEEP_TIME_MS 1000
#define LED0_NODE DT_ALIAS(led0)
#define SPI1_NODE DT_NODELABEL(spi1)

static const struct device *spi1_dev = DEVICE_DT_GET(SPI1_NODE);
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static const struct gpio_dt_spec cs = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(cs_one_pin), gpios, {0});

static struct spi_config spi_cfg = {
 .frequency = 1000000U,
 .operation = SPI_WORD_SET(8),
 .slave = 0
};

static void readRegister(uint8_t reg, uint8_t values[], uint8_t size)
{
 int err; 
 uint8_t tx_buffer[1];
 tx_buffer[0] = reg;
 
 struct spi_buf tx_spi_bufs[] = {
    {.buf = tx_buffer, .len = sizeof(tx_buffer)}
 };
 
 struct spi_buf_set spi_tx_buf_set = {
 .buffers = tx_spi_bufs, 
 .count = 1
 };
 
 struct spi_buf rx_spi_bufs[] = {
    {.buf = values, .len = size}
 };
 
 struct spi_buf_set spi_rx_buf_set = {
 .buffers = rx_spi_bufs, 
 .count = 1
 };
 
 gpio_pin_set_dt(&cs, 1U);
 
 do {
    err = spi_write(spi1_dev, &spi_cfg, &spi_tx_buf_set);
    if(err < 0)
    {
     break;
    }
     err = spi_read(spi1_dev, &spi_cfg, &spi_rx_buf_set);
    }
    while(false);
    gpio_pin_set_dt(&cs, 0U); 
  }
  
static void readChipID(void) {
 uint8_t rx_buf_chipid[1];
 readRegister(0x00, rx_buf_chipid, 1);
}

int main(void)
{
 int ret;
 bool led_state = true;
 if (!gpio_is_ready_dt(&led)) {
    return 0;
 }
 if(!device_is_ready(spi1_dev)) {
    return 0;
 }
 ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
 if (ret < 0) {
    return 0;
 }
 ret = gpio_pin_configure_dt(&cs, GPIO_OUTPUT);
 if (ret < 0) {
    return 0;
 }
 while (1) {
    ret = gpio_pin_toggle_dt(&led);
    if (ret < 0) {
        return 0;
    }
    readChipID();
    printf("LED state: %s\n", led_state ? "ON" : "OFF");
    k_msleep(SLEEP_TIME_MS);
 }
 return 0;
}

Any idea of what I am doing wrong?

I apologize for all these information, but I hope it will help others having the same issues.

Thank you

Parents
  • Hello,

    I can see in the overlay you have set CS pin active low. That means CS is high before the transfer (inactive state), CS is inactive while doing write+read operation. After the transfer CS will be pulled low.

    / {
     cs_one_pin: cs-one-pin {
     compatible = "nordic,gpio-pins";
     gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
     status = "okay";
     };

    But in the code, you set reverse. 

     gpio_pin_set_dt(&cs, 1U);
     
     do {
        err = spi_write(spi1_dev, &spi_cfg, &spi_tx_buf_set);
        if(err < 0)
        {
         break;
        }
         err = spi_read(spi1_dev, &spi_cfg, &spi_rx_buf_set);
        }
        while(false);
        gpio_pin_set_dt(&cs, 0U); 
      }

    You can try to fix this by asserting CS low before transfer the data and de-assert high after the transmission. 

    gpio_pin_set_dt(&cs, 0U);   // CS active (low)
    
    err = spi_transceive(spi1_dev, &spi_cfg,
                         &spi_tx_buf_set, &spi_rx_buf_set);// instead of spi_read you can use spi_transcive()
    
    gpio_pin_set_dt(&cs, 1U);   // CS inactive (high)

    In device tree overlay you have not binded spi1_default to spi1. 

    Try to change the device-tree following way:

    &pinctrl {
        spi1_default: spi1_default {
            group1 {
                psels = <NRF_PSEL(SPIM_SCK, 0, 31)>,
                        <NRF_PSEL(SPIM_MOSI, 0, 30)>,
                        <NRF_PSEL(SPIM_MISO, 0, 29)>;
            };
        };
    
        spi1_sleep: spi1_sleep {
            group1 {
                psels = <NRF_PSEL(SPIM_SCK, 0, 31)>,
                        <NRF_PSEL(SPIM_MOSI, 0, 30)>,
                        <NRF_PSEL(SPIM_MISO, 0, 29)>;
                low-power-enable;
            };
        };
    };
    
    &gpio0 {
        status = "okay";
    };
    
    &gpiote0 {
        status = "okay";
    };
    
    &spi1 {
        compatible = "nordic,nrf-spi";
        status = "okay";
        pinctrl-0 = <&spi1_default>;
        pinctrl-1 = <&spi1_sleep>;
        pinctrl-names = "default", "sleep";
    };
    
    / {
        cs_one_pin: cs-one-pin {
            compatible = "nordic,gpio-pins";
            gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
            status = "okay";
        };
    };

  • Thank you Kazi for your reply.

    My understanding is that if a pin is Active Low, then passing 0U to gpio_pin_set_dt(&cs, 0U) means that we intend to set the pin to its Inactive state, which is High.
    I confirmed this behavior with leds and so on, and clearly the trace from the logic analyzer shows that I am pulling the cs line low when transmitting data with the following code. And I've confirmed that If set &cs to 0U, then call tranceive and the set cs to 1U, I will not get any data transmission.

     

    gpio_pin_set_dt(&cs, 1U);
    err = spi_transceive(spi1_dev, &spi_cfg,
                     &spi_tx_buf_set, &spi_rx_buf_set);
    gpio_pin_set_dt(&cs, 0U);

    Now, I've updated the code as follows:
    #include <stdio.h>
    #include <zephyr/kernel.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/drivers/spi.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #define SLEEP_TIME_MS   5000
    #define LED0_NODE DT_ALIAS(led0)
    #define SPI1_NODE DT_NODELABEL(spi1)
    static const struct device *spi1_dev = DEVICE_DT_GET(SPI1_NODE);
    static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
    static const struct gpio_dt_spec cs = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(cs_one_pin), gpios, {0});
    static struct spi_config spi_cfg = {
    	.frequency = 1000000U,
    	.operation = SPI_WORD_SET(8),
    	.slave = 0
    };
    static void readRegister(uint8_t reg, uint8_t values[], uint8_t size)
    {
    	int err; 
    	uint8_t tx_buffer[3];
    	tx_buffer[0] = 0x80; // read operation
    	tx_buffer[1] = reg;  // registry
    	tx_buffer[2] = 0x00; // dummy byte for result
    
    	struct spi_buf tx_spi_bufs[] = {
    		{.buf = tx_buffer, .len = sizeof(tx_buffer)}
    	};
    	struct spi_buf_set spi_tx_buf_set = {
    		.buffers = tx_spi_bufs, 
    		.count = 1
    	};
    	struct spi_buf rx_spi_bufs[] = {
    		{.buf = values, .len = size}
    	};
    	struct spi_buf_set spi_rx_buf_set = {
    		.buffers = rx_spi_bufs, 
    		.count = 1
    	};
    
    	gpio_pin_set_dt(&cs, 1U);
    	err = spi_transceive(spi1_dev, &spi_cfg,
                         &spi_tx_buf_set, &spi_rx_buf_set);
    	gpio_pin_set_dt(&cs, 0U);
    	if(err > 0)
    	{
    		printf("Error when sending spi message!");
    	}   
    }
    static void readChipID(void) {
    	uint8_t rx_buf_chipid[4];
    	readRegister(0x00, rx_buf_chipid, 3);
    	printf("Received: %X, %X, %X\n", rx_buf_chipid[0], rx_buf_chipid[1], rx_buf_chipid[2]);
    }
    int main(void)
    {
    	int ret;
    	bool led_state = true;
    	if (!gpio_is_ready_dt(&led)) {
    		return 0;
    	}
    	if(!device_is_ready(spi1_dev)) {
    		return 0;
    	}
    	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    	if (ret < 0) {
    		return 0;
    	}
    	ret = gpio_pin_configure_dt(&cs, GPIO_OUTPUT);
    	if (ret < 0) {
    		return 0;
    	}
    	printf("Setup completed!");
    
    	while (1) {
    		ret = gpio_pin_toggle_dt(&led);
    		if (ret < 0) {
    			return 0;
    		}
    		readChipID();
    		k_msleep(SLEEP_TIME_MS);
    	}
    	return 0;
    }

     and the overlay file as:

    / {
        cs_one_pin: cs-one-pin {
                    compatible = "nordic,gpio-pins";
                    gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
                    status = "okay";
        };
    };
    
    &spi1 {
    	compatible = "nordic,nrf-spi";
    	status = "okay";
        pinctrl-0 = <&spi1_default>;
        pinctrl-1 = <&spi1_sleep>;
        pinctrl-names = "default", "sleep";
    };
    
    &pinctrl {
        spi1_default: spi1_default {
            group1 {
                psels = <NRF_PSEL(SPIM_SCK, 0, 31)>,
                        <NRF_PSEL(SPIM_MOSI, 0, 30)>,
                        <NRF_PSEL(SPIM_MISO, 0, 29)>;
            };
        };
    
        spi1_sleep: spi1_sleep {
            group1 {
                psels = <NRF_PSEL(SPIM_SCK, 0, 31)>,
                        <NRF_PSEL(SPIM_MOSI, 0, 30)>,
                        <NRF_PSEL(SPIM_MISO, 0, 29)>;
                low-power-enable;
            };
        };
    };


    However on nrf52dk I am receiving back the following values from the transmission:
    FF FF 40
    While the logic analyzer shows
    FF FE 60
    I am wondering what is causing this discrepancy as the correct registry value for the BMP390 is 0x60.
    I have confirmed that I am able to get the correct registry value from the sensor using arduino library.
    Could be this due to the following errata?

    https://docs.nordicsemi.com/bundle/errata_nRF52840_EngA/page/ERR/nRF52840/EngineeringA/latest/anomaly_840_58.html

    Moreover I noticed that in the example from Nordic Academy, there is no need to pull cs manually with the transceive command. Do I need to do so? 

    Do i need to add a node to the SPI (if so which node should I add, since I could not find a bmp390 in the library)?

    Thank you again.



Reply
  • Thank you Kazi for your reply.

    My understanding is that if a pin is Active Low, then passing 0U to gpio_pin_set_dt(&cs, 0U) means that we intend to set the pin to its Inactive state, which is High.
    I confirmed this behavior with leds and so on, and clearly the trace from the logic analyzer shows that I am pulling the cs line low when transmitting data with the following code. And I've confirmed that If set &cs to 0U, then call tranceive and the set cs to 1U, I will not get any data transmission.

     

    gpio_pin_set_dt(&cs, 1U);
    err = spi_transceive(spi1_dev, &spi_cfg,
                     &spi_tx_buf_set, &spi_rx_buf_set);
    gpio_pin_set_dt(&cs, 0U);

    Now, I've updated the code as follows:
    #include <stdio.h>
    #include <zephyr/kernel.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/drivers/spi.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #define SLEEP_TIME_MS   5000
    #define LED0_NODE DT_ALIAS(led0)
    #define SPI1_NODE DT_NODELABEL(spi1)
    static const struct device *spi1_dev = DEVICE_DT_GET(SPI1_NODE);
    static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
    static const struct gpio_dt_spec cs = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(cs_one_pin), gpios, {0});
    static struct spi_config spi_cfg = {
    	.frequency = 1000000U,
    	.operation = SPI_WORD_SET(8),
    	.slave = 0
    };
    static void readRegister(uint8_t reg, uint8_t values[], uint8_t size)
    {
    	int err; 
    	uint8_t tx_buffer[3];
    	tx_buffer[0] = 0x80; // read operation
    	tx_buffer[1] = reg;  // registry
    	tx_buffer[2] = 0x00; // dummy byte for result
    
    	struct spi_buf tx_spi_bufs[] = {
    		{.buf = tx_buffer, .len = sizeof(tx_buffer)}
    	};
    	struct spi_buf_set spi_tx_buf_set = {
    		.buffers = tx_spi_bufs, 
    		.count = 1
    	};
    	struct spi_buf rx_spi_bufs[] = {
    		{.buf = values, .len = size}
    	};
    	struct spi_buf_set spi_rx_buf_set = {
    		.buffers = rx_spi_bufs, 
    		.count = 1
    	};
    
    	gpio_pin_set_dt(&cs, 1U);
    	err = spi_transceive(spi1_dev, &spi_cfg,
                         &spi_tx_buf_set, &spi_rx_buf_set);
    	gpio_pin_set_dt(&cs, 0U);
    	if(err > 0)
    	{
    		printf("Error when sending spi message!");
    	}   
    }
    static void readChipID(void) {
    	uint8_t rx_buf_chipid[4];
    	readRegister(0x00, rx_buf_chipid, 3);
    	printf("Received: %X, %X, %X\n", rx_buf_chipid[0], rx_buf_chipid[1], rx_buf_chipid[2]);
    }
    int main(void)
    {
    	int ret;
    	bool led_state = true;
    	if (!gpio_is_ready_dt(&led)) {
    		return 0;
    	}
    	if(!device_is_ready(spi1_dev)) {
    		return 0;
    	}
    	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    	if (ret < 0) {
    		return 0;
    	}
    	ret = gpio_pin_configure_dt(&cs, GPIO_OUTPUT);
    	if (ret < 0) {
    		return 0;
    	}
    	printf("Setup completed!");
    
    	while (1) {
    		ret = gpio_pin_toggle_dt(&led);
    		if (ret < 0) {
    			return 0;
    		}
    		readChipID();
    		k_msleep(SLEEP_TIME_MS);
    	}
    	return 0;
    }

     and the overlay file as:

    / {
        cs_one_pin: cs-one-pin {
                    compatible = "nordic,gpio-pins";
                    gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
                    status = "okay";
        };
    };
    
    &spi1 {
    	compatible = "nordic,nrf-spi";
    	status = "okay";
        pinctrl-0 = <&spi1_default>;
        pinctrl-1 = <&spi1_sleep>;
        pinctrl-names = "default", "sleep";
    };
    
    &pinctrl {
        spi1_default: spi1_default {
            group1 {
                psels = <NRF_PSEL(SPIM_SCK, 0, 31)>,
                        <NRF_PSEL(SPIM_MOSI, 0, 30)>,
                        <NRF_PSEL(SPIM_MISO, 0, 29)>;
            };
        };
    
        spi1_sleep: spi1_sleep {
            group1 {
                psels = <NRF_PSEL(SPIM_SCK, 0, 31)>,
                        <NRF_PSEL(SPIM_MOSI, 0, 30)>,
                        <NRF_PSEL(SPIM_MISO, 0, 29)>;
                low-power-enable;
            };
        };
    };


    However on nrf52dk I am receiving back the following values from the transmission:
    FF FF 40
    While the logic analyzer shows
    FF FE 60
    I am wondering what is causing this discrepancy as the correct registry value for the BMP390 is 0x60.
    I have confirmed that I am able to get the correct registry value from the sensor using arduino library.
    Could be this due to the following errata?

    https://docs.nordicsemi.com/bundle/errata_nRF52840_EngA/page/ERR/nRF52840/EngineeringA/latest/anomaly_840_58.html

    Moreover I noticed that in the example from Nordic Academy, there is no need to pull cs manually with the transceive command. Do I need to do so? 

    Do i need to add a node to the SPI (if so which node should I add, since I could not find a bmp390 in the library)?

    Thank you again.



Children
No Data
Related