Example code to write to UICR

I am trying to store data to the UICR using SDK16, mesh SDK 4.2.0 and the nRF52840 chip.

I want to write to the UICR once on runtime and never again. To avoid messing with the softdevice, I am trying to write to the UICR before calling ble_stack_init() and after __LOG_INIT to get logs working.

This is the code:

NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}

uint32_t * consumer0 = (uint32_t *) 0x10001080;
*consumer0 = 0x00000005;

NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "%d\n", *consumer0);

NVIC_SystemReset();

So we put the NVMC in Write enable, wait for it to be ready, write to consumer0, put it in Read enable, wait for it to be ready and reset the device. I can see 5 logged to Segger console.

Then I comment what I don't need:

//NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
//while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}

uint32_t * consumer0 = (uint32_t *) 0x10001080;
//*consumer0 = 0x00000005;

//NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
//while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "%d\n", *consumer0);

//NVIC_SystemReset();

And I see -1 logged to Segger console, meaning the flash still has the 0xFFFF on that position. I can confirm it on Segger Memory explorer that 10001080 is never filled with the data I wanted. Am I doing something wrong?

Parents
  • Beware that sometimes Flash memory is cached by Segger and does not exactly show what you expect. I refer explicitly to 

    exec SetAllowFlashCache =0   

    Have you tried exiting Segger and starting it again to see if flash isn really set?

    In addition add a check in your coded to see what the value is.

    Finally choose your values wisely since if there PREVIOUS value of customer[0] was FFFFFFFF this will work BUT if the previous value was 05000000 it will not since write to flash can only reset bits. It is necessary to erase flash to set it to FFFFFFF

  • I tried exiting Segger and rechecking the memory, all was the same. I also added a small check for looking for the change in the flash like so:

    //NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
    //while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
    
    uint32_t * consumer0 = (uint32_t *) 0x10001080;
    //*consumer0 = 0x00000005;
    if(*consumer0 == 5){
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "*consumer0 = 5\n");
    }
    else {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Flash not correct, *consumer0 = %d\n", *consumer0);
    }
    
    //NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
    //while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
    
    //NVIC_SystemReset();

    As soon as I comment the lines commented in the code I get the second __LOG: Flash not correct, *consumer0 = -1

Reply
  • I tried exiting Segger and rechecking the memory, all was the same. I also added a small check for looking for the change in the flash like so:

    //NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
    //while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
    
    uint32_t * consumer0 = (uint32_t *) 0x10001080;
    //*consumer0 = 0x00000005;
    if(*consumer0 == 5){
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "*consumer0 = 5\n");
    }
    else {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Flash not correct, *consumer0 = %d\n", *consumer0);
    }
    
    //NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
    //while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
    
    //NVIC_SystemReset();

    As soon as I comment the lines commented in the code I get the second __LOG: Flash not correct, *consumer0 = -1

Children
  • Hi,

    I see nothing in the code that would explain this, the way you write to UICR seems correct (and is the same as what you can see in gpio_output_voltage_setup() in components\boards\boards.c).

    Perhaps the issue is with how you test instead? When you flash the new firmware that should read the UICR, perhaps you erase the UICR during that operation? Can you explain how you program the second time?

    You could also avoid the whole issue using something like this (not tested, may be typos) so that you don't re-flash the firmware (potentially erasing UICR in the process):

    // Input address and wrod to write to that address.
    //Output:
    // - True if target word is written
    // - False if a different value is allraedy written to register (it is not correct or all FF's)
    // - Does not return if write has been performed (in that case a soft reset is triggered)
    bool write_word_to_uicr(uint32_t * addr, uint32_t word)
    {
        if (*addr == word)
        {
            // Allready set. Nothing more to do.
            return true;
        }
        else if (*addr != 0xFFFFFFFF)
        {
            // The register allready has another value. Aborting.
            // (Note: could improve by checking if only bits that should be flipped to 0 has been,
            // if so it would still be possible to write the target word.)
            return false;
        }
        else
        {
            // Register has default value. Ready to write...
            NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
            while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
    
            *addr = word;
    
            NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
            while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
    
            NVIC_SystemReset();
        }
    }

    Then you could call the above function like this:

    write_word_to_uicr((uint32_t *)0x10001080, 0x00000005);

  • Thank you, this helped me diagnose the problem. When I comment the lines I was using to write to the flash, the program is recompiled and when Segger flashes the program to the chip, the UICR is erased and flashed with default values. Is there any way I can avoid overwriting the UICR every time the device is reprogrammed?

  • The UICR page should not be deleted by default with the SDK example project files. Can you explain in detail how you program the device? Do you for instance use "Erase All" before you program? If so, the UICR page will also be deleted.

  • Although this does not answer the original question,
    In the code provided by Einar,
    I believe the line

    if (*addr != 0xFFFFFFFF)

    should actually be

    if ( (*addr & word) != word )

              { /* UICR has bits cleared that word needs set. Erase is required */

         ....

              }
                   

    This is a problem with nrfjprog as reported in

    nrfjprog --memwr-0x10001080 --val 0x01010101 shouldn't fail second-time

    As a test, to assist with diagnosing,  you tried using nrfjprog?

    Is it necessary to restore NVM to read state using 

    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);

  • Hi All,

    I am experiencing the same problem, meaning I write to the UICR but when I flash the firmware again using SES or nRF Programmer the content of the UICR is also erased. Can you please help?

    If rmarques has resolved his problem it would be good if the solution is shared on this platform.

    Thank you.

    Kind regards
    Mohamed
Related