Serial Wire Debug

Serial Wire Output (SWO) alongside Serial Wire Debug (SWD) allows for the CPU to emit real-time trace data. In particular, when used with an Instrumentation Trace Macrocell (ITM), it can be used to form a Serial Wire Viewer (SWV). The ITM ports are provided by the ARM controller. The SWV typically implements a form of printf style debugging for embedded systems.

Getting Started

First, get your J-Link set up by instantiating an instance of a JLink and connecting to your target device. Once that is established, you want to call either swo_start():

speed = 9600
jlink.swo_start(swo_speed=speed)

or call swo_enable():

swo_speed = 9600
cpu_speed = 72000000 # 72 MHz
port_mask = 0x01
jlink.swo_enable(cpu_speed, swo_speed, port_mask)

Once enabled, you can begin reading data from the target.

Serial Wire Methods

class pylink.jlink.JLink(lib=None, log=None, detailed_log=None, error=None, warn=None, unsecure_hook=None, serial_no=None, ip_addr=None, open_tunnel=False)

Python interface for the SEGGER J-Link.

This is a wrapper around the J-Link C SDK to provide a Python interface to it. The shared library is loaded and used to call the SDK methods.

swd_read16(*args, **kwargs)

Gets a unit of 16 bits from the input buffer.

Parameters:
  • self (JLink) – the JLink instance
  • offset (int) – the offset (in bits) from which to start reading
Returns:

The integer read from the input buffer.

swd_read32(*args, **kwargs)

Gets a unit of 32 bits from the input buffer.

Parameters:
  • self (JLink) – the JLink instance
  • offset (int) – the offset (in bits) from which to start reading
Returns:

The integer read from the input buffer.

swd_read8(*args, **kwargs)

Gets a unit of 8 bits from the input buffer.

Parameters:
  • self (JLink) – the JLink instance
  • offset (int) – the offset (in bits) from which to start reading
Returns:

The integer read from the input buffer.

swd_sync(*args, **kwargs)

Causes a flush to write all data remaining in output buffers to SWD device.

Parameters:
  • self (JLink) – the JLink instance
  • pad (bool) – True if should pad the data to full byte size
Returns:

None

swd_write(*args, **kwargs)

Writes bytes over SWD (Serial Wire Debug).

Parameters:
  • self (JLink) – the JLink instance
  • output (int) – the output buffer offset to write to
  • value (int) – the value to write to the output buffer
  • nbits (int) – the number of bits needed to represent the output and value
Returns:

The bit position of the response in the input buffer.

swd_write16(*args, **kwargs)

Writes two bytes over SWD (Serial Wire Debug).

Parameters:
  • self (JLink) – the JLink instance
  • output (int) – the output buffer offset to write to
  • value (int) – the value to write to the output buffer
Returns:

The bit position of the response in the input buffer.

swd_write32(*args, **kwargs)

Writes four bytes over SWD (Serial Wire Debug).

Parameters:
  • self (JLink) – the JLink instance
  • output (int) – the output buffer offset to write to
  • value (int) – the value to write to the output buffer
Returns:

The bit position of the response in the input buffer.

swd_write8(*args, **kwargs)

Writes one byte over SWD (Serial Wire Debug).

Parameters:
  • self (JLink) – the JLink instance
  • output (int) – the output buffer offset to write to
  • value (int) – the value to write to the output buffer
Returns:

The bit position of the response in the input buffer.

swo_enable(*args, **kwargs)

Enables SWO output on the target device.

Configures the output protocol, the SWO output speed, and enables any ITM & stimulus ports.

This is equivalent to calling .swo_start().

Note

If SWO is already enabled, it will first stop SWO before enabling it again.

Parameters:
  • self (JLink) – the JLink instance
  • cpu_speed (int) – the target CPU frequency in Hz
  • swo_speed (int) – the frequency in Hz used by the target to communicate
  • port_mask (int) – port mask specifying which stimulus ports to enable
Returns:

None

Raises:

JLinkException – on error

swo_flush(*args, **kwargs)

Flushes data from the SWO buffer.

After this method is called, the flushed part of the SWO buffer is empty.

If num_bytes is not present, flushes all data currently in the SWO buffer.

Parameters:
  • self (JLink) – the JLink instance
  • num_bytes (int) – the number of bytes to flush
Returns:

None

Raises:

JLinkException – on error

swo_num_bytes(*args, **kwargs)

Retrives the number of bytes in the SWO buffer.

Parameters:self (JLink) – the JLink instance
Returns:Number of bytes in the SWO buffer.
Raises:JLinkException – on error
swo_read(*args, **kwargs)

Reads data from the SWO buffer.

The data read is not automatically removed from the SWO buffer after reading unless remove is True. Otherwise the callee must explicitly remove the data by calling .swo_flush().

Parameters:
  • self (JLink) – the JLink instance
  • offset (int) – offset of first byte to be retrieved
  • num_bytes (int) – number of bytes to read
  • remove (bool) – if data should be removed from buffer after read
Returns:

A list of bytes read from the SWO buffer.

swo_read_stimulus(*args, **kwargs)

Reads the printable data via SWO.

This method reads SWO for one stimulus port, which is all printable data.

Note

Stimulus port 0 is used for printf debugging.

Parameters:
  • self (JLink) – the JLink instance
  • port (int) – the stimulus port to read from, 0 - 31
  • num_bytes (int) – number of bytes to read
Returns:

A list of bytes read via SWO.

Raises:

ValueError – if port < 0 or port > 31

swo_set_emu_buffer_size(*args, **kwargs)

Sets the size of the buffer used by the J-Link to collect SWO data.

Parameters:
  • self (JLink) – the JLink instance
  • buf_size (int) – the new size of the emulator buffer
Returns:

None

Raises:

JLinkException – on error

swo_set_host_buffer_size(*args, **kwargs)

Sets the size of the buffer used by the host to collect SWO data.

Parameters:
  • self (JLink) – the JLink instance
  • buf_size (int) – the new size of the host buffer
Returns:

None

Raises:

JLinkException – on error

swo_speed_info(*args, **kwargs)

Retrieves information about the supported SWO speeds.

Parameters:self (JLink) – the JLink instance
Returns:A JLinkSWOSpeedInfo instance describing the target’s supported SWO speeds.
Raises:JLinkException – on error
swo_start(*args, **kwargs)

Starts collecting SWO data.

Note

If SWO is already enabled, it will first stop SWO before enabling it again.

Parameters:
  • self (JLink) – the JLink instance
  • swo_speed (int) – the frequency in Hz used by the target to communicate
Returns:

None

Raises:

JLinkException – on error

swo_stop(*args, **kwargs)

Stops collecting SWO data.

Parameters:self (JLink) – the JLink instance
Returns:None
Raises:JLinkException – on error
swo_supported_speeds(*args, **kwargs)

Retrives a list of SWO speeds supported by both the target and the connected J-Link.

The supported speeds are returned in order from highest to lowest.

Parameters:
  • self (JLink) – the JLink instance
  • cpu_speed (int) – the target’s CPU speed in Hz
  • num_speeds (int) – the number of compatible speeds to return
Returns:

A list of compatible SWO speeds in Hz in order from highest to lowest.

Examples

Serial Wire Viewer

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
# -*- coding: utf-8 -*-
# Copyright 2017 Square, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# Example Serial Wire Viewer.
#
# This module demonstrates implementing a Serial Wire Viewer using the PyLink
# library.
#
# Usage: swv.py jlink_serial_number device
# Author: Ford Peprah
# Date: Friday, September 23rd, 2016
# Copyright: 2016 Square, Inc.

import pylink

try:
    import StringIO
except ImportError:
    import io as StringIO
import string
import sys
import time


def serial_wire_viewer(jlink_serial, device):
    """Implements a Serial Wire Viewer (SWV).

    A Serial Wire Viewer (SWV) allows us implement real-time logging of output
    from a connected device over Serial Wire Output (SWO).

    Args:
      jlink_serial (str): the J-Link serial number
      device (str): the target CPU

    Returns:
      Always returns ``0``.

    Raises:
      JLinkException: on error
    """
    buf = StringIO.StringIO()
    jlink = pylink.JLink(log=buf.write, detailed_log=buf.write)
    jlink.open(serial_no=jlink_serial)

    # Use Serial Wire Debug as the target interface.  Need this in order to use
    # Serial Wire Output.
    jlink.set_tif(pylink.enums.JLinkInterfaces.SWD)
    jlink.connect(device, verbose=True)
    jlink.coresight_configure()
    jlink.set_reset_strategy(pylink.enums.JLinkResetStrategyCortexM3.RESETPIN)

    # Have to halt the CPU before getitng its speed.
    jlink.reset()
    jlink.halt()

    cpu_speed = jlink.cpu_speed()
    swo_speed = jlink.swo_supported_speeds(cpu_speed, 10)[0]

    # Start logging serial wire output.
    jlink.swo_start(swo_speed)
    jlink.swo_flush()

    # Output the information about the program.
    sys.stdout.write('Serial Wire Viewer\n')
    sys.stdout.write('Press Ctrl-C to Exit\n')
    sys.stdout.write('Reading data from port 0:\n\n')

    # Reset the core without halting so that it runs.
    jlink.reset(ms=10, halt=False)

    # Use the `try` loop to catch a keyboard interrupt in order to stop logging
    # serial wire output.
    try:
        while True:
            # Check for any bytes in the stream.
            num_bytes = jlink.swo_num_bytes()

            if num_bytes == 0:
                # If no bytes exist, sleep for a bit before trying again.
                time.sleep(1)
                continue

            data = jlink.swo_read_stimulus(0, num_bytes)
            sys.stdout.write(''.join(map(chr, data)))
            sys.stdout.flush()
    except KeyboardInterrupt:
        pass

    sys.stdout.write('\n')

    # Stop logging serial wire output.
    jlink.swo_stop()

    return 0


if __name__ == '__main__':
    exit(serial_wire_viewer(sys.argv[1], sys.argv[2]))