Programmatically disabling PINRESET - nRF52832, nRF5 SDK, SD112

Hello,

In a legacy (nRF5SDK) application, we notice a parasitic' pin resets reported by the system (RESREASON).

As the device does not have an accessible reset pin, we assume that these resets are induced by some parasitic EMC noise.

So we decided to disable the PINRESET altogether.

This is trivial for new devices manufactured - just undef CONFIG_GPIO_AS_PINRESET macro.

HOWEVER, as we have tens of thousands of sensors already deployed, we would like to implement it also in the DFU package. Here it gets complicated...

The logic I tried to implement is as follows - (right at the beginning of main)

  1. clone UICR to uicr_clone variable
  2. modify both PSELRESET[i] regsto 'disconnect'
  3. erase UICR by writing NRF_NVMC->ERASEUICR (wai until not busy)
  4. After UICR has been erased, write back all relevant UICR blocks from uicr_clone to the now erased UICR (do it serially for each register, wait until not busy)
  5. finally reset the system to hopefully 'no reset pin' configuration

While this works on flashed devices, it hangs after DFU.

Here is the code snippet, nothing fancy. WHat can go worng after DFU?

Thanks for any advice.

/* -- NVMC utility functions -- */
/* Waits until NVMC is done with the current pending action */
void _nvmc_wait(void)
{
    while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
}

/*  Configure the NVMC to "mode".
    Mode must be an enumerator of field NVMC_CONFIG_WEN */
void _nvmc_config(uint32_t mode)
{
    NRF_NVMC->CONFIG = mode << NVMC_CONFIG_WEN_Pos;
    _nvmc_wait();
}

void disconnect_pinreset(void)
{    /* Configure GPIO pads as Pin Reset pin if Pin Reset capabilities desired. If CONFIG_GPIO_AS_PINRESET is not
      defined, pin reset will not be available. One GPIO (see Product Specification to see which one) will then be
      reserved for PinReset and not available as normal GPIO. */
	
	#if defined (NRF52832_XXAA) 
    #define RESET_PIN 21
	#else
    #error "A supported device macro must be defined."
	#endif

	// Check if any PSELRESET bit 31 is 'connected'
	if (((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) == (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos)) ||
		((NRF_UICR->PSELRESET[1] & UICR_PSELRESET_CONNECT_Msk) == (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos))){

		NRF_UICR_Type uicr_clone;
		memcpy(&uicr_clone, NRF_UICR, sizeof(uicr_clone));
		uicr_clone.PSELRESET[0] = RESET_PIN | (UICR_PSELRESET_CONNECT_Disconnected << UICR_PSELRESET_CONNECT_Pos);
		uicr_clone.PSELRESET[1] = RESET_PIN | (UICR_PSELRESET_CONNECT_Disconnected << UICR_PSELRESET_CONNECT_Pos);

		// erase uicr
		_nvmc_config(NVMC_CONFIG_WEN_Een); //
		NRF_NVMC->ERASEUICR = NVMC_ERASEUICR_ERASEUICR_Erase<<NVMC_ERASEUICR_ERASEUICR_Pos;
		_nvmc_wait();

		// reprogram uicr with modified values
		_nvmc_config(NVMC_CONFIG_WEN_Wen);
		// write UICR.NRFFW block
		for(int i = 0; i < sizeof(uicr_clone.NRFFW)/sizeof(uint32_t); i++) {
			if(uicr_clone.NRFFW[i] != 0xFFFFFFFF) {
				NRF_UICR->NRFFW[i]= uicr_clone.NRFFW[i];
				_nvmc_wait();
			}
		}

		// write UICR.NRFHW block
		for(int i = 0; i < sizeof(uicr_clone.NRFHW)/sizeof(uint32_t); i++) {
			if(uicr_clone.NRFHW[i] != 0xFFFFFFFF) {
				NRF_UICR->NRFHW[i]= uicr_clone.NRFHW[i];
				_nvmc_wait();
			}
		}

		// write UICR.CUSTOMER block
		for(int i = 0; i < sizeof(uicr_clone.CUSTOMER)/sizeof(uint32_t); i++) {
			if(uicr_clone.CUSTOMER[i] != 0xFFFFFFFF) {
				NRF_UICR->CUSTOMER[i]= uicr_clone.CUSTOMER[i];
				_nvmc_wait();
			}
		}

		// write UICR.PSELRESET block
		for(int i = 0; i < sizeof(uicr_clone.PSELRESET)/sizeof(uint32_t); i++) {
			if(uicr_clone.PSELRESET[i] != 0xFFFFFFFF) {
				NRF_UICR->PSELRESET[i]= uicr_clone.PSELRESET[i];
				_nvmc_wait();
			}
		}

		// write UICR.NFCPINS block
		if(uicr_clone.NFCPINS != 0xFFFFFFFF) {
			NRF_UICR->NFCPINS = uicr_clone.NFCPINS;
			_nvmc_wait();
		}

		// write UICR.APPROTECT block
		if(uicr_clone.APPROTECT != 0xFFFFFFFF) {
			NRF_UICR->APPROTECT= uicr_clone.APPROTECT;
			_nvmc_wait();
		}
		
		

		_nvmc_config(NVMC_CONFIG_WEN_Ren);
		NVIC_SystemReset();
	}
}
#endif	// CONFIG_GPIO_AS_PINRESET

/**@brief Function for application main entry.
 */
int main(void)
{
	ret_code_t err_code = NRF_SUCCESS;
    bool erase_bonds;

#if !defined (CONFIG_GPIO_AS_PINRESET)
	disconnect_pinreset();
#endif
...


Parents
  • So it appears that the problem lies in the bootloader of the older version.

    Since it was build with CONFIG_GPIO_AS_PINRESET, it enables PINRESET and then transfers control to the app that tries to disable it and then reset, hence creating a boot loop.

    I would appreciate a clear instruction as how to OTA update a merged Bootloader+App file.

    If this is not possible in one step, please guide how to do it in two steps.

    I tried to rebuild the bootloader without the flag and generated a DFU zip file which I managed to DFU fine, then I'm trying to DFU the app, the device resets...

    Please advise

Reply
  • So it appears that the problem lies in the bootloader of the older version.

    Since it was build with CONFIG_GPIO_AS_PINRESET, it enables PINRESET and then transfers control to the app that tries to disable it and then reset, hence creating a boot loop.

    I would appreciate a clear instruction as how to OTA update a merged Bootloader+App file.

    If this is not possible in one step, please guide how to do it in two steps.

    I tried to rebuild the bootloader without the flag and generated a DFU zip file which I managed to DFU fine, then I'm trying to DFU the app, the device resets...

    Please advise

Children
  • Not sure if this helps, but it would be usual to make the reversion of the PINRESET in the App conditional on the version of the Bootloader; in other words the main App only turns off the pin reset (which requires a reset to load the new UICR) once the new bootloader has been installed and is invoking the main App. This requires that the new main App query the version of the bootloader.

    Edit: I forgot to mention that it may be possible to simply enable the pull-up on pin 21 to reduce EMC susceptibility. This works (may work) as the schematic in the data sheet is incorrect; the pull-up applies to the pin regardless of what mode the pin is in.

Related