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

How to Use SPI Interface in a Zephyr sample example?

Hi,

I am trying to understand how to enable SPI in blinky application provided by Nordic. My intention is to transfer data between the two Nordic development kit running blinky application over SPI. I have enabled SPI with the following details in the prj.conf file.

CONFIG_GPIO=y
CONFIG_SPI=y

CONFIG_SPI_NRFX=y
CONFIG_SPI_SLAVE=y
CONFIG_SPI_ASYNC=y
CONFIG_SPI_1=y

I see that DEVICE_INIT() in main.c and  DEVICE_AND_API_INIT(1) in spi_nrfx_spi.c do all the initialization based on the board dts file. And, I could use spi_read(), spi_write(), spi_transceive() as appropriate to send/receive data thru SPI interface.

Is my understanding correct? 

Please add if I am missing anything.

Thanks,

Ram

Parents
  • Hi Hakon,

    Thanks for your reply!

    I have decided to use nrfx SPI driver at this time instead of Zephyr SPI port, and I have created two simple projects (using minimal) to run on two separate nRF52840dk: one for the master and the other for the slave. I start the slave and then start the master. The interrupt handler is called on the slave but the rx_amount is showing 0. I also noticed that interrupt handler on master is called but nrfx_spim_xfer() returns an error code. The prj.conf files for the two projects and the main.c are attached here. 

    Slave:

    CONFIG_SPI=n
    CONFIG_NRFX_SPIS=y
    CONFIG_NRFX_SPIS1=y

    CONFIG_MAIN_STACK_SIZE=4096

    ---------------------------------------------------

    Master:

    CONFIG_SPI=n
    CONFIG_NRFX_SPIM=y
    CONFIG_NRFX_SPIM1=y
    CONFIG_MAIN_STACK_SIZE=4096

    //main on SPI master
    #include "nrfx_spim.h"
    #include "nrfx_gpiote.h"
    #include "drivers/nrfx_errors.h"
    #include <sys/printk.h>
    #include <string.h>
    
    #define SPI_INSTANCE  1
    static const nrfx_spim_t spim = NRFX_SPIM_INSTANCE(SPI_INSTANCE);
    
    #define APP_SPIM_CS_PIN     0x10
    
    #define APP_SPIM_SCK_PIN    0x1F
    #define APP_SPIM_MISO_PIN   0x28
    #define APP_SPIM_MOSI_PIN   0x1E
    
    #define NRFX_CUSTOM_ERROR_CODES 0 //used in nrfx_errors.h
    
    static nrfx_spim_config_t spim_config = NRFX_SPIM_DEFAULT_CONFIG(APP_SPIM_CS_PIN,   
                                         APP_SPIM_MISO_PIN,APP_SPIM_MOSI_PIN,APP_SPIM_SCK_PIN);
     
    #define TEST_STRING "1234567890"
    static uint8_t       m_tx_buf[] = TEST_STRING;
    static uint8_t       m_rx_buf[sizeof(TEST_STRING) + 1];
    static const uint8_t m_length = sizeof(m_tx_buf);
    
    static volatile bool spim_xfer_done; /**< Flag used to indicate that SPIM instance completed the transfer. */
    
    static void manual_isr_setup()
    {
        IRQ_DIRECT_CONNECT(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQn, 0, nrfx_spim_1_irq_handler, 0);
        irq_enable(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQn);
    }
     
    void spim_event_handler(nrfx_spim_evt_t const * p_event,
                           void * p_context)
    {
        if(p_event->type == NRFX_SPIM_EVENT_DONE)
        {
            spim_xfer_done = true;
            printk("Transfer completed.");
        }
    }
     
    void main(void)
    {
        printk("SPIM example");
        nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TX(m_tx_buf, 254);
     
        if (NRFX_SUCCESS != nrfx_spim_init(&spim, &spim_config, spim_event_handler, NULL))
        {
          printk("Init Failed");
          return;
        }
    
        manual_isr_setup();
     
    //   while (1)
    //    {
            // Reset rx buffer and transfer done flag
            memset(m_rx_buf, 0, m_length);
            spim_xfer_done = false;
     
            nrfx_err_t err_code = nrfx_spim_xfer(&spim, &xfer_desc, 0);
     
    	if (err_code == NRFX_ERROR_BUSY)
    	{
    		printk("SPI busy");
    	}
            
    	else
    	{
    		printk("Error code = %d",err_code);
    	}
            
     
            while (!spim_xfer_done)
            {
                __WFE();
            }
     
    //        nrfx_delay_ms(1000);
    //    }
    }
    
    //main on SPI slave
    #include "nrfx_spis.h"
    #include "nrfx_gpiote.h"
    #include <sys/printk.h>
    
    #include <string.h>
    #include <irq.h>
    
    #define SPIS_INSTANCE 1 /**< SPIS instance index. */
    static const nrfx_spis_t spis = NRFX_SPIS_INSTANCE(SPIS_INSTANCE);/**< SPIS instance. */
    
    #define APP_SPIS_CS_PIN     0x10
    
    #define APP_SPIS_SCK_PIN    0x1F
    #define APP_SPIS_MISO_PIN   0x28
    #define APP_SPIS_MOSI_PIN   0x1E
    
    static nrfx_spis_config_t spis_config = NRFX_SPIS_DEFAULT_CONFIG(APP_SPIS_CS_PIN,   
                                         APP_SPIS_MISO_PIN,APP_SPIS_MOSI_PIN,APP_SPIS_SCK_PIN);
    #define TEST_STRING "5678901234"
    static uint8_t       m_tx_buf[] = TEST_STRING;           /**< TX buffer. */
    static uint8_t       m_rx_buf[sizeof(TEST_STRING) + 1];    /**< RX buffer. */
    
    static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */
    
    
    static volatile bool spis_xfer_done; /**< Flag used to indicate that SPIS instance completed the transfer. */
    
    static void manual_isr_setup()
    {
        IRQ_DIRECT_CONNECT(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQn, 0, nrfx_spis_1_irq_handler, 0);
        irq_enable(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQn);
    }
    
    /**
     * @brief SPIS user event handler.
     *
     * @param event
     */
    void spis_event_handler(nrfx_spis_evt_t * event, 
                            void * p_context)
    {
        if (event->evt_type == NRFX_SPIS_XFER_DONE)
        {
          spis_xfer_done = true;
          printk("Transfer completed. Received: %d",event->rx_amount);
        }
    }
    
    int main(void)
    {
        // Enable the constant latency sub power mode to minimize the time it takes
        // for the SPIS peripheral to become active after the CSN line is asserted
        // (when the CPU is in sleep mode).
        NRF_POWER->TASKS_CONSTLAT = 1;
    
        printk("SPIS example");
    
        
        if (NRFX_SUCCESS != nrfx_spis_init(&spis, &spis_config, spis_event_handler, NULL))
        {
          printk("Init Failed");
          return 0;
        }
    
        manual_isr_setup();
    
        while (1)
        {
            memset(m_rx_buf, 0, m_length);
            spis_xfer_done = false;
    
            if (NRFX_SUCCESS != nrfx_spis_buffers_set(&spis, m_tx_buf, m_length, m_rx_buf, m_length))
            {
              printk("Receive Failed");
              return 0;
            }
    
            while (!spis_xfer_done)
            {
                __WFE();
            }
        }
    }
    

    *** Booting Zephyr OS build v2.4.0-ncs1-3-gfe00929d308d ***
    SPIM example Error ransfer completed.code = 195887104 (this is due to coding issue but this is NRFX_SUCCESS)

    *** Booting Zephyr OS build v2.4.0-ncs1-3-gfe00929d308d ***
    SPIS example Transfer completed. Received: 0                      It means slave is seeing the interrupt without any data.

    Could you please see the .config and main files and guide me what is missing for slave not reading the data? 

    Thanks,

    Ram

  • Hi Hakon,

    Thanks for your prompt reply!

    I have updated the pin ordering in the configuration on both sides. I have also changed the number of bytes to send.

    Is the setup for the event handler correct? I am ready to share my screen with you if you have a few minutes?

    Let me know. 

    Thanks

    Ram

Reply Children
  • Hi Ram,

     

    I slightly modified the samples, so that it sets up RX and TX transaction on the master side, and increments the first byte in the payload (cycles through ascii '0' to '9').

    I do not have two nrf52840dk's at my end at this point, so I'm using a nRF9160-DK as the master, but it should be possible to use nRF52/nRF53/nRF91 with no or little modifications. I tested both examples on a nRF52840 (ie: reversed the SPI roles)

    nRF52840 is the SPIS in my end with the below prints.

    Master should print like this when properly connected to the slave, and sends once per second (note: it prints in hex) 

    *** Booting Zephyr OS build v2.4.0-ncs2 ***
    SPIM example
    IRQ: 0
    Transfer completed
    Received: 35 36 37 38 39 30 31 32 33 34 0 0
    IRQ: 0
    Transfer completed
    Received: 35 36 37 38 39 30 31 32 33 34 0 0

     

    Slave should print this:

    *** Booting Zephyr OS build v2.4.0-ncs2 ***
    SPIS example
    ISR 0
    ISR 1
    bytes rx: 11
    7234567890ISR 0
    ISR 1
    bytes rx: 11
    8234567890ISR 0
    ISR 1
    bytes rx: 11
    9234567890ISR 0

    Here you should see that the first byte increments.

     

    The actual bus communication should look like this (here sampled with a logic analyzer from Saleae):

     

    Here are my projects: 

    nrfx_spi_master.zip

    nrfx_spi_slave.zip

     

    If you, after flashing and connecting SPIS -> SPIM, still do not receive or send data as expected, could you please use a logic analyzer to see if there's anything happening on the SPI pins?

      

    Kind regards,

    Håkon

Related