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?

Parents
  • 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.

Reply
  • 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.

Children
No Data
Related