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?

  • Good Morning Einar,
    We managed to solve the problem by just installing nRF Connect for Desktop on the new machine.
    Thank you for your support.
    Kind regards
    Mohamed
  • Hi Einar,

    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).

    I am finding that I cannot debug code on an older version QDAAA0. The code boots up and stops at the point where NRF_UICR->APPROTECT is checked, see code below.

    void system_SetDebugPortAccess(void)
    {
    #if (CONFIG_DEBUG_PORT_ACCESS)
    
        /* Prevent chip from locking itself in hardware (if not already set) */
        if (NRF_UICR->APPROTECT != UICR_APPROTECT_PALL_HwDisabled)
        {
            LOG_ERR("Device debug prevented on next POR (0x%08X), resetting to disable this.", NRF_UICR->APPROTECT);
            system_WriteDebugPortAccess(UICR_APPROTECT_PALL_HwDisabled);
        }
    
        /* Prevent chip from locking itself in software */
        NRF_APPROTECT->DISABLE = APPROTECT_DISABLE_DISABLE_SwDisable;
    
    #else
        /* Enforce HW protection (if not already set) */
        if (NRF_UICR->APPROTECT != UICR_APPROTECT_PALL_Enabled)
        {
            LOG_ERR("Device debug allowed on next POR (0x%08X), resetting to disable this.", NRF_UICR->APPROTECT);
            system_WriteDebugPortAccess(UICR_APPROTECT_PALL_Enabled);
        }
    
        /* Belts and braces, enforce SW protection */
        NRF_APPROTECT->FORCEPROTECT = APPROTECT_FORCEPROTECT_FORCEPROTECT_Force;
    
    #endif //CONFIG_DEBUG_PORT_ACCESS
    }
    

    This is what I see in Segger Embedded Studio (SES-Nordic Edition) Debug Terminal:

    *** Booting Zephyr OS build v2.6.99-ncs1 ***
    [00:00:00.025,848] <err> system: Device debug prevented on next POR (0xFFFFFFFF), resetting to disable this.

    So, basically NRF_UICR->APPROTECT != UICR_APPROTECT_PALL_HwDisabled

    I can debug the same code on a newer version of the chip QDAAB0.

    QDAAA0: content of APPROTECT: 10120000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE

    QDAAB0: content of APPROTECT: 1012000012000000120000005A000000FEFFFFFF65

    So, I wrote to APPROTECT of the QDAAA0 chip 0x0000005A  to disable the protection mechanism.

    C:\WINDOWS\system32>nrfjprog --recover
    Recovering device. This operation might take 30s.
    Erasing user code and UICR flash areas.

    C:\WINDOWS\system32>nrfjprog --memwr 0x10001208 --val 0x0000005A --verify
    Parsing parameters.
    Writing.
    Verified OK.

    I then read UICR back to check the value of APPROTECT

    C:\WINDOWS\system32>nrfjprog --readuicr hb-700078-3.ihex
    Storing data in 'hb-700078-3.ihex'.

    QDAAA0: new content of APPROTECT: 10120000FFFFFFFFFFFFFFFF5A000000FFFFFFFFEE

    But when I flash the firmware in SES and start a debug session I still cannot debug it. I get the same error, <err> system: Device debug prevented on next POR (0xFFFFFFFF), resetting to disable this.

    I then tried to read back UICR to check if APPROTECT is still disabled but the read command failed

    C:\WINDOWS\system32>nrfjprog --readuicr hb-700078-4.ihex
    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.

    Why?
    It looks as if the APPROTECT enable/disable does not work for older chip version such as QDFAAA0.
    Kind regards
    Mohamed

  • Hi Mohamed,

    The code in this snippet will not work for older revisions., which has a different APPROTECT mechanism. You need to handle the revisions separately, as is done in the MDK. Referring to nRF Connect SDK 1.9.1 you have modules/hal/nordic/nrfx/mdk/system_nrf52_approtect.h which handles APPROTECT. There you can see that the nrf52_configuration_249() is checked and this returns true for devices with the new APPROTECT mechanism and false for the older.

    As you want to disable APPROTECT, and older devices has APPROTECT disabled by default (, you can simply check which revision you have and avoid running any APPROTECT related code on the older devices.

    PS: To understand the difference between the old (Access port protection controlled by hardware) and new (Access port protection controlled by hardware and software) scheme, I suggest you refer to the Debug and trace chapter in the product specification.

  • Hello Einar,

    Thank you for the clarifications and the link.

    I will have a read. 

    Referring to nRF Connect SDK 1.9.1 you have modules/hal/nordic/nrfx/mdk/system_nrf52_approtect.h which handles APPROTECT. There you can see that the nrf52_configuration_249() is checked and this returns true for devices with the new APPROTECT mechanism and false for the older.
    I would like to avoid moving to v1.9.1 at this moment in time if I can help it.
    In SDK 1.7.0 I can only find in stystem_nrf52_approtect.h the function 
    static inline void nrf52_handle_approtect(void)
    Is there something similar in v1.7.0 that will allow me to read the chip revision ?
    Kind regards
    Mohamed
  • Hi Mohamed,

    You have the same functionality in 1.7.0. There you have nrf52_errata_249() in modules\hal\nordic\nrfx\mdk\nrf52_erratas.h which is used from modules\hal\nordic\nrfx\mdk\system_nrf52_approtect.h. So also there, this is handled automatically by the MDK and you don't really need to do anything. But if you for some reason want to have your own code for handing this (like it seems you do in your system_SetDebugPortAccess(), though I don't really see the need thins the MDK  handles it for you), you can use this function to distinguish between old revisions with old APPROTECT (HW only based) mechanism and new APPROTECT mechanism (HW + SW based).

Related