pyOCD Documentation

repository·main·Indexed 23 days ago

https://github.com/pyocd/pyocd

An open-source, Python-based tool for programming and debugging Arm Cortex-M microcontrollers. pyOCD provides a CLI and Python API for execution control, memory/register access, flash operations, and breakpoint management. It supports a wide range of debug probes, including CMSIS-DAP, STLink, J-Link, and Raspberry Pi Picoprobe, and allows for the addition of custom targets and boards.

Tokens
37.5K
Snippets
56
Records
218
Agent score
80%

What's inside pyOCD

  1. What pyOCD can do

    main

    pyOCD provides low-level control over Arm Cortex-M devices through its CLI and Python API, including:

    • Execution Control: halt, step, and resume.
    • Memory/Register Access: Read/write memory and core registers.
    • Breakpoints: Set and remove hardware and software breakpoints, and watchpoints.
    • Flash Operations: Write to flash memory and load binary, hex, or ELF files.
    • Hardware Access: Reset control and access to CoreSight DP and APs.
    • Debug Features: Support for SWO and SWV.
  2. Understand pyOCD terminology

    main

    To effectively use pyOCD, it is helpful to understand its core terminology regarding debug hardware, protocols, and software abstractions:

    Hardware and Connectivity

    • debug probe: The hardware device (usually USB-connected) that drives the wire protocol.
    • debug link: The physical connection between the debugger and the target.
    • target: The device being controlled by pyOCD.
    • SoC (System on Chip): The complete computer on a single chip (e.g., a microcontroller).
    • unique ID: The identifier for a debug probe, typically its serial number.

    Protocols and Architecture

    • wire protocol: The communication standard used on the debug link, typically JTAG or SWD (Serial Wire Debug).
    • SWO (Serial Wire Output): A single-pin output for SWV frames, accessible only when using SWD.
    • SWV (Serial Wire Viewer): A trace capability for monitoring reads, writes, exceptions, PC samples, and printf.
    • ADI (Arm Debug Interface): The Arm specification for how JTAG/SWD interfaces with CoreSight.
    • DAP (Debug Access Port): The debugging module accessed via JTAG/SWD, composed of a DP (Debug Port) and one or more APs (Access Ports).
    • MEM-AP: A standard type of AP used for memory reads and writes (e.g., AHB-AP, AXI-AP).

    pyOCD Software Concepts

    • commander: The pyocd commander subcommand providing an interactive REPL for exploring the target.
    • command: An instruction executed in the commander REPL or as a GDB monitor command.
    • session: The representation of a connection to a debug probe and the resulting runtime object graph.
    • session option: A named setting (set via CLI or config files) that controls pyOCD features for a specific session.
    • target type: The identifier (full part number or shortened form) for the target device.
    • flash algorithm: Code downloaded to target RAM to perform flash erase and program operations.
    • gdbserver: A server implementing the GDB Remote Serial Protocol (RSP) that allows pyOCD to act as a bridge between GDB and the target.
    • user script: A Python script loaded at runtime to extend/modify pyOCD behavior while the pyocd CLI tool is running.
  3. Use connection hooks in user scripts

    main

    User scripts can define functions that act as hooks at specific points in the connection lifecycle. Common hooks include:

    • will_connect(board): Called before the connection is established. The board object is provided as an argument.
    • did_connect(): Called after the connection is established. Note that board is not necessarily passed to this hook.

    Example: Adding a ROM region (Nordic nRF52)

    def will_connect(board):
        # Create the new ROM region for the FICR.
        ficr = RomRegion(
                    name="ficr",
                    start=0x10000000,
                    length=0x460
                    )
    
        # Add the FICR region to the memory map.
        target.memory_map.add_region(ficr)

    Example: Overriding a flash algorithm (NXP i.MX RT10x0)

    def will_connect():
        # Look up the external flash memory region.
        extFlash = target.memory_map.get_first_matching_region(name="flexspi")
    
        # Set the path to an .FLM flash algorithm.
        extFlash.flm = "MIMXRT105x_QuadSPI_4KB_SEC.FLM"

    Example: Writing to a register after connection (STM32L0x1)

    DBG_CR = 0x40015804
    
    def did_connect():
        # Set STANDBY, STOP, and SLEEP bits all to 1.
        target.write32(DBG_CR, 0x7)
    # This example applies to the Nordic nRF52 devices.
    
    def will_connect(board):
        # Create the new ROM region for the FICR.
        ficr = RomRegion(
                    name="ficr",
                    start=0x10000000,
                    length=0x460
                    )
    
        # Add the FICR region to the memory map.
        target.memory_map.add_region(ficr)
  4. Configure RTOS thread awareness in pyOCD gdbserver

    main

    pyOCD's gdbserver supports thread awareness for several RTOSes via plugins. When GDB connects, pyOCD attempts to enable thread awareness by querying available plugins.

    To control this behavior, use the following session options:

    • Select a specific RTOS: Set rtos.name to the name of the desired RTOS plugin to skip querying others.
    • Disable thread awareness: Set rtos.enable to false to completely disable thread reporting.

    Supported Builtin RTOS Plugins:

    RTOS Plugin NameDescription
    argonArgon RTOS
    freertosFreeRTOS
    rtx5RTX5
    threadxThreadX
    zephyrZephyr
  5. How target and board support differ

    main

    In pyOCD, target support and board support are distinct layers:

    • Target Support: Enables debugging and flash programming for a specific MCU. Targets are implemented as CoreSightTarget subclasses. A single target can be used across multiple different boards.
    • Board Support: Represents the physical assembly. A board contains a target.

    Users can explicitly override the target type when creating a Session or via the command line if the automatic detection does not match the intended MCU.

  6. How session options are prioritized in pyOCD

    main

    pyOCD allows you to control its behavior via session options. When multiple sources define the same option, pyOCD follows a specific precedence order (from highest to lowest priority):

    1. Dedicated command-line arguments.
    2. -O<option>=<value> command-line arguments.
    3. Probe-specific options from a config file.
    4. Global options from a config file.
    5. Changes to an option's default value (used in rare subcommand cases).
    6. The option's default value.
  7. Understand the pyOCD object graph

    main

    The pyOCD Python API is structured around a hierarchical object graph. The entry point for any interaction is the Session object, which manages the lifecycle of the debug probe and the board, as well as per-session configuration options.

    Key components include:

    • Session: The root object holding references to the debug probe and the board.
    • Board: Attached to the session; represents the physical hardware setup.
    • CoreSightTarget: Represents the MCU and is attached to the board. It manages communication via Debug Ports (DP) and Access Ports (AP).
    • CortexM: A subclass of Target representing a specific CPU core on the device. It is owned by the CoreSightTarget.
    • Target: An abstract base class for both CoreSightTarget and CortexM.
    • MemoryRegion: Objects within a CortexM memory map that define address ranges.
    • Flash: An object associated with flash MemoryRegion objects used to control flash programming.
  8. Understand session option priority layers

    main

    pyOCD uses a layered priority system for session options. When multiple sources define the same option, the value from the highest priority layer (the "front") is used. The OptionsManager manages these layers as an ordered sequence.

    Priority Order (from highest to lowest priority):

    1. Keyword arguments passed to the Session constructor (typically dedicated CLI arguments).
    2. _options_ parameter passed to the Session constructor (typically -O CLI arguments).
    3. Options set by CMSIS-Toolbox Run and Debug Management (cbuild-run).
    4. Probe-specific options from a config file.
    5. Global options from a config file.
    6. _option_defaults_ parameter passed to the Session constructor.
    7. Default values defined in the option definitions.

    Layer Manipulation:

    • .set(name, value): Modifies the value in the highest priority layer.
    • .add_front(dict): Adds a new dictionary of options to the front (highest priority).
    • .add_back(dict): Adds a new dictionary of options to the back (lower priority).
  9. Configure connection modes for target access

    main

    The connect_mode option determines how pyOCD establishes a connection to the target. Choose the mode that best fits your target's current state:

    • halt: Immediately halts all accessible cores upon connection. (Default)
    • pre-reset: Performs a hardware reset prior to connecting and halting.
    • under-reset: Asserts hardware reset during the connection sequence, then deasserts it after cores are halted. Use this to gain control of targets in deep low-power modes.
    • attach: Connects to a running target without halting any cores.
  10. How SWO and SWV work in pyOCD

    main

    Serial Wire Output (SWO) is a single-wire trace feature in Arm Cortex-M architectures used for printf-style debugging, profiling, and performance measurement.

    Serial Wire Viewer (SWV) refers to the combination of DWT (Data Watchpoint and Trace) and ITM (Instrumentation Trace Macrocell) packets transmitted via SWO.

    PyOCD provides three main ways to consume this data:

    1. gdbserver: Muxes SWV printf-style log output with semihosting stdout or a telnet server.
    2. Raw SWV Stream: Serves raw data over a TCP port while the gdbserver is running, allowing external tools like Orbuculum to process the stream.
    3. Python API: Provides classes for building custom trace event data flow graphs.
  11. Handling Nordic SoftDevice firmware

    main

    The Nordic nRF51 and nRF52 series support 'SoftDevice' firmware (Bluetooth LE or other wireless protocol APIs). When a SoftDevice is present, its flash sectors are locked.

    Standard Development Workflow

    For normal development where the SoftDevice does not change, no extra steps are required. pyOCD automatically scans flash sectors and only erases/programs sectors that are changing, effectively skipping the locked SoftDevice sectors.

    Erasing with SoftDevice

    Running pyocd erase --chip on a device with a SoftDevice will leave the SoftDevice intact and only erase the other sectors.

    Changing or Removing SoftDevice

    If you need to change the SoftDevice version/variant, or switch to firmware that does not include a SoftDevice, you must perform a mass erase. A mass erase is required to unlock the SoftDevice sectors for reprogramming.

    pyocd erase --mass
  12. Use Unique IDs (UIDs) for probe selection

    main

    Every debug probe has a Unique ID. For USB probes, this is typically the USB serial number. For network-accessed probes (like the remote client), the UID is the network address.

    To restrict selection to a specific type of probe, you can prefix the UID with the plugin name followed by a colon. For example, cmsisdap:UID ensures pyOCD only matches CMSIS-DAP probes.