This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

issues with implementing SPI slave on nrf9160DK

using nrf connect sdk 1.4.0 and nrf9160 DK

build: nrf9160dk_nrf9160ns

SES version: V5.10d

Windows 10 Pro 64bit

1. Please note I used https_client project to implement spi slave(but have removed all the https code.. ignore the cert file)

2. Used some details from tickets this and this.. Please trust me when I say i have searched the devzone and documents as much as I could

proj.conf looks like this

# SPI
CONFIG_SPI=y
## for slave only
CONFIG_SPI_SLAVE=y
CONFIG_SPI_3_OP_MODES=3

#commented these out as per some devzone discussions
#CONFIG_SPI_3=y
#CONFIG_SPI_NRFX=y
#CONFIG_SPI_3_NRF_SPIS=y #this gives an error while opening a project if uncommented


CONFIG_RESET_ON_FATAL_ERROR=n

overlay file

&spi3 {
compatible = "nordic,nrf-spis";
status = "okay";
mosi-pin = <10>;
miso-pin = <11>;
sck-pin = <12>;
csn-pin = <13>;
def-char = <0xde>;
};

main.c

/*
 * Copyright (c) 2020 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
 */

#include <string.h>
#include <zephyr.h>
#include <stdlib.h>
#include <drivers/spi.h>
#include <nrfx.h>
#include <nrfx_uarte.h>
#include "nrfx_spis.h"

#define PIN_SCK 10
#define PIN_MOSI 11
#define PIN_MISO 12
#define PIN_CSN 13
#define SPIS_NR 3

nrfx_spis_t spis_t = NRFX_SPIS_INSTANCE(SPIS_NR);
nrfx_spis_config_t spis_config_t = NRFX_SPIS_DEFAULT_CONFIG(PIN_SCK,PIN_MOSI,PIN_MISO,PIN_CSN);

uint8_t rx_buffer[2] = {0x0};
uint8_t tx_buffer[2] = {0xa5};

void spis_event_handler_t(nrfx_spis_evt_t const *p_event, void *p_context){
    printk("handler\n");
    int err;
    switch(p_event->evt_type){
        case NRFX_SPIS_XFER_DONE:
                printk("received %x, %x\n",rx_buffer[0], rx_buffer[1]);
            err = nrfx_spis_buffers_set(&spis_t, tx_buffer, sizeof(tx_buffer), rx_buffer, sizeof(rx_buffer));
            if(err != NRFX_SUCCESS){
                printk("Error with setting.\n");
            }
            break;
        case NRFX_SPIS_BUFFERS_SET_DONE:
            printk("buffers set\n");
            break;
        case NRFX_SPIS_EVT_TYPE_MAX:
        
            break;
        default:
            ;
    }
}

static void manual_isr_setup()
{
    //IRQ_DIRECT_CONNECT(SPIM3_SPIS3_TWIM3_TWIS3_UARTE3_IRQn, 0, nrfx_spis_3_irq_handler, 0);
    //irq_enable(SPIM3_SPIS3_TWIM3_TWIS3_UARTE3_IRQn);
    IRQ_DIRECT_CONNECT(UARTE3_SPIM3_SPIS3_TWIM3_TWIS3_IRQn, 0, nrfx_spis_3_irq_handler, 0);
    irq_enable(UARTE3_SPIM3_SPIS3_TWIM3_TWIS3_IRQn);    
}

void init_spis(){
    int err;

    //change mode
    spis_config_t.mode = NRF_SPIS_MODE_3;
    err = nrfx_spis_init(&spis_t,&spis_config_t,spis_event_handler_t,NULL);
    if(err != NRFX_SUCCESS){
        printk("nrfx_spis_init - Error. %x\n",err);
    } else {
        printk("SPIS started.\n");
    }
}


void spi_slave_test(void) {
    int err;
    init_spis();
    manual_isr_setup();

    err = nrfx_spis_buffers_set(&spis_t, tx_buffer, sizeof(tx_buffer), rx_buffer, sizeof(rx_buffer));
    if(err != NRFX_SUCCESS){
        printk("nrfx_spis_buffers_set - Error. %x\n", err);
    }
}


void main(void)
{
	printk("SPIS sample started \n\r");
        spi_slave_test();
        while (1) {
          //printk("alive \n");
          k_sleep(Z_TIMEOUT_TICKS(50000));
        }
}


Notes:

I have closed the solution and opened after changing proj.conf. I am using SPIS3

Issue is that nrfx_spis_init fails with error 0xbad0005.. and the reason for that is this line in nrfx_spi.c fails

    if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)

I am just confused to see that p_cb->state is set to NRFX_DRV_STATE for some reason
m_cb[p_instance->drv_inst_idx] has valid data... that array has ONLY ONE element (given only spi3 is available)  and drv_inst_idx=0;

It is clear that I a missing some configuration.. I was told to make some spis related changes using the SES ->project->configure nrf sdk project.. I tried to enable spis2 instance and spis3 driver and that made no difference.. I am sure you have some document in there somewhere in your ocean of documents explaining this but unfortunately I couldn't find any details

3. The SPI master worked without any issue.. Not that it helps but just FYI

4. attached the entire project in zip file

4331.https_client.zip

Parents
  • I am not sure if I replying  to the subthread or to the main question (my intention is to add info to my last reply but no longer sure.. looks like the format has changed recently)..

    I think I am getting multiple calls to the handler (way more than two that are expected per call.. one for buffer set and one for transaction complete) probably due to loose contact. I will get confirmation once I have that inspected in my lab tomrrow.. but any feedback from you is appreciated (based on the code submitted)..

    More importantly, my slave tries to send data back which is never recieved by master..  I do see master sending data and slave recieves it (even with the issue of multiple calls to the handler),.. I checked and confirm that my tx_buffer on slave side has the correct data .. but I don;t see it recieved by master (the rx bffer of thge master is empty/hasjunk).. is there anything else I need to do in my master/slave code in addition to what I have already done ? tx/rx buffers on both sides are of size 21 and i checked it 

  • Hi,

     

    Have you tried scoping the pins, using a oscilloscope or logic analyzer, to see how the communication looks?

    It almost sounds like one of the signals isn't properly connected or read.

     

    Kind regards,

    Håkon

  • that's what I will be doing today to check connectivity and make sure basic spi setup is ok hardware wise.. In the meantime, can you please confirm what's the corerct way to define Chip select pin when I use 1.4.0? 

    I tried csn-pin which seemed to compile on one laptop but wouldn't on another (same ncs being used) Something like cs-gpios = <&gpio0 7 0>; seemed to help ..

    I would need advice on defining chip select pins correctly for nrf5340 and nrf9160 while using ncs 1.4.0

  • Hi,

     

    My apologies for not spotting this earlier. Yes, your csn pin isn't configured. 

    Are you able to get the csn gpio to be set active/inactive?

    You can add CSN pin handling directly in the application:

    #define CSN_PIN_OF_CHOICE 30 // Change this to your liking
    
    struct device *dev;
    dev = device_get_binding("GPIO_0");
    gpio_pin_configure(dev, CSN_PIN_OF_CHOICE, GPIO_OUTPUT);
    gpio_pin_set(dev, CSN_PIN_OF_CHOICE, 1);
    
    ...
    gpio_pin_set(dev, CSN_PIN_OF_CHOICE, 0);
    spi_transceive(..);
    gpio_pin_set(dev, CSN_PIN_OF_CHOICE, 1);

     

    Or you can populate the .cs member of spi_cfg like I have here, which lets the spi-function take care of the csn pin:

    /*
    * Copyright (c) 2012-2014 Wind River Systems, Inc.
    *
    * SPDX-License-Identifier: Apache-2.0
    */
    
    #include <zephyr.h>
    #include <sys/printk.h>
    #include <drivers/spi.h>
    /* You can choose any other unused GPIO here as gpio_pin */
    struct spi_cs_control spi_cs = {
    	.gpio_pin = 14,
    	.gpio_dt_flags = GPIO_ACTIVE_LOW,
    	.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 = &spi_cs,
    };
    
    struct device * spi_dev;
    
    static void spi_init(void)
    {
    	const char* const spiName = "SPI_1";
    	
    	spi_cs.gpio_dev = device_get_binding("GPIO_0");
    	if (spi_cs.gpio_dev == NULL) {
    	    printk("Could not get GPIO_0 device\n");
    	}
    	spi_dev = device_get_binding(spiName);
    
    	if (spi_dev == NULL) {
    		printk("Could not get %s device\n", spiName);
    		return;
    	}
    }
    
    void spi_test_send(void)
    {
    	int err;
    	static uint8_t tx_buffer[2];
    	static uint8_t rx_buffer[2];
    
    	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
    	};
    
    	err = spi_transceive(spi_dev, &spi_cfg, &tx, &rx);
    	if (err) {
    		printk("SPI error: %d\n", err);
    	} else {
    		/* Connect MISO to MOSI for loopback */
    		printk("TX sent: %x\n", tx_buffer[0]);
    		printk("RX recv: %x\n", rx_buffer[0]);
    		tx_buffer[0]++;
    	}
    }
    
    void main(void)
    {
    	printk("SPIM Example\n");
    	spi_init();
    
    	while (1) {
    		spi_test_send();
    		k_sleep(K_MSEC(1000));
    	}
    }

    Do note the initialization of spi_cs.gpio_dev = device_get_binding("GPIO_0"); in spi_init().

    Which should give you a signal that looks like this:

    1. clock, 2. MOSI, 3. MISO (nothing connected here) 4. CSN

     

    The CSN pin is hard-coded to GPIO P0.14 here, but you can freely change this to any unused GPIO. On the nRF9160-DK, this specific pin is used for UART, so the next available one is P0.16, I believe.

     

    Kind regards,

    Håkon

  • Or you can populate the .cs member of spi_cfg like I have here, which lets the spi-function take care of the csn pin:
    that's the route I will prefer to take.. will report the status asap.. I had some trouble getting my logic analyzer going and hence no waveforms yet.

    Can you also please confirm if i repeat the same for the slave side too ?

    if we have to use your method for getting CS pin to work -  what's the value of entering CS details in the overlay structure ? and it looks like cthe way to enter s pin details for nrf5340 and nrf9160 are different

    for nrf5340
    &spi1 {
    compatible = "nordic,nrf-spim";
    status = "okay";
    mosi-pin = <4>;
    miso-pin = <10>; //<5>;
    sck-pin = <6>;
    cs-gpios = <&gpio0 7 0>;
    //csn-pin = <7>; DOES NOT WORK as project can not be opened
    };

    and for nrf9160DK
    &spi3 {
    compatible = "nordic,nrf-spis";
    status = "okay";
    mosi-pin = <10>;
    miso-pin = <11>;
    sck-pin = <12>;
    //cs-gpios = <&gpio0 13 0>; //DOES NOT WORK as project can not be opened
    csn-pin = <13>;
    def-char = <0xde>;
    };

    in order for me to use your method, do I have to remove chip select pin  entries from overlay structure ?

  • Hi,

     

    If you use my former section, the cs-gpios pin number is hard-coded in the SPIM source code side (see spi_cs variable).

    What you can do to derive it from DTS is this:

    struct spi_cs_control spi_cs = {
    	.gpio_pin = DT_GPIO_PIN_BY_IDX(DT_NODELABEL(spi1), cs_gpios, 0),
    	.gpio_dt_flags = GPIO_ACTIVE_LOW,
    	.delay = 0,
    };

    Then it shall follow what you set in the "cs-gpios" in your overlay file.

     

    The reason why cs-gpios is a bit hard to setup here is because the NRF_SPIMx peripheral does not have a CSN pin. It is expected from the hardware side that you use a generic GPIO as your CSN pin, and if you have several slaves on the bus; you're also using more CSN pins.

     

    For the slave side, NRF_SPIS, this has the CSN pin in the hardware peripheral, and you should set that using the DTS property "csn-pin".

     

    Summarized:

    compatible = "nordic,nrf-spim" -> use cs-gpios

    compatible = "nordic,nrf-spis" -> use csn-pin

     

    Kind regards,

    Håkon

Reply
  • Hi,

     

    If you use my former section, the cs-gpios pin number is hard-coded in the SPIM source code side (see spi_cs variable).

    What you can do to derive it from DTS is this:

    struct spi_cs_control spi_cs = {
    	.gpio_pin = DT_GPIO_PIN_BY_IDX(DT_NODELABEL(spi1), cs_gpios, 0),
    	.gpio_dt_flags = GPIO_ACTIVE_LOW,
    	.delay = 0,
    };

    Then it shall follow what you set in the "cs-gpios" in your overlay file.

     

    The reason why cs-gpios is a bit hard to setup here is because the NRF_SPIMx peripheral does not have a CSN pin. It is expected from the hardware side that you use a generic GPIO as your CSN pin, and if you have several slaves on the bus; you're also using more CSN pins.

     

    For the slave side, NRF_SPIS, this has the CSN pin in the hardware peripheral, and you should set that using the DTS property "csn-pin".

     

    Summarized:

    compatible = "nordic,nrf-spim" -> use cs-gpios

    compatible = "nordic,nrf-spis" -> use csn-pin

     

    Kind regards,

    Håkon

Children
No Data
Related