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? 

  • espian said:
    As soon as I modify the proj.conf file so that I can see the printk output, I start having issues.

    I am not sure why such is happening. 

    can you send your minimal project, just enough to show what you are facing. Please strip it down to minimal version just to show the functionality and error.

  • My last set of comments were with the GitHub master slave code with the only change being 1) changing several of the printk's to printf's and 2) the above changes to the proj.conf file.  

  • espian said:
    I get a toggling LED, as expected from the code.  However, I can not see any of the printk messages.

    I am using the same sample for 52840DK and I can see the messages on console (printing both messages on the same line).

    espian said:
    1) changing several of the printk's to printf's

    What do you mean by this? printk() is zephyr kernel function, and is supposed to be used with ncs/zephyr for console messages. 

    It is also important that you connect to the correct serial port.

  • I'm quite sure that the sample code is running properly.  However, I'm not going to see the UART output.

    I'm using a Fanstel eval kit (which is almost a carbon copy of the NRF52840DK), however the Fanstel module that is mounted on my board (BT840X) does not expose UART0 because it uses that on-module to control a PA.  This was very non-obvious and only mentioned in one line in their data sheet.

    I'm going to go back up in this thread to the actual issue/question as my CB is never being called.  I'll post more code related to that soon. 

  • 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:

Reply
  • 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:

Children
  • 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

  • Since there are a number of people subscribed to this ticket, I will document this issue and what fixed it.  Then wrap up with some other comments.

    The first two things that caused me issues were that the SPI samples I was finding were using the GPIOS definitions for the CS line.  In SPIS, that is not allowed.  Tracing back the -EINVAL error (and properly enabling the logged message) was the trick to figuring out this first step.  (You can see the result of this and the 'fix' above).

    Once past this hurdle, I had mentioned multiple times that there seemed to be something that I was fundamentally missing on understanding what within SPIS actually terminated an SPI message.  There is so much abstraction and so much that is 'automagically' done within the NRFSDK and Zephyr code bases, it is very difficult to know sometimes when you need to sit back and let the code-base do something for you and when you're required to handle something for yourself.  To be clear, I'm not an embedded newbie.  I have used SPI in designs starting in the early 1990's, so am pretty well versed in the hardware and typical software to support it.  Again, my issues here were largely around the things that were abstracted away and controlled by the software libraries and how they worked.

    I finally found in the Zephyr discord channel a mention that when using SPIS the driver expects to use the hardware CS line embedded in the SPI transceiver hardware and a follow-up mention of "don't forget to set your pinctrl's".

    In the overlay, I added 

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

    };
    };
    And almost immediately my code started working.  Simply the CS line was not 'connected' to the code and as such the end of message was never being triggered because it relies on the hardware CSN line to detect that state.  I'm still not sure where in the codebase this is setup/controlled.  I'm quite sure I would struggle to find it partially due to the lack of comments in the code.
    The frustrating thing(s) to me about all of this (semi-rant follows):
    1) I had expressed where I thought my short-coming was in my understanding (not know what or how an SPI message was terminated) and yet support never seemed to completely read through my messages and information to answer those specific questions.
    2) I feel like I went to great lengths to document as much as I could, what I perceived the issues to be and yet, the postings were never read in detail and responded to in a manner that took that information fully into account.
    3) There were multiple times that I posted follow-ups and yet the support responses continued to not respond to the most recent postings, but rather something further up the message thread (again not reading everything provided).
    4) So much of this codebase is horribly documented.  For instance, the spi_nrfx_spis.c file has zero comments (besides the copyright header) throughout 320 lines of code.  The comments sprinkled throughout other code files are equally bland--often just describing what an if statement is testing for (well, I can plainly see that) but rarely going into the 'why' .
    5) The sample code often has almost no comments within it, as well.  It seems like by taking the time to document some of this better, people would be much more likely to diagnose their own issues without bothering Nordic support. (Zero comments in the master-slave sample code or overlay)
    6) For both Nordic and Zephyr, if what you are wanting to do is largely in the mainstream, there are often samples that can be leveraged to allow you to develop fairly quickly, often without fully understanding everything that is going on under the hood.  If anything that you're working on is outside of the most common use-cases, it can be super difficult to almost reverse engineer what's going on to utilize the libraries properly, partially do to lack of proper documentation/examples/comments and partially due to the level of abstraction going on.  
    7) The Zephyr docs can be downright horrible.  Click on a library documentation and it's largely a list of function prototypes--this is not support documentation, I can read the code myself.
    8). I know many people that are much more accomplished and competent software/firmware developers than myself.  EVERYONE of them that have used the Nordic/Zephyr code bases had talked about how absolutely painful it is to learn these platforms.  Often times representing months of efforts to go up the learning curve to be somewhat proficient.  This simply shouldn't be so painful.
    Good luck!
Related