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 Children
  • Hello,

    I've tried the nrfx_nvmc_uicr_erase(), but it doesn't help, the nrf52840 isn't able to erase the UICR.

    I've also tried this on the nrf52832, where it does work, but there it was already working in the first place.

  • In that case:

    Could you explain how you see that it does not work?

    What does nrfx_nvmc_uicr_erase() return?

  • I have written a few debug lines, such that upon startup the first customer register is read and send to my serial terminal. Then that value from the customer register is incremented by one and inserted as the first uint32 of a dummy serial number, then given to the write function to be written.

    The write function will perform a NVIC_SystemReset() to update the UICR configuration, this will then reset the nrf and begin the cycle anew.

    The result in the nrf52832 is a nicely incrementing output in the terminal on every boot.

    But in the nrf52840 the message in the terminal is always the same; 0x00, 0x00, 0x00, 0x00 followed by the rest of the dummy serial.

    As for the output of the nrfx_nvmc_uicr_erase(), it was 0x0BAD0000.

  • 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

  • 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;
Related