This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

SPIS data corrupted (it gets worse at faster speeds)

Hi,

I'm using two dev kits to test out some SPI firmware before I deploy it to our custom boards and I've been running into a weird issue where my SPIS sends out corrupted data. The data corruption exists at an SCK of 1MHz and it gets worse when I go up to 4MHz and even worse at 8MHz.

An example of the data corruption is as follows:

I fill up the SPIS's m_tx_buf with: 0x41410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000202

but when a spi transaction is triggered, the SPI peripheral shifts out the following over the MISO line:

0xff41410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002

 

I've probed the MISO line with an oscope and here's a screenshot of the first couple bytes. In it you can see that the spis actually 'adds' ff to the beginning. 

sometimes the data is corrupted differently and I will receive something like:

0xffa0a08000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 which has 9 bits of 1 at the front (right?).

I've tried printing out these bytes in debug mode (using NRF_LOG_INFO()) and those report the correct bytes back regardless of when I query the buffer. My spis code is built off the example in SDK 17.1 and it's really really quite similar - is there some limitation for SPI packets >= 65 bytes? Here is a copy of my code as reference:

#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 const uint8_t m_length = sizeof(m_tx_buf);        //< Transfer length. > 
*/

static uint8_t       m_tx_buf[] = {65,65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                                   0,0,0,2,2};


static uint8_t       m_rx_buf[sizeof(m_tx_buf) + 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. */

/**
 * @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;
        //NRF_LOG_INFO(" Transfer completed. Received: %s",(uint32_t)m_rx_buf);
    }
}

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();
        }

        NRF_LOG_FLUSH();

        bsp_board_led_invert(BSP_BOARD_LED_0);
    }
}



  • No worries! I tried this out but kept hitting hard faults whenever the debugger would hit the nrf_drv_gpiote_init function. I was having a little trouble decoding what the error code meant - how would you recommend looking up the specific error meaning?

    Regardless, however, is this recommended for all SPIS use cases? Since I'm seeing this with the base example code maybe something else is wrong.

    Thank you so much for your help, Edvin!

    Ryan

  • Hello Ryan,

    ryerye120 said:
    Regardless, however, is this recommended for all SPIS use cases? Since I'm seeing this with the base example code maybe something else is wrong.

    You said that you are using the default nrfx_spim example. What example do you mean exactly?

    I tested these two, and connected the DKs using some PCB wires, and this is my outcome:

    SDK17.1.0\examples\peripheral\spi

    SDK17.1.0\examplws\peripheral\spis

    The master (spi example) is to the left, and the spis example is to the right. I don't see any issues using these unmodified examples, at least. Did you test them? I see that in your original question, your message is larger, and not from the examples. Is there a way for me to reproduce this using two nrf52840 DKs without any additional hardware? If so, can you zip the two project folders (please specify what SDK version you are using), and I can give it a go.

    Best regards,

    Edvin

  • Hi Edvin,

    I too got things to work fine with the examples you mentioned in your post. I'm building off of a different example though (and I think the behaviors are actually different). I'm using the following 2 examples:

    SDK17.1.0/examples/peripherals/nrfx_spim

    SDK17.1.0/examples/peripherals/spis

    I've modified them slightly (to disable dcx and send larger packets) so you can use the base examples or my versions (attached below):

    0407.nrfx_spim.zip

    2262.spis.zip

    Thank you so so much - I can't tell you how much I appreciate it.

    Kindest regards,

    Ryan

  • Hello Ryan,

    I see. I actually wasn't aware there was an example called nrfx_spim. I guess I just used the spi example (which also uses the nrfx driver), and didn't notice that it was introduced (whenever that was).

    I haven't looked into the differences between nrfx_spim and spi, but both of them uses nrfx_spim_init(), so I guess they are using the same driver, but a bit differently.

    I tested the unmodified nrfx_spim with the spis example, and I saw, like you saw, that the first byte was corrupted. I tried adding a delay before pulling the CS/SS pin low in the nrfx_spim's main.c, and then I got the first byte to show correctly again.

    Can you try something like this:

    // main.c:
    
    int main(void)
    {
        ...
        	nrf_gpio_cfg_output(NRFX_SPIM_SS_PIN);
    		nrf_gpio_pin_set(NRFX_SPIM_SS_PIN);
        ...
            spi_config.ss_pin         = NRFX_SPIM_PIN_NOT_USED;//NRFX_SPIM_SS_PIN;
        ...
        
        while (1)
        {
            nrf_gpio_pin_clear(NRFX_SPIM_SS_PIN);
            // Reset rx buffer and transfer done flag
            memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
    
            APP_ERROR_CHECK(nrfx_spim_xfer_dcx(&spi, &xfer_desc, 0, 15));
    
            while (!spi_xfer_done)
            {
                __WFE();
            }
    				
    				nrf_gpio_pin_set(NRFX_SPIM_SS_PIN);
    
            NRF_LOG_FLUSH();
    
            bsp_board_led_invert(BSP_BOARD_LED_0);
            nrf_delay_ms(1000);
        }
    }

    I attached the entire main.c file as well, for reference. Please note that I changed the pin numbers to match the spis example's pin numbers. You don't need to change these.

    /**
     * Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    #include "nrfx_spim.h"
    #include "app_util_platform.h"
    #include "nrf_gpio.h"
    #include "nrf_delay.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 NRFX_SPIM_SCK_PIN  26//3
    #define NRFX_SPIM_MOSI_PIN 29//4
    #define NRFX_SPIM_MISO_PIN 30//28
    #define NRFX_SPIM_SS_PIN   31//29
    #define NRFX_SPIM_DCX_PIN  30
    
    #define SPI_INSTANCE  3                                           /**< SPI instance index. */
    static const nrfx_spim_t spi = NRFX_SPIM_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
    
    static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    
    #define TEST_STRING "Nordic123456789012345678901234567890"
    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. */
    
    void spim_event_handler(nrfx_spim_evt_t const * p_event,
                           void *                  p_context)
    {
        spi_xfer_done = true;
        NRF_LOG_INFO("Transfer completed.");
        if (m_rx_buf[0] != 0)
        {
            NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
        }
    }
    
    int main(void)
    {
        bsp_board_init(BSP_INIT_LEDS);
    
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    		nrf_gpio_cfg_output(NRFX_SPIM_SS_PIN);
    		nrf_gpio_pin_set(NRFX_SPIM_SS_PIN);
    
        nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(m_tx_buf, m_length, m_rx_buf, m_length);
    
        nrfx_spim_config_t spi_config = NRFX_SPIM_DEFAULT_CONFIG;
        spi_config.frequency      = NRF_SPIM_FREQ_1M;
        spi_config.ss_pin         = NRFX_SPIM_PIN_NOT_USED;//NRFX_SPIM_SS_PIN;
        spi_config.miso_pin       = NRFX_SPIM_MISO_PIN;
        spi_config.mosi_pin       = NRFX_SPIM_MOSI_PIN;
        spi_config.sck_pin        = NRFX_SPIM_SCK_PIN;
        spi_config.dcx_pin        = NRFX_SPIM_PIN_NOT_USED; //NRFX_SPIM_DCX_PIN;
        spi_config.use_hw_ss      = true;
        spi_config.ss_active_high = false;
        APP_ERROR_CHECK(nrfx_spim_init(&spi, &spi_config, spim_event_handler, NULL));
    
        NRF_LOG_INFO("NRFX SPIM example started.");
    
        while (1)
        {
    				nrf_gpio_pin_clear(NRFX_SPIM_SS_PIN);
            // Reset rx buffer and transfer done flag
            memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
    
            APP_ERROR_CHECK(nrfx_spim_xfer_dcx(&spi, &xfer_desc, 0, 15));
    
            while (!spi_xfer_done)
            {
                __WFE();
            }
    				
    				nrf_gpio_pin_set(NRFX_SPIM_SS_PIN);
    
            NRF_LOG_FLUSH();
    
            bsp_board_led_invert(BSP_BOARD_LED_0);
            nrf_delay_ms(1000);
        }
    }
    

    Best regards,

    Edvin

  • Hi Edvin,

    That did the trick! I must have messed up the init code when I tried toggling the ss earlier - removing my changes and adding yours worked like a charm!!

    Thank you so much for your help, I really really appreciate it.

    Kindest regards,

    Ryan

Related