SPI example for nRF52833 with nRF Connect SDK 2.3.0

Dear Support Team,

I just started evaluating a nRF52833 DK board with the nRF Connect SDK 2.3.0. At this point I would like to start playing with the SPI but unfortunately I can't find any working example that I could use.

Could you please point me to a working example without using the deprecated configuration parameters? 

Thank you very much in advance and all the best,

Viktor

  • Hi Viktor,

    One of my colleagues has made an SPI sample in v2.1.0 that you can find here: https://github.com/too1/ncs-spi-master-slave-example. This is using pinctrl and should not have any deprecated configurations.
    You need to make a few changes to the sample to migrate it to v2.3.0, such as adding the zephyr/ prefix to the include files, changing zephyr.h to kernel.h, and replacing spi_transceive_async() with spi_transceive_signal(). See the diff below for which changes to make.

    diff --git a/main.c b/main_v2-3-0.c
    index 2dc4978..11c6138 100644
    --- a/main.c
    +++ b/main_v2-3-0.c
    @@ -4,11 +4,11 @@
      * SPDX-License-Identifier: Apache-2.0
      */
    
    -#include <zephyr.h>
    -#include <device.h>
    -#include <devicetree.h>
    -#include <drivers/gpio.h>
    -#include <drivers/spi.h>
    +#include <zephyr/kernel.h>
    +#include <zephyr/device.h>
    +#include <zephyr/devicetree.h>
    +#include <zephyr/drivers/gpio.h>
    +#include <zephyr/drivers/spi.h>
    
     /* 1000 msec = 1 sec */
     #define SLEEP_TIME_MS   1000
    @@ -80,7 +80,7 @@ static int spi_write_test_msg(void)
            k_poll_signal_reset(&spi_done_sig);
    
            // Start transaction
    -       int error = spi_transceive_async(spi_dev, &spi_cfg, &tx, &rx, &spi_done_sig);
    +       int error = spi_transceive_signal(spi_dev, &spi_cfg, &tx, &rx, &spi_done_sig);
            if(error != 0){
                    printk("SPI transceive error: %i\n", error);
                    return error;
    @@ -147,7 +147,7 @@ static int spi_slave_write_test_msg(void)
            k_poll_signal_reset(&spi_slave_done_sig);
    
            // Start transaction
    -       int error = spi_transceive_async(spi_slave_dev, &spi_slave_cfg, &s_tx, &s_rx, &spi_slave_done_sig);
    +       int error = spi_transceive_signal(spi_slave_dev, &spi_slave_cfg, &s_tx, &s_rx, &spi_slave_done_sig);
            if(error != 0){
                    printk("SPI slave transceive error: %i\n", error);
                    return error;

    Best regards,
    Marte

  • Hi Marte!

    Thank you very much for the quick reply!

    So, for example if I want to communicate with an external sensor (accelerometer) would this be correct config?

    Overlay:

    &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;
    		};
    	};
    };
    
    my_spi_master: &spi1 {
    	compatible = "nordic,nrf-spi";
    	status = "okay";
    	pinctrl-0 = <&spi1_default>;
    	pinctrl-1 = <&spi1_sleep>;
    	cs-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>;
    	reg_my_spi_master: spi-dev-a@0 {
    		reg = <0>;
    	};
    };

    Initialize SPI master:

    #define MY_SPI_MASTER DT_NODELABEL(my_spi_master)
    
    // SPI master functionality
    const struct device *spi_dev;
    static struct k_poll_signal spi_done_sig = K_POLL_SIGNAL_INITIALIZER(spi_done_sig);
    
    struct spi_cs_control spim_cs = {
    	.gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(reg_my_spi_master)),
    	.delay = 0,
    };
    
    
    static void spi_init(void)
    {
    	spi_dev = DEVICE_DT_GET(MY_SPI_MASTER);
    	if(!device_is_ready(spi_dev)) {
    		printk("SPI master device not ready!\n");
    	}
    	if(!device_is_ready(spim_cs.gpio.port)){
    		printk("SPI master chip select device not ready!\n");
    	}
    }
    
    static const struct spi_config spi_cfg = {
    	.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB |
    				 SPI_MODE_CPOL | SPI_MODE_CPHA,
    	.frequency = 4000000,
    	.slave = 0,
    	.cs = &spim_cs,
    };
    
    
    

    Where can I find documentation of the "spi_transceive_signal" function? The IDE can't find anything (warning: implicit declaration of function 'spi_transceive_signal')

    Is it correct that I should rather use the following function to read/write registers of the accelerometer in this case?:

    int error = spi_transceive_dt(spi_dev, &tx, &rx);

    All the best,

    Viktor

  • Hi Marte!

    I managed to make the communication to the sensor work! I post the solution here so others can use it as well.

    Thanks again for the help!

    Overlay:

    &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;
    		};
    	};
    };
    
    my_spi_master: &spi1 {
    	compatible = "nordic,nrf-spi";
    	status = "okay";
    	pinctrl-0 = <&spi1_default>;
    	pinctrl-1 = <&spi1_sleep>;
    	cs-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>;
    	reg_my_spi_master: spi-dev-a@0 {
    		reg = <0>;
    	};
    };

    SPI initialization:

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/drivers/spi.h>
    
    #define MY_SPI_MASTER DT_NODELABEL(my_spi_master)
    
    // SPI master functionality
    const struct device *spi_dev;
    
    struct spi_cs_control spim_cs = {
    	.gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(reg_my_spi_master)),
    	.delay = 0,
    };
    
    
    static const struct spi_config spi_cfg = {
    	.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB |
    				 SPI_MODE_CPOL | SPI_MODE_CPHA,
    	.frequency = 4000000,
    	.slave = 0,
    	.cs = &spim_cs,
    };
    
    static void spi_init(void)
    {
    	spi_dev = DEVICE_DT_GET(MY_SPI_MASTER);
    	if(!device_is_ready(spi_dev)) {
    		printk("SPI master device not ready!\n");
    	}
    	if(!device_is_ready(spim_cs.gpio.port)){
    		printk("SPI master chip select device not ready!\n");
    	}
    }

    Test code that reads the accelerometer device ID:

    static int spi_test(void)
    {
    	static uint8_t tx_buffer[3];
    	static uint8_t rx_buffer[3];
    
    	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
    	};
    
    
    	/*
    	first 2 bytes of tx specify read/write action and on which register to perform
    	last byte of rx contains the respons from the accelerometer
    	*/
    	tx_buffer[0] = XL367_REG_READ;
    	tx_buffer[1] = XL367_DEVID_AD;
    
    	int error = spi_transceive(spi_dev, &spi_cfg, &tx, &rx);
    	if(error != 0){
    		printk("SPI transceive error: %i\n", error);
    		return error;
    	}
    
    
    	if(DEVICE_ID == rx_buffer[2])
    	{
    		printk("Successfull ACC communication\n");
    	}
    	else
    	{
    		printk("Faild ACC communication\n");
    	}
    
    	return 0;
    }

  • Hi Viktor,

    That is great to hear, and thank you for sharing the solution here for others to find!

    Best regards,
    Marte

  • Hi Marte,

    Just one more question related to this topic:

    What exactly this line is doing in the overlay SPI definition?

    reg_my_spi_master: spi-dev-a@0 {
    		reg = <0>;
    	};

    What exactly spi-dev-a@0 refers to and what is reg = <0>?

    Do I have to change anything to this part when trying to enable both SPI0 and SPI1 ? Does it relate to which SPI is beeing used? 

    Thank you in advance.

Related