SPIS on NRF52840

I've been struggling bringing up a working SPIS test application and would appreciate any help I can get.  I'm much more of a HW person, so this hyper abstracted Zephyr stuff is not easy for me.

First Question:

In my overlay (see below) for the reg: attribute, I get the warning:  

Node spi-dev-a should have "compatible" property
Node should only occur on the undefined bus.

/soc/spi@40004000/spi-dev-a@0/

I've seen in https://devzone.nordicsemi.com/f/nordic-q-a/93484/struggling-to-use-spi-with-zephyr  

the following response:  "The overlay warnings I can see here also, but they don't seem to affect the example. I will try to find some time later to look into this."  referring to a similar warning, so I'm not sure if this actually an issue or not.

my_spis: &spi1 {
    compatible = "nordic,nrf-spis";
    status = "okay";
    pinctrl-0 = <&spi1_default>;
    pinctrl-1 = <&spi1_sleep>;
    pinctrl-names = "default", "sleep";
    cs-gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
    def-char = <0x00>;

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

};


&spi1_default {
    group1 {
        psels = <NRF_PSEL(SPIS_SCK, 0, 31)>,
                <NRF_PSEL(SPIS_MOSI, 0, 30)>,
                <NRF_PSEL(SPIS_MISO, 1, 8)>;

    };
};

Are there any issues that are easily seen with this?

if (!device_is_ready(spi_cs.gpio.port)) and  if (!device_is_ready(spi_dev))  both report back that the SPI instance and the CS are ready.  So, I'm inclined to think that this is a non-issue.  Thoughts?
Second Question:
I am calling:  err = spi_transceive_cb(spi_dev, &spi_cfg, NULL, &rx, spi_slave_callback, NULL); which is constantly returning -22 (EINVAL).
Besides the overlay, here are the other relevant bits:
CONFIG_SPI=y
CONFIG_GPIO=y
CONFIG_SPI_SLAVE=y
CONFIG_SPI_ASYNC=y
CONFIG_DEBUG=y
CONFIG_PRINTK=y
#CONFIG_NRFX_SPIS1=y
CONFIG_USERSPACE=n
CONFIG_UART_CONSOLE=y
CONFIG_LOG=y
#CONFIG_LOG_BACKEND_RTT=n
CONFIG_LOG_BACKEND_UART=y
CONFIG_LOG_PRINTK=y
CONFIG_LOG_DEFAULT_LEVEL=4 


CONFIG_HEAP_MEM_POOL_SIZE=50512
#CONFIG_IDLE_STACK_SIZE=4096
#CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
CONFIG_MAIN_STACK_SIZE=4096


CONFIG_USE_SEGGER_RTT=n
#CONFIG_RTT_CONSOLE=n
CONFIG_SERIAL=y
struct spi_config spi_cfg = {
	.operation = SPI_WORD_SET(8) | SPI_OP_MODE_SLAVE | SPI_TRANSFER_MSB |
				 SPI_LINES_SINGLE,
	.frequency = 4000000,
	.slave = 0,
};
After the CS line is tested as ready:
	spi_cfg.cs = &spi_cs;
Here is setting the spi_cs_control struct:
static struct spi_cs_control spi_cs = {
	//	.gpio.pin = cs_gpio_pin,
	//	.gpio.dt_flags = cs_gpio_flags,
	.gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(reg_my_spis)),
	.delay = 0,
};
Here is setting up the rx buffer:
		const struct spi_buf rx_buf = {
			.buf = buffer,
			.len = BUFFER_SIZE,
		};
		const struct spi_buf_set rx = {
			.buffers = &rx_buf,
			.count = 1,
		};
Here is the prototype for the CB:
void spi_slave_callback(const struct device *dev, int result, void *data)
There is a print statement upon enter the CB, so it's obviously not getting that far.
Does anything look obviously amiss here?  Does anyone have any suggestions on figuring out what is triggering the -EINVAL?  
Thank you for any guidance!
Parents
  • Ok, I have the log information now going.  The -EINVAL is from this error message:   spi_nrfx_spis: CS control via GPIO is not supported

    I am assuming at this point that something in my overlay is not quite right with regards to the CS definition.  This information should be in the previous post.

    Thanks in advance for any thoughts.

    -Keith

  • As I understand this now, the SPI Slave code does not support monitoring a GPIO line assigned as a CS control line.  This is still a bit opaque from the zephyr and other documentation.

    Passing a NULL value into spi_cfg.cs allows the spi_transceive_cb to be called without an immediate error being thrown.

    I'm in the process of manually checking for the state of a cs line and should have some more code ready test later today.  

    Does anyone know if there is a decent write-up on the SPI support software and its functionality for NRF running zephyr? 

  • I did fix a couple of items in my original code.  However, the issue remains that the call back function is never called.  I have changed the buffer size up and down to check for impact there and nothing.  It doesn't seem to matter if I underflow, overflow, or perfectly match the buffer size with the spi incoming data, the cb is never called.

    I'm still not clear as to what triggers the 'end' of an spi transaction in the driver and I suspect that is the fundamental issue that I'm having.

    I've included everything that I can think of below.  The GPIO registers, the code properly waits for the cs line to go active (low) and then beings the spi call back setup, pauses and then waits.

    Thanks for having a look.

    Here is my full current code:

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/dt-bindings/gpio/gpio.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/drivers/spi.h>
    #include <nrfx_spis.h>
    #include <zephyr/logging/log.h>
    
    // #define NRFX_LOG_MODULE MY_CODE
    // #include <nrfx_log.h>
    
    LOG_MODULE_REGISTER(my_module);
    
    #define SPI_DEVICE_NAME "my_spis"
    #define BUFFER_SIZE 1
    static uint8_t buffer[BUFFER_SIZE] = {0};
    // static uint8_t ack_message[] = "ACK";
    
    static struct k_poll_signal spi_slave_done_sig = K_POLL_SIGNAL_INITIALIZER(spi_slave_done_sig);
    
    static struct device *spi_dev;
    
    static struct spi_config spi_cfg = {
    	.operation = SPI_WORD_SET(8) | SPI_OP_MODE_SLAVE | SPI_TRANSFER_MSB |
    				 SPI_LINES_SINGLE,
    	.frequency = 1000000,
    	.slave = 0,
    };
    
    #define MY_SPIS DT_NODELABEL(my_spis)
    const struct device *gpio_dev;
    #define CS_GPIO_NODE DT_NODELABEL(cs_gpio)
    const struct device *gpio_dev = DEVICE_DT_GET(CS_GPIO_NODE);
    const uint32_t cs_pin = 29;
    
    void spi_slave_callback(const struct device *dev, int result, void *data)
    {
    	// Check for errors in the result
    	if (result < 0)
    	{
    		printk("SPI transaction failed with error code %d\n", result);
    		return;
    	}
    
    	// Print the received data
    	printk("Received data: ");
    	for (int i = 0; i < BUFFER_SIZE; i++)
    	{
    		printk("%02x ", buffer[i]);
    	}
    
    	printk("\n");
    
    	// Print the result of the SPI transaction
    	k_poll_signal_raise(&spi_slave_done_sig, result);
    	printk("SPI transaction completed with status %d\n", result);
    }
    
    static int spi_begin_transaction(struct device *spi_dev, const struct spi_buf_set *rx)
    {
    	int err;
    	printk("In spi_check_for_message. \n");
    	k_poll_signal_reset(&spi_slave_done_sig);
    	__asm__ volatile("nop");
    	err = spi_transceive_cb(spi_dev, &spi_cfg, NULL, rx, spi_slave_callback, &spi_slave_done_sig);
    	__asm__ volatile("nop");
    	printk("Out of spi_transceive_cb\n RET: %d\n", err);
    	return (err);
    }
    
    static int spi_slave_check_for_message(void)
    {
    	int signaled, result;
    	k_poll_signal_check(&spi_slave_done_sig, &signaled, &result);
    	if (signaled != 0)
    	{
    		return 0;
    	}
    	else
    		return -1;
    }
    
    void main(void)
    {
    
    	static int err, loop_count;
    
    	// log_init();
    
    	printk("Entering Main\n");
    
    
    	if (!device_is_ready(gpio_dev))
    	{
    		printk("Device not ready.\n");
    		return;
    	}
    
    	spi_dev = DEVICE_DT_GET(DT_NODELABEL(my_spis));
    	if (!spi_dev)
    	{
    		printk("Could not find %s!\n", SPI_DEVICE_NAME);
    		return;
    	}
    
    	printk("Found %s!\n", SPI_DEVICE_NAME);
    
    	spi_cfg.cs = NULL;
    
    	/* configure the pin as input */
    	int ret = gpio_pin_configure(gpio_dev, cs_pin, GPIO_INPUT);
    	if (ret != 0)
    	{
    		printk("Didn't configure pin.\n");
    		/* handle error */
    	}
    
    	if (!device_is_ready(spi_dev))
    	{
    		printk("SPI device not ready \n");
    	}
    	else
    	{
    		printk("SPI device ready \n");
    	}
    
    	LOG_ERR("Test Error Message to confirm log works\n");
    	loop_count = 0;
    	while (1)
    	{
    		// printk("Loop %d\n", loop_count++);
    		const struct spi_buf rx_buf = {
    			.buf = buffer,
    			.len = BUFFER_SIZE,
    		};
    		const struct spi_buf_set rx = {
    			.buffers = &rx_buf,
    			.count = 1,
    		};
    		/*
    				const struct spi_buf tx_buf = {
    					.buf = buffer,
    					.len = BUFFER_SIZE,
    				};
    				const struct spi_buf_set tx = {
    					.buffers = &tx_buf,
    					.count = 1,
    				};
    		*/
    
    		// LOG_ERR("About to Call pin_get\n");
    		int cs_state = gpio_pin_get(gpio_dev, cs_pin);
    		// LOG_ERR("Just after calling pin_get\n");
    		if (cs_state < 0)
    		{
    			printk("error in reading cs pin state.\n"); /* handle error */
    		}
    		else if (cs_state == 0)
    		{
    			//cs is active so, begin transaction and setup callback and then wait for callback to be called.
    			err = spi_begin_transaction(spi_dev, &rx);
    			printk("Starting Wait. \n");
    
    			k_msleep(1);
    			printk("Done waiting. \n");
    			/* CS line is active, ready to transceive data */
    			printk("waiting... ");
    			do
    			{
    				err = spi_slave_check_for_message();
    				printk(".");
    			} while (err < 0);
    			printk("\n");
    			printk("Received data: ");
    			for (int i = 0; i < BUFFER_SIZE; i++)
    			{
    				printk("%02x ", buffer[i]);
    			}
    
    			printk("\n");
    		}
    
    		else
    		{
    
    			__asm__ volatile("nop");
    		}
    
    		if (err < 0)
    		{
    			printk("SPI transceive error: %d\n", err);
    		}
    	}
    }
    

    Here is the current proj.conf:


    CONFIG_GPIO=y
    
    CONFIG_SPI=y
    CONFIG_SPI_ASYNC=y
    
    CONFIG_SPI_SLAVE=y
    # nothing here
    #CONFIG_SPI=y
    #CONFIG_GPIO=y
    #CONFIG_GPIO_NRFX=y
    #CONFIG_SPI_SLAVE=y
    #CONFIG_SPI_ASYNC=y
    CONFIG_DEBUG=y
    #CONFIG_PRINTK=y
    #CONFIG_LOG_PRINTK=y
    CONFIG_LOG_MODE_IMMEDIATE=y
    #CONFIG_NRFX_SPIS1=y
    #CONFIG_USERSPACE=n
    CONFIG_LOG=y
    #CONFIG_LOG_BACKEND_RTT=n
    CONFIG_LOG_BACKEND_UART=y
    CONFIG_LOG_PRINTK=y
    CONFIG_LOG_DEFAULT_LEVEL=4 
    CONFIG_UART_CONSOLE=y
    #CONFIG_PM=n
    
    #CONFIG_STACK_SENTINEL=y
    
    
    
    
    #CONFIG_HEAP_MEM_POOL_SIZE=50512
    #CONFIG_IDLE_STACK_SIZE=2048
    #CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
    #CONFIG_MAIN_STACK_SIZE=8192
    
    
    
    #CONFIG_USE_SEGGER_RTT=n
    #CONFIG_RTT_CONSOLE=n
    CONFIG_SERIAL=y
    
    
    
    
    
    
    
    
    
    
    
    
    

    Here is a copy of the console output:

    Here is a screen shot of the logic analyzer capture feeding the dk:

  • Naeem,

    Any further thoughts?  

    Thanks,

    Keith

  • Hi Keith,

    Sorry for the delayed response

    I am note able to reproduce the issue that you are having.

    Are you able to compile and run the sample correctly?

    Can you send a complete zip folder which I could build for nrf52840dk to reproduce the error you are having?

    If there are any other special considerations, do let me know as well.

  • What issue have you not been able to replicate?

    If you are referring to the sample master-slave code example, I had posted that it was, in fact, operating properly, and that I was returning to dealing with the initial issues that I had posted about.

    Are you referring to the code and overlay that I followed up with, above?  That code has issues and definitely reacts the way I've described.  I actually just found a major reason for it, but have not had time to post the reason and the fix.

  • Hello,

    espian said:
    If you are referring to the sample master-slave code example, I had posted that it was, in fact, operating properly, and that I was returning to dealing with the initial issues that I had posted about.

    Yes, I was referring to the sample code (master/slave) and use with the DK.

    I did not test with your code, or with other boards.

    espian said:
    I actually just found a major reason for it,

    Good that you that you found the issue. 

    BR

Reply
  • Hello,

    espian said:
    If you are referring to the sample master-slave code example, I had posted that it was, in fact, operating properly, and that I was returning to dealing with the initial issues that I had posted about.

    Yes, I was referring to the sample code (master/slave) and use with the DK.

    I did not test with your code, or with other boards.

    espian said:
    I actually just found a major reason for it,

    Good that you that you found the issue. 

    BR

Children
No Data
Related