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!
  • 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? 

  • Hi Keith,

    Thank you for contacting DevZone at NordicSemi.

    I have been assigned this ticket and I did not get a chance to look at it.

    I will come back to it tomorrow.

    Regards,

    Naeem

  • Hi Keith,

    Thank you for being patient.

    Device yaml files define the device bindings and that can be used as guidelines for writing overlays.

    If some properties are marked as required, then those must be define in the DT overlays for those devices.

    As you are using nordic spis driver, looking at the driver code suggests the same what you were referring to.

    The spi_nrfx_transceive function, under the hood, calls transceive function which in turn calls device configure (configure(dev,spi_cfg)) function. If, in calling transceive from nrf_spis driver, spi_cfg->cs is defined then it would return error. So definitely, putting NULL in the cs should resolve this issue.

  • Thank you for confirming this.

    I have code that now manually monitors a cs line and triggers a call to spi_transceive_cb.  (see below).  The first SPI transaction calls spi_transceive_cb and it returns a zero.  The second transaction throws up some debug messages from the MPU module (see further below).  In both cases I never see output from my callback function.

    I'll continue to debug on this, but if there is something obvious that I'm not doing correctly, please let me know.

    I have verified with a logic analyzer that the SPI transmission to the NRF are happening correctly.

    struct spi_config spi_cfg = {
    	.operation = SPI_WORD_SET(8) | SPI_OP_MODE_SLAVE | SPI_TRANSFER_MSB |
    				 SPI_LINES_SINGLE,
    	.frequency = 4000000,
    	.slave = 0,
    };
    
    ...................
    
    while (1)
    	{
    		//printf("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,
    				};
    		*/
    		// receive data packet
    		//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)
    		{
    			printf("error in reading cs pin state.\n"); /* handle error */
    		}
    		else if (cs_state == 0)
    		{
    			__asm__ volatile("nop");
    			err = spi_transceive_cb(spi_dev, &spi_cfg, NULL, &rx, spi_slave_callback, NULL);
    			__asm__ volatile("nop");
    			printf("Out of spi_transceive_cb\n RET: %d\n", err);
    			/* CS line is active, ready to transceive data */
    		}
    		else
    		{
    			/* CS line is not active */
    			__asm__ volatile("nop");
    		}
    
    		if (err < 0)
    		{
    			printf("SPI transceive error: %d\n", err);
    		}
    	}

    Here is the callback:

    void spi_slave_callback(const struct device *dev, int result, void *data)
    {
    	// Check for errors in the result
    	if (result < 0)
    	{
    		printf("SPI transaction failed with error code %d\n", result);
    		return;
    	}
    
    	// Check if the buffer contains data
    	if (buffer == NULL || BUFFER_SIZE == 0)
    	{
    		printf("Buffer is empty or not initialized\n");
    		return;
    	}
    
    	// Print the received data
    	printf("Received data: ");
    	for (int i = 0; i < BUFFER_SIZE; i++)
    	{
    		printf("%02x ", buffer[i]);
    	}
    
    	printf("\n");
    
    	// Print the result of the SPI transaction
    	printf("SPI transaction completed with status %d\n", result);
    }

    Here is the console output:

    Out of spi_transceive_cb

     RET: 0

    [00:00:35.624,877] <dbg> mpu: mpu_configure_region: Configure MPU region at index 0x2

    [00:00:35.633,087] <dbg> mpu: region_allocate_and_init: Program MPU region at index 0x2

    [00:00:35.641,510] <dbg> mpu: region_init: [2] 0x200015c0 0x150b000a

Related