This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Writing to nvram

I would like help in understanding the limitations of the NVRAM. The documentation for the nRF52840 and the nRF52832 are different. This is what the nRF52840 reads:

Nvram write 52840 doc

Do I understand correctly that, for any word in a 4K block, it can only be written twice before the entire page must be erased?

The nRF52832 seems to have a different limitation:

nvram writing nRF52840

This is more complicated. Here the page is divided into 512 byte blocks and the limitations is 181 writes per block before page erase is needed. Here nothing is said about a 32 bit word write.

The reason I ask is that I am using Gazell pairing. It seems to me that, for part of the database in nvram, it partitions up its information into 4bit chunks, 8 to a 32 bit word. It shuffles bits and requires a byte to be written, I think for each pairing, which of course turns into a 32 bit word being written per byte demanded i.e. potentially 8 times. It would appear therefore that the nRF52840 is incompatible with the current version of Gazell, which, to say the least is worrying to me since I am sort-of committed to both. What is wrong with my understanding above?

  • Do I understand correctly that, for any word in a 4K block, it can only be written twice before the entire page must be erased?

     Yes, this is true for the 840. But more specifically the limitations is that you cannot write 0 to the same bit more than twice. In theory the flash allows 8 programs to the same address (but still the same bit cannot be programmed to ‘0’ more than twice). Can you point me to what file/line you are looking at for gazell pairing that does the writes? Thanks

  • Edit: OOPs, I failed to mention that this is from SDK 15.2 - I haven't migrated yet to revised versions. I think 16 is the same though.

    Hello Runar, Ah, not being able to attempt to write 0 more than twice as opposed to not being able to write a 32 bit word more than twice, puts an entirely different light on the limitation. Presumeably, if the bit written 0 the first time, contains a 1 in the next 7  writes, that will be OK?

    I did not check whether all the bits already zero are set to 1 on the subsequent writes. That will take a bit of figuring out. Meanwhile, you will find the code in components\proprietary_rf\gzll\nrf_gzp_device.c specifically:

    static void gzp_index_db_add(uint8_t val)
    {
        int16_t i;
        uint8_t temp_val;
        uint32_t  addr;
    
        // Search for unwritten loacation in index DB
        for (i = 0; i < GZP_INDEX_DB_SIZE; i++)
        {
            temp_val = *(uint8_t*)(GZP_INDEX_DB_ADR + i);
    
            // Lower nibble
            if (i != (GZP_INDEX_DB_SIZE - 1))
            {
                if ((temp_val & 0x0f) == 0x0f)
                {
                    temp_val = (temp_val & 0xf0) | val;
                    break;
                }
                // Upper nibble
                else if ((temp_val & 0xf0) == 0xf0)
                {
                    temp_val = (temp_val & 0x0f) | (val << 4);
                    break;
                }
            }
            else
            {
                temp_val = (GZP_PARAMS_DB_MAX_ENTRIES << 4) | val;
                break;
            }
        }
    
        // Write index DB
        addr = (GZP_INDEX_DB_ADR + i);
        nrf_nvmc_write_byte(addr, temp_val);
    }

    The "write byte" is in modules\nrfx\hal\nrf_nvmc.c and specifically is:

    void nrf_nvmc_write_byte(uint32_t address, uint8_t value)
    {
        uint32_t byte_shift = address & (uint32_t)0x03;
        uint32_t address32 = address & ~byte_shift; // Address to the word this byte is in.
        uint32_t value32 = (*(uint32_t*)address32 & ~((uint32_t)0xFF << (byte_shift << (uint32_t)3)));
        value32 = value32 + ((uint32_t)value << (byte_shift << 3));
    
        // Enable write.
        NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
        __ISB();
        __DSB();
    
        *(uint32_t*)address32 = value32;
        wait_for_flash_ready();
    
        NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
        __ISB();
        __DSB();
    }

    Had the specification been more specific, I would have checked the code carefully before troubling you with such details. I cannot afford the time today, but I will check carefully myself whether anything breaks the clarified restrictions you have given. It would be REALLY nice if you could persuade the specification writers to be more er, specific - your clarification makes a huge difference to the use of the nvram as a permanent data store.

    Many thanks for your response, I appreciate the support given by Nordic in such matters,

    Regards, Ray Foulkes

    PS, I was unable to preview the post prior to replying - it give an error. Apologies if it is messy.

  • RayFoulkes said:
    Presumeably, if the bit written 0 the first time, contains a 1 in the next 7  writes, that will be OK?

     Yes, that's my understanding as well. Did you find time to check the write routine? I am afraid I did not this week, sorry for the inconvenience. Regardless I will register this write routine (the gazell part) as an internal issue so the SDK team can take a look. I have a feeling this is something that was not considered when porting the library to the new chip/platform.

  • Sorry Runar, I have been overwhelmed this week. I will try to make some time over the weekend. Thanks for your attention.

    Ray

  • Hello again. Sorry that this has taken so long. I have now updated to version 17 of the sdk and analysed the code of nrf_nvmc.c and my initial conclusions are not optimistic. I include the code below with my comments interspersed so the logic can be checked by one of Nordic engineers. Essentially the code makes no attempt to avoid re-writing zeros to the bytes NOT being written when the write_byte function is called. What it does is to install the values it wishes to write into the correct place in the 32 bit word, leaving the remainder of the word intact. Therefore to write zeros into the four bytes of a word guarantees that at least some of the zeros are written 4 times i.e. once for the first byte write, then repeated 3 more times for the remainder of the bytes.

    Here is the guilty code as far as I can see:

    void nrf_nvmc_write_byte(uint32_t address, uint8_t value)
    {
        uint32_t byte_shift = address & (uint32_t)0x03; //the address of the byte in a 32 bit word.
        uint32_t address32 = address & ~byte_shift; // Address to the word this byte is in.
        //take the contents of the 32 bit word containing the addressed byte somewhere in it (up to>>).
        //Then shift 0xFF by four times the address of the byte i.e. byte 0 no shift, byte 3 by 12 bits.
        //Then Negate that and AND it with the word i.e. zero the contents of the byte to be written.
        //Thus value32 is the original nvram 32 bit word with the byte to be written zeroed.
        uint32_t value32 = (*(uint32_t*)address32 & ~((uint32_t)0xFF << (byte_shift << (uint32_t)3)));
        //Then, take the value to be written, shift it into position in a 32 bit word and add to value32.
        //Thus the result will be a new word value with the new value in it's correct place in the word.
        value32 = value32 + ((uint32_t)value << (byte_shift << 3));
    
        // Enable write.
        NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
        __ISB();
        __DSB();
        //actually do the write.
        *(uint32_t*)address32 = value32;
        wait_for_flash_ready();
    
        NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
        __ISB();
        __DSB();
    }

    Of course, I am not infallible so you will need a software engineer to check that.

    I cannot imagine why it would be difficult to fix - simply write 0xFF into all the other bytes instead of trying to install the byte value into the existing contents.

    Instead of reading the existing value, simply set the initial word value to 0xFFFFFFFF and apply all the same logic (or perhaps just OR the value in instead of using addition - a strange choice of the original author.

    It is as though the original author thought that zeros could be written back to ones, or is that the case with some of the Nordic chips??? Is it a question of conditional coding for the nrf52840 - the answer to those questions are beyond my knowledge.

    Once again, sorry to be rather slow to carry out the analysis.

Related