Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

nRF5 SDK 17 SPIS example is not capturing all transfers from Master

I am running the subject SPIS example software on a nRF52DK, pca10040, board, as the SPI Slave. The Master is capturing CAN bus messages, 8 bytes per message, and sending them to the slave, along with 2 to 4 additional bytes of information, for output on the serial monitor. The Slave correctly captures and outputs, to the serial monitor, the received transfers from the master for all single frame and first frame messages but only periodically outputs consecutive frame messages. Although the Master makes no use of the messages from the slave, the slave sends out the default "Nordic" message for each completed transfer from the master. A logic analyzer output (snapshot below) shows that all the master messages are being sent to the slave on the MOSI line (second row), but the slave messages on the MISO line (forth row) only appear for the messages that get sent to the serial monitor. The consecutive frames that don't have an associated a slave message do not get sent to the serial monitor. I suspect that this is a problem with the Semaphore Acquire and Release programming, but I can't find the associated code in the example problem. I currently have the master clock rate set as low as it will go at 158 kHz. The attached logic analyzer snapshot shows a first frame message, at the far left, followed by two consecutive frames. The MISO messages are the yellow columns at the bottom. It can be seen that only every eighth consecutive frame has an associated slave message, which are the ones that get sent to the serial monitor. The chip select events are shown at the top and it can be seen that a start and end signal is present for every byte sent by the master. My question is, where can I find the code, in the SPIS example, that detects the start and end events and what parameters should I look at that might be causing this behavior?

Parents
  • Hi,

    By serial monitor you mean logging over the RTT backend or UART backend?

    the received transfers from the master for all single frame and first frame messages but only periodically outputs consecutive frame messages

    This issue sounds like a processing issue. Can you share your code that shows how you process the data and sends it on the serial monitor and reply with the "Nordic" data back to the master? My understanding is that you have modified the SPIS sample? 

    My question is, where can I find the code, in the SPIS example, that detects the start and end events and what parameters should I look at that might be causing this behavior?

    I'm not sure this is related to the hardware level implementaion of the driver, but to answer your question: You can find the implementation of the SPIS driver here

    regards

    Jared

  • UART backend. I've been looking at the nrfx_spis.c file but don't find where it detects the change in state of the CS pin that determines the start and end of Master TX events and the corresponding Acquire and Release of the semaphore. Also, I've been unable to get the existing NRFX_LOG_DEBUG statements in that file to compile and work. I created a copy of the nrfx_spis.c file, added it to my project and excluded the original from the build so that I could make modifications, but without debug logging I can't tell what's going on. One thing I forgot to mention in my original post is that the Slave sends the default character 0xFF, indicating that the Slave was unable to acquire the semaphore, for those messages that don't get output.

    .

    #include "sdk_config.h"
    #include "nrf_drv_spis.h"
    #include "nrf_gpio.h"
    #include "boards.h"
    #include "app_error.h"
    #include <string.h>
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #define SPIS_INSTANCE 1 /**< SPIS instance index. */
    static const nrf_drv_spis_t spis = NRF_DRV_SPIS_INSTANCE(SPIS_INSTANCE);/**< SPIS instance. */
    
    #define TEST_STRING "Nordic..........."
    static uint8_t       m_tx_buf[] = TEST_STRING;           /**< TX buffer. */
    //static uint8_t       m_rx_buf[sizeof(TEST_STRING) + 1];    /**< RX buffer. */
    static uint8_t       m_rx_buf[200];    /**< 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. */
    
    
    /**
     * @brief SPIS user event handler.
     *
     * @param event
     */
    void spis_event_handler(nrf_drv_spis_event_t event)
    {
        if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
        {
            spis_xfer_done = true;
    //        m_tx_buf[0] = count; // does this automatically get sent?
            //NRF_LOG_INFO(" Transfer completed. Received: %s",(uint32_t)m_rx_buf);
            NRF_LOG_INFO(" Transfer completed by Slave. Received:");
            //NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
            NRF_LOG_RAW_HEXDUMP_INFO(m_rx_buf, 16); // Function creates a new line after 8 bytes
        }
    }
    
    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;
    
        bsp_board_init(BSP_INIT_LEDS);
    
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        NRF_LOG_INFO("SPIS example");
    
        nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
        spis_config.csn_pin               = APP_SPIS_CS_PIN;
        spis_config.miso_pin              = APP_SPIS_MISO_PIN;
        spis_config.mosi_pin              = APP_SPIS_MOSI_PIN;
        spis_config.sck_pin               = APP_SPIS_SCK_PIN;
    
        APP_ERROR_CHECK(nrf_drv_spis_init(&spis, &spis_config, spis_event_handler));
    
        while (1)
        {
            memset(m_rx_buf, 0, m_length);
            spis_xfer_done = false;
    
            APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, m_tx_buf, m_length, m_rx_buf, m_length));
    
            while (!spis_xfer_done)
            {
    
                __WFE(); // Wait For Event
            }
            NRF_LOG_FLUSH();
    
            bsp_board_led_invert(BSP_BOARD_LED_0);
        }
    }

  • I finally realized that the delay between each Slave reception was caused by the time it took to send the logging messages to the UART serial monitor. During this delay, several consecutive frames were being missed. I eliminated all logging to the serial monitor and copied the rx buffer into the tx buffer after each reception. I then received Slave messages for every Master message sent to the Slave. Each Slave message was an echo of the previous Master message and allowed verification that the Master messages were being received. I'll have to create a holding buffer for the incoming Master messages and use that for input to the serial monitor because I don't think the UART baud rates can keep up.

Reply
  • I finally realized that the delay between each Slave reception was caused by the time it took to send the logging messages to the UART serial monitor. During this delay, several consecutive frames were being missed. I eliminated all logging to the serial monitor and copied the rx buffer into the tx buffer after each reception. I then received Slave messages for every Master message sent to the Slave. Each Slave message was an echo of the previous Master message and allowed verification that the Master messages were being received. I'll have to create a holding buffer for the incoming Master messages and use that for input to the serial monitor because I don't think the UART baud rates can keep up.

Children
  • Now that I've resolved the original issue with the SPIS example, I want to make SPI0 the slave and setup SPI1 to interact with an SD card peripheral in accord with the "fatfs" example problem. I'm confused as to what settings in the sdk_config file need to be changed to have SPI0 running as a Slave and SPI1 running as a fatfs peripheral. In the fatfs example the config file has NRFX_SPIM_ENABLED 1 (enabled) and NRFX_SPIM0,1 &2_ENABLED 0 (disabled). But it also has NRFX_SPI_ENABLED 1 and NRFX_SPI0,1&2_ENABLED 0. Do I leave NRFX_SPIM_ENABLED 1 and NRFX_SPI_ENABLED 1 and change both NRFX_SPIM1_ENABLED 1 and NRFX_SPI1_ENABLED 1 to make SPI1 the fatfs device? And similarily, what changes are needed in the SPIS config file to make SPI0 the slave?

  • Hi,

    I see that you were able to resolve your previous problem, good job!

    Stroker347 said:
    Now that I've resolved the original issue with the SPIS example, I want to make SPI0 the slave and setup SPI1 to interact with an SD card peripheral in accord with the "fatfs" example problem. I'm confused as to what settings in the sdk_config file need to be changed to have SPI0 running as a Slave and SPI1 running as a fatfs peripheral.

    Just to be clear, it's only the SPIS peripheral that supports SPI slave. The SPI and SPIM both implements SPI master but the difference is that the latter use EasyDMA.

    Stroker347 said:
    I'm confused as to what settings in the sdk_config file need to be changed to have SPI0 running as a Slave and SPI1 running as a fatfs peripheral. In the fatfs example the config file has NRFX_SPIM_ENABLED 1 (enabled) and NRFX_SPIM0,1 &2_ENABLED 0 (disabled). But it also has NRFX_SPI_ENABLED 1 and NRFX_SPI0,1&2_ENABLED 0. Do I leave NRFX_SPIM_ENABLED 1 and NRFX_SPI_ENABLED 1 and change both NRFX_SPIM1_ENABLED 1 and NRFX_SPI1_ENABLED 1 to make SPI1 the fatfs device?

    The fatfs example use SPIM instance 0, while the SPIS sample use SPIS1. To merge the examples you should start with diff the two sdk_config.h files. You can use VS Code for that. You'll then see what you need to add for the all of the correct configs to be enabled. 

    In short to enable SPIS1 in the config you need to add:

    NRFX_SPIS_ENABLED 1
    SPIS_ENABLED 1
    SPIS1_ENABLED 1
    You also need to add the other SPIS related configs such as IRQ priority and DEFAULT_DEF. Again, if you diff the files then it would be clear what you need to add,
     
    regards
    Jared 
  • Jared, I finally got the fatfs example code merged into the spis example code and all the errors eliminated. I created a merged sdk_config file. but it appears that I don't have everything needed for the fatfs portion to work. Is SPI0 the peripheral that the default SPIM runs on? The SPIS portion does work and I assume it should be running on SPI1 with SPIS1_ENABLED 1. I downloaded the VS Code that you recommended, but I don't see any options to do a file comparison.

  • Jarad, I compared my combined sdk_config.h file with the one from the fatfs example, using WinMerge, and everything in the fatfs file is included in the combined file. The only difference is that fatfs has NRF_LOG_DEFERRED 0 whereas the combined file has NRF_LOG_DEFERRED 1. This difference prevents the messages, from the fatfs portion of the combined project, from displaying and appearing not to work. When I changed it to 0, the fatfs portion displays the SD card info and shows that it is working.

  • Hi Randy,

    Stroker347 said:
    difference prevents the messages, from the fatfs portion of the combined project, from displaying and appearing not to work. When I changed it to 0, the fatfs portion displays the SD card info and shows that it is working.

    The logger module can be used in two different modes:

    1. Deferred: Which means that the logger will place the log message in a queue and it will be processed and outputted on the serial line, when the NRF_LOG_PROCESS() is called . This is usually done in the main loop in many of our examples.
    2. In-place: Which means that the logger will process the log message exactly when NRF_LOG_INFO() is called and will immediately output it on the serial line. This is not preffered if you have real time critical requirements.

    See the documentation on the logger module for more on the different modes,

    regards

    Jared 

Related