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

  • Hi Mohamed,

    Generally, when Access port protection is enabled, the only way to recover is to do a full chip erase (ERASE ALL), and that will erase the UICR. So the only way to avoid this is to ensure that access port protection is not enabled in the first place.

    The code snippet you have here works with the latest revision of the ICs, which improved APPROTECT. Can you first double check which IC revision you are using so that you know this code matches the revision you have? Assuming it does and there are no bugs in this code (I might overlook something and I dont know your system_WriteDebugPortAccess() function), you will always have to do a recover / erase all if your CONFIG_DEBUG_PORT_ACCESS is false/0.

  • Hi Thorsrud,

    So the only way to avoid this is to ensure that access port protection is not enabled in the first place.

    I use two versions of prj.conf, prj_debug.conf where CONFIG_DEBUG_PORT_ACCESS=y and prj_release.conf where CONFIG_DEBUG_PORT_ACCESS=n.

    you will always have to do a recover / erase all if your CONFIG_DEBUG_PORT_ACCESS is false/0.
    So, in debug mode I should NOT be experiencing this problem, right?
    Also, isn't the whole purpose of the access port protection is to make sure it is enabled before product deployment?
    Can you first double check which IC revision you are using so that you know this code matches the revision you have?

    We are currently using a mixture of N52833 QDAAB0 and QDAAA0 but ultimately we will be using only revision QDAAB0.

    Assuming it does and there are no bugs in this code (I might overlook something and I dont know your system_WriteDebugPortAccess() function)

    Here is my function

    static void system_WriteDebugPortAccess(uint32_t value)
    {
        /* Allow UICR access */
        NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { }
    
        /* Set new value for HW protection of AP */
        NRF_UICR->APPROTECT = value;
    
        /* Disallow UICR access */
        NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { }
    
        /* Reboot to take new UICR values */
        system_Reset();
    }
    

    Thank you.

    Kind regards
    Mohamed
  • Hi Mohamed,

    Learner said:
    So, in debug mode I should NOT be experiencing this problem, right?

    I do not know everything you do, but yes: as long as debug port access is enabled, then you can erase and write specific sectors and do not need to do a full chip erase.

    Learner said:
    Also, isn't the whole purpose of the access port protection is to make sure it is enabled before product deployment?

    Yes it is. But that also means that debug access is blocked, and to enable it you must do an ERASE ALL (recover), which also erases UICR.

    Learner said:
    We are currently using a mixture of N52833 QDAAB0 and QDAAA0 but ultimately we will be using only revision QDAAB0.

    I see. The code snippet you have seems to match QDAAB0, which has the improved access port mechanism (IN-149). With this debugging is disabled by default and you need to disable it by writing to UICR and also writing to  NRF_APPROTECT->DISABLE on every boot. If not, a full erase is needed to be able to debug again.

    Note that it is also so that the only way to erase UICR is to erase the whole flash, so if the UICR is "suddenly" erased it is because the tools you use for some reason do an erase all. The question is why. Can you start by reading data from UICR to see if debug access is enabled and the data is still there? then what exactly do you do when the UICR is erased by the debugger?

  • Hi Thorsrud,

    Before I try what you suggested I would like you to clarify the statement below.

    write to flash can only reset bits. It is necessary to erase flash to set it to FFFFFFF

    Is the above statement from dgerman correct?

    I see you are not erasing flash in the example code you shared earlier with rmarques.

    Please clarify.

    Thank you.

    Kind regards
    Mohamed
  • Hi Thorsrud,

    The code snippet you have seems to match QDAAB0, which has the improved access port mechanism (IN-149).

    Can I use the same code snippet with other Soc version e.g. QDAAA0?

    Also, when I use nRF Programmer v2.3.3 to flash the same debug version of the firmware merged.hex the UICR content gets erased. However, when I use SES Nordic Edition v5.60 to flash the same debug version merged.hex the content of the UICR is preserved.

    Note, when using nRF Programmer only the 'Erase & write' option is available. The 'Write' only option is disabled, see attached screen shot below.

    Thank you.

    Kind regards
    Mohamed
Reply
  • Hi Thorsrud,

    The code snippet you have seems to match QDAAB0, which has the improved access port mechanism (IN-149).

    Can I use the same code snippet with other Soc version e.g. QDAAA0?

    Also, when I use nRF Programmer v2.3.3 to flash the same debug version of the firmware merged.hex the UICR content gets erased. However, when I use SES Nordic Edition v5.60 to flash the same debug version merged.hex the content of the UICR is preserved.

    Note, when using nRF Programmer only the 'Erase & write' option is available. The 'Write' only option is disabled, see attached screen shot below.

    Thank you.

    Kind regards
    Mohamed
Children
  • Regarding my statement:

    write to flash can only reset bits.
    It is necessary to erase flash to set it to FFFFFFF

    The second part is NOT correct!

    Unfortunately 

    NRFJPROG incorrectly requires it see:

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

    In fact you could use a "counter" (up to 31) by repeatedly clearing bits.
    counter =1: 7FFFFFF,  counter=2:3FFFFFFF, counter=3 :1FFFFFFF, =4:0FFFFFFF ... =30:00000003, 31:00000001 with no intervening erasures. 


    ++++++++++++++

    You can use nrfjprog 

    --sectorerase

     to only erase the area that is being programmed which can preserve UCIR.

  • Learner said:
    Can I use the same code snippet with other Soc version e.g. QDAAA0?

    If you refer to the code snippet to write to flash, then yes. Writing to flash (including the UICR) is the same for all revisions. (As mentioned deleting the UICR page is special though, as it can only be done with a full chip erase).

    Learner said:
    Also, when I use nRF Programmer v2.3.3 to flash the same debug version of the firmware merged.hex the UICR content gets erased. However, when I use SES Nordic Edition v5.60 to flash the same debug version merged.hex the content of the UICR is preserved.

    The nRF Connect Programmer version >= 2.0.0 unfortunately always does an erase on write, and this is a full chip erase and not a sector erase (erasing only sectors to be writtne to). This has been reported, but is unfortunately the case at the moment. So you must use another tool in order to program without erasing the whole chip (including the UICR). A simple tool for this is nrfjprog.

  • Hi Thorsrud,

    Thank you for your support.

    The nRF Connect Programmer version >= 2.0.0 unfortunately always does an erase on write, and this is a full chip erase and not a sector erase (erasing only sectors to be writtne to).

    Unfortunately, this is what we were planning to use. It looks like we will have to go to plan B.

    A simple tool for this is nrfjprog.

    nrfjprog is plan B. I have never used it before. I have now downloaded v10.15.

    nrfjprog version: 10.15.4 external
    JLinkARM.dll version: 7.58b

    I have read the documentation but I am still not sure how to use 'sectorerase'. I would like to use the following command line to flash our firmware using nrfjprog and avoiding to erase UICR,

    nrfjprog -f NRF52 --program merged.hex –-sectorerase <????>

    Thank you for your help.

    Kind regards
    Mohamed

  • Hi Mohamed,

    What you have found is correct (specifying family is optional). Specifically, nrfjprog never does an erase without "being told so", so that is no problem. To just flash your firmware if there was nothing there before, you can simply use "nrfjprog --program <hexfile>". If you want to overwrite an existing application (the pages you are writing to are not all FFFF), then add --sectorerase like this: "nrfjprog --program <hex> --sectorerase". With this, all pages that will be written to are erased first, but non of the others, and then the hex file is written.

  • Hi Thorsrud,

    I see, I thought I needed to explicitly specify the pages I wanted to erase because 'sectorerase expects arguments. so I don't need to specify the pages number after --sectorerase at the end of the command line. 

    I tried the command 

    nrfjprog -f NRF52 --program merged.hex –-sectorerase

    First I got this error,

    C:\Sandbox\HomeBeacon_dev_sb\build_nrf52833dk_nrf52833_v133_rel\zephyr>nrfjprog -f NRF52 --program merged.hex --sectorerase
    ERROR: The operation attempted is unavailable due to readback protection in
    ERROR: your device. Please use --recover to unlock the device.
    NOTE: For additional output, try running again with logging enabled (--log).
    NOTE: Any generated log error messages will be displayed.

    Then I tried

    C:\Sandbox\HomeBeacon_dev_sb\build_nrf52833dk_nrf52833_v133_rel\zephyr>nrfjprog -f NRF52 --recover --program merged.hex --sectorerase
    ERROR: Two arguments were provided that cannot be combined. Use --help to read
    ERROR: about the valid argument combinations.
    NOTE: For additional output, try running again with logging enabled (--log).
    NOTE: Any generated log error messages will be displayed.

    Finally, I tried

    C:\Sandbox\HomeBeacon_dev_sb\build_nrf52833dk_nrf52833_v133_rel\zephyr>nrfjprog -f NRF52 --recover --program merged.hex
    Recovering device. This operation might take 30s.
    Parsing image file.
    WARNING: A programming operation has been performed without --verify.
    WARNING: Programming can fail without error.

    But I ended up erasing the content of the UICR which I wanted to avoid.

    What am I doing wrong?

    Actually, I think the reason the command nrfjprog -f NRF52 --program merged.hex --sectorerase did not work it is because the device had the release version of the code which has CONFIG_DEBUG_PORT_ACCESS=n.

    So, I flashed the debug version (CONFIG_DEBUG_PORT_ACCESS=y) into the device then I tried the same command nrfjprog -f NRF52 --program merged.hex --sectorerase again and this time the UICR register was not erased. So, we can flash the device without erasing the whole flash including the UICR only if  CONFIG_DEBUG_PORT_ACCESS=y.

    Kind regards
    Mohamed
Related