nRF5340 SPI slave doesnt seem to receive

Hi,

I have ported my already working nRF52840 SPI slave code to a nRF5340, but it doesnt seem to receive any data. I have verified the CS, SCK and MOSI signals, but no MISO from nRF5340.

.
.
static const struct spi_config spis_cfg = {
	.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_OP_MODE_SLAVE | SPI_MODE_CPOL | SPI_MODE_CPHA,
	.slave = 1,
};
.
.
static void spi_slave_init(void)
{
	spis_dev = DEVICE_DT_GET(MY_SPI_SLAVE);
	
	if (!device_is_ready(spis_dev)) {
		printk("SPI slave device not ready!\n");
	}
	else
		LOG_INF ("SPI slave ready");
}
.
.
static int spi_slave_check_for_message(void)
{
	int signaled, result;

	k_poll_signal_check(&spi_slave_done_sig, &signaled, &result);
	
	if (signaled != 0){
		slave_tx_buffer [0] = 0x01;	// init slave tx buffer
		return 0;
	}
	
	else return -1;
}
.
.
static int spi_slave_wait_msg(uint8_t txlen, uint8_t rxlen)
{
	const struct spi_buf s_tx_buf = {
		.buf = slave_tx_buffer,
		.len = txlen 
	};
	const struct spi_buf_set s_tx = {
		.buffers = &s_tx_buf,
		.count = 1
	};

	struct spi_buf s_rx_buf = {
		.buf = slave_rx_buffer,
		.len = rxlen
	};
	const struct spi_buf_set s_rx = {
		.buffers = &s_rx_buf,
		.count = 1
	};

	// Reset signal - this flag the next msg check 
	k_poll_signal_reset(&spi_slave_done_sig);
	
	// Start transaction
	int error = spi_transceive_signal(spis_dev, &spis_cfg, &s_tx, &s_rx, &spi_slave_done_sig);	// once a cycle is complete, the 'spi_slave_done_sig' will get signelled

	if(error != 0){
		LOG_ERR("SPI slave transceive error: %i\n", error);
		return error;
	}
	
	return 0;
}
.
.
static void spis_handler (struct k_work *item) {

static uint8_t txlen, rxlen;
int8_t i=0, loopCnt=0;
static uint8_t startRec=0;
uint16_t hostFWRev;

	if (spi_slave_check_for_message() == 0){
		
		LOG_INF ("---- Received SPI msg -----");

		switch (slave_rx_buffer [0]) {
			case 'V':	// Feature 7
				hostFWRev = EncVerString ();
				LOG_INF ("Host radio FW : %04x", hostFWRev);
				
				slave_tx_buffer[0] = 'A';
				slave_tx_buffer[1] = (uint8_t)(hostFWRev >> 8);
				slave_tx_buffer[2] = (uint8_t)(hostFWRev & 0x00ff);
				txlen = 3;
				rxlen = 1;
				break;
			

			case 'A':	// ACK/NAK request. This is the second byte send by host after the command. Only thing we need is to send the ACK/NAK of last command
				//LOG_INF ("ACK/NAK command");
				break;

			default :
				LOG_ERR ("default %x, %c", slave_rx_buffer [0], slave_rx_buffer [0]);
				slave_tx_buffer[0] = 'K';
				txlen = 1;
				rxlen = 1;
		}
		// Prepare the next SPI slave transaction -  this means the ACK/NAK doesnt get send immediately, but in next rx cycle. 
		// This means we have to either send same command twice or have a ACK/NAK request command, which is send after each command
		spi_slave_wait_msg(txlen, rxlen);	
	}

	k_msleep (1);
	k_work_submit (item);
}
.
.
void main(void)
{
.
.
    k_poll_signal_reset(&spi_slave_done_sig);
	spi_slave_init ();
	spi_slave_wait_msg (1, 1);	// this starts the k_poll event to wait for next spi rx

	k_work_init(&spis_work, spis_handler);		// spis handling is done in system queue to avoid issues with spi async transfers
	k_work_submit (&spis_work);
	.
	.
}

I get 'SPI slave ready' as a result of invoking spi_slave_init () function.

I can see the spis_handler () is invoked repeatedly, but 'spi_slave_check_for_message() == 0' seems to fail all the time.

I use nordic SDK 2.9.0.

I saw in the nRF5340 user guide that there is a hardware semaphore for accessing spi buffers, which was not available in nRF52840. Is there anything I need to implement in the application level to do that?

I have tried all I can think of and need some help urgently.

Thanks,

Kaushalya

Parents
  • Hello,

    I suggest to look at the driver test examples for spi, which also include spis:
    \zephyr\tests\drivers\spi\spi_controller_peripheral\src\main.c

    By default I can see there is no overlay for nRF5340, but I would expect you can rename nrf52840dk_nrf52840.overlay to nrf5340dk_nrf5340_cpuapp.overlay, and update the pins used for spi and spis, and then it should work.

    Kenneth

  • Hi,

    We need some help urgently as we are stuck at this point.

    After refering bit more on NORA B1 user guide, I come across this.

    "SPIM4: For the fastest SPI mode, the special purpose GPIO pins are enabled using the Peripheral setting of the MCUSEL pin of the PIN_CNF register. When activated, the SPIM PSEL settings are ignored, and the dedicated pins are used. The GPIO must use the extra high drive E0E1 configuration in the DRIVE field of the PIN_CNF GPIO register."

    I tried setting the MCUSEL to peripheral as follows.

    	#define SPIM4_SCK  NRF_GPIO_PIN_MAP(0,8)
    	#define SPIM4_MOSI NRF_GPIO_PIN_MAP(0,9)
    	#define SPIM4_MISO NRF_GPIO_PIN_MAP(0,10)
    
    	nrf_gpio_cfg(SPIM4_SCK, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
    	nrf_gpio_cfg(SPIM4_MOSI, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
    	nrf_gpio_cfg(SPIM4_MISO, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
    
    	nrf_gpio_pin_control_select(SPIM4_SCK, NRF_GPIO_PIN_SEL_PERIPHERAL);
    	nrf_gpio_pin_control_select(SPIM4_MOSI, NRF_GPIO_PIN_SEL_PERIPHERAL);
    	nrf_gpio_pin_control_select(SPIM4_MISO, NRF_GPIO_PIN_SEL_PERIPHERAL);

    But when I debug and check register at GPIO0-Pin 8, I see it is still set as APPMCU.

    So I have following questions.

    1. Can P0.8, P0.9 and P0.10 only be used as SPI4 in master mode, not as a slave?

    2. If SPI4 on the above pins can be used as a slave, how to do it?

    Cheers,

    Kaushalya

  • Thanks Kenneth,

    I figured out that SPI4 has only master mode, but what I cant figure out is why cant I assign P0.08, P0.09, P0.10 and P0.11 to any other SPI interface like SPI2. I guess if we dont use them as NFC or tracedata, they could be assigned to SPI function. Please confirm.

    Even after I assigned NFC as GPIO, my SPI comms were not working. I was running out of options (and time) so wired the SPI to different set of pins (P0.13, P0.14, P0.15 and P1.01) and immediately it was working!! So there is something with P0.8-P0.11 that prevented them from being used as SPI slave.

    Also one other observation is when I debugged it and check the MCUSEL bits of corresponding pins, I saw them as assigned to APPCPU. Even my new pin assignment is same. I thing for the SPI to work, they should be connected to 'Peripheral', not 'APPCPU'. Can you please confirm?

    Cheers,

    Kaushaya

  • Hi,

    Think I found the problem. I compiled hello world for nRF5340 and looked at the zephyr.dts file in the build folder. I can find 4 pins are assigned by default to the network core, like this:

    	gpio_fwd: nrf-gpio-forwarder {
    		compatible = "nordic,nrf-gpio-forwarder";
    		status = "okay";
    		uart {
    			gpios = < &gpio1 0x1 0x0 >, < &gpio1 0x0 0x0 >, < &gpio0 0xb 0x0 >, < &gpio0 0xa 0x0 >;
    		};
    	};
    Amongst those are for instance P0.10 and P0.11, I assume that is the cause of your problems. To answer your questions:
    kaushalyasat said:
    I thing for the SPI to work, they should be connected to 'Peripheral', not 'APPCPU'. Can you please confirm?

    Looks like you are right, for SPIM4 and 32Mbps you need to configure MCUSEL to "Peripheral" yes.

    Kenneth

  • Hi Kenneth,

    Thanks again. I have also noticed this but when I check from the GUI devicetree view, the nrf-gpio-forwarder was not visible. But as you point out in the zephyr.dts I can see the relevant pins being used.

    1. Why wouldn't the devicetree compiler complains when the same pins is assigned to two interfaces?

    2. I have given up using P0.8 - P0.11 and picked up other four GPIOs as SPI2S and I selected them as following.

    nCS - P0.13

    SCLK - P0.14 

    MOSI - P1.1

    MISO - P0.15

    Then I could see the spi handler gets invoked but the received character was always 0x00. Then I changed MOSI to P0.18 and all was good. 

    Now after seeing your comment, I see P1.1 is also used in nrf-gpio-forwarder and remapped all my spi2 related pins from nrf-gpio-forwarder. I verified it in zephyr.dts, but P1.1 doesnt seem to work!! Any ideas?

    3.

    for SPIM4 and 32Mbps you need to configure MCUSEL to "Peripheral"

    This means if I map P0.8, P0.9 etc as SPI2S, it doesn't need to be mapped as a peripheral? I thought SPI2S is also acts as a peripheral. Even after SPI2S is working fully, the CNF register indicates that each pin belongs to APPCPU, not Peripheral.

    Cheers,

    Kaushalya

  • kaushalyasat said:
    1. Why wouldn't the devicetree compiler complains when the same pins is assigned to two interfaces?

    In an ideal world it would, but it doesn't.

    kaushalyasat said:
    I verified it in zephyr.dts, but P1.1 doesnt seem to work!! Any ideas?

    If you are using the DK maybe check out:
    https://docs.nordicsemi.com/bundle/ug_nrf5340_dk/page/UG/dk/dyn_hw_flow_control.html#d10e117 

    kaushalyasat said:
    This means if I map P0.8, P0.9 etc as SPI2S, it doesn't need to be mapped as a peripheral? I

    Correct.

    Kenneth

  • Hi Kenneth,

    If you are using the DK maybe check out:

    I am not using the DK. I am using UBlox NORA B126 in my board. There is no other connection to P1.1. When I debug into SPI2S init, I can see the MOSI is assigned to P1.1 and is connected to the peripheral. But when I send a byte from the master, all I receive is 0. 

    This is my zephyr.dts after the build with P1.1 set as MOSI.

    06736.zephyr.dts

    I couldn't find gpio 1,1 being used in any other place. May be you can correct me if I am wrong.

    Can you see any clue as to why the P1.1 is not functioning as SPI2S MOSI?

    Cheers,

    Kaushalya

  • Reply
    • Hi Kenneth,

      If you are using the DK maybe check out:

      I am not using the DK. I am using UBlox NORA B126 in my board. There is no other connection to P1.1. When I debug into SPI2S init, I can see the MOSI is assigned to P1.1 and is connected to the peripheral. But when I send a byte from the master, all I receive is 0. 

      This is my zephyr.dts after the build with P1.1 set as MOSI.

      06736.zephyr.dts

      I couldn't find gpio 1,1 being used in any other place. May be you can correct me if I am wrong.

      Can you see any clue as to why the P1.1 is not functioning as SPI2S MOSI?

      Cheers,

      Kaushalya

    Children
    • Hi,

      It's a bit hard to decode the files, but looks like uart1 might be using port1 pin1. I would start looking there. Does the pin work as a normal gpio (if you don't use it for spis)?

      Kenneth

    • Hi Kenneth, 

      Yes uart1 was using it, but I had disabled uart1 in my overlay file. However I tried to reassign different pins to uart1 as in this overlay file.

      8306.zmhostradio.overlay

      Also I assigned gpio1, 1 as led3 under leds node and tried to drive it.

      I tried like 

      	ret = dk_leds_init();
      	if (ret) {
      		LOG_ERR("Could not initialize leds, err code: %d", ret);
      		goto end;
      	}
      	dk_set_led_on(DK_LED4);
      	dk_set_led_off(DK_LED4);

      and also

      #define LED3_NODE DT_ALIAS(led3)
      	int ret;
      	
      	static const struct gpio_dt_spec gpio11 = GPIO_DT_SPEC_GET(LED3_NODE, gpios);
      
      	if (!gpio_is_ready_dt(&gpio11)) {
      		return 0;
      	}
      
      	ret = gpio_pin_configure_dt(&gpio11, GPIO_OUTPUT_ACTIVE);
      	if (ret < 0) {
      		return 0;
      	}
      
      	ret = gpio_pin_toggle_dt(&gpio11);

      No matter what, gpio1, 1 doesn't seem like its configured as an output. 

      I then tried debugging into it (both nrf connect debugger and ozone debugger) and check DIR register of P1_NS peripheral, and it shoes pin 1 as an input!!

      Can this pin be assigned to something in network processor? How to verify it?

      I checked the zephyr.dts and it seems my led3 mapping is correct. 

      I am totally puzzled. What is going on here??

      Thanks,

      Kaushalya

    • Hello,

      I notice you are mentioning P1_NS, does this mean you are working with non-secure and have TF-M? If yes, try to set CONFIG_TFM_LOG_LEVEL_SILENCE=y, ref:
      https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/security/tfm.html#building 

      Kenneth

    • Hi Kenneth,

      Yes we use NS+TF-M. When I add ' CONFIG_TFM_LOG_LEVEL_SILENCE=y' to my prj.conf, I get 

      d:/Projects/nrf/zm2hostradiofw/prj.conf:89: warning: ignoring malformed line ' CONFIG_TFM_LOG_LEVEL_SILENCE=y'

      It seems I have not built TF-M with my application. So I added CONFIG_BUILD_WITH_TFM=y and then the project got built, but then the app doesnt seem to run. (I have disabled UART1 from my overlay as explained in https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/security/tfm.html#building

      Apparently TF-M uses UART1. I have tried assigning different pins to the UART1 in my overlay as follows.

          uart1_default: uart1_default {
              group1 {
                  psels = <NRF_PSEL(UART_TX, 1, 5)>,
                      <NRF_PSEL(UART_RTS, 0, 11)>;
              };
              group2 {
                  psels = <NRF_PSEL(UART_RX, 1, 0)>,
                      <NRF_PSEL(UART_CTS, 0, 10)>;
                  bias-pull-up;
              };
          };

          uart1_sleep: uart1_sleep {
              group1 {
                  psels = <NRF_PSEL(UART_TX, 1, 5)>,
                      <NRF_PSEL(UART_RX, 1, 0)>,
                      <NRF_PSEL(UART_RTS, 0, 11)>,
                      <NRF_PSEL(UART_CTS, 0, 10)>;
                  low-power-enable;
              };
          };
      But still P0.01 doesnt seem to work for SPI slave.
      My time limit for this project has almost finished. So any help is much appreciated.

      Cheers,

      Kaushalya

    • Can you at least make sure it works without TF-M?

      The overlay you refer to , what is the name of that file?

      Kenneth

    Related