emdbg.debug.jlink

J-Link Debug Probe

The J-Link debug probe is a closed-source, commercial hardware probe which supports almost all Cortex-M devices.

Command Line Interface

Common tasks are wrapped in a simple Python CLI. For more complex use-cases, use the J-Link drivers directly.

Reset the device remotely:

python3 -m emdbg.debug.jlink -device STM32F765II reset

Run the JLinkGDBServer as a blocking process

python3 -m emdbg.debug.jlink -device STM32F765II run

Upload firmware to a device:

python3 -m emdbg.debug.jlink -device STM32F765II upload --source path/to/firmware.elf
python3 -m emdbg.debug.jlink -device STM32F765II upload --source path/to/firmware.bin --load-addr 0x08008000

Connect to RTT channel 0 for up- and downlink. Opens a telnet client that can be terminated with Ctrl+D.

python3 -m emdbg.debug.jlink -device STM32F765II rtt --channel 0

Output log output over ITM port 1 at 4MHz

python3 -m emdbg.debug.jlink -device STM32F765II itm --channel 1 --baudrate 4000000

Installation

You need to have the J-Link drivers installed for this module to work:

Ubuntu

wget --post-data "accept_license_agreement=accepted" https://www.segger.com/downloads/jlink/JLink_Linux_x86_64.deb
sudo dpkg -i JLink_Linux_x86_64.deb

macOS

brew install segger-jlink
  1# Copyright (c) 2023, Auterion AG
  2# SPDX-License-Identifier: BSD-3-Clause
  3
  4"""
  5.. include:: jlink.md
  6"""
  7
  8from __future__ import annotations
  9import os
 10import time
 11import signal
 12import platform
 13import subprocess
 14import logging
 15import tempfile
 16from pathlib import Path
 17
 18from .backend import ProbeBackend
 19from . import gdb
 20
 21LOGGER = logging.getLogger("debug:jlink")
 22
 23
 24# -----------------------------------------------------------------------------
 25class JLinkBackend(ProbeBackend):
 26    """
 27    J-Link specific debug backend implementation. Starts the `JLinkGDBServer` in
 28    its own subprocess and connects GDB to port `2331` of the localhost.
 29
 30    See `call()` for additional information.
 31    """
 32    def __init__(self, device: str, speed: int, serial: str = None, rtos: Path = None):
 33        """
 34        :param device: part name of the microcontroller to debug.
 35        :param speed: SWD connection baudrate in kHz.
 36        :param serial: Serial number of J-Link for selection.
 37        :param rtos: Path to RTOS plugin for thread-aware debugging.
 38        """
 39        super().__init__(":2331")
 40        self.device = device
 41        self.speed = speed
 42        self.serial = serial
 43        self.rtos = rtos
 44        self.process = None
 45        self.name = "jlink"
 46
 47    def start(self):
 48        self.process = call(self.device, self.speed, self.serial, self.rtos,
 49                            blocking=False, silent=True)
 50        LOGGER.info(f"Starting {self.process.pid}...")
 51
 52    def stop(self):
 53        if self.process is not None:
 54            LOGGER.info(f"Stopping {self.process.pid}.")
 55            os.killpg(os.getpgid(self.process.pid), signal.SIGINT)
 56            os.waitpid(os.getpgid(self.process.pid), 0)
 57            self.process = None
 58
 59
 60# -----------------------------------------------------------------------------
 61def call(device: str, speed: int, serial: str = None, rtos: Path = None,
 62         blocking: bool = True, silent: bool = False) -> "int | subprocess.Popen":
 63    """
 64    Starts the `JLinkGDBServer` and connects to the microcontroller without
 65    resetting the device and without GUI. You can overwrite the default binary
 66    by exporting an alternative in your environment:
 67
 68    ```sh
 69    export PX4_JLINK_GDB_SERVER=path/to/JLinkGDBServer
 70    ```
 71
 72    :param device: part name of the microcontroller to debug.
 73    :param speed: SWD connection baudrate in kHz.
 74    :param serial: Serial number of J-Link for selection.
 75    :param rtos: Path to RTOS plugin for thread-aware debugging.
 76    :param blocking: Run in current process as a blocking call.
 77                     Set to `False` to run in a new subprocess.
 78    :param silent: Disable any reporting from `JLinkGDBServer`.
 79
 80    :return: The process return code if `blocking` or the Popen object.
 81    """
 82    binary = os.environ.get("PX4_JLINK_GDB_SERVER", "JLinkGDBServer")
 83
 84    command_jlink = f"{binary} -device {device} -speed {speed} -if swd -noreset -nogui"
 85    if serial: command_jlink += f" -SelectEmuBySN {serial}"
 86    if rtos: command_jlink += f" -rtos {Path(rtos).absolute()}"
 87    if silent: command_jlink += " -silent"
 88
 89    LOGGER.debug(command_jlink)
 90
 91    kwargs = {"cwd": os.getcwd(), "shell": True}
 92    if blocking:
 93        return subprocess.call(command_jlink, **kwargs)
 94
 95    # Disconnect the JLink process from this process, so that any Ctrl-C usage
 96    # in GDB does not get passed on to the JLink process.
 97    kwargs["start_new_session"] = True
 98    return subprocess.Popen(command_jlink, **kwargs)
 99
100
101# -----------------------------------------------------------------------------
102def itm(device: str, baudrate: int = None, port: int = None, serial: str = None) -> int:
103    """
104    Launches `JLinkSWOViewer`, connects to the microcontroller. You can
105    overwrite the default binary by exporting an alternative in your environment:
106
107    ```sh
108    export PX4_JLINK_SWO_VIEWER=path/to/JLinkSWOViewer
109    ```
110
111    :param device: part name of the microcontroller to debug.
112    :param baudrate: optional frequency of the SWO connection.
113    :param port: ITM port to display at startup. You can modify this at runtime.
114    :param serial: Serial number of J-Link for selection.
115
116    :return: the process return code
117    """
118    binary = os.environ.get("PX4_JLINK_SWO_VIEWER", "JLinkSWOViewer")
119    command_jlink = f"{binary} -device {device} -itmport {port or 0}"
120    if baudrate: command_jlink += f" -swofreq {baudrate}"
121    try:
122        return subprocess.call(command_jlink, shell=True)
123    except KeyboardInterrupt:
124        pass
125
126
127def rtt(backend: JLinkBackend, channel: int = 0) -> int:
128    """
129    Launches the backend in the background and connects a telnet client to the
130    Real-Time Transfer process. You can disconnect with Ctrl+D.
131
132    :param backend: A J-Link backend object.
133    :param channel: The RTT channel to connect to.
134
135    :return: the process return code
136    """
137    import telnetlib
138    # Start JLinkGDBServer in the background
139    with backend.scope():
140        with telnetlib.Telnet("localhost", 19021) as tn:
141            try:
142                tn.interact()
143            except KeyboardInterrupt:
144                pass
145    return 0
146
147# -----------------------------------------------------------------------------
148def erase(device: str, speed: int, address_range: tuple[int, int] = None,
149          serial: str = None) -> int:
150    """
151    Erases (part of) the device via JLink.
152
153    :param device: part name of the microcontroller to program. You can
154                   overwrite the default binary by exporting an alternative in
155                   your environment:
156                   ```sh
157                   export PX4_JLINK=path/to/JLinkExe
158                   ```
159    :param speed: SWD connection baudrate in kHz.
160    :param address_range: Optional [start, end] address to erase only part of device.
161    :param serial: Serial number of J-Link for selection.
162
163    :return: the process return code of JLink
164    """
165    binary = os.environ.get("PX4_JLINK", "JLinkExe")
166    if address_range is not None:
167        address_range = f"{address_range[0]} {address_range[1]}"
168    with tempfile.NamedTemporaryFile() as fcmd:
169        commands = f"Erase {address_range or ''}\nExit"
170        Path(fcmd.name).write_text(commands)
171        jcmd = f"{binary} -device {device} -speed {speed} -ExitOnError 1 " \
172               f"-if swd -autoconnect 1 -nogui 1 -commandfile {fcmd.name}"
173        if serial: jcmd += f" -SelectEmuBySN {serial}"
174        LOGGER.debug(f"{jcmd}\n{commands}")
175        return subprocess.call(jcmd, shell=True)
176
177def program(source: Path, device: str, speed: int, serial: str = None, load_addr: int = None) -> int:
178    """
179    Loads the source file into the microcontroller and resets the device. You can
180    overwrite the default binary by exporting an alternative in your environment:
181
182    ```sh
183    export PX4_JLINK=path/to/JLinkExe
184    ```
185
186    :param source: path to a `.bin`, `.hex`, or `.elf` file to upload.
187    :param device: part name of the microcontroller to program.
188    :param speed: SWD connection baudrate in kHz.
189    :param serial: Serial number of J-Link for selection.
190    :param load_addr: Specifies the start address to load a `.bin` file.
191
192    :return: the process return code of JLink
193    """
194    binary = os.environ.get("PX4_JLINK", "JLinkExe")
195    if load_addr is None and Path(source).suffix == ".bin":
196        load_addr = 0x0800_0000
197    with tempfile.NamedTemporaryFile() as fcmd:
198        # LoadFile erases the correct amount of sectors, then writes the new
199        # binary or hex file. We still need to reset afterwards.
200        commands = f"LoadFile {source} {load_addr or ''}\nReset\nExit"
201        Path(fcmd.name).write_text(commands)
202        jcmd = f"{binary} -device {device} -speed {speed} -ExitOnError 1 " \
203               f"-if swd -autoconnect 1 -nogui 1 -commandfile {fcmd.name}"
204        if serial: jcmd += f" -SelectEmuBySN {serial}"
205        LOGGER.debug(f"{jcmd}\n{commands}")
206        return subprocess.call(jcmd, shell=True)
207
208def reset(device: str, speed: int, serial: str = None) -> int:
209    """
210    Resets the device via JLink.
211
212    :param device: part name of the microcontroller to program. You can
213                   overwrite the default binary by exporting an alternative in
214                   your environment:
215                   ```sh
216                   export PX4_JLINK=path/to/JLinkExe
217                   ```
218    :param speed: SWD connection baudrate in kHz.
219    :param serial: Serial number of J-Link for selection.
220
221    :return: the process return code of JLink
222    """
223    binary = os.environ.get("PX4_JLINK", "JLinkExe")
224    with tempfile.NamedTemporaryFile() as fcmd:
225        commands = "Reset\nExit"
226        Path(fcmd.name).write_text(commands)
227        jcmd = f"{binary} -device {device} -speed {speed} -ExitOnError 1 " \
228               f"-if swd -autoconnect 1 -nogui 1 -commandfile {fcmd.name}"
229        if serial: jcmd += f" -SelectEmuBySN {serial}"
230        LOGGER.debug(f"{jcmd}\n{commands}")
231        return subprocess.call(jcmd, shell=True)
232
233
234# -----------------------------------------------------------------------------
235def _add_subparser(subparser):
236    parser = subparser.add_parser("jlink", help="Use JLink as Backend.")
237    parser.add_argument(
238            "-device",
239            required=True,
240            help="Connect to this device.")
241    parser.add_argument(
242            "-speed",
243            type=int,
244            default=12000,
245            help="SWO baudrate in kHz.")
246    parser.add_argument(
247            "-serial",
248            default=None,
249            help="Serial of the J-Link.")
250    parser.set_defaults(backend=lambda args: JLinkBackend(args.device, args.speed, args.serial))
251    return parser
252
253
254# -----------------------------------------------------------------------------
255if __name__ == "__main__":
256    import argparse
257    import emdbg
258
259    parser = argparse.ArgumentParser(
260        description="JLink debug probe: Upload, reset, and logging")
261    parser.add_argument(
262        "-device",
263        required=True,
264        help="Connect to this device.")
265    parser.add_argument(
266        "-speed",
267        type=int,
268        default=12000,
269        help="SWD baudrate in kHz.")
270    parser.add_argument(
271        "-serial",
272        default=None,
273        help="Serial of the J-Link.")
274    parser.add_argument(
275        "-v",
276        dest="verbosity",
277        action="count",
278        help="Verbosity level.")
279
280    subparsers = parser.add_subparsers(title="Command", dest="command")
281
282    subparsers.add_parser("reset", help="Reset the device.")
283
284    subparsers.add_parser("run", help="Run JLinkGDBServer.")
285
286    erase_parser = subparsers.add_parser("erase", help="Erase devices.")
287    erase_parser.add_argument(
288        "--range",
289        help="The range of addresses to erase as a tuple separated by comma. "
290             "For example: --range 0x0800_0000,0x0800_1000")
291
292    upload_parser = subparsers.add_parser("upload", help="Upload firmware.")
293    upload_parser.add_argument(
294        "--source",
295        required=True,
296        help="The firmware to upload: `.bin`, `.hex`, or `.elf` file")
297    upload_parser.add_argument(
298        "--load-addr",
299        help="The load address of the binary file")
300
301    rtt_parser = subparsers.add_parser("rtt", help="Connect to an RTT channel.")
302    rtt_parser.add_argument(
303        "--channel",
304        type=int,
305        default=0,
306        help="The RTT channel to connect to.")
307
308    itm_parser = subparsers.add_parser("itm", help="Show ITM log output.")
309    itm_parser.add_argument(
310        "--baudrate",
311        type=int,
312        help="Force a baudrate instead of auto-selecting it.")
313    itm_parser.add_argument(
314        "--channel",
315        type=int,
316        help="The channel to output.")
317
318    args = parser.parse_args()
319    emdbg.logger.configure(args.verbosity)
320
321    if args.command == "reset":
322        exit(reset(args.device, args.speed, args.serial))
323
324    if args.command == "run":
325        exit(call(args.device, args.speed, args.serial, blocking=True))
326
327    if args.command == "erase":
328        addr_range = [int(a, 0) for a in args.range.split(",")] if args.range else None
329        exit(erase(args.device, args.speed, addr_range, args.serial))
330
331    if args.command == "upload":
332        exit(program(os.path.abspath(args.source), args.device, args.speed, args.serial))
333
334    if args.command == "rtt":
335        backend = JLinkBackend(args.device, args.speed, args.serial)
336        exit(rtt(backend, args.channel))
337
338    if args.command == "itm":
339        exit(itm(args.device, args.baudrate, args.channel, args.serial))
340
341    LOGGER.error("Unknown command!")
342    exit(1)
LOGGER = <Logger debug:jlink (WARNING)>
class JLinkBackend(emdbg.debug.backend.ProbeBackend):
26class JLinkBackend(ProbeBackend):
27    """
28    J-Link specific debug backend implementation. Starts the `JLinkGDBServer` in
29    its own subprocess and connects GDB to port `2331` of the localhost.
30
31    See `call()` for additional information.
32    """
33    def __init__(self, device: str, speed: int, serial: str = None, rtos: Path = None):
34        """
35        :param device: part name of the microcontroller to debug.
36        :param speed: SWD connection baudrate in kHz.
37        :param serial: Serial number of J-Link for selection.
38        :param rtos: Path to RTOS plugin for thread-aware debugging.
39        """
40        super().__init__(":2331")
41        self.device = device
42        self.speed = speed
43        self.serial = serial
44        self.rtos = rtos
45        self.process = None
46        self.name = "jlink"
47
48    def start(self):
49        self.process = call(self.device, self.speed, self.serial, self.rtos,
50                            blocking=False, silent=True)
51        LOGGER.info(f"Starting {self.process.pid}...")
52
53    def stop(self):
54        if self.process is not None:
55            LOGGER.info(f"Stopping {self.process.pid}.")
56            os.killpg(os.getpgid(self.process.pid), signal.SIGINT)
57            os.waitpid(os.getpgid(self.process.pid), 0)
58            self.process = None

J-Link specific debug backend implementation. Starts the JLinkGDBServer in its own subprocess and connects GDB to port 2331 of the localhost.

See call() for additional information.

JLinkBackend( device: str, speed: int, serial: str = None, rtos: pathlib.Path = None)
33    def __init__(self, device: str, speed: int, serial: str = None, rtos: Path = None):
34        """
35        :param device: part name of the microcontroller to debug.
36        :param speed: SWD connection baudrate in kHz.
37        :param serial: Serial number of J-Link for selection.
38        :param rtos: Path to RTOS plugin for thread-aware debugging.
39        """
40        super().__init__(":2331")
41        self.device = device
42        self.speed = speed
43        self.serial = serial
44        self.rtos = rtos
45        self.process = None
46        self.name = "jlink"
Parameters
  • device: part name of the microcontroller to debug.
  • speed: SWD connection baudrate in kHz.
  • serial: Serial number of J-Link for selection.
  • rtos: Path to RTOS plugin for thread-aware debugging.
device
speed
serial
rtos
process
name
def start(self):
48    def start(self):
49        self.process = call(self.device, self.speed, self.serial, self.rtos,
50                            blocking=False, silent=True)
51        LOGGER.info(f"Starting {self.process.pid}...")

Starts the debug probe as a non-blocking subprocess.

def stop(self):
53    def stop(self):
54        if self.process is not None:
55            LOGGER.info(f"Stopping {self.process.pid}.")
56            os.killpg(os.getpgid(self.process.pid), signal.SIGINT)
57            os.waitpid(os.getpgid(self.process.pid), 0)
58            self.process = None

Halts the debug probe process.

def call( device: str, speed: int, serial: str = None, rtos: pathlib.Path = None, blocking: bool = True, silent: bool = False) -> int | subprocess.Popen:
62def call(device: str, speed: int, serial: str = None, rtos: Path = None,
63         blocking: bool = True, silent: bool = False) -> "int | subprocess.Popen":
64    """
65    Starts the `JLinkGDBServer` and connects to the microcontroller without
66    resetting the device and without GUI. You can overwrite the default binary
67    by exporting an alternative in your environment:
68
69    ```sh
70    export PX4_JLINK_GDB_SERVER=path/to/JLinkGDBServer
71    ```
72
73    :param device: part name of the microcontroller to debug.
74    :param speed: SWD connection baudrate in kHz.
75    :param serial: Serial number of J-Link for selection.
76    :param rtos: Path to RTOS plugin for thread-aware debugging.
77    :param blocking: Run in current process as a blocking call.
78                     Set to `False` to run in a new subprocess.
79    :param silent: Disable any reporting from `JLinkGDBServer`.
80
81    :return: The process return code if `blocking` or the Popen object.
82    """
83    binary = os.environ.get("PX4_JLINK_GDB_SERVER", "JLinkGDBServer")
84
85    command_jlink = f"{binary} -device {device} -speed {speed} -if swd -noreset -nogui"
86    if serial: command_jlink += f" -SelectEmuBySN {serial}"
87    if rtos: command_jlink += f" -rtos {Path(rtos).absolute()}"
88    if silent: command_jlink += " -silent"
89
90    LOGGER.debug(command_jlink)
91
92    kwargs = {"cwd": os.getcwd(), "shell": True}
93    if blocking:
94        return subprocess.call(command_jlink, **kwargs)
95
96    # Disconnect the JLink process from this process, so that any Ctrl-C usage
97    # in GDB does not get passed on to the JLink process.
98    kwargs["start_new_session"] = True
99    return subprocess.Popen(command_jlink, **kwargs)

Starts the JLinkGDBServer and connects to the microcontroller without resetting the device and without GUI. You can overwrite the default binary by exporting an alternative in your environment:

export PX4_JLINK_GDB_SERVER=path/to/JLinkGDBServer
Parameters
  • device: part name of the microcontroller to debug.
  • speed: SWD connection baudrate in kHz.
  • serial: Serial number of J-Link for selection.
  • rtos: Path to RTOS plugin for thread-aware debugging.
  • blocking: Run in current process as a blocking call. Set to False to run in a new subprocess.
  • silent: Disable any reporting from JLinkGDBServer.
Returns

The process return code if blocking or the Popen object.

def itm( device: str, baudrate: int = None, port: int = None, serial: str = None) -> int:
103def itm(device: str, baudrate: int = None, port: int = None, serial: str = None) -> int:
104    """
105    Launches `JLinkSWOViewer`, connects to the microcontroller. You can
106    overwrite the default binary by exporting an alternative in your environment:
107
108    ```sh
109    export PX4_JLINK_SWO_VIEWER=path/to/JLinkSWOViewer
110    ```
111
112    :param device: part name of the microcontroller to debug.
113    :param baudrate: optional frequency of the SWO connection.
114    :param port: ITM port to display at startup. You can modify this at runtime.
115    :param serial: Serial number of J-Link for selection.
116
117    :return: the process return code
118    """
119    binary = os.environ.get("PX4_JLINK_SWO_VIEWER", "JLinkSWOViewer")
120    command_jlink = f"{binary} -device {device} -itmport {port or 0}"
121    if baudrate: command_jlink += f" -swofreq {baudrate}"
122    try:
123        return subprocess.call(command_jlink, shell=True)
124    except KeyboardInterrupt:
125        pass

Launches JLinkSWOViewer, connects to the microcontroller. You can overwrite the default binary by exporting an alternative in your environment:

export PX4_JLINK_SWO_VIEWER=path/to/JLinkSWOViewer
Parameters
  • device: part name of the microcontroller to debug.
  • baudrate: optional frequency of the SWO connection.
  • port: ITM port to display at startup. You can modify this at runtime.
  • serial: Serial number of J-Link for selection.
Returns

the process return code

def rtt(backend: JLinkBackend, channel: int = 0) -> int:
128def rtt(backend: JLinkBackend, channel: int = 0) -> int:
129    """
130    Launches the backend in the background and connects a telnet client to the
131    Real-Time Transfer process. You can disconnect with Ctrl+D.
132
133    :param backend: A J-Link backend object.
134    :param channel: The RTT channel to connect to.
135
136    :return: the process return code
137    """
138    import telnetlib
139    # Start JLinkGDBServer in the background
140    with backend.scope():
141        with telnetlib.Telnet("localhost", 19021) as tn:
142            try:
143                tn.interact()
144            except KeyboardInterrupt:
145                pass
146    return 0

Launches the backend in the background and connects a telnet client to the Real-Time Transfer process. You can disconnect with Ctrl+D.

Parameters
  • backend: A J-Link backend object.
  • channel: The RTT channel to connect to.
Returns

the process return code

def erase( device: str, speed: int, address_range: tuple[int, int] = None, serial: str = None) -> int:
149def erase(device: str, speed: int, address_range: tuple[int, int] = None,
150          serial: str = None) -> int:
151    """
152    Erases (part of) the device via JLink.
153
154    :param device: part name of the microcontroller to program. You can
155                   overwrite the default binary by exporting an alternative in
156                   your environment:
157                   ```sh
158                   export PX4_JLINK=path/to/JLinkExe
159                   ```
160    :param speed: SWD connection baudrate in kHz.
161    :param address_range: Optional [start, end] address to erase only part of device.
162    :param serial: Serial number of J-Link for selection.
163
164    :return: the process return code of JLink
165    """
166    binary = os.environ.get("PX4_JLINK", "JLinkExe")
167    if address_range is not None:
168        address_range = f"{address_range[0]} {address_range[1]}"
169    with tempfile.NamedTemporaryFile() as fcmd:
170        commands = f"Erase {address_range or ''}\nExit"
171        Path(fcmd.name).write_text(commands)
172        jcmd = f"{binary} -device {device} -speed {speed} -ExitOnError 1 " \
173               f"-if swd -autoconnect 1 -nogui 1 -commandfile {fcmd.name}"
174        if serial: jcmd += f" -SelectEmuBySN {serial}"
175        LOGGER.debug(f"{jcmd}\n{commands}")
176        return subprocess.call(jcmd, shell=True)

Erases (part of) the device via JLink.

Parameters
  • device: part name of the microcontroller to program. You can overwrite the default binary by exporting an alternative in your environment:

           
    export PX4_JLINK=path/to/JLinkExe
    
  • speed: SWD connection baudrate in kHz.

  • address_range: Optional [start, end] address to erase only part of device.
  • serial: Serial number of J-Link for selection.
Returns

the process return code of JLink

def program( source: pathlib.Path, device: str, speed: int, serial: str = None, load_addr: int = None) -> int:
178def program(source: Path, device: str, speed: int, serial: str = None, load_addr: int = None) -> int:
179    """
180    Loads the source file into the microcontroller and resets the device. You can
181    overwrite the default binary by exporting an alternative in your environment:
182
183    ```sh
184    export PX4_JLINK=path/to/JLinkExe
185    ```
186
187    :param source: path to a `.bin`, `.hex`, or `.elf` file to upload.
188    :param device: part name of the microcontroller to program.
189    :param speed: SWD connection baudrate in kHz.
190    :param serial: Serial number of J-Link for selection.
191    :param load_addr: Specifies the start address to load a `.bin` file.
192
193    :return: the process return code of JLink
194    """
195    binary = os.environ.get("PX4_JLINK", "JLinkExe")
196    if load_addr is None and Path(source).suffix == ".bin":
197        load_addr = 0x0800_0000
198    with tempfile.NamedTemporaryFile() as fcmd:
199        # LoadFile erases the correct amount of sectors, then writes the new
200        # binary or hex file. We still need to reset afterwards.
201        commands = f"LoadFile {source} {load_addr or ''}\nReset\nExit"
202        Path(fcmd.name).write_text(commands)
203        jcmd = f"{binary} -device {device} -speed {speed} -ExitOnError 1 " \
204               f"-if swd -autoconnect 1 -nogui 1 -commandfile {fcmd.name}"
205        if serial: jcmd += f" -SelectEmuBySN {serial}"
206        LOGGER.debug(f"{jcmd}\n{commands}")
207        return subprocess.call(jcmd, shell=True)

Loads the source file into the microcontroller and resets the device. You can overwrite the default binary by exporting an alternative in your environment:

export PX4_JLINK=path/to/JLinkExe
Parameters
  • source: path to a .bin, .hex, or .elf file to upload.
  • device: part name of the microcontroller to program.
  • speed: SWD connection baudrate in kHz.
  • serial: Serial number of J-Link for selection.
  • load_addr: Specifies the start address to load a .bin file.
Returns

the process return code of JLink

def reset(device: str, speed: int, serial: str = None) -> int:
209def reset(device: str, speed: int, serial: str = None) -> int:
210    """
211    Resets the device via JLink.
212
213    :param device: part name of the microcontroller to program. You can
214                   overwrite the default binary by exporting an alternative in
215                   your environment:
216                   ```sh
217                   export PX4_JLINK=path/to/JLinkExe
218                   ```
219    :param speed: SWD connection baudrate in kHz.
220    :param serial: Serial number of J-Link for selection.
221
222    :return: the process return code of JLink
223    """
224    binary = os.environ.get("PX4_JLINK", "JLinkExe")
225    with tempfile.NamedTemporaryFile() as fcmd:
226        commands = "Reset\nExit"
227        Path(fcmd.name).write_text(commands)
228        jcmd = f"{binary} -device {device} -speed {speed} -ExitOnError 1 " \
229               f"-if swd -autoconnect 1 -nogui 1 -commandfile {fcmd.name}"
230        if serial: jcmd += f" -SelectEmuBySN {serial}"
231        LOGGER.debug(f"{jcmd}\n{commands}")
232        return subprocess.call(jcmd, shell=True)

Resets the device via JLink.

Parameters
  • device: part name of the microcontroller to program. You can overwrite the default binary by exporting an alternative in your environment:

           
    export PX4_JLINK=path/to/JLinkExe
    
  • speed: SWD connection baudrate in kHz.

  • serial: Serial number of J-Link for selection.
Returns

the process return code of JLink