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)
- clone UICR to uicr_clone variable
- modify both PSELRESET[i] regsto 'disconnect'
- erase UICR by writing NRF_NVMC->ERASEUICR (wai until not busy)
- 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)
- 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
...