zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.77k stars 6.57k forks source link

west: nrfjprog and jlink runner leave SW-DP registers in enabled state #26139

Closed JordanYates closed 4 years ago

JordanYates commented 4 years ago

Describe the bug After running west flash, the jlink and nrfjprog runners leave the Coresight debug hardware enabled. This increases idle current consumption by 1.6mA. The hardware remains enabled until either the debugger manually disables it, or a hard power reset. Note that a pin reset (nrfjprog -p) does not resolve the issue, as the CTRL/STAT register is only reset on POWERUP. Furthermore, because the SW-DP registers cannot be accessed by the CPU, an application has no way of detecting or recovering from this condition.

The debug interface can be disabled by writing 0 to the CTRL/STAT register (writeDP 1 0 using JLink.exe) The following .jlink script resolves the issue at runtime for demonstration purposes.

si 1
speed 4000
connect
writeDP 1 0
writeDP 1 0
exit

Run by: JLink.exe -device NRF52840_XXAA -CommandFile debugoff.jlink

To Reproduce Steps to reproduce the behavior:

  1. west build
  2. west flash
  3. Observe power consumption

Expected behavior Debug mode should not be enabled after flashing.

Impact Significant, in some situations it is not feasible to power cycle a device after programming (soldered on batteries).

Screenshots or console output Included is a screenshot of the power consumption of a running program. The drop is when the above jlink script is run. SWDP_Disabling

Resolution For the jlink runner, this issue can be resolved by adding the following lines to the autogenerated command file:

        lines.append('g') # Start the CPU

        lines.append('writeDP 1 0') # Disable Coresight Debug
        lines.append('writeDP 1 0') # Second write because the first does not stick

        lines.append('q') # Close the connection and quit

For unknown reasons, the first write does not stick. The second write has not been observed to fail.

For nrfjprog, I am unsure of the resolution. The runner does not create a command file, and the nrfjprog command line tool does not provide the facility to write to these register AFAICT. pynrfjprog does allow this via write_debug_port_register.

Register Reference: https://developer.arm.com/docs/100536/0302/about-the-programmers-model/dap-registers/jtag-dp-registers

carlescufi commented 4 years ago

@simtind I would very much appreciate your input here

simtind commented 4 years ago

It's natural for J-Link to do this if your J-Link script sets up debug power manually. If you set it up, you clean it in a way.

For nrfjprog, this is a bug that was recently fixed in 10.9.0, actually caused by the tool trying to check if debug power needed to be disabled. The check could cause debug power to get reenabled. Please check if 10.9.0 solves the issue.

JordanYates commented 4 years ago

RE: nrfjprog runner: @simtind Thanks for the input. I have updated nrfjprog to 10.9.0 and the issue is still present.

C:\Users\Jordan\code\zephyr>nrfjprog --version
nrfjprog version: 10.9.0
JLinkARM.dll version: 6.80a

Interestingly, performing a pinreset actually turns the debug module back on, if I manually fix the issue with the above script and then run it via nrfjprog -p .

JordanYates commented 4 years ago

RE: jlink runner: As additional context, I have worked out this morning that the debug mode is only left enabled when another instance of a JLink tool is running in the background (SEGGER J-Link Remote Server for example). Presumably the DLL is checking to see if anyone else has the DLL loaded, and if so not changing the power state. Simply loading one of these tools after the application is running does not enable the debug hardware.

carlescufi commented 4 years ago

RE: jlink runner: As additional context, I have worked out this morning that the debug mode is only left enabled when another instance of a JLink tool is running in the background (SEGGER J-Link Remote Server for example). Presumably the DLL is checking to see if anyone else has the DLL loaded, and if so not changing the power state. Simply loading one of these tools after the application is running does not enable the debug hardware.

Does this mean that 10.9.0 indeed fixes the problem unless there's another instance running?

JordanYates commented 4 years ago

Does this mean that 10.9.0 indeed fixes the problem unless there's another instance running?

No, after a clean reboot, west flash -d build\board\app results in 1.6mA with nrfprog as the default runner. west flash -d build\board\app -r jlink drops it back to the appropriate 300uA. The multiple instance comment only appears to apply to the jlink runner.

carlescufi commented 4 years ago

OK so here is the sequences that west flash applies:;

west flash:

nrfjprog --program /home/carles/src/zephyr/zephyr/build/zephyr/zephyr.hex -f NRF52 --snr 683182989 --sectoranduicrerase
nrfjprog --pinresetenable -f NRF52 --snr 683182989
nrfjprog --pinreset -f NRF52 --snr 683182989

west flash --erase:

nrfjprog --eraseall -f NRF52 --snr 683182989
nrfjprog --program /home/carles/src/zephyr/zephyr/build/zephyr/zephyr.hex -f NRF52 --snr 683182989
nrfjprog --pinresetenable -f NRF52 --snr 683182989
nrfjprog --pinreset -f NRF52 --snr 683182989

@simtind should the sequences above leave the debug port enabled, when using nrfjprog 10.9.0?

JordanYates commented 4 years ago

As I noted previously, the pinreset command by itself (nrfjprog -p) is enough to turn the debug port back on.

anangl commented 4 years ago

As I noted previously, the pinreset command by itself (nrfjprog -p) is enough to turn the debug port back on.

I can confirm the above. Observed using nrfjprog 10.9.0. But if I do nrfjprog -r, the current consumption is as expected.

carlescufi commented 4 years ago

@simtind could you confirm if nrfjprog -p turning the debug port on is a bug in nrfjprog?

simtind commented 4 years ago

@JordanYates, can you elaborate on what the other jlink sessions are doing? If it's connected to the debug probe in any way, the current behavior is expected. In that case nrfjprog / the jlink script is not the owner of the debug power up request, and therefore shouldn't power it down. The other session may also be doing stuff to actively keep the request live.

I've asked the Nordic HW engineers to confirm that the reset pin resets the debug port ctrl/stat register. The current assumption in nrfjprog is that pin reset resets the entire debug system (including the debug port), and therefore the device should not be touched after the pin reset is performed. That's the reason behind the difference between nrfjprog -r (system reset, nrfjprog does explicit cleanup on exit) and nrfjprog -p (pin reset, chip is already clean, so nrfjprog just tears down the PC side of the connection).

JordanYates commented 4 years ago

@simtind For nrfjprog -p, the debug port is enabled whether other jlink tools are running or not. Normally, nrfjprog -r will correctly reset the chip with the DP disabled.

However nrfjprog -r will also leave the DP enabled if another instance of jlink tools are running. This appears to be the same problem that was affecting the jlink runner.

My standard test case at this point is to run SEGGER J-Link Remote Server. By itself, the program does nothing beyond confirming that a debug adapter is connected. This can be confirmed by starting that program with the debug adapter not physically connected to anything.

If the remote server is closed, the behavior of nrfjprog -r reverts to disabling the DP.

simtind commented 4 years ago

Hm, I seem to be unable to reproduce your results. Below are power traces taken from a nRF52840-dk v0.10.0 using a 15Ohm resistor and a Digilent Analog Discovery.

After a power cycle: nRF52 power cycle

Pin reset (nrfjprog -p): nRF52 pin reset

System reset (nrfjprog -r): nRF52 sys reset

Debug reset (nrfjprog -d): nRF52 debug reset

The device actually looks like it starts with around 3.5mA of current, only dropping to around 2.5mA after a pin reset. Looks like we have an issue with system reset, it is taking us back up to 3.5mA, but pin reset worked correctly in my tests.

The high base current draw can be explained by the device being completely empty, so the cpu is running in a lockup loop. The low section during system reset is probably the cpu being halted.

simtind commented 4 years ago

Does look like the system reset call is modified by having a jlink remote server running, but I could not see any change in pin reset behavior. Pin reset with remote server running: nRF52 pin reset with remote

Sys reset with remote running, now actually goes back to 2.5mA: nRF52 sys reset with remote

simtind commented 4 years ago

Interesting, actually putting a program on the device changes things. I compiled and programmed the folowing simple program using Segger Embedded Studio:

void main(void) {
  int i;

  do {
    __WFE();
  } while (1);
}

Now I get the following readings: Bootup: nRF52 power cycle with program

Pin reset: nRF52 pin reset with program

Sys reset: nRF52 sys reset with program

Debug reset: nRF52 debug reset with program

This is clearly a bug in nrfjprog, we'll have to take a closer look.

github-actions[bot] commented 4 years ago

This issue has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this issue will automatically be closed in 14 days. Note, that you can always re-open a closed issue at any time.