nRF5 SDK is not maintained anymore
More Info: Consider nRF Connect SDK for new designs
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);
    }
}



Parents
  • Hello,

    What is your SPI master? Can you please try to set the Chip Select pin low a little bit before you start the clock from the central and see whether the behavior changes?

    BR,

    Edvin

  • Hi Edvin,

    I'm using SPIM3 (I built my SPI master code off the nrfx_spim example from SDK 16 - I made it a while ago)! I tried adding a delay between the CS going low and the start of the clock by adding nrf_delay_us(10); right before spim_xfer() but that wouldn't change the timing between CS going low and the first SCLK. Do you have another way of changing the timing?

    nrfx_err_t nrfx_spim_xfer(nrfx_spim_t     const * const p_instance,
                              nrfx_spim_xfer_desc_t const * p_xfer_desc,
                              uint32_t                      flags)
    {
        spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
        NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
        NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
        NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
        NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
                                         p_xfer_desc->rx_length,
                                         p_xfer_desc->tx_length));
    
        nrfx_err_t err_code = NRFX_SUCCESS;
    
        if (p_cb->transfer_in_progress)
        {
            err_code = NRFX_ERROR_BUSY;
            NRFX_LOG_WARNING("Function: %s, error code: %s.",
                             __func__,
                             NRFX_LOG_ERROR_STRING_GET(err_code));
            return err_code;
        }
        else
        {
            if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER |
                                            NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)))
            {
                p_cb->transfer_in_progress = true;
            }
        }
    
        p_cb->evt.xfer_desc = *p_xfer_desc;
    
        if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
        {
    #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
            if (!p_cb->use_hw_ss)
    #endif
            {
                if (p_cb->ss_active_high)
                {
                    nrf_gpio_pin_set(p_cb->ss_pin);
                }
                else
                {
                    nrf_gpio_pin_clear(p_cb->ss_pin);
                }
            }
        }
        
        nrf_delay_us(10);
        return spim_xfer(p_instance->p_reg, p_cb,  p_xfer_desc, flags);
    }

  • 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):

    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.

    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

Reply Children
No Data
Related