Skip to main content
Control embedded debug operations including device connection, firmware flashing, reset, and memory access using J-Link debug probes.

Overview

The debug module provides low-level functions for embedded debugging operations. For most use cases, the CLI commands (lager debug) are the recommended interface. Python scripts running on the Lager Box can use these functions for advanced automation scenarios. Note: Debug operations require a J-Link debug probe connected to the Lager Box.

Import

# Core API
from lager.debug import (
    connect_jlink,
    disconnect,
    reset_device,
    flash_device,
    chip_erase,
    erase_flash,
)

# Exceptions
from lager.debug import (
    DebugError,
    JLinkStartError,
    JLinkAlreadyRunningError,
    JLinkNotRunning,
    DebuggerNotConnectedError,
)

# Status and diagnostics
from lager.debug import get_jlink_status

# GDB utilities
from lager.debug import get_arch, get_controller, gdb_reset

# GDB Server management
from lager.debug import (
    start_jlink_gdbserver,
    stop_jlink_gdbserver,
    get_jlink_gdbserver_status,
)

# Low-level access (advanced)
from lager.debug import JLink

Functions

Core API

FunctionDescription
connect_jlink()Connect to target via J-Link
disconnect()Disconnect from debug target
reset_device()Reset the connected device
flash_device()Flash firmware to device
chip_erase()Perform full chip erase
erase_flash()Erase specific flash region

Status & Diagnostics

FunctionDescription
get_jlink_status()Check J-Link connection status
get_arch()Get device architecture (arm, cortex-m, etc.)
get_controller()Get controller type
gdb_reset()Reset device via GDB

GDB Server Management

FunctionDescription
start_jlink_gdbserver()Start J-Link GDB server
stop_jlink_gdbserver()Stop J-Link GDB server
get_jlink_gdbserver_status()Get GDB server status

Exception Classes

ExceptionDescription
DebugErrorBase class for debug errors
JLinkStartErrorJ-Link failed to start or connect
JLinkAlreadyRunningErrorJ-Link is already running
JLinkNotRunningJ-Link is not running (operation requires connection)
DebuggerNotConnectedErrorGDB debugger is not connected

Function Reference

Connect to target device via J-Link debug probe.
from lager.debug.api import connect_jlink

# Basic connection
status = connect_jlink(
    speed='4000',
    device='NRF52840_XXAA',
    transport='SWD'
)

# Connection with halt
status = connect_jlink(
    speed='adaptive',
    device='R7FA0E107',
    transport='SWD',
    attach='reset-halt'
)
Parameters:
ParameterTypeDefaultDescription
speedstrNoneInterface speed in kHz (e.g., ‘4000’) or ‘adaptive’. Defaults to ‘4000’.
devicestr-J-Link device name (e.g., ‘NRF52840_XXAA’, ‘R7FA0E107’)
transportstr-Transport protocol (‘SWD’ or ‘JTAG’)
forceboolFalseForce connection even if already connected
ignore_if_connectedboolFalseReturn success if already connected
attachstr'attach'Attach mode: ‘attach’, ‘reset’, or ‘reset-halt’
vardefslistNoneList of (varname, varvalue) tuples for RTOS support
idcodestrNone16-byte IDCODE for locked devices (e.g., Renesas)
Returns: dict - Status dictionary with connection information Raises:
  • JLinkAlreadyRunningError - If J-Link is running and force=False
  • JLinkStartError - If J-Link fails to start or connect to target
Disconnect from debug target.
from lager.debug.api import disconnect

# Full disconnect (stop J-Link GDB server)
disconnect()

# Disconnect GDB client but keep J-Link running for external clients
disconnect(keep_jlink_running=True)
Parameters:
ParameterTypeDefaultDescription
mcustrNoneMCU identifier (optional)
keep_jlink_runningboolFalseKeep J-Link running for external GDB clients
Returns: dict - Status dictionary

reset_device(halt=False, mcu=None)

Reset the connected device.
from lager.debug.api import reset_device

# Reset and continue execution
for line in reset_device(halt=False):
    print(line)

# Reset and halt for debugging
for line in reset_device(halt=True):
    print(line)
Parameters:
ParameterTypeDefaultDescription
haltboolFalseHalt CPU after reset
mcustrNoneMCU identifier (optional)
Returns: Generator yielding output lines Raises: JLinkNotRunning - If J-Link is not running

flash_device(files, preverify=False, verify=True, run_after=False, mcu=None)

Flash firmware to the connected device.
from lager.debug.api import flash_device

# Flash a hex file
hexfiles = ['/path/to/firmware.hex']
binfiles = []
elffiles = []

for line in flash_device(
    files=(hexfiles, binfiles, elffiles),
    mcu='NRF52840_XXAA'
):
    print(line)

# Flash a binary file at specific address
hexfiles = []
binfiles = [('/path/to/firmware.bin', 0x08000000)]
elffiles = []

for line in flash_device(files=(hexfiles, binfiles, elffiles)):
    print(line)
Parameters:
ParameterTypeDescription
filestupleTuple of (hexfiles, binfiles, elffiles) where binfiles are (path, address) tuples
preverifyboolVerify before flashing (not currently used)
verifyboolVerify after flashing (not currently used)
run_afterboolReset and run after flashing
mcustrMCU identifier (e.g., ‘nRF52833_XXAA’)
Returns: Generator yielding output lines Raises: JLinkNotRunning - If J-Link GDB server is not running

chip_erase(device, speed='4000', transport='SWD', mcu=None)

Perform full chip erase. This erases ALL flash memory including protection settings.
from lager.debug.api import chip_erase

# Full chip erase
for line in chip_erase(
    device='NRF52840_XXAA',
    speed='4000',
    transport='SWD'
):
    print(line)
Parameters:
ParameterTypeDefaultDescription
devicestr-J-Link device name
speedstr'4000'Interface speed in kHz
transportstr'SWD'Transport protocol (‘SWD’ or ‘JTAG’)
mcustrNoneMCU identifier (optional)
Returns: Generator yielding output lines Raises: JLinkStartError - If J-Link fails to start

erase_flash(start_addr, length, mcu=None)

Erase a specific region of flash memory.
from lager.debug.api import erase_flash

# Erase 64KB starting at 0x80000000
for line in erase_flash(
    start_addr=0x80000000,
    length=65536
):
    print(line)
Parameters:
ParameterTypeDescription
start_addrintStarting address to erase
lengthintNumber of bytes to erase
mcustrMCU identifier (optional)
Returns: Generator yielding output lines Raises: JLinkNotRunning - If J-Link is not running Check the current J-Link connection status.
from lager.debug import get_jlink_status

status = get_jlink_status()
print(f"J-Link connected: {status.get('connected', False)}")
Returns: dict - Status dictionary with connection information

get_arch()

Get the device architecture.
from lager.debug import get_arch

arch = get_arch()
print(f"Architecture: {arch}")  # e.g., 'arm', 'cortex-m'
Returns: str - Architecture string Raises: DebuggerNotConnectedError - If debugger is not connected

get_controller()

Get the controller type.
from lager.debug import get_controller

controller = get_controller()
print(f"Controller: {controller}")
Returns: str - Controller type string Raises: DebuggerNotConnectedError - If debugger is not connected

gdb_reset(halt=False)

Reset the device via GDB.
from lager.debug import gdb_reset

# Reset and run
gdb_reset(halt=False)

# Reset and halt
gdb_reset(halt=True)
Parameters:
ParameterTypeDefaultDescription
haltboolFalseHalt CPU after reset
Raises: DebuggerNotConnectedError - If debugger is not connected Start the J-Link GDB server for remote debugging.
from lager.debug import start_jlink_gdbserver

result = start_jlink_gdbserver(
    device='NRF52840_XXAA',
    speed='4000',
    transport='SWD',
    halt=True,
    gdb_port=2331
)
print(f"GDB server started on port {result.get('gdb_port', 2331)}")
Parameters:
ParameterTypeDefaultDescription
devicestr-J-Link device name (e.g., ‘R7FA0E107’, ‘NRF52840_XXAA’)
speedstr'adaptive'Interface speed in kHz or ‘adaptive’
transportstr'SWD'Transport protocol (‘SWD’ or ‘JTAG’)
haltboolFalseWhether to halt the device when connecting
gdb_portint2331GDB server port number
Returns: dict with keys:
  • pid - Process ID of the GDB server
  • status - Status message
  • gdb_port - Port number the server is listening on
Raises: JLinkStartError - If GDB server fails to start Stop the running J-Link GDB server.
from lager.debug import stop_jlink_gdbserver

stop_jlink_gdbserver()
print("GDB server stopped")
Get the current GDB server status.
from lager.debug import get_jlink_gdbserver_status

status = get_jlink_gdbserver_status()
if status.get('running'):
    print(f"GDB server running on port {status.get('port')}")
else:
    print("GDB server not running")
Returns: dict - Status dictionary with keys:
  • running (bool) - Whether GDB server is running
  • port (int) - GDB server port (if running)
  • pid (int) - Process ID (if running)

Examples

Flash Firmware and Reset

from lager.debug.api import connect_jlink, flash_device, reset_device, disconnect

# Connect to target
status = connect_jlink(
    speed='4000',
    device='NRF52840_XXAA',
    transport='SWD'
)
print(f"Connected: {status}")

# Flash firmware
hexfiles = ['/etc/lager/firmware/app.hex']
for line in flash_device(
    files=(hexfiles, [], []),
    mcu='NRF52840_XXAA'
):
    print(line)

# Reset and run
for line in reset_device(halt=False):
    print(line)

# Disconnect
disconnect()

Chip Erase Before Programming

from lager.debug.api import chip_erase, connect_jlink, flash_device, disconnect

# Erase entire chip first (ensures clean state)
print("Erasing chip...")
for line in chip_erase(device='R7FA0E107', speed='4000', transport='SWD'):
    print(line)

# Connect after erase
status = connect_jlink(
    speed='4000',
    device='R7FA0E107',
    transport='SWD'
)

# Flash new firmware
for line in flash_device(
    files=(['/etc/lager/firmware/app.hex'], [], []),
    mcu='R7FA0E107'
):
    print(line)

disconnect()

Error Handling

from lager.debug.api import (
    connect_jlink,
    disconnect,
    DebugError,
    JLinkStartError,
    JLinkNotRunning
)

try:
    status = connect_jlink(
        speed='4000',
        device='NRF52840_XXAA',
        transport='SWD'
    )
    print(f"Connected successfully")

except JLinkStartError as e:
    print(f"J-Link failed to start: {e}")
    print("Check debug probe connection and target power")

except DebugError as e:
    print(f"Debug error: {e}")

finally:
    try:
        disconnect()
    except JLinkNotRunning:
        pass  # Already disconnected
For most use cases, the CLI provides a simpler interface:
# Start GDB server (connect to target)
lager debug <net> gdbserver --box <gateway>

# Flash firmware
lager debug <net> flash --hex firmware.hex --box <gateway>

# Reset device
lager debug <net> reset --box <gateway>

# Erase flash
lager debug <net> erase --box <gateway>

# Read memory
lager debug <net> memrd 0x20000000 256 --box <gateway>

# Disconnect
lager debug <net> disconnect --box <gateway>

# Check status
lager debug <net> status --box <gateway>
See the CLI Debug Reference for full CLI documentation.

RTT Streaming

For SEGGER Real-Time Transfer (RTT) communication, see the RTT documentation.
from lager.core import RTT

# RTT requires an active debug connection
with RTT() as rtt:
    data = rtt.read_some()
    print(data.decode())

Supported Devices

J-Link supports a wide range of ARM Cortex-M and other microcontrollers. Common device names:
ManufacturerDevice NameDescription
NordicNRF52840_XXAAnRF52840
NordicNRF52833_XXAAnRF52833
NordicNRF5340_XXAA_APPnRF5340 Application Core
RenesasR7FA0E107RA0E1 Series
RenesasR7FA2L1RA2L1 Series
STMicroSTM32F103C8STM32F1 Series
STMicroSTM32F407VGSTM32F4 Series
STMicroSTM32L476RGSTM32L4 Series
For a complete list, see SEGGER’s supported devices.

Notes

  • Debug operations require a J-Link debug probe connected to the Lager Box
  • The CLI (lager debug) is recommended for most use cases
  • Python API is intended for advanced automation scripts running on the Lager Box
  • Always disconnect when finished to release the debug probe
  • Flash operations automatically reset and run the device
  • Use chip_erase() to clear protection settings on locked devices
  • RTT requires an active J-Link connection (see RTT documentation)