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

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

  • 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
Reply
  • 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
Children
No Data
Related