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

Simple question about the peripheral reset code

Hi,

    For a peripheral reset, I was recommended to use the code below.

    I was just wondering about what the middle line does. Is this a kind of delay to make the reset valid?

    *(volatile uint32_t*)0x40002FFC = 0;
    *(volatile uint32_t*)0x40002FFC;
    *(volatile uint32_t*)0x40002FFC = 1;
Thank you.
Parents
  • That is the UART power control which is accessed by the AHB->APB bus, which takes lower priority than executing instructions on the AHB bus. The intention of the middle line is to ensure the first instruction has actually completed before the third instruction is issued by performing an intermediate read-back of the power-control register. Does this work as intended? Who knows, some compilers might optimise away the middle line even though the register is volatile.

    A better solution is to enforce a wait - minuscule in time - until the instruction has completed thus:

      // In app_uart_close() peripheral is disabled by writing 0 to the NRF_UARTE0->ENABLE
      // register. On 2840 this seems to not stop the HF clk and close the DMA bus, which could be a bug. Power
      // cycle the peripheral after calling app_uart_close() the current consumption goes down.
      *(volatile uint32_t*)0x40002FFC = 0;
      // Data Synchronization Barrier: completes when all explicit memory accesses before this instruction complete
      __DSB();
      *(volatile uint32_t*)0x40002FFC = 1;
      // Data Synchronization Barrier: completes when all explicit memory accesses before this instruction complete
      __DSB();

    However also note that the 3-line work-around advice you are using has been superceded as the original high-consumption issue was later found to be a bug in the Nordic driver, if I recall correctly.

    So, is it still required? Depends on SDK version and probably best to perform a test on the application; high current consumption can be corrected with this work-around even if the work-around is slightly askew.

  • If Nordic modules (UART, SPI, TWI) are essentially the same set of registers, does this problem also apply to other modules?

Reply Children
  • If by problem you mean that the peripheral requires a power-cycle, then it may not actually be a problem if (say) the UARTE issue was indeed a library bug which was not recognised at the time the reset advice was issued. But yes, it appears that most peripherals have a power control register at the same or similar address offset within the instance. We don't have confirmation of this as these registers are undocumented except in (I think)  .. hmm, I can't find it now but I did find one peripheral where it was listed.

    Trying to do the same power-reset sequence for the PWM some time ago  I was using this, but it didn't work well as it turned out to be a different issue:

    //*(volatile uint32_t *)(NRF_PWM0_BASE | 0xFFC) = 0; __DSB(); *(volatile uint32_t *)(NRF_PWM0_BASE | 0xFFC) = 1;

    Best if Nordic engineers provide a more accurate explanation, given the registers are not listed in the documentation. If the registers are indeed real, it's not clear why they are not documented.

    Here is another example for errata 89, these are my notes taken from the errata doc of the time:

    // 3.27 [89] GPIOTE: Static 400 uA current while using GPIOTE
    // ===========================================================
    // This anomaly applies to IC Rev. Rev 2, build codes QFAA-E00, CIAA-E00, QFAB-E00.
    // It was inherited from the previous IC revision Rev 1.
    // Symptoms Static current consumption between 400 uA and 450 uA when using SPIM or TWIM in combination with GPIOTE.
    // Conditions * GPIOTE is configured in event mode  * TWIM/SPIM utilizes EasyDMA
    // Consequences Current consumption higher than specified.
    // Workaround Turn the TWIM/SPIM off and back on after it has been disabled. To do so, write 0 followed by 1 to the
    // POWER register (address 0xFFC) of the TWIM/SPIM that must be disabled:
    // If TWIM0 or SPIM0 is used:
    //  (volatile uint32_t *)0x40003FFC = 0;
    //  (volatile uint32_t *)0x40003FFC;
    //  (volatile uint32_t *)0x40003FFC = 1;
    // If TWIM1 or SPIM1 is used:
    //  (volatile uint32_t *)0x40004FFC = 0;
    //  (volatile uint32_t *)0x40004FFC;
    //  (volatile uint32_t *)0x40004FFC = 1;
    // If SPIM2 is used:
    //  (volatile uint32_t *)0x40023FFC = 0;
    //  (volatile uint32_t *)0x40023FFC;
    //  (volatile uint32_t *)0x40023FFC = 1;
    // Reconfiguration of TWIM/SPIM is required before next usage.

Related