Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

QSPI data read/write inconsistent with the sdk (nrf5_sdk_15.3.0) example ../peripheral/qspi slightly modified

I slightly modified the qspi example code to try something that I'd eventually like to implement as part of my application. But when I try to interleave reads and writes then I get inconsistent data.

I made sure that my read write addresses are 4byte aligned, so that should not be a problem. Also another thing I noticed is that if I write the whole array m1 in one nrf_drv_qspi_write() call, and then read it into m2 in one nrf_drv_qspi_read() call - then the data is consistent. Only when I interleave read and write calls of smaller chunks, I see an issue.

Here is the code to illustrate what I'm doing.

typedef struct {
    uint8_t buffer[6];
    uint32_t value;
} my_struct;

my_struct m1[19], m2[19];

int main(void)
{
    uint32_t i;
    uint32_t err_code;

    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO(""
                 "QSPI write and read example using 32bit addressing mode");

    srand(0);
    for (i = 0; i < QSPI_TEST_DATA_SIZE; ++i)
    {
        m_buffer_tx[i] = (uint8_t)rand();
    }

    nrfx_qspi_config_t config = {
        .xip_offset  = NRFX_QSPI_CONFIG_XIP_OFFSET,
        .pins = {
            .sck_pin     = QSPI_PIN_SCK,
            .csn_pin     = QSPI_PIN_CSN,
            .io0_pin     = QSPI_PIN_IO0,
            .io1_pin     = QSPI_PIN_IO1,
            .io2_pin     = QSPI_PIN_IO2,
            .io3_pin     = QSPI_PIN_IO3,
        },
        .irq_priority   = 6,
        .prot_if = {
            .readoc     = NRF_QSPI_READOC_FASTREAD,
            .writeoc    = NRF_QSPI_WRITEOC_PP,
            .addrmode   = NRF_QSPI_ADDRMODE_32BIT,
            .dpmconfig  = false,
        },
        .phy_if = {
            .sck_freq   = NRF_QSPI_FREQ_32MDIV2,
            .sck_delay  = 1,
            .spi_mode   = NRF_QSPI_MODE_0,
            .dpmen      = false
        },
    };

    err_code = nrf_drv_qspi_init(&config, qspi_handler, NULL);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_INFO("QSPI example started.");

    configure_memory();

    m_finished = false;
    err_code = nrf_drv_qspi_erase(QSPI_ERASE_LEN_LEN_All, 0);
    APP_ERROR_CHECK(err_code);
    WAIT_FOR_PERIPH();
    NRF_LOG_INFO("Process of erasing first block start");

    int count = 0;
    for(int i = 0; i <19; i++) {
        m1[i].buffer[0] = count+1;
        m1[i].buffer[1] = count+2;
        m1[i].buffer[2] = count+3;
        m1[i].buffer[3] = count+4;
        m1[i].buffer[4] = count+3;
        m1[i].buffer[5] = count+4;
        m1[i].value = count+1234;
        count++;
    }

    err_code = nrf_drv_qspi_write(&m1, 10*sizeof(my_struct),  0);
    APP_ERROR_CHECK(err_code);
    WAIT_FOR_PERIPH();
    err_code = nrf_drv_qspi_write(&m1[10], 9*sizeof(my_struct),  20*sizeof(my_struct));
    APP_ERROR_CHECK(err_code);
    WAIT_FOR_PERIPH();
    err_code = nrf_drv_qspi_read(&m2, 10*sizeof(my_struct),  0);
    APP_ERROR_CHECK(err_code);
    WAIT_FOR_PERIPH();
    err_code = nrf_drv_qspi_read(&m2[10], 9*sizeof(my_struct),  20*sizeof(my_struct));
    APP_ERROR_CHECK(err_code);
    WAIT_FOR_PERIPH();
    NRF_LOG_INFO("Compare...");
    NRF_LOG_INFO("Struct size %u", sizeof(my_struct));
    for(int i = 0; i < 19; i++) {
        if (memcmp(&m1[i], &m2[i], sizeof(my_struct)) == 0)
        {
            NRF_LOG_INFO("Data consistent at index %u", i);
        }
        else
        {
            NRF_LOG_INFO("Data inconsistent at index %u", i);
            NRF_LOG_INFO("WRITE -> %u %u %u %u %u %u", m1[i].buffer[0], m1[i].buffer[1], m1[i].buffer[2], m1[i].buffer[3], m1[i].buffer[4], m1[i].value);
            NRF_LOG_INFO("READ -> %u %u %u %u %u %u", m2[i].buffer[0], m2[i].buffer[1], m2[i].buffer[2], m2[i].buffer[3], m2[i].buffer[4], m2[i].value);
        }
    }

    nrf_drv_qspi_uninit();

    for (;;)
    {
    }
}

And when this is the output for the code:

<info> app: QSPI write and read example using 32bit addressing mode
<info> app: QSPI example started.
<info> app: Process of erasing first block start
<info> app: Compare...
<info> app: Struct size 12
<info> app: Data inconsistent at index 0
<info> app: WRITE -> 1 2 3 4 3 1234
<info> app: READ -> 0 0 1 0 0 1024
<info> app: Data inconsistent at index 1
<info> app: WRITE -> 2 3 4 5 4 1235
<info> app: READ -> 0 1 0 0 0 1024
<info> app: Data inconsistent at index 2
<info> app: WRITE -> 3 4 5 6 5 1236
<info> app: READ -> 1 0 1 0 0 1024
<info> app: Data inconsistent at index 3
<info> app: WRITE -> 4 5 6 7 6 1237
<info> app: READ -> 0 1 2 0 0 0
<info> app: Data inconsistent at index 4
<info> app: WRITE -> 5 6 7 8 7 1238
<info> app: READ -> 1 2 3 0 0 0
<info> app: Data inconsistent at index 5
<info> app: WRITE -> 6 7 8 9 8 1239
<info> app: READ -> 4 3 0 0 0 0
<info> app: Data inconsistent at index 6
<info> app: WRITE -> 7 8 9 10 9 1240
<info> app: READ -> 5 0 1 0 0 0
<info> app: Data inconsistent at index 7
<info> app: WRITE -> 8 9 10 11 10 1241
<info> app: READ -> 0 1 2 0 0 1024
<info> app: Data consistent at index 8
<info> app: Data consistent at index 9
<info> app: Data inconsistent at index 10
<info> app: WRITE -> 11 12 13 14 13 1244
<info> app: READ -> 0 0 1 0 0 1024
<info> app: Data inconsistent at index 11
<info> app: WRITE -> 12 13 14 15 14 1245
<info> app: READ -> 0 1 0 0 0 1024
<info> app: Data inconsistent at index 12
<info> app: WRITE -> 13 14 15 16 15 1246
<info> app: READ -> 1 0 1 0 0 1024
<info> app: Data inconsistent at index 13
<info> app: WRITE -> 14 15 16 17 16 1247
<info> app: READ -> 0 1 2 0 0 0
<info> app: Data inconsistent at index 14
<info> app: WRITE -> 15 16 17 18 17 1248
<info> app: READ -> 1 2 3 0 0 0
<info> app: Data inconsistent at index 15
<info> app: WRITE -> 16 17 18 19 18 1249
<info> app: READ -> 4 3 0 0 0 0
<info> app: Data inconsistent at index 16
<info> app: WRITE -> 17 18 19 20 19 1250
<info> app: READ -> 5 0 1 0 0 0
<info> app: Data inconsistent at index 17
<info> app: WRITE -> 18 19 20 21 20 1251
<info> app: READ -> 0 1 2 0 0 1024
<info> app: Data inconsistent at index 18
<info> app: WRITE -> 19 20 21 22 21 1252
<info> app: READ -> 9 10 11 12 11 1242

Please let me know if I'm doing something horribly wrong or if this is a known issue with a workaround.

  • If you happen to be writing to a hardware device such as a flash memory then it is probable that a minimum write size must be performed, say 256 or 2048 bytes or whatever the block size for that device. Interrupting a write by sending a smaller number of bytes then issuing a read command can mess up the flash memory pointers. Some (larger devices) use cache memory, but that has to be controlled. The net effect is data gets overwritten such that '1's eventually become '0's

  • The adafruit feather nrf52840 I'm using comes with the GD25Q16C flash. And the block size is 256 bytes. 

    To try out your recommendation I tried interleaving reads and writes for block size, and I see the same results.

    Here is the link to the datasheet http://www.elm-tech.com/en/products/spi-flash-memory/gd25q16/gd25q16.pdf

  • I think your issue may be slightly more esoteric, though I don't have time to look closely. Consider this code taken from the listing above, where one might incorrectly expect the size would be (6+4)x19:

    typedef struct {
        uint8_t buffer[6];
        uint32_t value;
    } my_struct;
    
    my_struct m1[19], m2[19];
    STATIC_ASSERT(sizeof(m1) == 12*19, "my_struct size issue");

    Yet as this test passes the size is actually 12x19 bytes, not 10x19. To get 10x19 either pack the struct or (maybe)re-order the definition:

    typedef struct {
        uint8_t buffer[6];
        uint32_t value;
    } __attribute__((packed)) my_struct;
    
    my_struct m1[19], m2[19];
    STATIC_ASSERT(sizeof(m1) == 10*19, "my_struct size issue");

    For SES the attribute "__attribute__((packed))" is required, other compilers use different syntax.

  • Correct me if I'm wrong here - I was under the impression that my writes/reads have to be at 4 byte aligned addresses.

    So the reason why I have the structure the way I do - is because its 12 bytes - so 4 byte aligned addresses starting from 0.

    Also, I think you're confusing the number of array elements with the size of each element. That "10" in the code is for 10 elements of the array, not saying that the array size of 10 Slight smile

    [I was basically trying to write parts of the array using different write calls, to mimic interleaved read and writes]

Related