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?

  • Hi Einar,

    Thank you.

    The reason I am looking at using nrf52_errata_249() is, as you suggested, to distinguish between chips with the older APPROTECT mechanism and those with the new one in system_SetDebugPortAccess().

    There is one thing I am not sure about though.

    If NRF_UICR->APPROTECT is set to UICR_APPROTECT_PALL_Enabled

    Will I still be able to write to NRF_UICR->CUSTOMER flash area in the firmware at runtime?

    Kind regards

    Mohamed

  • Hi,

    If NRF_UICR->APPROTECT is set to UICR_APPROTECT_PALL_Enabled

    Will I still be able to write to NRF_UICR->CUSTOMER flash area in the firmware at runtime?

    Yes. The APPROTECT mechanism only prevents debugger access. The CPU still has ability to write to the UICR. (The CPU cannot erase the UICR page, though).

  • Thank you Einar.

    (The CPU cannot erase the UICR page, though)

    Does this mean I can only write to UICR->CUSTOMER locations which are FFFF... i.e. the UICR locations that have not been written to since the last erase?

    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.

    Looking in system_nrf52_approtect.h I can see the code inside the function nrf52_handle_approtect() is disabled because NRF52_ERRATA_249_PRESENT is defined as 1 in nrf52_erratas.h.                                              

    Do I need to define ENABLE_APPROTECT?

    Yet you said this is handled automatically in the MDK. I must be missing something.

    Also, it seems the the function nrf52_errate_249() always returns false unless NRF52_SERIES is defined.    How can I add the pre-processor directive -DNRF52_SERIES in Segger Embedded Studio v5.60? 

    There are many macros and I am not sure which ones I need to define and which ones are handled automatically by the MDK. Please clarify.

    /* ========= Errata 249 ========= */
    #if    defined (NRF52820_XXAA) || defined (DEVELOP_IN_NRF52820) \
        || defined (NRF52832_XXAA) || defined (DEVELOP_IN_NRF52832) \
        || defined (NRF52832_XXAB) || defined (DEVELOP_IN_NRF52832) \
        || defined (NRF52833_XXAA) || defined (DEVELOP_IN_NRF52833) \
        || defined (NRF52840_XXAA) || defined (DEVELOP_IN_NRF52840)
        #define NRF52_ERRATA_249_PRESENT 1
    #else
        #define NRF52_ERRATA_249_PRESENT 0
    #endif
    
    #ifndef NRF52_ERRATA_249_ENABLE_WORKAROUND
        #define NRF52_ERRATA_249_ENABLE_WORKAROUND NRF52_ERRATA_249_PRESENT
    #endif
    
    static bool nrf52_errata_249(void)
    {
        #ifndef NRF52_SERIES
            return false;
        #else
            #if defined (NRF52820_XXAA) || defined (DEVELOP_IN_NRF52820)\
             || defined (NRF52832_XXAA) || defined (DEVELOP_IN_NRF52832)\
             || defined (NRF52832_XXAB) || defined (DEVELOP_IN_NRF52832)\
             || defined (NRF52833_XXAA) || defined (DEVELOP_IN_NRF52833)\
             || defined (NRF52840_XXAA) || defined (DEVELOP_IN_NRF52840)
                uint32_t var1 = *(uint32_t *)0x10000130ul;
                uint32_t var2 = *(uint32_t *)0x10000134ul;
            #endif
    ...
    ...
            #if defined (NRF52833_XXAA) || defined (DEVELOP_IN_NRF52833)
                if (var1 == 0x0D)
                {
                    switch(var2)
                    {
                        case 0x00ul:
                            return false;
                        case 0x01ul:
                            return false;
                        case 0x02ul:
                            return true;
                        default:
                            return true;
                    }
                }
            #endif
    ...
    ...
            return false;
        #endif
    }
    

    Kind regards
    Mohamed
Related