ERASEUICR not erasing UICR

I have a problem erasing data written to the NRF_UICR->CUSTOMER registers.

I want to store the hardware version and serial number in these registers, but the serial number may change once in the lifetime of the product. Thus I would like to be able to update it.

The function I've written works on the NRF52832 chip, but doesn't seem to work on the NRF52840.

The infocenter says that when the erase bit in the confic register is set, I could erase all customer registers.

But I cannot get this to work on the NRF52840.

I've also disabled the protection registers using;

NRF_APPROTECT->DISABLE = APPROTECT_DISABLE_DISABLE_SwDisable;

But that doesn't seem to help.

Any help would be appreciated.

The function in question;

                uint8_t total_flash_size = ROUND_UP(HARDWARE_VERSION_SZ + HARDWARE_KEYWORD_SZ + SERIAL_NUMBER_SZ + SERIAL_KEYWORD_SZ, 4);
                uint32_t flash_copy_array[(total_flash_size / 4)];
                serial_number_t serial_number;
                uint32_t *pversion_flash = HARDWARE_VERSION_PTR; //Hardware version is first so use that as origin
               
                //Get data from flash
                memcpy((uint8_t*)flash_copy_array, (uint8_t*)pversion_flash, total_flash_size);
               
                //Put new data in temp stuct
                memcpy(serial_number.u.data, data, SERIAL_NUMBER_SZ);
                serial_number.keyword = SERIAL_NUMBER_KEYWORD;
//
                //HardwareVersionPointer is the first address, so this is used to calculate the offset for the array
                memcpy(&((uint8_t*)flash_copy_array)[SERIAL_NUMBER_PTR - HARDWARE_VERSION_PTR], (uint8_t*)&serial_number, SERIAL_NUMBER_SZ + SERIAL_KEYWORD_SZ);
               
                __disable_irq();
                //Configure for erase
                NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos;
                while(NRF_NVMC->READY == NVMC_READY_READY_Busy){;}
                NRF_NVMC->ERASEUICR = NVMC_ERASEUICR_ERASEUICR_Erase << NVMC_ERASEUICR_ERASEUICR_Pos;

                //Wait for erase to complete
                while(NRF_NVMC->READY == NVMC_READY_READY_Busy){;}

                //Configure for write
                NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
                while(NRF_NVMC->READY == NVMC_READY_READY_Busy){;}

                //Write data to flash
                for(int i = 0; i < (total_flash_size / 4); i++)
                {
                    while(NRF_NVMC->READYNEXT == NVMC_READY_READY_Busy){;}//NRF52840 has this register, so use it. Maybe it will help? nop
                    pversion_flash[i] = flash_copy_array[i];
                }
                //memcpy(pversion_flash, flash_copy_array, sizeof(flash_copy_array));
                while(NRF_NVMC->READY == NVMC_READY_READY_Busy){;}

                //Undo configuration
                NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
                while(NRF_NVMC->READY == NVMC_READY_READY_Busy){;}
                __enable_irq();

                SendCMD_Data(kAck, (uint8_t*)paddr, MEMORY_ADDRESS_SIZE);
                //System reset is needed for the new UICR configuration to take effect
                k_msleep(200);
                NVIC_SystemReset();
Parents Reply
  • nrfx_nvmc_uicr_erase should actually not be able to return the value you mentioned (at least not the one in the nRF5 SDK version 17). It always returns NRFX_SUCCESS.

    Anyway, I have a similar problem (which is why I stumbled upon this), but apparently only with a specific chip revision. I'm calling nrfx_nvmc_uicr_erase, but when I check NRF_UICR->CUSTOMER directly afterwards, it's not 0xFFFFFFFF (I can only "debug via buzzer", since I have ready products w/o debug connectors on my desk. Would need to do some tinkering to get the Chip revision out).

    Edit: NRF_FICR->INFO.VARIANT is 0x41414430 / AAD0

Children
  • Sort of nice to hear that I'm not the only one with this problem.

    My NRF_FICR->INFO.VARIANT is 0x41414630 / AAF0. But the datasheet lists AAF0 as 0x41414530, which is weird as 0x45 is an 'E'.

    However, I've looked up the possible return values of the nrfx_nvmc_uicr_erase() function (e.g. NRFX_SUCCESS)  and those are actually 0x0BAD0000 + the error indicator.

    This is in nrfx_errors.h;

    #define NRFX_ERROR_BASE_NUM         0x0BAD0000
    typedef enum {
        NRFX_SUCCESS                    = (NRFX_ERROR_BASE_NUM + 0),  ///< Operation performed successfully.
        NRFX_ERROR_INTERNAL             = (NRFX_ERROR_BASE_NUM + 1),  ///< Internal error.
        NRFX_ERROR_NO_MEM               = (NRFX_ERROR_BASE_NUM + 2),  ///< No memory for operation.
        NRFX_ERROR_NOT_SUPPORTED        = (NRFX_ERROR_BASE_NUM + 3),  ///< Not supported.
        NRFX_ERROR_INVALID_PARAM        = (NRFX_ERROR_BASE_NUM + 4),  ///< Invalid parameter.
        NRFX_ERROR_INVALID_STATE        = (NRFX_ERROR_BASE_NUM + 5),  ///< Invalid state, operation disallowed in this state.
        NRFX_ERROR_INVALID_LENGTH       = (NRFX_ERROR_BASE_NUM + 6),  ///< Invalid length.
        NRFX_ERROR_TIMEOUT              = (NRFX_ERROR_BASE_NUM + 7),  ///< Operation timed out.
        NRFX_ERROR_FORBIDDEN            = (NRFX_ERROR_BASE_NUM + 8),  ///< Operation is forbidden.
        NRFX_ERROR_NULL                 = (NRFX_ERROR_BASE_NUM + 9),  ///< Null pointer.
        NRFX_ERROR_INVALID_ADDR         = (NRFX_ERROR_BASE_NUM + 10), ///< Bad memory address.
        NRFX_ERROR_BUSY                 = (NRFX_ERROR_BASE_NUM + 11), ///< Busy.
        NRFX_ERROR_ALREADY_INITIALIZED  = (NRFX_ERROR_BASE_NUM + 12), ///< Module already initialized.

        NRFX_ERROR_DRV_TWI_ERR_OVERRUN  = (NRFX_ERROR_DRIVERS_BASE_NUM + 0), ///< TWI error: Overrun.
        NRFX_ERROR_DRV_TWI_ERR_ANACK    = (NRFX_ERROR_DRIVERS_BASE_NUM + 1), ///< TWI error: Address not acknowledged.
        NRFX_ERROR_DRV_TWI_ERR_DNACK    = (NRFX_ERROR_DRIVERS_BASE_NUM + 2)  ///< TWI error: Data not acknowledged.
    } nrfx_err_t;
  • We had an fix to approtect a while ago, so approtect behaves differently for different nRF52840 revisions. See  Working with the nRF52 Series' improved APPROTECT for a list.

    We can see the difference between the old and new at Enabling access port protection mechanism:

    As you can see, The new one (Hardware and software) is automatically enabled on reset.

    You can not erase UICR with approtect enabled.

    You say that you have disabled approtect in the post here, but I suspect you might have missed part of it. Did you verify that approtect was indeed disabled by flashing the device without --recover?

    DaRu said:
    However, I've looked up the possible return values of the nrfx_nvmc_uicr_erase() function (e.g. NRFX_SUCCESS)

    I checked, and looks like this function will return NRFX_SUCCESS if approtect is locked, so that unfortunately does not give us the info we are looking for.

  • I've taken a loot at the approctect disabling, only did

    NRF_APPROTECT->DISABLE = APPROTECT_DISABLE_DISABLE_SwDisable;

    as first thing in main().

    I've added code to disable the NRF_UICR approtect as follows;

    int main(void)
    {
        __NOP();
        __NOP();
        __NOP();
       
        //Configure for write
        NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
        while(NRF_NVMC->READY == NVMC_READY_READY_Busy){;}
       
        //Disable protection
        NRF_UICR->APPROTECT = UICR_APPROTECT_PALL_HwDisabled << UICR_APPROTECT_PALL_Pos;
        while(NRF_NVMC->READY == NVMC_READY_READY_Busy){;}

        //Undo configuration
        NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
        while(NRF_NVMC->READY == NVMC_READY_READY_Busy){;}


        NRF_APPROTECT->DISABLE = APPROTECT_DISABLE_DISABLE_SwDisable;

    Afterwards I've implemented a check to determine if the UICR setting has stuck;

    if((NRF_UICR->APPROTECT & UICR_APPROTECT_PALL_Msk) == (UICR_APPROTECT_PALL_HwDisabled << UICR_APPROTECT_PALL_Pos)){

    Which tells me that it has worked, as in the UICR register is indeed set to disabled

    While this has caused some progress, this creates a weird behavior, where instead of counting up, it will oscillate between 0x00000000 and 0x00000001 on restarts.
    So for some reason it seems to only reset the last bit changed?

    To be more specific;

    The first value returned is 0xFFFFFFFF, then it adds 1 and writes + NVIC_SystemReset();

    The second value is 0x00000000, then adds 1 again, write and reset

    The third value is 0x00000000, then adds 1 again, write and reset

    The third value is 0x00000001, then adds 1, writes and reset

    The fifth value is 0x00000000 again. It adds 1, writes and reset

    The sixth value is 0x00000001 again. Then add, write and reset.

    The values after that will oscillate between 0 and 1.

    If I tell it to add 2 instead, it will output nearly the same;

    First 0xFFFFFFFF,

    Second 0x00000001,

    Third 0x00000001,

    Fourth 0x000000003,

    Fifth 0x00000001

    Sixth 0x00000003.

    And then oscillate between 1 and 3.

  • I realize that this is not possible after all with the new APPROTECT version. See my colleguas answer at  NRF52840: UICR not erasable when RBP is set?

Related