SPIM3 is not working properly

Hello all,

I am using the nrf52840 MCU and NCS v2.6.2 for my application development. Here I am using SPIM3.
I am using a peripheral which have an internal FIFO. From that peripheral, I receive the interrupt when the FIFO is full. I received the interrupt every 160ms and read 360 bytes of data. It uses a fixed register read/write cycle every interrupt for the FIFO read. This process is successful over the longtime. After some random point in time SPI driver sent the wrong value sequence, and due to that, my peripheral internal configuration changed, and it stopped working as per expectations.

  • A successful send sequence of 4 bytes is 0xFF,0xFF,0xFF,0xFF.

  • Found wrong sequence of 4 bytes is 0x00,0xFF,0xFF,0xFF. After this sequence peripheral goes into failure.

           

If I swap the SPIM2 and SPIM3. The issue is not reproduced, and the peripheral is working fine.

I found the errata document(section 3.29) from nrf web. In that mention, like the tx pointer corruption issue, sometimes, when the CPU accesses the same memory. That causes this issue. I am researching the same, and I found CONFIG_NRF52_ANOMALY_198_WORKAROUND, CONFIG_NRFX_SPIM3 as a part of the solution. This config is already turned on, still I am still facing the same issue.

Can anyone help me with the SPIM3 issue?

Thanks,
Dinkar

Parents
  • Hi Dinkar,

    You also need to make sure that the same RAM AHB is not used for SPIM Tx buffer and application data. The simplest way to do that is probably as shown in this post.

    (Alternatively, unless you need high SPI frequency or have use dall the other serial periperal instances, you could consider using another SPIM instance that do not have this issue, as you have allready tested).

    Einar

  • Hello Einar,

    Thanks for the quick revert.

    I checked the post that you suggested. But seems it is not clear what changes I need to make for the working SPIM3 to work properly. Do I need to make use of the global buffer for SPI read or write? Can you please add more here?  If you give some example code with those changes, that will help a lot.

    Dinkar

  • Let me translate that for your: If you needed SPIM >8MHz, redesign with a newer NRF chip generation.

    The problem is catastrophic, the fix requires a fairly complete understanding how to put buffers into specific RAM locations - which Gnu LD does not like to do at all.

    There cannot be a generic fix because it matters how the SPI data is used later, and because it needs to reserve quite a bit of RAM.

  • Hello,

    As mentioned in the ticket, I made 2 different arrays of 8KB each for TX and RX in the .noinit section. But still, it does not solve my issue.
    Here is the sample file of my sensor driver implementation for SPI read and write.

    
    #include <string.h>
    #include <zephyr/logging/log.h>
    
    LOG_MODULE_REGISTER(MY_DRV_SPI, LOG_LEVEL_INF);
    
    volatile uint8_t tx_buf[8192] __attribute__((section(".noinit"), aligned(0x2000), used));
    volatile uint8_t rx_buf[8192] __attribute__((section(".noinit"), aligned(0x2000), used));
    
    
    struct spi_buf tx_bufs[] = {
        {.buf = tx_buf, .len = 4}
    };
    
    struct spi_buf rx_bufs[] = {
        {.buf = rx_buf, .len = 4}
    };
    
    struct spi_buf_set tx = {
        .buffers = tx_bufs,
        .count = ARRAY_SIZE(tx_bufs)
    };
    
    struct spi_buf_set rx = {
        .buffers = rx_bufs,
        .count = ARRAY_SIZE(rx_bufs)
    };
    
    
    
    int my_spi_write(const struct device *dev, const uint8_t reg_addr, const uint32_t reg_data)
    {
        int16_t ret = 0;
        int  ret_spi = 0;
        
        if ((dev == NULL)) {
          ret = -1;
        } else {
    
            const struct my_config *cfg = dev->config;
    
            tx_buf[0] = reg_addr,
            tx_buf[1] = (uint8_t)((reg_data >> 16) & 0xFF);
            tx_buf[2] = (uint8_t)((reg_data >> 8) & 0xFF);
            tx_buf[3] = (uint8_t)(reg_data & 0xFF);
    
            ret_spi =  spi_transceive_dt(&cfg->bus, &tx, &rx);
    
            if (ret_spi != 0) {
                LOG_ERR("spi ERROR read %d",ret_spi);
                ret = -2;
            }
        }
        LOG_DBG("spi ERROR write %d",ret);
        return ret;
    }
    
    int my_spi_read(const struct device *dev, const uint8_t reg_addr, uint8_t *data)
    {
        int16_t ret = 0;
    
        int  ret_spi = 0;
    
        if ((dev == NULL) || (data == NULL)) {
                ret = -1;
        } else {
    
            const struct my_config *cfg = dev->config;
    
            tx_buf[0] = reg_addr,
            tx_buf[1] = 0xFF;   //write dummy value
            tx_buf[2] = 0xFF;   //write dummy value
            tx_buf[3] = 0xFF;   //write dummy value
    
            ret_spi =  spi_transceive_dt(&cfg->bus, &tx, &rx);
            
            if( ret_spi != 0){
                LOG_ERR("spi ERROR read %d",ret_spi);
                ret = -2;//-EIO;
            }
            *data = 0;
            *(data + 0) = rx_buf[1];
            *(data + 1) = rx_buf[2];
            *(data + 2) = rx_buf[3];
    
        }
        LOG_DBG("spi ERROR read %d",ret_spi);
        return ret;
    }
    
    

    Can you please check my attached file? Is my understanding correct that I added in the attached file?

    Following is the .map file screenshot for tx and tx buffer used for SPIM with its address.

    Thanks,
    Dinkar

Reply
  • Hello,

    As mentioned in the ticket, I made 2 different arrays of 8KB each for TX and RX in the .noinit section. But still, it does not solve my issue.
    Here is the sample file of my sensor driver implementation for SPI read and write.

    
    #include <string.h>
    #include <zephyr/logging/log.h>
    
    LOG_MODULE_REGISTER(MY_DRV_SPI, LOG_LEVEL_INF);
    
    volatile uint8_t tx_buf[8192] __attribute__((section(".noinit"), aligned(0x2000), used));
    volatile uint8_t rx_buf[8192] __attribute__((section(".noinit"), aligned(0x2000), used));
    
    
    struct spi_buf tx_bufs[] = {
        {.buf = tx_buf, .len = 4}
    };
    
    struct spi_buf rx_bufs[] = {
        {.buf = rx_buf, .len = 4}
    };
    
    struct spi_buf_set tx = {
        .buffers = tx_bufs,
        .count = ARRAY_SIZE(tx_bufs)
    };
    
    struct spi_buf_set rx = {
        .buffers = rx_bufs,
        .count = ARRAY_SIZE(rx_bufs)
    };
    
    
    
    int my_spi_write(const struct device *dev, const uint8_t reg_addr, const uint32_t reg_data)
    {
        int16_t ret = 0;
        int  ret_spi = 0;
        
        if ((dev == NULL)) {
          ret = -1;
        } else {
    
            const struct my_config *cfg = dev->config;
    
            tx_buf[0] = reg_addr,
            tx_buf[1] = (uint8_t)((reg_data >> 16) & 0xFF);
            tx_buf[2] = (uint8_t)((reg_data >> 8) & 0xFF);
            tx_buf[3] = (uint8_t)(reg_data & 0xFF);
    
            ret_spi =  spi_transceive_dt(&cfg->bus, &tx, &rx);
    
            if (ret_spi != 0) {
                LOG_ERR("spi ERROR read %d",ret_spi);
                ret = -2;
            }
        }
        LOG_DBG("spi ERROR write %d",ret);
        return ret;
    }
    
    int my_spi_read(const struct device *dev, const uint8_t reg_addr, uint8_t *data)
    {
        int16_t ret = 0;
    
        int  ret_spi = 0;
    
        if ((dev == NULL) || (data == NULL)) {
                ret = -1;
        } else {
    
            const struct my_config *cfg = dev->config;
    
            tx_buf[0] = reg_addr,
            tx_buf[1] = 0xFF;   //write dummy value
            tx_buf[2] = 0xFF;   //write dummy value
            tx_buf[3] = 0xFF;   //write dummy value
    
            ret_spi =  spi_transceive_dt(&cfg->bus, &tx, &rx);
            
            if( ret_spi != 0){
                LOG_ERR("spi ERROR read %d",ret_spi);
                ret = -2;//-EIO;
            }
            *data = 0;
            *(data + 0) = rx_buf[1];
            *(data + 1) = rx_buf[2];
            *(data + 2) = rx_buf[3];
    
        }
        LOG_DBG("spi ERROR read %d",ret_spi);
        return ret;
    }
    
    

    Can you please check my attached file? Is my understanding correct that I added in the attached file?

    Following is the .map file screenshot for tx and tx buffer used for SPIM with its address.

    Thanks,
    Dinkar

Children
No Data
Related