pyocd / pyOCD

Open source Python library for programming and debugging Arm Cortex-M microcontrollers
https://pyocd.io
Apache License 2.0
1.11k stars 477 forks source link

PSoC6: gdb server broken on v0.28.0 onwards #995

Closed bohdan-tymkiv closed 3 years ago

bohdan-tymkiv commented 3 years ago

I've just noticed that gdb server is not usable with pyOCD master and PSoC6A-2M target. Any attempt to reset the target e.g. using 'monitor reset' command always leads to 'TransferError: No ACK received' exception and makes any further communication with the target impossible.

Short investigation showed that this if statement: https://github.com/pyocd/pyOCD/blob/aefed9151a37bf15a8ddf8222397bee089af2b37/pyocd/probe/shared_probe_proxy.py#L76-L78

Makes this a NO-OP: https://github.com/pyocd/pyOCD/blob/aefed9151a37bf15a8ddf8222397bee089af2b37/pyocd/target/family/target_psoc6.py#L64-L68

PSoC6 behavior is somewhat strange, even soft-reset via SYSRESETREQ causes partial reset of the DAP so it switches back to JTAG mode and contents of some DAP registers (e.g. TAR) gets lost. Full re-initialization of the DAP after Reset is a must with PSoC6 targets (JTAG-to-SWD, read IDCODE, power-up debug domain, etc). DAP re-initialization code can be found in numerous places in the family/target_psoc6.py file.

Removing this if statement https://github.com/pyocd/pyOCD/blob/aefed9151a37bf15a8ddf8222397bee089af2b37/pyocd/probe/shared_probe_proxy.py#L77 resolves the issue but I clearly understand that this is not a valid fix.

I will try to find a proper way to re-initialize the DAP on my own but I am not closely familiar with pyOCD architecture, any support will be appreciated.

Thanks in advance, Bohdan

flit commented 3 years ago

Hi @bohdan-tymkiv , thanks for reporting this and your investigation. Apologies for the unintended regression!

What's not clear is why this fails. Unless you are connecting to the probe server prior to connecting gdb, the _connect_count attribute should be equal to 1.

Regardless, there are obviously issues with the current shared probe proxy design. (There are also issues that can occur on disconnect.) I'll think about possible ways to improve it.

It might also be a good idea to have a more architected reconnect procedure, rather than simply re-initialising everything.

Btw, we will be relocating and rebuilding the pyocd (and DAPLink) CI setup soon, and I hope to get a PSoC6 board added. That should help prevent this kind of issue in the future.

bohdan-tymkiv commented 3 years ago

Hi @flit

The problem is that self._ap.dp.init() eventually calls SharedDebugProbeProxy.connect(), this will increase _connect_count by one making further calls to SharedDebugProbeProxy.swj_sequence() a no-op. This breaks communication if DAP switches back to JTAG mode after Reset. There are many targets out there which behave in this way, especially if hardware nSRST is used to reset the target.

The following code seems to be sufficient to reinitialize the DAP properly (at least it works with PSoC6A-2M) however, this looks to me like unnecessary code duplication.

if core.session.options.get('dap_swj_enable'):
    use_dormant = core.session.options.get('dap_swj_use_dormant')
    swj = SWJSequenceSender(core.ap.dp.probe, use_dormant)
    swj.select_protocol(core.ap.dp.probe.wire_protocol)

for ap in core.ap.dp.aps.values():
    ap.reset_did_occur()

core.ap.dp.probe.read_dp(DP_IDR, now=True)
core.ap.dp.clear_sticky_err()
core.ap.dp.power_up_debug()
core.flush()

There are several places where dp.init() + dp.power_up_debug() sequence is used, e.g.: https://github.com/pyocd/pyOCD/blob/master/pyocd/target/builtin/target_CC3220SF.py#L102-L103 https://github.com/pyocd/pyOCD/blob/master/pyocd/target/builtin/target_s5js100.py#L235-L236 https://github.com/pyocd/pyOCD/blob/master/pyocd/target/builtin/target_s5js100.py#L275-L276

There is a chance that support for these targets is now broken.

P.S. I will contact my manager to arrange delivery of several PSoC6 kits for you.

Bohdan

flit commented 3 years ago

Thanks for the details of the sequence. I agree that the solution above is unnecessary code duplication, especially since it needs to be done for multiple targets, as you've discovered. We really do need a way to cleanly re-establish the connection. I'll be working on a solution this weekend.

bohdan-tymkiv commented 3 years ago

Hi @flit Have you had a chance to look into this? I am about to submit PR with support for new secure PSoC64 chips but I do not know how to proceed further. Code functionality has been tested with DAP re-initialization code from my previous comment but if re-initialization method will change in mainline we will have to update the code and re-test everything.

Bohdan

flit commented 3 years ago

@bohdan-tymkiv Could you please verify that #1018 does indeed fix the reconnect issues with PSoC6? If not, please reopen this issue.