nrf52840, Zephyr, ncs 3.4.1
For a few months I have been tracking an intermittent issue with a product that is close to production release.
The symptom of this problem is an excess 0.4 mA current during sleep. The excess current was observed to start after a burst of application activity (including QSPI flash writes), and continues until the next Bluetooth radio event.
The current profile is flat. Mostly this problem does not occur. But on some builds it occurs nearly every sleep. Then making the smallest change to the firmware would cause the problem to vanish, making this
super-difficult to investigate.
With Claude's help I have been able to identify the circumstances where it occurs, and build a minimal example that runs on the development kit board.
The circumstances are:
* It requires a certain pattern of QSPI flash writes. The minimal example uses a pattern of three writes that is common to our application. The issue does not occur after a single flash write.
* The source of the flash write needs to be in RAM8 (RAM above 0x20010000). The issue does not occur if the writes are from a lower RAM address (RAM0 to RAM7).
* The write needs to occur from a thread whose stack is in RAM8. The issue does not occur if the stack is at a lower address.
* Code alignment is an issue too. Adding some non-executed NOP instructions to a function in `main.c` shifts the rest of the application linked after it. Shifting by 2 to 6 bytes affects whether the issue occurs. I have not investigated exactly which instruction is sensitive.
The excess current will last indefinitely, but it seems to be ended by another EasyDMA transfer. We have tried two:
* In the product it ends at the next radio event. In the example built with a Bluetooth beacon, on the DK, it ends at the next advertising event.
* In an earlier version of the example, encrypting one AES block on the ECB, which reads and writes through EasyDMA, ends it at once, whether the ECB's data was in RAM8 or below it.
It is drawn by the nRF52840 itself. On the DK, the current measurement covers the nRF52840's supply alone, without the QSPI flash: 400 µA at 3.0 V, against a 2 µA floor when the issue doesn't occur. The results for each build are in the example's README.
What I have done:
* Published a minimal example that reproduces the excess 0.4 mA on the development kit, and demonstrates the expected low sleep current with trivial program changes.
* Reproduced it with nRF Connect SDK v3.4.1 exactly as released, every repository at its manifest revision with no local changes.
* Confirmed the current difference is not due to any expected effect from the firmware. In the high-current state, read through the debugger: the QSPI peripheral is disabled with its pins in their sleep state, the flash is in deep power-down, and the peripheral enables, timers, PPI, GPIOTE, pin configuration and RAM power registers are the same as at the normal floor. It looks like this code is triggering some incorrect internal silicon state.
* Confirmed this is not anomaly 122. That errata documentation is light on details, it looks similar, but nrfx already applies the documented workaround at every disable (`nrf_qspi_disable()` in `hal/nrf_qspi.h`. Doubling up this workaround (in various ways) has no effect on this issue.
* Ruled out anomaly 276, which describes a similar 400 to 450 µA after the SAADC stops in scan mode: the example never enables the SAADC.
The chip on our module reads build code D0 (FICR INFO.VARIANT = AAD0), which is Revision 2
What I have not done:
* Confirmed that all of the code widgets written by Claude (for example the kconfig options to move stacks into different blocks of ram) have expected effect. But I have no specific reason to doubt.
At this point I have a workaround which involves copying every QSPI flash write through a buffer at a controlled RAM address. This appears to eliminate all problems, in the example and in our product. This workaround has proven solid (so far) so there is no urgency from our side, but it would be good to understand what is going on here.
Reproduction example is here: github.com/.../tailissue