This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Calling NVIC_SoftDevice() after modifying UICR registers causes device to hang

Hello,

For our product, we wish to store a custom post-production name (essentially a serial number) in the UICR registers of the nRF52840. We understand that this can only be done once (without erasing the Flash), and have put in the necessary precautions to ensure that this is only done once.

But our issue stems from what happens after initially writing to it. We write to the registers, and then attempt a NVIC_SoftReset(). This does successfully write to the UICR registers, however the NVIC_SoftReset hangs our system. The only way to make it functional again is to either power-cycle the whole board, or to initiate a POR by having another co-processor on the board triggering the reset line. After doing so, the UICR registers can be read just fine and our post-production serial number can be found just as expected. We'd like to keep this functionality, but remove the need for a hard POR reset (a simple NVIC_SoftReset() or similar would be ideal).

We are running a slightly modified version of theble_peripheral  ble_app_uart project, within SDK 16.0.0 and SoftDevice S140 7.0.1. We also have the secure_bootloader running, however we see this exact same behaviour whether the bootloader is present or not, so we believe that this is irrelevant. None of the flash addresses or similar have been modified.

Below is the code snippet that we use to write to the UICR registers.

 nrf_sdh_disable_request();
const uint32_t *nameAsInts = (uint32_t*)name;
const uint32_t numInts = (strlen(name) + 4) / 4;
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;

while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
for (int i=0; i<numInts; i++)
NRF_UICR->CUSTOMER[i] = nameAsInts[i];

strncpy(NRF_UICR->CUSTOMER, name, sizeof(device_name));
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;

while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NVIC_SystemReset();
while(1) {};

When ran in Debug mode, we see that the app crashes on call address 0x0000.0A60, which is a simple  ldr r3, [pc, #4]  instruction. This call happens sometime after strncpy() is called, but before the final  while (NRF_NVMC->READY == NVMC_READY_READY_Busy)  line .

Cheers,

Tyrel K

Parents
  • Okay I think I solved my own silly issue. I was doing a strncpy when one wasn't needed at all. I was also missing a "wait" within my for loop.

    New code snippet below: this works great! Note: name is passed in as a const char *name

     // convert the name to unsigned long ints (uint32_t)
    const uint32_t *nameAsInts = (uint32_t*)name;
    const uint32_t numInts = (strlen(name) + 4) / 4;

    // disable the SoftDevice
    nrf_sdh_disable_request();

    // enable write (0x01 at pos 0)
    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
    // wait until the NVMC peripheral has finished writting to the UICR register
    while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}

    for (int i=0; i<numInts; i++) {
    // write to the UICR register
    NRF_UICR->CUSTOMER[i] = nameAsInts[i];
    // wait until the NVMC peripheral has finished writting to the UICR register
    while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
    }

    // disable write, enable read (0x02 at pos 0)
    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;

    // UICR registers require a reset after setting them
    NVIC_SystemReset();
    while(1) {};
Reply
  • Okay I think I solved my own silly issue. I was doing a strncpy when one wasn't needed at all. I was also missing a "wait" within my for loop.

    New code snippet below: this works great! Note: name is passed in as a const char *name

     // convert the name to unsigned long ints (uint32_t)
    const uint32_t *nameAsInts = (uint32_t*)name;
    const uint32_t numInts = (strlen(name) + 4) / 4;

    // disable the SoftDevice
    nrf_sdh_disable_request();

    // enable write (0x01 at pos 0)
    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
    // wait until the NVMC peripheral has finished writting to the UICR register
    while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}

    for (int i=0; i<numInts; i++) {
    // write to the UICR register
    NRF_UICR->CUSTOMER[i] = nameAsInts[i];
    // wait until the NVMC peripheral has finished writting to the UICR register
    while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
    }

    // disable write, enable read (0x02 at pos 0)
    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;

    // UICR registers require a reset after setting them
    NVIC_SystemReset();
    while(1) {};
Children
No Data
Related