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.
- self (JLink) – the
-
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.
- self (JLink) – the
-
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.
- self (JLink) – the
-
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
- self (JLink) – the
-
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
andvalue
Returns: The bit position of the response in the input buffer.
- self (JLink) – the
-
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.
- self (JLink) – the
-
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.
- self (JLink) – the
-
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.
- self (JLink) – the
-
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- self (JLink) – the
-
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- self (JLink) – the
-
swo_num_bytes
(*args, **kwargs) Retrives the number of bytes in the SWO buffer.
Parameters: self (JLink) – the JLink
instanceReturns: 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
isTrue
. 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.
- self (JLink) – the
-
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 forprintf
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
– ifport < 0
orport > 31
- self (JLink) – the
-
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- self (JLink) – the
-
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- self (JLink) – the
-
swo_speed_info
(*args, **kwargs) Retrieves information about the supported SWO speeds.
Parameters: self (JLink) – the JLink
instanceReturns: 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- self (JLink) – the
-
swo_stop
(*args, **kwargs) Stops collecting SWO data.
Parameters: self (JLink) – the JLink
instanceReturns: 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.
- self (JLink) – the
-
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]))
|