Recent ST-Link firmwares (J33,J34,J35) cannot access APs with APSEL>0
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.5k
- Forks
- 560
- Avg merge
- 1h 41m
- Merged PRs (30d)
- 3
Description
I am enabling APPROTECT (lockout main AP function in nrf52) in a production programming setup using pyOCD:
from pyocd.core.helpers import ConnectHelper
from pyocd.core.memory_map import FlashRegion
from pyocd.flash.flash import Flash
with ConnectHelper.session_with_chosen_probe(target_override="nrf52") as session:
target = session.board.target
target.reset_and_halt()
fl = FlashLoader(session)
mmap = target.memory_map
uicr2 = FlashRegion(start=0x10001200, end=0x1000120f, blocksize=0x10, is_testable=False)
uicr2.flash = Flash(target, mmap.get_boot_memory().algo)
uicr2.flash.region = uicr2
mmap.add_region(uicr2)
fl.add_data(APPROTECT_REG, b'\x00')
fl.commit()
It's a little dance to dynamically add the second page (?) of the UICR to the memory map. I wasn't sure how to upstream this (poorly documented) memory region. It's not clear if it is a second page / can be erased separately, why the address gap with the rest of the UICR, what happens if pyOCD tries to write/erase the gap, &c. This hack works well enough for a write once operation.
I also added a way to check if the chip is locked out:
def nrf52_locked():
session = start_uninit_session()
target = session.board.target
locked = not target.dp.read_ap(1 << 24 | 0xc)
session.close()
return locked
and several functions that should work while the nrf52 is locked (via CTRL-AP @1):
def recover():
session = start_uninit_session()
target = session.board.target
target.dp.init()
target.dp.power_up_debug()
target.dp.write_ap(1 << 24 | 4, 1)
while target.dp.read_ap(1 << 24 | 8):
sleep(0.1)
_ctrl_ap_reset(session)
session.close()
def _ctrl_ap_reset(session=None):
if not session:
session = start_uninit_session()
target = session.board.target
target.dp.write_ap(1 << 24 | 0, 1)
sleep(0.001)
target.dp.write_ap(1 << 24 | 0, 0)
This works as intended with ST-Link v2 firmware 2J29S7, but with later firmwares (including all of those still available for download from ST (2J33xx, 2J34xx, 2J35xx) have stopped working.
The ST-Link has started returning JTAG_NO_DEVICE_CONNECTED when running either JTAG_WRITE_DAP_REG or JTAG_READ_DAP_REG even when the address is on another unlocked AP.
I looked into the pyOCD probe driver, but the ST-Link protocol is very high level. I can't imagine there's a way to work around this. It's still submitting the correct commands to the probe... I think it's a regression in the firmware; but I don't know how to proceed (I'm not a big ST customer).
It's currently sufficient for us to remain at 2J29S7 for our v2 probes, but v3 probes are similarly broken and I'm unaware of a working firmware version for that hardware.
Please advise.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the pyOCD probe driver and its high-level ST-Link protocol handling. Reproduce the DAP register failures with firmware 2J29S7 and later 2J33–2J35 versions, including access to APSEL>0. Done would be a confirmed regression analysis with a documented workaround or an actionable upstream path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools, embedded-iot
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100