Skip to content

Commit 2889387

Browse files
committed
Fix RTT auto-detection for nRF54L15 and similar devices
- Add search_ranges parameter to rtt_start() for custom RTT search ranges - Add reset_before_start parameter for devices requiring reset - Auto-generate search ranges from device RAM info when available - Ensure RTT is fully stopped before starting (clean state) - Re-confirm device name is set correctly for auto-detection - Use correct (start, size) format for SetRTTSearchRanges per UM08001 - Improve polling mechanism with exponential backoff - Only resume device if definitely halted, trust RTT Viewer behavior otherwise Fixes #249, addresses #209
1 parent 8f40e8c commit 2889387

File tree

3 files changed

+387
-31
lines changed

3 files changed

+387
-31
lines changed

BUG_REPORT_ISSUE_249.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Bug Report for Issue #249
2+
3+
## Environment
4+
5+
- **Operating System**: macOS 24.6.0 (Darwin)
6+
- **J-Link Model**: SEGGER J-Link Pro V4
7+
- **J-Link Firmware**: V4 compiled Sep 22 2022 15:00:37
8+
- **Python Version**: 3.x
9+
- **pylink-square Version**: Latest master branch
10+
- **Target Device**: Seeed Studio nRF54L15 Sense (Nordic nRF54L15 microcontroller)
11+
- **Device RAM**: Start: 0x20000000, Size: 0x00040000 (256 KB)
12+
- **RTT Control Block Address**: 0x200044E0 (verified with SEGGER RTT Viewer)
13+
14+
## Expected Behavior
15+
16+
The `rtt_start()` method should successfully auto-detect the RTT control block on the nRF54L15 device, similar to how SEGGER's RTT Viewer successfully detects and connects to RTT.
17+
18+
Expected flow:
19+
1. Call `jlink.rtt_start()` without parameters
20+
2. Method should automatically detect RTT control block
21+
3. `rtt_get_num_up_buffers()` should return a value greater than 0
22+
4. RTT data can be read from buffers
23+
24+
## Actual Behavior
25+
26+
The `rtt_start()` method fails to auto-detect the RTT control block, raising a `JLinkRTTException`:
27+
28+
```
29+
pylink.errors.JLinkRTTException: The RTT Control Block has not yet been found (wait?)
30+
```
31+
32+
This occurs even though:
33+
- The device firmware has RTT enabled and working (verified with RTT Viewer)
34+
- The RTT control block exists at address 0x200044E0
35+
- SEGGER RTT Viewer successfully connects and reads RTT data
36+
- The device is running and connected via J-Link
37+
38+
## Steps to Reproduce
39+
40+
1. Connect J-Link to nRF54L15 device
41+
2. Flash firmware with RTT enabled
42+
3. Verify RTT works with SEGGER RTT Viewer (optional but recommended)
43+
4. Run the following Python code:
44+
45+
```python
46+
import pylink
47+
48+
jlink = pylink.JLink()
49+
jlink.open()
50+
jlink.connect('NRF54L15_M33', verbose=False)
51+
52+
# This fails with JLinkRTTException
53+
jlink.rtt_start()
54+
55+
# Never reaches here
56+
num_up = jlink.rtt_get_num_up_buffers()
57+
print(f"Found {num_up} up buffers")
58+
```
59+
60+
5. The exception is raised during `rtt_start()` call
61+
62+
## Workaround
63+
64+
Manually set RTT search ranges before calling `rtt_start()`:
65+
66+
```python
67+
jlink.exec_command("SetRTTSearchRanges 20000000 2003FFFF")
68+
jlink.rtt_start()
69+
```
70+
71+
This workaround works, but requires manual configuration and device-specific knowledge.
72+
73+
## Root Cause Analysis
74+
75+
The issue appears to be that `rtt_start()` does not configure RTT search ranges before attempting to start RTT. Some devices, particularly newer ARM Cortex-M devices like the nRF54L15, require explicit search ranges to be set via the `SetRTTSearchRanges` J-Link command.
76+
77+
The J-Link API provides device RAM information via `JLINK_DEVICE_GetInfo()`, which returns `RAMAddr` and `RAMSize`. This information could be used to automatically generate appropriate search ranges, but the current implementation does not do this.
78+
79+
## Additional Information
80+
81+
- **RTT Viewer Configuration**: RTT Viewer uses search range `0x20000000 - 0x2003FFFF` for this device
82+
- **Related Issues**: This may also affect other devices that require explicit search range configuration
83+
- **Impact**: Prevents automated RTT logging in CI/CD pipelines or automated test environments where RTT Viewer's GUI is not available
84+
85+
## Proposed Solution
86+
87+
Enhance `rtt_start()` to:
88+
1. Automatically generate search ranges from device RAM info when available
89+
2. Allow optional `search_ranges` parameter for custom ranges
90+
3. Add polling mechanism to wait for RTT control block initialization
91+
4. Ensure device is running before starting RTT
92+
93+
This would make the method work out-of-the-box for devices like nRF54L15 while maintaining backward compatibility.
94+

README_PR_fxd0h.md

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
# Pull Request: Improve RTT Auto-Detection for nRF54L15 and Similar Devices
2+
3+
## Motivation
4+
5+
The `rtt_start()` method in pylink-square was failing to auto-detect the RTT (Real-Time Transfer) control block on certain devices, specifically the nRF54L15 microcontroller. While SEGGER's RTT Viewer successfully detects and connects to RTT on these devices, pylink's implementation was unable to find the control block, resulting in `JLinkRTTException: The RTT Control Block has not yet been found (wait?)` errors.
6+
7+
This issue affects users who want to use pylink for automated RTT logging and debugging, particularly in CI/CD pipelines or automated test environments where RTT Viewer's GUI is not available.
8+
9+
## Problem Analysis
10+
11+
### Root Causes Identified
12+
13+
1. **Missing Search Range Configuration**: The original `rtt_start()` implementation did not configure RTT search ranges before attempting to start RTT. Some devices, particularly newer ARM Cortex-M devices like the nRF54L15, require explicit search ranges to be set via the `SetRTTSearchRanges` J-Link command.
14+
15+
2. **Insufficient Device State Management**: The implementation did not ensure the target device was running before attempting to start RTT. RTT requires an active CPU to function properly.
16+
17+
3. **Lack of Polling Mechanism**: After sending the RTT START command, the original code did not poll for RTT readiness. Some devices need time for the J-Link library to locate and initialize the RTT control block in memory.
18+
19+
4. **No Auto-Generation of Search Ranges**: When search ranges were not provided, the code made no attempt to derive them from device information available through the J-Link API.
20+
21+
### Device-Specific Findings
22+
23+
For the nRF54L15 device:
24+
- RAM Start Address: `0x20000000`
25+
- RAM Size: `0x00040000` (256 KB)
26+
- Required Search Range: `0x20000000 - 0x2003FFFF` (matches RTT Viewer configuration)
27+
- RTT Control Block Location: `0x200044E0` (within the search range)
28+
29+
The J-Link API provides device RAM information via `JLINK_DEVICE_GetInfo()`, which returns `RAMAddr` and `RAMSize`. This information can be used to automatically generate appropriate search ranges.
30+
31+
## Solution
32+
33+
### Changes Implemented
34+
35+
The `rtt_start()` method has been enhanced with the following improvements:
36+
37+
1. **New Optional Parameters**:
38+
- `search_ranges`: List of tuples specifying (start, end) address ranges for RTT control block search
39+
- `reset_before_start`: Boolean flag to reset the device before starting RTT
40+
41+
2. **Automatic Search Range Generation**:
42+
- When `search_ranges` is not provided, the method now automatically generates search ranges from device RAM information obtained via the J-Link API
43+
- Uses the full RAM range: `ram_start` to `ram_start + ram_size - 1`
44+
- Falls back to a 64KB range if RAM size information is unavailable
45+
46+
3. **Device State Management**:
47+
- Ensures RTT is fully stopped before starting (multiple stop calls for clean state)
48+
- Re-confirms device name is set correctly (required for auto-detection per SEGGER KB)
49+
- Checks if the device is halted and resumes it if necessary
50+
- Uses direct DLL calls (`JLINKARM_IsHalted()`, `JLINKARM_Go()`) for more reliable state checking
51+
- Only resumes device if definitely halted (`is_halted == 1`), trusts RTT Viewer behavior for ambiguous states
52+
53+
4. **Polling Mechanism**:
54+
- After sending the RTT START command, waits 0.5 seconds for initialization
55+
- Polls `rtt_get_num_up_buffers()` with exponential backoff (0.05s to 0.5s intervals)
56+
- Maximum wait time of 10 seconds
57+
- Verifies buffers persist before returning (double-check for stability)
58+
- Returns immediately when RTT buffers are detected and verified
59+
60+
5. **Backward Compatibility**:
61+
- All new parameters are optional with sensible defaults
62+
- Existing code using `rtt_start()` or `rtt_start(block_address)` continues to work unchanged
63+
- The method maintains the same return value and exception behavior
64+
65+
### Code Changes
66+
67+
The implementation adds approximately 100 lines to the `rtt_start()` method in `pylink/jlink.py`, including:
68+
- Device state verification and resume logic
69+
- Search range configuration via `exec_command("SetRTTSearchRanges ...")`
70+
- Polling loop with timeout handling
71+
- Comprehensive error handling
72+
73+
## Testing
74+
75+
### Test Environment
76+
77+
- Hardware: Seeed Studio nRF54L15 Sense development board
78+
- J-Link: SEGGER J-Link Pro V4
79+
- Firmware: Zephyr RTOS with RTT enabled
80+
- Python: 3.x
81+
- pylink-square: Latest master branch
82+
83+
### Test Scenarios
84+
85+
All tests were performed with the device running firmware that has RTT enabled and verified working with SEGGER RTT Viewer.
86+
87+
1. **Auto-Detection Test**:
88+
- Call `rtt_start()` without parameters
89+
- Verify automatic search range generation from device RAM info
90+
- Confirm RTT buffers are detected
91+
92+
2. **Explicit Search Ranges Test**:
93+
- Call `rtt_start(search_ranges=[(0x20000000, 0x2003FFFF)])`
94+
- Verify custom ranges are used
95+
- Confirm RTT buffers are detected
96+
97+
3. **Specific Address Test**:
98+
- Call `rtt_start(block_address=0x200044E0)`
99+
- Verify specific control block address is used
100+
- Confirm RTT buffers are detected
101+
102+
4. **Backward Compatibility Test**:
103+
- Call `rtt_start()` with no parameters (original API)
104+
- Verify existing code continues to work
105+
- Confirm RTT buffers are detected
106+
107+
5. **Reset Before Start Test**:
108+
- Call `rtt_start(reset_before_start=True)`
109+
- Verify device reset occurs before RTT start
110+
- Confirm RTT buffers are detected
111+
112+
6. **Combined Parameters Test**:
113+
- Call `rtt_start()` with multiple optional parameters
114+
- Verify all parameters work together correctly
115+
- Confirm RTT buffers are detected
116+
117+
7. **RTT Data Read Test**:
118+
- Start RTT successfully
119+
- Read data from RTT buffers
120+
- Verify data can be retrieved
121+
122+
### Test Results
123+
124+
All 7 test scenarios passed successfully:
125+
- Auto-detection: PASS
126+
- Explicit ranges: PASS
127+
- Specific address: PASS
128+
- Backward compatibility: PASS
129+
- Reset before start: PASS
130+
- Combined parameters: PASS
131+
- RTT data read: PASS
132+
133+
### Comparison with RTT Viewer
134+
135+
The implementation now matches RTT Viewer's behavior:
136+
- Uses the same search range: `0x20000000 - 0x2003FFFF` for nRF54L15
137+
- Detects the same control block address: `0x200044E0`
138+
- Successfully establishes RTT connection and reads data
139+
140+
## Technical Details
141+
142+
### Search Range Configuration
143+
144+
The `SetRTTSearchRanges` command is executed via `exec_command()` before calling `JLINK_RTTERMINAL_Control(START)`. According to SEGGER UM08001 documentation, the command format is:
145+
```
146+
SetRTTSearchRanges <start_addr> <size>
147+
```
148+
149+
Note: The format is `(start, size)`, not `(start, end)`. The implementation converts `(start, end)` tuples to `(start, size)` format internally.
150+
151+
For nRF54L15, this becomes:
152+
```
153+
SetRTTSearchRanges 20000000 40000
154+
```
155+
156+
Where `0x40000` is the size (256 KB) of the RAM range starting at `0x20000000`.
157+
158+
### Polling Implementation
159+
160+
The polling mechanism uses exponential backoff:
161+
- Initial interval: 0.1 seconds
162+
- Maximum interval: 0.5 seconds
163+
- Growth factor: 1.5x per iteration
164+
- Maximum wait time: 10 seconds
165+
166+
The polling checks `rtt_get_num_up_buffers()` which internally calls `JLINK_RTTERMINAL_Control(GETNUMBUF)`. When this returns a value greater than 0, RTT is considered ready.
167+
168+
### Error Handling
169+
170+
The implementation handles several error scenarios gracefully:
171+
- Device state cannot be determined: Assumes device is running and proceeds
172+
- Search range configuration fails: Continues with RTT start attempt
173+
- Device connection state unclear: Proceeds optimistically (RTT Viewer works in similar conditions)
174+
175+
For auto-detection mode (no `block_address` specified), if polling times out, the method returns without raising an exception, allowing the caller to implement fallback strategies. If `block_address` is specified and polling times out, a `JLinkRTTException` is raised.
176+
177+
## Backward Compatibility
178+
179+
This change is fully backward compatible:
180+
- Existing code using `rtt_start()` continues to work
181+
- Existing code using `rtt_start(block_address)` continues to work
182+
- No breaking changes to the API
183+
- All new functionality is opt-in via optional parameters
184+
185+
## Related Issues
186+
187+
This PR addresses:
188+
- Issue #249: RTT auto-detection fails on nRF54L15
189+
- Issue #209: RTT search ranges not configurable
190+
191+
## Code Quality
192+
193+
- Follows pylink-square coding conventions (Google Python Style Guide)
194+
- Maximum line length: 120 characters
195+
- Comprehensive docstrings with Args, Returns, and Raises sections
196+
- No linter errors
197+
- Uses only existing J-Link APIs (no external dependencies)
198+
- No XML parsing or file system access
199+
200+
## Future Considerations
201+
202+
While this implementation solves the immediate problem, future enhancements could include:
203+
- Device-specific search range presets for common devices
204+
- Configurable polling timeout
205+
- More sophisticated device state detection
206+
- Support for multiple simultaneous RTT connections
207+
208+
However, these enhancements are beyond the scope of this PR and can be addressed in future contributions.
209+
210+
## Conclusion
211+
212+
This PR improves RTT auto-detection reliability for devices that require explicit search range configuration, particularly the nRF54L15. The changes are minimal, backward-compatible, and follow pylink-square's design principles of using existing J-Link APIs without adding external dependencies.
213+
214+
The implementation has been tested and verified to work correctly with the nRF54L15 device, matching the behavior of SEGGER's RTT Viewer.
215+

0 commit comments

Comments
 (0)