-
Notifications
You must be signed in to change notification settings - Fork 46
Project History
THIS IS A HISTORICAL COPY OF WEBSITE DATED 2010..2013 THAT DOCUMENTS FROM SCRATCH RESEARCH AND DEVELOPMENT OF LIBSWD PROJECT TO SHOW HOW MUCH WORK IT REQUIRED |
|
This project was started by Tomek Cedro to create and document Free and Open-Source SWD (Serial Wire Debug) access to new ARM-Cortex cores. SWD is an alternative to JTAG method for accessing the TAP (Test Access Port) that allows low-level access to system resources such as system bus, memory, IO, even single stepping the code execution - a must-have for an embedded systems developer. Because Stm32Primer Development Kits designed by Raisonance are relatively cheap and freely accessible, they became my target hardware for this project. Please note that SWD will also work on more advanced devices from the ARM Cortex family. Some parts of this research are conducted as a cooperation between Orange Labs Warsaw and Orange Labs Paris, and some additionally by Cybernetic Research Student Group from Warsaw Univeristy of Technology in Poland that I am founder and member.
By default Cortex-design CPU or FPGA'a IP Core is both JTAG and SWD capable, so the common name for this access is SWJ (Serial Wire and JTAG). It is the application requirement and designer choice if a final product supports JTAG, SWD, or both (SWJ). Here you can read short and interesting article on how SWD overcomes JTAG limitations.
Target software that allows JTAG access is OpenOCD (memory access + debug) and UrJTAG (low level operations). When this project started there was no SWD support in neither of these nice utilities, so it had to be created from scratch. Because UrJTAG is a bit simpler (no debug) I will start from this program to test low level operations on SWD, then move to OpenOCD and try the debug functionality.
Work in progress... meanwhile you can take a look at:
I have created LibSWD, open, flexible and platform independent Serial Wire Debug Open Framework, to provide universal API for SWD transport layer. LibSWD can be standalone or incorporated into existing low-level access utilities such as UrJTAG and OpenOCD extending their functionality and making use of existing components, such as drivers, but it also can become an integral part of the dedicated hardware firmware. There has been some releases of the LibSWD already, please take a look at the project website. Initial integration with UrJTAG is complete, but its implemented as standalone source code for now, after work on OpenOCD integration is complete I will come back to UrJTAG and implement it just as in OpenOCD. The OpenOCD integration is almost done and the source code is available on the dedicated git repository - it required substantial effort and extension of the OpenOCD code, but it also uncovered very elegant method of integration in bigger project using git submodules. For more details please visit project webstibe at http://libswd.sf.net.
Note: The UrJTAG SWD implementation was based on LibSWD before initial release just to test if the communication with the DAP is working, since then there were some bugfixes implemented during following releases and integration with OpenOCD, therefore everything presented below can be considered as backlog but is already outdated, also the screenshorts have bits swapped etc. I will update this description below after LibSWD+OpenOCD integration is finished and I will get back to the proper LibSWD+UrJTAG integration :-)
A driver for KT-LINK interface working in JTAG mode had to be first created to test JTAG functionality on target Stm32Primer and Stm32Primer2. Because it is FT2232H based device not embedded into Primer, it also gives access to other targets. Driver code is ready and available on SVN since trunk #1683, GIT commit 6402fdd84a409cdd27de50de908b45d8f0a30099, see code section at project website.
Below is the work in progress description of the SWD implementation in UrJTAG. It will evolve and may change. Comments and suggestions are welcome on how to implement it better. I want to expand the software and keep the features as much as they were before, but some things do work different in SWD and JTAG therefore some minor changes are necessary. Below are the main points I have already decided to implement and keep as the implementation rules:
- All of the functions should stay as they are for backward compatibility. They may be implemented by different functions for different transports. Wrappers will decide what and how these functions can be called. New functions will provide new functionalities, old functions should behave just as before from the user perspective.
- Because neither JTAG nor SWD are the only transports available for embedded tracing, I have decided not to implement SWD as an alternative or even in place of JTAG (as I wanted at first), but introduced TRANSPORT layer that will allow accessing the target's DAP (Debug Access Port).
- Probably the same thing must happen to the DP (Debug Port) residing inside DAP as it can be specific to SWD, JTAG, and probably others. Unfortunately I did not manage to wrap the SWD operations within the JTAG calls, but this might avoid huge mess in future, when each TRANSPORT and DAP will have its own set of functions called similarly from one commandline function.
- This way other ICE/DAP transport layers can be introduced in future, or even simple direct buses such as SPI, I2C, etc can expand functionality of the software.
- This is now true - transport layer separates functionalities that can use existing drivers, use wrapped version of existing functions or their own commands.
- Because the first thing to be done after launching UrJTAG is the cable selection ("cable" command), this will be also the good place to select TRANSPORT as an optional commandline parameter.
- "cable" data structure is expanded with "int transport" property that will hold the information about the transport to be used for communication.
- Other data structures such as "chain" and "part" also are expanded with the "transport" property to know if they support selected transport (to be done). This could also allow to have different transport-capable-devices on one interface in future.
- When "cable" data structure is being created "transport" property is initalized with URJ_TRANSPORT_UNKNOWN value.
- This will not matter for old drivers, but new drivers will know if user selected some specific transport mode or not.
- User can know if the cable supports additional modes, if the property's value has changed after "connect" call.
- A new driver-specific "connect" function wrapper must be introduced to set the transport mode and then call the generic connect function.
- Cable/Interface driver function "connect" is used to set logic cable working mode as it is aware of the commandline parameters (and "init" is not).
- If no transport mode is selected on the commandline, the default mode if selected (driver specific) by the new "connect" function.
- If selected mode is unsupported, "connect" function returns URJ_ERROR_UNSUPPORTED so the cable cannot be used.
- Apropriate hardware initialization is then made inside "init" function based upon "transport" parameter value.
- If the "cable" command is invoked with old syntax it will work in JTAG mode, calling old "connect" function that will not change the cable's "transport" value.
- The new "cable" command syntax requires additional (optional) parameter that will tell the driver what transport to be used. All initialization is being done inside cable-specific "connect" function - it will also check for (un)supported modes (bitmask) that were selected by the user, or switch the default transport mode.
- After cable is initialized, "detect" command must be issued to create swd context and detect debug access port.
- Debug and logging messages are now supported, libswd will inherit log level from target application using swd_log_level_inherit for best tranlation of application log levels into swd log levels (that may differ). Debug level can be changed even before "detect" command. Debug level will be automatically inherited at "detect" command invocation.
- New interfaces may require to switch output buffers between Transmit and Receive mode. To maintain backward compatibility with existing drivers I have created another control signal URJ_POD_CS_RnW, just as the nTRST and nSRST, that can be deferred and queued to switch the physical interface transceivers during Turnaround period.
- URJ_POD_CS_RnW is a bitmask for aCbus and aDbus of the FT2232 chip stored within "cable->params->bitmask_RnW" and "cable->params->bitmask_nRnW" so any pin can be set high or low this way at one clock cycle. bitmask_RnW is being set low to transmit data, while bitmask_nRnW is being set high to transmit data - this way when RnW=0 or RnW=1 both bitmasks are applied to provide proper signalling.
- Drivers are now functional - it is possible to drive swd interface pins with "pod" command.
UrJTAG 0.10 #1864 Copyright (C) 2002, 2003 ETC s.r.o. Copyright (C) 2007, 2008, 2009 Kolja Waschk and the respective authors UrJTAG is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. There is absolutely no warranty for UrJTAG. jtag.c:518 main() Warning: UrJTAG may damage your hardware! Type "quit" to exit, "help" for help. jtag> cable kt-link Transport not selected or unsupported. Default transport is: JTAG Connected to libftdi driver. nSRST pin state is high... KT-LINK JTAG Mode Initialization OK! jtag> pod reset=0 jtag> frequency 10000 Setting TCK frequency to 10000 Hz jtag> detect IR length: 9 Chain length: 2 Device Id: 00111011101000000000010001110111 (0x3BA00477) Unknown manufacturer! (01000111011) (/mnt/stuff/tmp/swd/target/share/urjtag/MANUFACTURERS) Device Id: 00000110010000010100000001000001 (0x06414041) Unknown manufacturer! (00000100000) (/mnt/stuff/tmp/swd/target/share/urjtag/MANUFACTURERS)
jtag> cable kt-link Transport not selected or unsupported. Default transport is: JTAG Connected to libftdi driver. nSRST pin state is high... KT-LINK JTAG Mode Initialization OK!
jtag> cable kt-link jtag Connected to libftdi driver. nSRST pin state is high... KT-LINK JTAG Mode Initialization OK!
jtag> cable kt-link swd Connected to libftdi driver. nSRST pin state is high... KT-LINK SWD Mode Initialization OK!
jtag> cable kt-link help Usage: cable KT-LINK [vid=VID] [pid=PID] [desc=DESC] [TRANSPORT] VID USB Device Vendor ID (hex, e.g. 0abc) PID USB Device Product ID (hex, e.g. 0abc) DESC Some string to match in description or serial no. TRANSPORT Setup cable transport mode (jtag, swd, ...). Default: vid=403 pid=bbe2 driver=ftdi-mpsse
Before we start we need to select and initialize the interface and its swd mode with cable <name></name> swd command:
jtag> cable kt-link swd Connected to libftdi driver. nSRST pin state is high... KT-LINK SWD Mode Initialization OK!
Standard detect invocation with successful connection (no target reset necessary, but it is possible with pod reset=0):
jtag> detect IDCODE=0x0EE2805D8 (11101110001010000000010111011000)
Device is powered off - libswd returns SWD_ERROR_ACK error to the master application (UrJTAG) and produces error string with problem description:
jtag> detect Error: detect.c:566 urj_tap_detect_swd() Cable<->DAP transport error: swd_dap_detect() failed ([SWD_ERROR_ACK] acknowledge error).
We want some more information - debug level set to detail using UrJTAG's command debug detial - target application's verbosity log-level is then inherited and translated into apropriate swd-log-level by swd_log_level_inherit() function (you can see the message on debug level):
jtag> debug detail jtag> detect Detecting SWD devices... SWD_I: Executing swd_dap_activate(0x2833ccc0, SWD_OPERATION_EXECUTE) SWD_I: Executing swd_dap_reset(0x2833ccc0, SWD_OPERATION_EXECUTE) SWD_I: Executing swd_dp_read_idcode(0x2833ccc0, SWD_OPERATION_EXECUTE) SWD_I: swd_dp_read_idcode() succeeds, IDCODE=EE2805D8 (11101110001010000000010111011000) IDCODE=0x0EE2805D8 (11101110001010000000010111011000)
We want to see full debug output to trace potential errors - with debug debug command - we get the swd context memory location, queue root location, each of the command's location, type and bistream/payload:
jtag> debug debug swd_log_level_inherit(): SWD Context not (yet) initialized... Return in urj_parse_line r=0 jtag> detect Detecting SWD devices... swd_init() OK SWD_I: Executing swd_dap_activate(0x2833cb40, SWD_OPERATION_EXECUTE) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832b920) bits=0 cmdtype=UNDEFINED returns=0 payload=0x00000000 (00000000) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832b960) bits=1 cmdtype=MOSI_TRN returns=1 payload=0x00000000 (00000000) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bc00) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bc20) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bc40) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bc60) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bc80) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bca0) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bcc0) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bce0) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bd00) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0x00000079 (01111001) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bd20) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffe7 (11100111) SWD_I: Executing swd_dap_reset(0x2833cb40, SWD_OPERATION_EXECUTE) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bd40) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bd60) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bd80) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bda0) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bdc0) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bde0) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832be00) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832be20) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0xffffffff (11111111) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832be40) bits=8 cmdtype=MOSI_CONTROL returns=8 payload=0x00000000 (00000000) SWD_I: Executing swd_dp_read_idcode(0x2833cb40, SWD_OPERATION_EXECUTE) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832be60) bits=8 cmdtype=MOSI_REQUEST returns=8 payload=0xffffffa5 (10100101) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832be80) bits=1 cmdtype=MISO_TRN returns=1 payload=0x00000001 (00000001) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bea0) bits=3 cmdtype=MISO_ACK returns=3 payload=0x00000004 (00000100) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bec0) bits=32 cmdtype=MISO_DATA returns=32 payload=0xee2805d8 (11101110001010000000010111011000) SWD_D: swd_drv_transmit(0x2833cb40, 0x2832bee0) bits=1 cmdtype=MISO_PARITY returns=1 payload=0x00000000 (00000000) SWD_I: swd_dp_read_idcode() succeeds, IDCODE=EE2805D8 (11101110001010000000010111011000) swd_dap_detect() OK IDCODE=0x0EE2805D8 (11101110001010000000010111011000) Return in urj_parse_line r=0
Note that memory locations of the data structures can be used to inspect data, ie. p *(swd_ctx_t *)0x2833cd80 in gdb after symbols are loaded :-)
As you can see on the debug level, there are few basic operations on the bus (control, trn, request, ack, data, parity) chained into more complex operations on the target, ie. swd_dp_read_idcode() functions consists of request, trn, ack, data and parity, where trn is being automatically by libswd depending on the pervious/next command direction (MOSI stands for Master Output Slave Input, that is Write, while MISO stands for Master Input Slave Output, that is Read operation).
OpenOCD is relatively young open-source project that provides flash memory access and gdb-remote debug bridge with use of JTAG Test Access Port. It supports many different target CPU families, common flash memory type (NOR and NAND) and jtag interfaces - all can be extended with higher level TCL scripting. The software is jtag-centric and there is no good division of the functionalities. In 2010 David Brownell proposed idea to create yet another layer that will represent transport system between interface and the target access port that was joined with external LibSWD library for low-level SWD implementation created by Tomek Cedro. This is brilliant idea that should be standardized and implemented during SWD implementation/integration. OpenOCD has however somehow ugly undocumented internal organization with global structures, void parameters, uncentralized information organization and unclear program flow (mixed calls of C functions and TCL commands), therefore soon it needs general reorganization to become more developer-friendly and fully integrate new functionalities ;-)
The source tree clearly needs reorganization and unamiguous division into functionalities with compatibile interfaces between each of the layers below. However I have dropped this task as for now the most important is to finish the transport infrastructure, integrate with libswd and make swd transport work, so other developers can make use of it and extend its functionality, maybe add some other transports...
- interface: dongle drivers - this will allow to flush the queue and in general transfer bits over the wire.
- transport: jtag, swd, spi, ... - this will convert commands into bitstream and bistream into results.
- Access Port or Board: TAP (JTAG), DAP (SWD), ... - this will allow some basic operations on target such as detect, reset and others that does not fir neirther into transport nor target.
- target: arm*, cortex, mips, ... - this will allow to access target registers and memory and create bridge between higher layers (flash, rtos, ...) and the physical target.
- flash - this will allow to access flash memory of the target device.
- rtos - this will allow to access various operating system internals such as process list, kernel modules and internals, programs execution, etc.
- smp - this will allow to control multiple processors on the multicore devices.
- ...
Below I will place information on what is already done:
- jtag centric drivers based on
struct jtag_interface
was extended withtransfer_bits
andsignal_operate
to create common API for interface signals manipulation (before each interface had its own device specific procedure to flush jtag queue). - interface driver (
struct jtag_interface
) has now dynamic list field that can contain both transport and interface independent signals to implement necessary transport layer operations (ie. output buffers switch for TRN operation). - SWD DP and AP procedures for OpenOCD using LibSWD are now ready and compatibile with existing arm_adi_v5 infrastructure (change between JTAG and SWD should not affect higher layers of existing works, maybe transport specific differences will have to be wrapped somehow).
- Driver bridge between OpenOCD and LibSWD is now ready, not yet verified.
- SWD driver for KT-LINK interface is ready.
-
struct jtag_interface ft2232_swd_interface
is now ready based on existing ft2232 drivers pool and additional crafted methods to work with interface signalls and bitsream. - Program builds successfully ;-)
- Program runs as expected for JTAG transport - changes did not break existing functionality (there was a hidden bug in setting transport clock, but it is already fixed in current source tree).
- For interface having only one transport the transport is selected correctly (ie. jtag for ft2232_interface, swd for ft2232_swd_interface).
- LibSWD build system is now integrated with OpenOCD build system. By default LibSWD will be fetched from git repository into OpenOCD source tree and built/installed together. It is possible to disable internal libswd build with
--disable-internal-libswd
and use some other libswd already installed on the system. - interface initialization now work for jtag and swd transport
- tcl interface has now frontend to inetrface signals (
interface_signal
command that can list, add, delete signals) management and bitbang (bitbang
that supports many signals read and write operations at one invocation). These operations can now be used to operate specified signals by hand or with automation scripts. - verify crafted interface methods to work on interface signals and bitstream - done!
- verify driver bridge between openocd drivers and libswd - done! i had to create generic driver architecture for transports other than jtag :-)
- verify interface operation, bitsream, etc - done!
- read out the idcode using swd transport - done!
- swd command set and tcl interface basics - done!
- separation of loglevels in openocd and libswd to improve debug - done!
- swd transport infrastructure - verified!
- remove jtag-specific code pieces from arm target - a wrapper has been created to provide jtag and swd specific functions based on the selected transport.
- make arm target work with swd transport - already done.
- implement transport independent error handling as jtag and swd use different error handling mechanisms - it was implemented inside libswd_dap functions.
- access internal bus - done.
- access flash in read/write mode - done flash write.
- make debug work - to be verified but can work soon.
In order to allow access to non-JTAG devices, transport layer has been created by David Brownell to abstract operations on the bus interconnecting interface and target system. Implementation for SWD transport in OpenOCD based on LibSWD was created by Tomasz Cedro. A new interface ft2232_swd
has been created reusing existing code for FT2232 devices. The code was developed and tested on KT-LINK interface, a first on the market inexpensive FT2232H-based design by Krzysztof Kajstura supporting both JTAG and SWD. Everything created around SWD is backward compatible and make (re)use of existing code and design, so it should be fairly easy to add new inetrfaces and transports now. It should be also possible to use existing FT2232 based devices with SWD transport with small buffer/interface between interface pins and the target. Accomplishing this goal was quite a challenge, but it turned out to be possible :-)
OpenOCD had only jtag-specific flush_queue()
function to transfer logical data into interface hardware that was not usable for transfering bitstream for other transports. In order to implement transports other than jtag at interface level it was necessary to create bit-bang functionality allowing free control over read/write access to the interface electrical signals. Because OpenOCD has integrated TCL interpreter I have created interface_signal
and bitbang
frontend for mentioned underlying interface signal operations. Example bitbanging is presented below, it can be also used for full interface configuration at script/configuration level, so there is no need to hard-code complex routines anymore for new interfaces or transports:
%telnet localhost 4444 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Open On-Chip Debugger > interface_signal list Interface Signal Name | Mask | Value ---------------------------------------------------------- RnW | 0x00001000 | 0x00001000 LED | 0x00008000 | 0x00008000 srst | 0x00000A00 | 0x00000A00 > bitbang led=hi LED=0x00008000 > bitbang led=lo LED=0x00000000 > bitbang led=hi LED=0x00008000 > interface_signal list Interface Signal Name | Mask | Value ---------------------------------------------------------- RnW | 0x00001000 | 0x00001000 LED | 0x00008000 | 0x00008000 srst | 0x00000A00 | 0x00000A00 > bitbang led=lo LED=0x00000000 > interface_signal list Interface Signal Name | Mask | Value ---------------------------------------------------------- RnW | 0x00001000 | 0x00001000 LED | 0x00008000 | 0x00000000 srst | 0x00000A00 | 0x00000A00 > interface_signal Bad syntax! interface_signal (add|del|list) signal_name [mask] in procedure 'interface_signal' >
No need to mention that such commands can be grouped in functions and then called for some target-specific operations (i.e. SPI memory access). This wont be as fast as built-in transport but definitely will come handy for testing :-)
interface_signal
and bitbang
brings new possibilities to interface scripting. Signals can be added dynamically at runtime with no need to hardcode them or recompile program. Signals can be driven read or write with selected values and masks allowing unlimited control over interface pinout. It is now possible to easily write external scripts for additional interface hardware, such as ADC or DAC, that was not possible before. Below is an example configuration file for KT-LINK interface (...and its example usage presented above):
interface ft2232_swd ft2232_device_desc "KT-LINK" ft2232_layout ktlink_swd ft2232_vid_pid 0x0403 0xBBE2 interface_signal add RnW 0x1000 interface_signal add LED 0x8000 interface_signal add SRST 0x0a00
Later on I have also added some additional signals that comes handy in SWD transport and general driver/target testing:
interface_signal add SRSTin 0x0040 interface_signal add CLK 0x01 interface_signal add MOSI 0x02 interface_signal add MISO 0x04 interface_signal add nSWDsel 0x20
At the moment transport initialization requires defined target, so it it not possible to work on a target when no target is defined inside openocd - this is the existing openocd organization - but it can change if necessary.
Current work is aimed at making existing Target infrastructure work using SWD transport. The example configuration for use with Stm32Primer2 and KT-LINK-SWD can be following (please note flash driver change stm32x -> stm32f1x change during last year):
if { [info] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32 } if { [info] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 16kB if { [info] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz adapter_khz 10000 if { [info] } { set _CPUTAPID $CPUTAPID } else { # See STM Document RM0008 # Section 26.6.3 set _CPUTAPID 0x3ba00477 } swd newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m3 -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m3 reset_config sysresetreq
First the interface (and so the transport) is set up, then the interface/adapter speed that is board-specific, then the SWD TAP and Target is created (using existing JTAG infrastructure a.t.m.) using SWD command set selected by swd transport select call. Later on targets is detected and commands are accepted on the telnet commandline - halt and flash memory access is now possible.
Below a fresh screenshots of integration between LibSWD (0.5 devel) and OpenOCD (0.7 devel) is being made on top of the openocd's git head from November 2012 - this is the code that will be included into main OpenOCD branch..
The Interface infrastructure is now done. Interface Bitbang, Transfer, Feature is now done. ft2232_swd driver is now done. Transport for swd and swd_libswd is now done. There are still some jtag-dependent code in mem-ap sections, but the target can be detected...
What happens if target is powered down or not connected? We get error message and LibSWD explains what is the problem.
% ./openocd -f stm32swd.cfg Open On-Chip Debugger 0.7.0-dev-gc1e217b-dirty (2012-11-15-21:21) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html Info : only one transport option; autoselect 'swd' Info : Selected LibSWD as SWD transport mechanism, adding driver features... Info : Interface signal - 'RnW' added. Info : Interface signal - 'LED' added. Info : Interface signal - 'SRST' added. Info : Interface signal - 'SRSTin' added. Info : Interface signal - 'CLK' added. Info : Interface signal - 'MOSI' added. Info : Interface signal - 'MISO' added. Info : Interface signal - 'nSWDsel' added. adapter speed: 1000 kHz adapter_nsrst_delay: 100 cortex_m3 reset_config sysresetreq Info : KT-LINK SWD-Mode initialization complete... Info : max TCK change to: 30000 kHz Info : clock speed 1000 kHz LIBSWD_N: Using libswd master-GIT-devel (http://libswd.sf.net) LIBSWD_N: (c) Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) Info : New SWD context initialized at 0x0x801423400 LIBSWD_I: Executing libswd_dap_activate(libswdctx=@0x801423400, operation=LIBSWD_OPERATION_EXECUTE) LIBSWD_I: Executing libswd_dap_reset(libswdctx=@0x801423400, operation=LIBSWD_OPERATION_EXECUTE) LIBSWD_I: Executing libswd_dp_read_idcode(libswdctx=@0x801423400, operation=LIBSWD_OPERATION_EXECUTE) LIBSWD_E: libswd_drv_transmit(libswdctx=@0x801423400, cmd=@0x801440f70): Unknown ACK detected / Protocol Error Sequence! DAP Stalled or Target Power Off? Error: libswd_dap_detect() error -19 ([LIBSWD_ERROR_ACKUNKNOWN] got unknown acknowledge) in procedure 'transport' in procedure 'init'
Interface selection works fine, transport selection works fine, executing operations from Interface Feature provided by LibSWD Transport works fine, target detection (Transport Init) works fine. Still hardcoded jtag parts in mem-ap support in current openocd code needs to be developed/fixed:
% ./openocd -f stm32swd.cfg Open On-Chip Debugger 0.7.0-dev-gcf35ed5-dirty (2012-11-16-02:03) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html Info : only one transport option; autoselect 'swd' Info : Interface 'ft2232_swd' defines its own 'oocd_feature_arm_dap' features. Info : Interface signal - 'RnW' added. Info : Interface signal - 'LED' added. Info : Interface signal - 'SRST' added. Info : Interface signal - 'SRSTin' added. Info : Interface signal - 'CLK' added. Info : Interface signal - 'MOSI' added. Info : Interface signal - 'MISO' added. Info : Interface signal - 'nSWDsel' added. adapter speed: 1000 kHz adapter_nsrst_delay: 100 Info : KT-LINK SWD-Mode initialization complete... Info : max TCK change to: 30000 kHz Info : clock speed 1000 kHz LIBSWD_N: Using libswd master-GIT-devel (http://libswd.sf.net) LIBSWD_N: (c) Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) Info : New SWD context initialized at 0x0x801423340 LIBSWD_I: Executing libswd_dap_activate(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE) LIBSWD_I: Executing libswd_dap_reset(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE) LIBSWD_I: Executing libswd_dp_read_idcode(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE) LIBSWD_I: libswd_dp_read_idcode(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE, **idcode=0x1BA01477/00011011101000000001010001110111). Info : SWD transport initialization complete. Found IDCODE=0x1BA01477. LIBSWD_I: libswd_dp_read(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE, addr=0x4, **data=0x0/00000000000000000000000000000000). LIBSWD_I: libswd_dp_write(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE, addr=0x4, *data=0x20/00000000000000000000000000100000). LIBSWD_I: libswd_dp_read(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE, addr=0x4, **data=0x0/00000000000000000000000000000000). LIBSWD_I: libswd_dp_write(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE, addr=0x4, *data=0x50000000/01010000000000000000000000000000). LIBSWD_I: libswd_dp_read(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE, addr=0x4, **data=0xF0000000/11110000000000000000000000000000). LIBSWD_I: libswd_dp_read(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE, addr=0x4, **data=0xF0000000/11110000000000000000000000000000). LIBSWD_I: libswd_dp_write(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE, addr=0x4, *data=0x50000001/01010000000000000000000000000001). LIBSWD_I: libswd_dp_read(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE, addr=0x4, **data=0xF0000001/11110000000000000000000000000001). LIBSWD_I: libswd_ap_write(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE, addr=0x0, *data=0xA2000012/10100010000000000000000000010010). LIBSWD_I: libswd_ap_write(libswdctx=@0x801423340, operation=LIBSWD_OPERATION_EXECUTE, addr=0x4, *data=0xE000ED00/11100000000000001110110100000000). Assertion failed: (jtag_trst == 0), function jtag_checks, file core.c, line 339. Abort (core dumped)
What happens if we choose an interface that does not provide features necessary for a given transport? Default LibSWD features are tried, and if that fils program quits because there are no features required to run swd transport...
% ./openocd -f stm32swd.cfg Open On-Chip Debugger 0.7.0-dev-gbdd0f79-dirty (2012-11-16-00:35) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html Info : only one transport option; autoselect 'swd' Error: Invalid features list selected (no features)! Info : Trying to select LibSWD as SWD transport mechanism, adding driver features... Error: Invalid features list selected (no features)! Warn : Transport features 'oocd_feature_arm_dap' failed to attach to interface 'ft2232_swd'! Error: Interface 'ft2232_swd' does not provide/accept features required by transport 'swd'! Runtime Error: /tmp/openocd/target/share/openocd/scripts/interface/kt-link-swd.cfg:4:
Both Stm32Primer and Stm32Primer2, except some fancy user interface devices onboard, consist of the CPU and RLink interface - both have their own USB connectors. RLink allows code memory access and program execution trace with no additional hardware, but it is a proprietary device with proprietary protocol, so using Stm32Primer development kits with non-Raisonance software is made difficult.
Stm32Primer use JTAG mode for programming and is already supported by OpenOCD and UrJTAG, Stm32Primer2 use SWD and need some additional work documented in this project. I want to make JTAG+SWD modes work on both RLink interfaces, but also make SWD working with more generic FT2232H based device - KT-LINK seems just perfect for this purpose.
Also it is important to remember not to use both RLink and other interface simultaneously as this may damage both interfaces and the CPU. When device is going to be used with an external inerface, internal one must be disconnected by desoltering the resistors or simply cutting the wires on the PCB. It is also necessary to connect ground and reference voltage pins for the logic buffers to work properly on the external interface.
Device: Stm32Primer
CPU: STM32F103RBT6
Programming: Onboard USB RLink JTAG
To access the SWJ pins on the Stm32Primer you need to connect external interface to signal points shown on the pictures below. I have made a simple socket connector for easier connect/disconnect. Here you can get a high quality pdf file.
Device: Stm32Primer2
CPU: STM32F103VET6
Programming: Onboard USB RLink SWD
To access the SWJ pins on the Stm32Primer2 you need to connect external interface to signal points shown on the pictures below. Here you can get a high quality pdf file.
To have ability to test JTAG and SWD on the same device, also the ability to switch to and from one of the modes, full JTAG connector must be first created. There are some problems however with a brand new Primer2 taken out of the box - it is only SWD aware so no JTAG connection is available between the CPU and builtin RLink, also the remaining JTAG pins are set as outputs driving the audio codec chip onboard (I have physically cut off this connection). Because TRST signal behavior can be also obtained with toggling the TCK/TMS and this signal should reset the TAP, in most cases this is enough to reset device and zero the port registers setting their function to default - but not this time. A separate SRST signal needs to hold device after power up and before the program starts and lock out the pins. In case of KT-LINK SRST signal has to high impedance to reset target at command (urjtag command "pod reset=0"), so I had to apply low state on reset line and then power on the device - below is the result:
%./jtag UrJTAG 0.10 #1862 Copyright (C) 2002, 2003 ETC s.r.o. Copyright (C) 2007, 2008, 2009 Kolja Waschk and the respective authors UrJTAG is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. There is absolutely no warranty for UrJTAG. jtag.c:518 main() Warning: UrJTAG may damage your hardware! Type "quit" to exit, "help" for help. jtag> cable kt-link Connected to libftdi driver. SRST pin state is high... KT-LINK JTAG Mode Initialization OK! jtag> pod reset=0 jtag> detect Error: parse.c:208 urj_parse_file() no error: Cannot open file '~/.jtag/rc' to parse jtag> detect IR length: 9 Chain length: 2 Device Id: 00111011101000000000010001110111 (0x3BA00477) Unknown manufacturer! (01000111011) (/mnt/stuff/tmp/swd/target/share/urjtag/MANUFACTURERS) Device Id: 00000110010000010100000001000001 (0x06414041) Unknown manufacturer! (00000100000) (/mnt/stuff/tmp/swd/target/share/urjtag/MANUFACTURERS)
SWD transport is now ready using UrJTAG and KT-LINK external interface:
%./jtag UrJTAG 0.10 #1864 Copyright (C) 2002, 2003 ETC s.r.o. Copyright (C) 2007, 2008, 2009 Kolja Waschk and the respective authors UrJTAG is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. There is absolutely no warranty for UrJTAG. jtag.c:518 main() Warning: UrJTAG may damage your hardware! Type "quit" to exit, "help" for help. jtag> cable kt-link swd Connected to libftdi driver. nSRST pin state is high... KT-LINK SWD Mode Initialization OK! jtag> detect IDCODE=0x0EE2805D8 (11101110001010000000010111011000)
Device: KT-LINK
Chipset: FT2232H
JTAG+SWD Capable Programmer Interface
Because SWD is a bidirectional bus, more advanced buffering is required than in case of JTAG where one pin was used for input and another for output signal. Therefore not all dongles supporting JTAG will support SWD, or at least in their default configuration, please keep that in mind. Here you can get the KT-LINK specification. Also note that different interfaces might have slightly different pinout (especially the VCC pin).
There is an Open-Source libftdi library that allows multiplatform communication with FT2232 devices. There is also a free but proprietary libftd2xx library released by the Future Technology Devices International (FT2232 manufacturer), however audience is limited I will not use this one in this project.
Older JTAG interfaces use FT2232D silicon, that is Full-Speed USB version (12MBit/s max. throughput). Newer devices, such as KT-LINK, use already Hi-Speed FT2232H version (480MBit/s max. throughput), that became supported by libftdi release 0.16 - if you have this chip remember to use up-to-date library!
The UrJTAG's driver for KT-LINK working both in JTAG and SWD mode is now ready. The OpenOCD's driver is also ready and the work on SWD framework using libswd is almost finished :-)
Buffers Organization Buffers Organization
RLink interface can be found as OEM standalone or embedded programming interface. Stm32Primer device family has this interface embedded on one board with the CPU, so I will concentrate only on this version. In this section I will place any information usable to make it work with Open-Source utilities. Several transmission dumps using swd transport are available here to download and work on.
If you want to support this work, please help reverse engineering the protocol to write open source driver for this device.
In this section I will provide essential information on the components that are used to access ARM Cortex system bus and debug unit with SWJ and will be helpful for developers and testers. Information here is also an input for LibSWD that I am working on based on ADIv5 (5.0) specification - that unfortunately contains some bugs and misleading information, but it is already updated with ADIv5.1 that clarifies some things and brings new functionalities. When ADIv5 is fully supported by libswd, works will move to support ADIv5.1. All information presented here can be found on the ARM Website, specifically in their ARM Info Center. If you prefer PDF documentation search for "Arm Debug Interface ADIv5". ARM holds copyright to this materials according to their policy specified on the website and within the documents. If you have any comments, questions or find a bug - please let me know :-)
Note: Information presented below was taken from buggy "Cortex-M series processors Cortex-M1 Revision: r0p1 specification". This caused confusion and implementation troubles at some points. For more unabiguous information please use ADIv5 PDF + Errata as it contains updated and more correct information.
Before we start with the general DAP description lets take a look at the STM32F103VE microcontroller block diagram (picture copyrighted by the STM Microelectronics) - this will give a good perspective on how the components are interconnected and dependent on each other, making it easier to understand the specific block registers, their function and meaning in terms of being a part of bigger system:
As we can see the SW/JTAG (so called SWJ-DP) in the left top corner of the block diagram is placed right next to the ARM-Cortex-M3 CPU. The bus connections are important to know how it can interact with the rest of the system. There is no need to remember the names exactly, but this diagram will be helpful when reading the further chapters. Let's start with the Debus Access Port then and focus only on the SWJ-DP (transport layer access port) and the AHB-AP (memory and peripherial access).
Debug Access Port (DAP) includes some internal logic, Serial Wire JTAG Debug Port (SWJ-DP) as an interface to the debugger and Advanced High-performance Bus Access Port (AHB-AP) interface to enable the SWJ-DP to access the system over an AHB interface. The SWJ-DP is a debug port that combines the JTAG-DP and Serial Wire Debug Port (SW-DP). By default, after power up JTAG-DP is active, however special sequences can switch between JTAG and SWD DP. It is recommended that after power up selection is performed before and during the debug session with no further switchover - reselecting the DP when debug is already active requires hard reset, or unpredictable result may occur. The switching sequences are as follows:
- JTAG-to-SWD:
- Send more than 50 SWCLKTCK cycles with SWDIOTMS=1. This ensures that both SWD and JTAG are in their reset states.
- Send the 16-bit JTAG-to-SWD select sequence on SWDIOTMS.
- Send more than 50 SWCLKTCK cycles with SWDIOTMS=1. This ensures that if SWJ-DP was already in SWD mode, before sending the select sequence, the SWD goes to line reset.
- Perform a READID to validate that SWJ-DP has switched to SWD operation.
- The 16-bit JTAG-to-SWD select sequence is defined to be 0111100111100111, MSB first. This can be represented as 16'h79E7 transmitted MSB first or 16'hE79E (0x9E,0xE7 bytewise!) when transmitted LSB first.
- SWD-to-JTAG:
- Send more than 50 SWCLKTCK cycles with SWDIOTMS=1. This ensures that both SWD and JTAG are in their reset states.
- Send the 16-bit SWD-to-JTAG select sequence on SWDIOTMS.
- Send at least 5 SWCLKTCK cycles with SWDIOTMS=1. This ensures that if SWJ-DP was already in JTAG mode before sending the select sequence, that JTAG goes into the TLR state.
- Set the JTAG-DP IR to READID and shift out the DR to read the ID.
- The 16-bit SWD-to-JTAG select sequence is defined to be 0011110011100111, MSB first. This can be represented as 16'h3CE7 transmitted MSB first or 16'hE73C (0x3C,0xE7 bytewise!) when transmitted LSB first.
JTAG-DP contains a debug port state machine (JTAG) that controls the JTAG-DP operation, including controlling the scan chain interface that provides the external physical interface to the JTAG-DP. It is based closely on the JTAG TAP State Machine, see IEEE Std 1149.1 (2001).
nTRST asynchronously takes the JTAG state machine logic to the Debug-Logic-Reset state. Debug-Logic-Reset state can also always be entered synchronously from any state by a sequence of five TCK cycles with TMS high, however depending on the initial state of the JTAG this might take the state machine through one of the Update states, with the resulting side effects. When the JTAG goes through the Capture-IR state, a value is transferred onto the Instruction Register (IR) scan chain. The IR scan chain is connected between TDI and TDO. While the JTAG is in the Shift-IR state, and for the transition from Capture-IR to Shift-IR, the IR scan chain advances one bit for each tick of TCK. This means that on the first tick, the LSB of the IR is output on TDO, bit [1] of the IR is transferred to bit [0], bit [2] is transferred to bit [1], for example. The MSB of the IR is replaced with the value on TDI. When the JTAG goes through the Update-IR state, the value scanned into the scan chain is transferred into the Instruction Register. When the JTAG goes through the Capture-DR state, a value is transferred from one of a number of Data Registers (DRs) onto one of a number of Data Register scan chains, connected between TDI and TDO. This data is then shifted while the JTAG is in the Shift-DR state, in the same manner as the IR shift in the Shift-IR state. When the JTAG goes through the Update-DR state, the value scanned into the scan chain is transferred into the Data Register. When the JTAG is in the Run-Test/Idle state, no special actions occur. Debuggers can use this as a true resting state.
The JTAG-DP registers are only accessed when the Instruction Register (IR) for the DAP access contains the IDCODE, DPACC, or ABORT instruction. The JTAG-DP register accessed depends on both Instruction Register (IR) value for the DAP access and the address field of the DAP access.
JTAG IR is a 4-bit register that holds the current DAP Controller instruction. On debug logic reset, IDCODE becomes the current instruction. If the IR register is set to IR instruction value out of scope (that is not implemented, or reserved), then the Bypass Register is selected.
Standard IR instructions are:
- b1000: ABORT (DR: 1bit) - JTAG-DP Abort Register (ABORT) - Access the DP Abort Register, to force a DAP abort.
- b1010: DPACC (DR: 35bits) - JTAG DP Access Registers (DPACC) - Initiate a Debug Port (DP) or Access Port (AP) access, to access a debug port or access port register. The DPACC and APACC are used for read and write accesses to registers - DPACC to access the CTRL/STAT, SELECT and RDBUFF registers, while APACC is used to access all of the access port registers.
- b1011: APACC (DR: 35bits) - JTAG AP Access Registers (APACC) - The DPACC and APACC scan chains have the same format. See DPACC (above).
- b1110: IDCODE (DR: 32bits) - JTAG Device ID Code Register (IDCODE) - Device identification. The Device ID Code value enables a debugger to identify the debug port to which it is connected. Different debug ports have different Device ID Codes, so that a debugger can make this distinction.
- b1111 BYPASS (DR: 1bit) - JTAG Bypass Register (BYPASS) - Bypasses the device, by providing a direct path between TDI and TDO.
There are five physical DR registers: BYPASS, IDCODE, DPACC, APACC, ABORT. There is a scan chain associated with each of these registers - the IR register determines which of these scan chains is connected to the TDI and TDO signals.
Access the DP Abort Register, to force a DAP abort. The debugger must scan the value 0x0000008 into this scan chain. This value writes the RnW bit as 0, A[3:2] field as b00, 1 into bit 0, the DAPABORT bit, of the Abort Register.
- Version, bit [31:28], is set to 3
- Part number, bit [27:12], is set to 0xBA00
- Manufacturer ID, bit [11:1], is set to 0x23B
- Reserved, bit [0], is set to 1.
Initiate a debug port or access port access, to access a debug port or access port register.
In the Capture-DR state, the result of the previous transaction, if any, is returned, together with a 3-bit ACK response. Only two ACK responses are implemented (all others reserved):
- b010 OK/FAULT response to a DPACC or APACC access: If the response indicated by ACK[2:0] is OK/FAULT, the previous transaction has completed. The response code does not show whether the transaction completed successfully or was faulted. You must read the CTRL/STAT register to find whether the transaction was successful:
- If the previous transaction was a read that completed successfully, then the captured ReadResult[31:0] is the requested register value. This result is shifted out as Data[34:3].
- If the previous transaction was a write, or a read that did not complete successfully, the captured ReadResult[31:0] is Unpredictable. If Data[34:3] is shifted out it must be discarded.
- b001 WAIT response to a DPACC or APACC access: A WAIT response indicates that the previous transaction has not completed. The host should retry the DPACC or APACC access. Normally, if software detects a WAIT response, it retries the same transfer. This enables the protocol to process data as quickly as possible. However, if the software has retried a transfer a number of times, permitting enough time for a slow interconnect and memory system to respond, it might write to the ABORT register, to cancel the operation. This signals to the active access port that it can terminate the transfer it is currently attempting and permits access to other parts of the debug system. An access port might not be able to terminate a transfer on its ASIC interface. However, on receiving an ABORT, the access port must free its JTAG interface.
- Update-DR operation following an OK/FAULT response.
- Update-DR operation following a WAIT response: No request is generated at the Update-DR state and the shifted-in data is discarded. The captured value of ReadResult[31:0] is Unpredictable. You can detect a WAIT response without shifting through the entire DP or AP Access Register
If the current IR instruction is APACC, causing an APACC access:
- If any sticky flag is set in the DP CTRL/STAT Register, the transaction is discarded. The next scan returns an OK/FAULT response immediately.
- If pushed compare or pushed verify operations are enabled then the scanned-in value of RnW must be 0, otherwise behavior is Unpredictable. On Update-DR, a read request is issued and the returned value compared against DATAIN[31:0]. The STICKYCMP flag in the DP CTRL/STAT register is updated based on this comparison.
- The AP access does not complete until the access port signals it as completed.
Most common situations handling:
- Read Operation returns OK/FAULT - Capture read data.
- Write Operation returns OK/FAULT - No more action required.
- Read or Write Operation returns WAIT - Repeat the same access until either an OK/FAULT ACK is received or the wait timeout is reached. If necessary, use the DAP ABORT register to enable access to the AP.
- Read or Write Operation returns Invalid ACK - Assume a target or line error has occurred and treat as a fatal error.
The SW-DP operates with a synchronous serial interface. This uses a single bidirectional data signal and a clock signal.
Each sequence of operations on the wire consists of two or three phases:
- Packet request - The external host debugger issues a request to the debug port. The debug port is the target of the request.
- Acknowledge response - The target sends an acknowledge response to the host.
- Data transfer phase - This phase is only present when either:
- Data Read or Data Write request is followed by a valid (OK) - acknowledge response.
- ORUNDETECT flag is set to 1 in the CTRL/STAT Register (if CTRL/STAT=1 then data transfer is required on all responses).
- target to host, following a read request (RDATA)
- host to target, following a write request (WDATA).
The SW-DP clock, SWCLKTCK, can be asynchronous to the device/system CLK. SWCLKTCK can be stopped when the debug port is idle, but host must continue to clock the interface for a number of cycles after the data phase of any data transfer - this ensures that the transfer can be clocked through the SW-DP. 100k high-pullup resistor is recommended at target on SWTMSIO line, therefore this line should be driven high before entering low power mode.
Interface reset or resynchronization occurs at 50 clocks with data line set high and then IDCODE read ended with OK response. Device will signal request for reset by not driving the data line at response stage, after two bad data sequences in a row target locks out and requests reset sequence described before. Additionally host should give target some time for command processing to return a payload, host can request IDCODE read and when it fails it should reset Target.
Note: After reset and jtag-to-swd sequence SWDIOTMS line must be driven low with at least one clock pulse on SWCLK line, otherwise target will not respond to any request! JTAG-TO-SWD sequence presented by ARM is incomplete and will not work without IDLE cycle. It is good to implement IDLE command that consists of SWDIOTMS line set low with 8 clock pulses on SWCLK line (kind of request with 0x00 payload) that will allow SW-DP to successfully complete commands execution when appended at the end of long queue or reset sequences.
- Start - single start bit, with value 1.
- APnDP - single bit, indicating whether the DP or the AP Access Register is to be accessed. This bit is 0 for a DPACC access, or 1 for an APACC access.
- RnW - single bit, indicating whether the access is a read or a write. This bit is 0 for an write access, or 1 for a read access.
- A[2:3] - two bits, giving the A[3:2] address field for the DP or AP Register Address (shifted out LSB first):
- APACC access, the register being addressed depends on the A[3:2] value and the value held in the SELECT register.
- DPACC access, the A[3:2] value determines the address of the register in the SW-DP register map.
- Parity - single parity bit for the preceding packet.
- Stop - single stop bit. In the synchronous SWD protocol this is always 0.
- Park - single bit. The host must drive the line high before tristating the line. The target reads this bit as 1.
- Trn (Turnaround) - this is a period when the line is not driven and the state of the line is Undefined. The length of the turnaround period is controlled by the TURNROUND field in the Wire Control Register. The default setting is a turnaround period of one clock cycle. By default turnaround time is one cycle.
- ACK - 3-bit target-to-host response. Transmitted LSB first on the wire.
- WDATA[0:31] - 32 bits of write data, from host to target.
- RDATA[0:31] - 32 bits of read data, from target to host.
- Packet requests - parity check is made over the APnDP, RnW and A[2:3] bits (when the number of bits set to 1 is odd then the parity bit is set to 1, when the number of bits set to 1 is even then the parity bit is set to 0).
- Data transfers (WDATA and RDATA) - parity check is made over the 32 data bits, WDATA[0:31] or RDATA[0:31]. If, of these 32 bits (if the number of bits set to 1 is odd then the parity bit is set to 1, if the number of bits set to 1 is even then the parity bit is set to 0).
A successful write operation consists of three phases:
- 8-bit write packet request, from the host to the target
- 3-bit OK acknowledge response, from the target to the host
- 33-bit data write phase, from the host to the target
By default, there are single-cycle turnaround periods between each of these phases. The OK response only indicates that the debug port is ready to accept the write data. The debug port writes this data after the write phase has completed. The response to the debug port write itself is given on the next operation. There is no turnaround phase after the data phase. The host is driving the line and can start the next operation immediately. SW-DP can buffer writes to the APBUS.
The SW-DP implements a write buffer that enables it to accept write operations even when other transactions are still outstanding. The debug port issues an OK response to a write request if it can accept the write into its write buffer. This means that an OK response to a write request, other than a write to the DP ABORT Register, indicates only that the write has been accepted by the debug port. It does not indicate that all previous transactions have completed.
If a write is accepted into the write buffer but later abandoned, the WDATAERR flag is set in the CTRL/STAT Register, see Control/Status Register, CTRL/STAT. A buffered write is abandoned if:
- A sticky flag is set by a previous transaction.
- A debug port read of the IDCODE or CTRL/STAT Register is made. Because the debug port is not permitted to stall reads of these registers, it must:
- perform the IDCODE or CTRL/STAT Register access immediately
- discard any buffered writes, because otherwise they would be performed out-of-order.
- A debug port write of the ABORT Register is made. This is because the debug port cannot stall an ABORT Register access.
The write buffer must be emptied before the following operations can be performed:
- any access port read operation
- any debug port operation other than a read of the IDCODE or CTRL/STAT Register, or a write of the ABORT Register.
A successful read operation consists of three phases:
- 8-bit read packet request, from the host to the target
- 3-bit OK acknowledge response, from the target to the host
- 33-bit data read phase, where data is transferred from the target to the host.
By default, there are single-cycle turnaround periods between the first and second of these phases and after the third phase. However, there is no turnaround period between the second and third phases.
The SW-DP CTRL/STAT register includes a READOK flag, bit [6]. This register is described in Control/Status Register, CTRL/STAT. The READOK flag is updated on every access port read access and on every RDBUFF read request. When the SW-DP initiates the access port access it clears the READOK flag to 0 and, when the SW-DP target gives an OK response to the read request, it sets the READOK flag to 1. This means that if a host receives a corrupted ACK response to an access port or RDBUFF read request it can check whether the read actually completed correctly. The host can read the DP CTRL/STAT Register to find the value of the READOK flag:
- If the flag is set to 1 then the read was performed correctly. The host can use a RESEND request to obtain the read result, see Read Resend Register, RESEND (SW-DP only).
- If the flag is set to 0 then the read was not successful. The host must retry the original access port or RDBUFF read request.
- On the first access port read access, the read data returned is Undefined. You must discard this result.
- If you immediately make another access port read access this returns the result of the previous access port read.
- You can repeat this for any number of access port reads.
- Issuing the last access port read packet request returns the last-but-one access port read result.
- You must then read the DP RDBUFF Register to obtain the last access port read result.
A WAIT response to a read or write packet request consists of two phases:
- 8-bit read or write packet request, from the host to the target
- 3-bit WAIT acknowledge response, from the target to the host.
By default, there are single-cycle turnaround periods between these two phases and after the second phase. If Overrun Detection is enabled then a data phase is required on a WAIT response. Writing to the ABORT register after receiving a WAIT response enables the debugger to access other parts of the debug system.
A WAIT response is issued by the SW-DP if it is not able to immediately process the request from the debugger. However, a WAIT response must not be issued to the following requests. SW-DP must always be able to process these three requests immediately: IDCODE, CTRL/STAT, ABORT. With any request other than those listed, the SW-DP issues a WAIT response, with no data phase, if it cannot process the request. This happens if a previous access port or debug port access is outstanding, or if the new request is an access port read request and the result of the previous AP read is not yet available.
Normally, when a debugger receives a WAIT response it retries the same operation. This enables it to process data as quickly as possible. However, if several retries have been attempted, and time permitted for a slow interconnection and memory system to respond, if appropriate, the debugger might write to the ABORT register. This signals to the active access port that it must terminate the transfer that it is currently attempting. An access port implementation might be unable to terminate a transfer on its ASIC interface. However, on receiving an ABORT request the access port must free up the SWD interface.
A FAULT response to a read or write packet request consists of two phases:
- 8-bit read or write packet request, from the host to the target
- 3-bit FAULT acknowledge response, from the target to the host.
By default, there are single-cycle turnaround periods between these two phases and after the second phase. If Overrun Detection is enabled then a data phase is required on a FAULT response.
SW-DP does not issue a FAULT response to an access to the IDCODE, CTRL/STAT or ABORT registers. For any other access, the SW-DP issues a FAULT response if any sticky flag is set in the CTRL/STAT Register. Use of the FAULT response enables the protocol to remain synchronized. A debugger might stream a block of data and then check the CTRL/STAT register at the end of the block. The sticky error flags are cleared by writing bits in the ABORT register, see Abort Register, ABORT.
A protocol error occurs when a host issues a packet request but the target fails to return any acknowledge response. If the SW-DP detects a parity error in the packet request it does not reply to the request.
When the host receives no reply to its request, it must back off, in case the SW-DP has lost frame synchronization for some reason. After this, it can issue a new transfer request. In this situation it must read the IDCODE register - this is mandated by this specification because a successful read of the IDCODE register confirms that the target is operational. If there is no response at the second attempt, the debugger must force a line reset to ensure frame synchronization and valid operation. This is necessary because the SW-DP is in a state where it only responds to a line reset. After the line reset the debugger must read the IDCODE register before it attempts any other operations.
If the transfer that resulted in the original protocol error response was a write, you can assume that no write occurred. If the original transfer was a read, it is possible that the read was issued to an access port. Although this is unlikely, you must consider this possibility because reads are pipelined and the debug port might implement a write buffer.
- address b00:
- R, APnDP=b0: Identification Code Register, IDCODE.
- W, APnDP=b0: Abort Register, ABORT
- address b01
- CTRLSEL=b0: R/W: Control/Status Register, CTRL/STAT
- CTRLSEL=b1: R/W: Wire Control Register, WCR (SW-DP only)
- address b10:
- R: Read Resend Register, RESEND (SW-DP only)
- W: AP Select Register, SELECT
- addrsss b11:
- R: Read Buffer, RDBUFF
The Abort Register is always present on all debug port implementations. Its main purpose is to force a DAP abort. On a SW-DP, it is also used to clear error and sticky flag conditions. A write-only register. Always accessible and returns an OK response if a valid transaction is received. Abort Register accesses always complete on the first attempt.
Bit description:
- [31:5] - Reserved, SBZ.
- [4] ORUNERRCLR - Write b1 to this bit to clear the STICKYORUN overrun error flagb (SW-DP only).
- [3] WDERRCLR - Write b1 to this bit to clear the WDATAERR write data error flagb (SW-DP only).
- [2] STKERRCLR - Write b1 to this bit to clear the STICKYERR sticky error flagb (SW-DP only).
- [1] STKCMPCLR - Write b1 to this bit to clear the STICKYCMP sticky compare flagb (SW-DP only).
- [0] DAPABORT - Write b1 to this bit to generate a DAP abort. This aborts the current access port transaction. This must only be done if the debugger has received WAIT responses over an extended period.
After a debug port abort is requested, new transactions can be accepted by the debug port. However, an access port access to the access port that was aborted can result in more WAIT responses. Other access ports can be accessed, however, the state of the system might make it impossible to continue with debug.
Clearing error and sticky compare flags - When a debugger, connected to a SW-DP, checks the Control/Status Register and finds that an error flag is set, or that the sticky compare flag is set, it must write to the Abort register to clear the error or sticky compare flag. Table 9-14 on page 9-56 lists the flags that might be set in the Control/Status Register and shows which bit of the Abort register is used to clear each of the flags. You can use a single write of the Abort Register to clear multiple flags, if this is necessary. After clearing the flag, you might have to access the debug port and access port registers to find what caused the flag to be set. Typically:
- For the STICKYCMP or STICKYERR flag, you must find which location was accessed to cause the flag to be set.
- For the WDATAERR flag, after clearing the flag you must resend the data that was corrupted.
- For the STICKYORUN flag, you must find which debug port or access port transaction caused the overflow. You then have to repeat your transactions from that point.
The Identification Code Register is always present on all debug port implementations. It provides identification information about the ARM Debug Interface. It is at address 0b00 on read operations when the APnDP bit=1. It is a read-only register and always accessible.
Bits description:
- [31:28] Version code: JTAG-DP=0x3, SW-DP=0x2
- [27:12] PARTNO - Part Number for the debug port. Current ARM-designed debug ports have the following PARTNO values: JTAG-DP=0xBA00, SW-DP=0xBA10
- [11:1] MANUFACTURER - JEDEC Manufacturer ID, an 11-bit JEDEC code that identifies the manufacturer of the device. The ARM default value for this field is 0x23B.
- [0] - Always 0b1.
- Continuation code, 4 bits, [11:8]: b0100, 0x4
- Identity code, 7 bits, [7:1]: b0111011, 0x3B
The Control/Status Register is always present on all debug port implementations. It provides control of the debug port and status information about the debug port. It is located at address 0b01 on read and write operations when the APnDP=b1 and the CTRLSEL=b0 in the Select Register. It is a read-write register, in which some bits have different access rights. It is implementation-defined whether some fields in the register are supported - below is an obligatory bit list and description.
Bits description:
- [31], RO: CSYSPWRUPACK - System power-up acknowledge.
- [30], R/W: CSYSPWRUPREQ - System power-up request. After a reset this bit is LOW (0).
- [29], RO: CDBGPWRUPACK - Debug power-up acknowledge.
- [28], R/W: CDBGPWRUPREQ - Debug power-up request. After a reset this bit is LOW (0).
- [27], RO: CDBGRSTACK - Debug reset acknowledge.
- [26], R/W: CDBGRSTREQ - Debug reset request. After a reset this bit is LOW (0).
- [25:24] - Reserved, RAZ/SBZP.
- [21:12], R/W: TRNCNT - Transaction counter. After a reset the value of this field is Unpredictable.
- [11:8], R/W: MASKLANE - Indicates the bytes to be masked in pushed compare and pushed verify operations. After a reset the value of this field is Unpredictable. The MASKLANE field, bits [11:8] of the CTRL/STAT Register, is only relevant if the Transfer Mode is set to pushed verify or pushed compare operation. In the pushed operations, the word supplied in an access port write transaction is compared with the current value of the target access port address. The MASKLANE field lets you specify that the comparison is made using only certain bytes of the values. Each bit of the MASKLANE field corresponds to one byte of the access port values. Therefore, each bit is said to control one byte lane of the compare operation:
- b1XXX: Include byte lane 3 in comparisons (0xFF------)
- bX1XX: Include byte lane 2 in comparisons (0x--FF----)
- bXX1X: Include byte lane 1 in comparisons (0x----FF--)
- bXXX1: Include byte lane 0 in comparisons (0x------FF)
- [7], RO[1]: WDATAERR[1] - This bit is set to 1 if a Write Data Error occurs. This bit can only be cleared by writing b1 to the WDERRCLR field of the Abort Register, see Abort Register, ABORT. After a power-on reset this bit is LOW (0). It is set if:
- there is a a parity or framing error on the data phase of a write
- a write that has been accepted by the debug port is then discarded without being submitted to the access port.
- [6], RO[1]: READOK[1] - This bit is set to 1 if the response to a previous access port or RDBUFF was OK. It is cleared to 0 if the response was not OK. This flag always indicates the response to the last access port read access. After a power-on reset this bit is LOW (0).
- [5], RO[2]: STICKYERR - This bit is set to 1 when the processor receives a bus error on the system AHB-Lite bus. When STICKYERR is set, no transaction is passed from the JTAG or SW interfaces to the debug AHB system bus. Any read that is performed when STICKYERR is set results in data that is Unpredictable. To clear this bit write b1 to the STKERRCLR field of the Abort Register, see Abort Register, ABORT. After a power-on reset this bit is LOW (0).
- [4], RO[2]: STICKYCMP - This bit is set to 1 when a match occurs on a pushed compare or a pushed verify operation. To clear this bit write b1 to the STKCMPCLR field of the Abort Register, see Abort Register, ABORT. After a power-on reset this bit is LOW (0).
- [3:2], R/W: TRNMODE - This field sets the transfer mode for access port operations. After a power-on reset the value of this field is Unpredictable. In normal operation, access port transactions are passed to the access port for processing. In pushed verify and pushed compare operations, the debug port compares the value supplied in the access port transaction with the value held in the target access port address. Below is a list of the permitted values of this field and their meaning:
- b00: Normal operation
- b01: Pushed verify operation
- b10: Pushed compare operation
- b11: Reserved
- [1], RO[2]: STICKYORUN - If overrun detection is enabled (see bit [0] of this register), this bit is set to 1 when an overrun occurs. To clear this bit write b1 to the ORUNERRCLR field of the Abort Register, see Abort Register, ABORT. After a power-on reset this bit is LOW (0).
- [0], R/W: ORUNDETECT - This bit is set to b1 to enable overrun detection. After a reset this bit is Low (0).
The AP Select Register is always present on all debug port implementations. Its main purpose is to select the current Access Port (AP) and the active four-word register window in that access port. On a SW-DP, it also selects the Debug Port address bank. It is at address 0b10 on write operations when the APnDP=b1 and is a write-only register. Access to the AP Select Register is not affected by the value of the CTRLSEL bit.
Bits description:
- [31:24], APSEL: Selects current access port. Note: Because the processor has only one access port, APSEL must be 8'b00000000. The reset value of this field is Unpredictable.
- [23:8], - Reserved. SBZ/RAZ[1].
- [7:4], APBANKSEL - Selects the active 4-word register window on the current access port. The reset value of this field is Unpredictable.
- [3:1], - Reserved. SBZ/RAZ[1].
- [0], CTRLSEL: SW-DP Debug Port address bank select, SW-DP only. After a reset this field is b0. However the register is WO so you cannot read this value. The CTRLSEL field, bit [0], controls which debug port register is selected at address b01 on a SW-DP. Meaning of the different values of CTRLSEL is as follows:
- 0: CTRL/STAT, see Control/Status Register, CTRL/STAT
- 1: WCR, see Wire Control Register, WCR (SW-DP only)
The 32-bit Read Buffer is always present on all debug port implementations. However, there are significant differences in its implementation on JTAG and SW Debug Ports. On SW-DP it is at address 0xC on read operations when the APnDP=b1 and is a read-only register. Access to the Read Buffer is not affected by the value of the CTRLSEL bit in the SELECT Register.
On a SW-DP, performing a read of the Read Buffer captures data from the access port, presented as the result of a previous read, without initiating a new access port transaction. This means that reading the Read Buffer returns the result of the last access port read access, without generating a new AP access. After you have read the Read Buffer, its contents are no longer valid. The result of a second read of the Read Buffer is Unpredictable.
If you require the value from an access port register read, that read must be followed by one of:
- A second access port register read. You can read the Control/Status Register (CSW) if you want to ensure that this second read has no side effects.
- A read of the DP Read Buffer. This access, to the access port or the debug port depending on which option you used, stalls until the result of the original access port read is available.
The Wire Control Register is always present on any SW-DP implementation. Its purpose is to select the operating mode of the physical serial port connection to the SW-DP. It is a read/write register at address 0b01 on read and write operations when the CTRLSEL=b1 in the Select Register. For information about the CTRLSEL bit see AP Select Register, SELECT. Note: When the CTRLSEL=b1, to enable access to the WCR, the DP Control/Status Register is not accessible. Many features of the Wire Control Register are implementation-defined!
Bits description:
- [31:10], - Reserved. SBZ/RAZ.
- [9:8], TURNROUND: Turnaround tristate period. After a reset this field is b00. This field defines the turnaround tristate period. This turnaround period allows for pad delays when using a high sample clock frequency. The possible values of this field and their meanings is presented below:
- b00: 1 sample period
- b01: 2 sample periods
- b10: 3 sample periods
- b11: 4 sample periods
- [7:6], WIREMODE: Identifies the operating mode for the wire connection to the debug port. After a reset this field is b01. This field identifies SW-DP as operating in Synchronous mode only. This field is required. The possible values of the field and their meanings is presented below:
- b00: Reserved
- b01: Synchronous (no oversampling)
- b1X: Reserved
- [5:3], - Reserved. SBZ/RAZ.
- [2:0], PRESCALER: Reserved. SBZ/RAZ.
The Read Resend Register is always present on any SW-DP implementation. Its purpose is to enable the read data to be recovered from a corrupted debugger transfer, without repeating the original AP transfer. It is a 32-bit read-only register at address 0b10 on read operations. Access to the Read Resend Register is not affected by the value of the CTRLSEL bit in the SELECT Register.
Performing a read to the RESEND register does not capture new data from the access port. It returns the value that was returned by the last AP read or DP RDBUFF read. Reading the RESEND register enables the read data to be recovered from a corrupted transfer without having to re-issue the original read request or generate a new DAP or system level access. The RESEND register can be accessed multiple times. It always returns the same value until a new access is made to the DP RDBUFF register or to an access port register.
This section describes the AHB Access Port (AHB-AP), for access to a system AHB bus through an AHB-Lite master. It acts as a slave to the DAP internal bus, driven by only a single debug port, SWJ-DP, at any one time.
The AHB-AP has two interfaces:
- An internal DAP bus interface that connects to the SWJ-DP
- An AHB master port for connection through the matrix to the external AHB-Lite interface and the PPB.
The AHB-Lite master port supports AHB in AMBA v2.0. The AHB-Lite master port does not support: BURST and SEQ, Exclusive accesses, Unaligned transfers. The other AHB-AP ports are included:
- DBGEN, Input[1]: Enables AHB-AP transfers if HIGH
- SPIDEN, Input[2]: Permits secure transfers to take place on the AHB-AP
- nCDBGPWRDN, Input[1]: Indicates that the debug infrastructure is powered down
- nCSOCPWRDN, Input[1]: Indicates that the system AHB interface is powered down
The following AHB-AP registers are available:
- 0x00, R/W, 32bit: Control/Status Word, CSW (reset value: 0x43800042)
- 0x04, R/W, 32bit: Transfer Address, TAR (reset value: 0x00000000)
- 0x08, Reserved SBZ
- 0x0C, R/W, 32bit: Data Read/Write, DRW
- 0x10, R/W, 32bit: Banked Data 0, BD0
- 0x14, R/W, 32bit: Banked Data 1, BD1
- 0x18, R/W, 32bit: Banked Data 2, BD2
- 0x1C, R/W, 32bit: Banked Data 3, BD3
- 0x20-0xF7, Reserved SBZ
- 0xF8, RO, 32bit: Debug ROM table (reset value: 0xE00FF000)
- 0xFC, RO, 32bit: Identification Register, IDR (reset value: 0x24770001)
This is the control word used to configure and control transfers through the AHB interface.
Bits description:
- [31], Reserved SBZ.
- [30], Reserved SB0.
- [29:28], Reserved SBZ.
- [27:24], R/W, Prot: Specifies the protection signal encoding to be output on HPROT[3:0]. Reset value is noncacheable, non-bufferable, data access, privileged = b0011.
- [23], RO, SPIStatus: Indicates the status of the SPIDEN port. Always reads as b1.
- [22:12], Reserved SBZ.
- [11:8], R/W, Mode (reset value: b0000): Specifies the mode of operation:
- b0000 = Normal download/upload model
- b0001-b1111 = Reserved SBZ.
- [7], RO, TrInProg: Transfer in progress. This field indicates if a transfer is currently in progress on the AHB master port.
- [6], RO, DbgStatus: Indicates the status of the DBGEN port. Always reads as b1 = AHB transfers permitted.
- [5:4], R/W, AddrInc (reset value: b00): Auto address increment and packing mode on Read or Write data access. Only increments if the current transaction completes without an Error Response. Does not increment if the transaction completes with an Error Response or the transaction is aborted. Auto address incrementing and packed transfers are not performed on access to Banked Data registers 0x10-0x1C. The status of these bits is ignored in these cases. Increments and wraps within a 1KB address boundary, for example, for word incrementing from 0x1400-0x17FC. If the start is at 0x14A0, then the counter increments to 0x17FC, wraps to 0x1400, then continues incrementing to 0x149C. Size of address increment is defined by the Size field, bits [2:0].
- b00 = auto increment off
- b01 = increment, single. Single transfer from corresponding byte lane.
- b10 = increment, packed. Word = same effect as single increment. Byte/Halfword. Packs four 8-bit transfers or two 16-bit transfers into a 32-bit DAP transfer. Multiple transactions are carried out on the AHB interface.
- b11 = Reserved SBZ, no transfer.
- [3], Reserved SBZ, R/W = b0
- [2:0], R/W, Size (reset value: b010): Size of the data access to perform:
- b000 = 8 bits
- b001 = 16 bits
- b010 = 32 bits
- b011-b111 = Reserved SBZ.
Bits description:
- [31:0], R/W, Address (reset value: 0x00000000): Address of the current transfer. Unaligned address values with respect to the Size field of the Control/Status Word Register are unsupported.
Bits description:
- [31:0], R/W, Data:
- Write mode: Data value to write for the current transfer.
- Read mode: Data value read from the current transfer.
BD0-BD3 provide a mechanism for directly mapping through DAP accesses to AHB transfers without having to rewrite the Transfer Address Register (TAR) within a four-location boundary. BD0 reads/writes from TA. BD1 reads/writes from TA+4. Below is the AHB-AP Banked Data Register bit assignments:
- [31:0], R/W, Data: If DAPADDR[7:4] = 0x0001, so accessing AHB-AP registers in the range 0x10-0x1C, the derived HADDR[31:0] is:
- Write mode: Data value to write for the current transfer to external address TAR[31:4] + DAPADDR[3:2] + 2'b00.
- Read mode: Data value read from the current transfer from external address TAR[31:4] + DAPADDR[3:2] + 2'b00.
Bits description:
- [31:0], RO, Debug AHB ROM Address: Base address of a ROM table. The ROM provides a look-up table for system components. Set to 0xE00FF000 in the AHB-AP in the initial release.
The register reset value is 0x247700001. Bits description:
- [31:28], RO, Revision: Reset value is 0x2 for AHB-AP.
- [27:24], RO, JEDEC bank: Reset value is 0x4 (Using JEDEC bank 0x0 with a JEDEC code of 0x00 is reserved for use by ARM.)
- [23:17], RO, JEDEC code: Reset value is 0x3B.
- [16], RO, ARM AP: Reset value is b1.
- [15:8], Reserved SBZ.
- [7:0], RO, Identity value: Reset value is 0x01 for AHB-AP.
The AHB-AP has two clock domains that are connected together. HCLK drives both of them:
- DAPCLK - Drives the DAP bus interface and access control for register read and writes. DAPCLK must be driven by a constant clock. When started, it must not be stopped or altered while the DAP is in use.
- HCLK - AHB clock domain driving AHB interface.
- DBGRESETn - Initializes the state of all registers in the AHB-AP.
The AHB-Lite master port supports AHB in AMBA v2.0:
- HPROT[3:0] is provided as an external port (see AHB-AP Control/Status Word Register, CSW, 0x00 for values of the Prot field) and is programmed from the Prot field in the CSW register with the following conditions:
- HPROT[3:0] programming is supported.
- Exclusive access is not supported, so HRESP[2] is not supported.
- HRESP[0] is the only RESPONSE signal required by the AHB-AP:
- AHB-Lite devices do not support SPLIT and RETRY and so HRESP[1] is not required.
- HRESP[2] is not supported in the AHB-AP.
The AHB-AP cannot initiate a new AHB transfer every clock cycle (unpacked) because of the additional cycles required to serial scan in the new address or data value through a debug port. The AHB-AP supports two HTRANS transfer types, IDLE and NONSEQ. When a transfer is in progress, it is of type NONSEQ. When no transfer is in progress and the AHB-AP is still granted the bus then the transfer is of type IDLE. The only unpacked HBURST encoding supported is SINGLE. Packed 8-bit transfers or 16-bit transfers are treated as individual NONSEQ, SINGLE transfers at the AHB-Lite interface. This ensures that there are no issues with boundary wrapping, to avoid additional AHB-AP complexity.
The DAP internal interface is a 32-bit data bus. 8-bit or 16-bit transfers can be formed on AHB according to the Size field in the Control/Status Word Register at 0x00. The AddrInc field in the Control/Status Word Register enables optimized use of the DAP internal bus to reduce the number of accesses from the tools to the DAP. It indicates if the entire data word is to be used to pack more than one transfer. Address incrementing is automatically enabled if packet transfers are initiated so that multiple transfers are carried out at the sequential addresses. The size of the address increment is based on the size of the transfer. See AHB-AP Control/Status Word Register, CSW, 0x00 for values of the AddrInc field and AHB-AP Data Read/Write Register, DRW, 0x0C for Data Read/Write Register bit values.
Examples of the transactions are:
- For an unpacked 16-bit write to an address base of 0x2 (CSW[2:0]=b001, CSW[5:4]=b01), HWDATA[31:16] is written from bits [31:16] in the Data Read/Write Register.
- For an unpacked 8-bit read to an address base of 0x1, (CSW[2:0]=b000, CSW[5:4]=b01), HRDATA[31:16] and HRDATA[7:0] are zeroed and HRDATA[15:8] contains read data.
- For a packed byte write at a base address 0x2, (CSW[2:0]=b000, CSW[5:4]=b10), four write transfers are initiated, the order of data being sent is:
- HWDATA[23:16], from DRW[23:16], to HADDR[31:0]=0x2
- HWDATA[31:24], from DRW[31:24], to HADDR[31:0]=0x3
- HWDATA[7:0], from DRW[7:0], to HADDR[31:0]=0x4
- HWDATA[15:8], from DRW[15:8], to HADDR[31:0]=0x5
- For a packed halfword reading at a base address of 0x2, (CSW[2:0]=b001, CSW[5:4]=b10), two read transfers are initiated:
- HRDATA[31:16] is stored into DRW[31:16] from HADDR[31:0]=0x2
- HRDATA[15:0] is stored into DRW[15:0] from HADDR[31:0]=0x4
I will place this chapter here because it is AHB-AP related and it can give good overview on the memory and peropherial access. The processor contains two bus interfaces:
- external interface
- memory interfaces
This is an AHB-Lite bus interface. Processor accesses and debug accesses to external AHB peripherals are implemented over this bus. Because processor AHB access to zero wait state slaves typically take two cycles longer than TCM accesses, instructions and data must be contained in TCM where possible. If on-chip FPGA memory is used for the processor, highest performance is possible if this is TCM memory, rather than SRAM mapped onto the AHB interface.
Processor accesses and debug accesses share the external interface. Debug accesses take priority over processor accesses. Timing of processor accesses might be changed by the presence of debug accesses. Giving highest priority to debug means that debug cannot be locked-out by a continuously executing stream of core instructions. Because debug accesses tend to be infrequent, debug accesses do not have a major impact on processor accesses.
Any vendor specific components can populate this bus. If an external AHB peripheral incorrectly deadlocks the AHB bus, the debugger might not be able to halt or access the core registers. Contact your implementation team for FPGA probing tools to debug the system external to the core. Unaligned accesses to this bus are not supported.
To prevent bus wait cycles from stalling the processor during data stores, stores to the external interfaces go through a one-entry write buffer. If the write buffer is full, subsequent accesses to the bus stall until the write buffer has drained. DMB and DSB instructions wait for the write buffer to drain before completing.
Below is the encoding for HPROT[3:0]:
HPROT[3] | HPROT[2] | HPROT[1] | HPROT[0] | Description |
---|---|---|---|---|
0 | 0 | 0 | 0 | Invalid |
0 | 0 | 0 | 1 | Invalid |
0 | 0 | 1 | 0 | Instruction fetch |
0 | 0 | 1 | 1 | Data fetch |
0 | 1 | X | X | Invalid |
1 | X | X | X | Invalid |
The processor has two memory interfaces:
- ITCM
- DTCM
Byte-write sizeITCMBYTEWR value Size of write:
- 4'b1111: Word
- 4'b0011 or 4'b1100: Halfword
- 4'b0001, 4'b0010, 4'b0100 or 4'b1000: Byte
For writes, the write address, write data, and control signals are driven on the same cycle. The write enable signals ensure individual bytes within a word are written without corrupting the other bytes in the same word. For example, if ITCMBYTEWR[1] is asserted, bits ITCMBYTEWR[15:8] are written in to byte 1 of the word at address ITCMADRR.
ITCM read signal timings:
Instruction and Data TCM sizes:
CFGITCMSZE or CFGDTCMSZE |
TCM size |
---|---|
4'h0 | 0KB |
4'h1 | 1KB |
4'h2 | 2KB |
4'h3 | 4KB |
4'h4 | 8KB |
4'h5 | 16KB |
4'h6 | 32KB |
4'h7 | 64KB |
4'h8 | 128KB |
4'h9 | 256KB |
4'hA | 512KB |
4'hB | 1MB |
If you use other values than those that Table 10.3 shows, the effects are Unpredictable.
These common features for both JTAG-DP and SWD-DP mainly affect the way that a debugger is able to perform transactions with the DAP. The programmer's model of accessing the DAP and AHB-AP is different for both of these AP's and DP dependent (ie. different for JTAG and SWD). The common part is luckily the Error Detection mechanisms implemented with Sticky Flags and Error Responses and they obey to the following areas of functionality: Read and write errors, Overrun detection, Protocol errors (SW-DP only), Pushed compare and pushed verify operations.
When set to 1, a sticky flag remains set until it is explicitly cleared to 0. Even if the condition that caused the flag to be set no longer applies, the flag remains set until the debugger clears it. The method for clearing sticky flags is different for the SW-DP and JTAG-DP however (see Programmer's Model).
Errors can be returned by the DAP itself, or might come from a debug resource, for example, from a memory access made by a MEM-AP to a debug register file of a processor that is powered down. In the debug port, errors are flagged by sticky flags in the DP Control/Status Register (CTRL/STAT). When an error is flagged, the current transaction is completed. Any further APACC (AP Access) transactions are discarded until the sticky flag is cleared.
The debug port response to an error condition might be:
- To signal an error response immediately. This happens with the SW-DP.
- To immediately discard all transactions as complete. This happens with the JTAG‑DP.
A read or write error might occur in the debug port, or come from the system being debugged as the result of an AHB-AP access in response to an access port request. In either case, when the error is detected the Sticky Error flag, STICKYERR, in the Control/Status Register is set to b1. A read/write error is also generated if the debugger makes an access port transaction request while the debug power domain is powered down.
Debug ports support an overrun detection mode. This mode enables an emulator on a high latency, high throughput connection to be sent blocks of commands. These must be sent with sufficient in-line delays to make overrun errors unlikely. However, if an overrun error occurs, the debug port detects and flags the overrun errors, by setting a flag in the Control/Status Register. In overrun detection mode, the debugger must check for overrun errors after each sequence of APACC transactions, by checking the Sticky Overrun flag in the Control/Status Register. It is not necessary for the emulator to react immediately to the overrun condition.
Overrun detection mode is enabled by setting the Overrun Detect bit, ORUNDETECT, in the DP Control/Status Register. When this bit is set, the only permitted response to any transaction is OK/FAULT on the JTAG-DP and OK on the SW-DP. In overrun detection mode, any other response, at any point, is treated as an error and causes the Sticky Overrun flag, STICKYORUN, in the DP Control/Status Register to be set to b1. The Sticky Error flag, STICKYERR, is not set. The debugger must clear STICKYORUN to 0 to enable transactions to resume. The method of clearing the STICKYORUN flag to 0 is different for a JTAG-DP and a SW-DP:
- On a SW-DP, this bit is cleared by writing b1 to the ORUNERRCLR bit of the ABORT register.
- On a JTAG-DP, this bit can be read normally. Writing 1 to this bit clears the bit to 0.
- check the value of the STICKYORUN bit in the Control/Status register
- clear the STICKYORUN bit, if it is set
- clear the ORUNDETECT bit, to stop overrun detection mode.
Although these errors can only be detected with the SW-DP, they are described here because they are part of the sticky flags error handling mechanism. On the SWD interface, protocol errors can occur, for example because of wire-level errors. These errors might be detected by the parity checks on the data. On receiving a FAULT response from the SW-DP a debugger must read the CTRL/STAT register and check the sticky flag values. The WDATAERR flag is cleared by writing b1 to the WDERRCLR field of the Abort Register.
If the SW-DP detects a parity error in a message header, the debug port does not respond to the message. The debugger must be aware of this possibility. If it does not receive a response to a message, the debugger must back off. It must then request a read of the IDCODE register, to ensure the debug port is responsive, before retrying the original access. If the SW-DP detects a parity error in the data phase of a write transaction, it sets the Sticky Write Data Error flag, WDATAERR, in the Control/Status (CTRL/STAT) Register. Subsequent accesses from the debugger, other than IDCODE, CTRL/STAT or ABORT, result in a FAULT response.
The SW-DP and JTAG-DP debug ports support pushed operations, where the value written as an access port transaction is used at the debug port level to compare against a target read. Pushed operations improve performance where writes might be faster than reads. They are used as part of in-line tests, for example Flash ROM programming and monitor communication. Pushed operations are carried out as follows:
- The debugger writes a value as an access port transaction.
- The debug port performs a read from the access port.
- The debug port compares the two values and updates the Sticky Compare flag, STICKYCMP, in the DP Control/Status register, based on the result of the comparison:
- pushed compare sets STICKYCMP to b1 if the values match
- pushed verify sets STICKYCMP to b1 if the values do not match.
- Whenever the STICKYCMP bit is set, on detection of a valid comparison, any outstanding transaction repeats are cancelled.
Considering pushed operations on a specific access port makes it easier to understand how these operations are implemented. On an AHB-AP, if you perform an access port write transaction to the Data Read/Write (DRW) Register, or to one of the Banked Data (BD0 to BD3) Registers, with either pushed compare or pushed verify active:
- The debug port holds the data value from the access port write transaction in the pushed compare logic, see Figure 9.20.
- The access port reads from the address indicated by the AP Transfer Address Register (TAR), see AHB-AP Transfer Address Register, TAR, 0x04.
- The value returned by this read is compared with the value held in the pushed compare logic and the STICKYCMP bit is set depending on the result. The comparison is masked as required by the MASKLANE bits. For more information see Control/Status Register, CTRL/STAT.
You can use pushed verify to verify the contents of system memory.
- Make sure that the AHB-AP Control/Status Word (CSW) is set up to increment the Transfer Address Register after each access. See Control/Status Register, CTRL/STAT.
- Write to the Transfer Address Register to indicate the start address of the Debug Register region that is to be verified, see AHB-AP Transfer Address Register, TAR, 0x04.
- Write a series of expected values as access port transactions. On each write transaction, the debug port issues an access port read access, compares the result against the value supplied in the access port write transaction, and sets the STICKYCMP bit in the CTRL/STAT Register if the values do not match. See Control/Status Register, CTRL/STAT.
- The TAR is incremented on each transaction.
You can use pushed find to search system memory for a particular word. If you use pushed find with byte lane masking you can search for one or more bytes.
- Make sure that the AHB-AP Control/Status Word (CSW) is set up to increment the TAR (Transfer Address Register) after each access. See Control/Status Register, CTRL/STAT.
- Write to the Transfer Address Register (TAR) to indicate the start address of the Debug Register region that is to be searched. See AHB-AP Transfer Address Register, TAR, 0x04.
- Write the value to be searched for as an AP write transaction. The debug port repeatedly reads the location indicated by the TAR. On each debug port read:
- The value returned is compared with the value supplied in the access port write transaction. If they match, the STICKYCMP flag is set.
- The TAR is incremented.
- This continues until STICKYCMP is set, or ABORT is used to terminate the search.
- LibSWD Project Website - Serial Wire Debug Open Library
- ARM Document on SWD - Low Pin-Count Debug Interfaces for Multi-device Systems - short but good introduction, recommended lecure!
- Stm32Circle - homepage of the Raisonance's Stm32Primer devices, full of resources and example projects.
- STM32F103VE - ST website dedicated to the CPU used in Stm32Primer2, full documentation and examples.
- Stm32Primer2 JTAG/SWD signals - a PDF file containing pictures of Stm32Primer2 with marked JTAG and SWD signals.
- Stm32Primer JTAG signals - a PDF file containting pictures of Stm32Primer with marked JTAG signals.
- OpenOCD - Open-Source utility to (re)program target's memory and code debug.
- UrJTAG - Open-Source utility to perform low-level TAP operations on various hardware targets.
- KT-LINK - inexpensive Polish design USB-SWJ dongle.
- Future Technology Device International - designer and manufacturer of FT2232 chip used widely for USB-JTAG access.
- FT2232H Datasheet - Documentation of the HiSpeed USB (480MBit/s) IC, also the programming referance manual and memory map for use with libftdi.
- libftdi - gives multiplatform access to FT2232 devices family.
- ARM SWD Website - Official ARM website with SWD description.
- STM32 SWD Website - Official STM32 with SWD description.
- ARM Info Center - every information you need to get about ARM product is there (including CoreSight on-chip trace and debug)