Serial Wire Debug Open Library.

0.0.1

Introduction

LibSWD is an Open-Source framework to deal with with Serial Wire Debug Port in accordance to ADI (Arm Debug Interface, version 5.0 at the moment) specification. It is released under 3-clause BSD license. For more information please visit project website at http://libswd.sf.net

What is this about

Serial Wire Debug is an alternative to JTAG (IEEE1149.1) transport layer for accessing the Debug Access Port in ARM-Cortex based devices. LibSWD provides methods for bitstream generation on the wire using simple but flexible API that can reuse capabilities of existing applications for easier integration. Every bus operation such as control, request, turnaround, acknowledge, data and parity packet is named a "command" represented by a swd_cmd_t data type that builds up the queue that later can be flushed into real hardware using standard set of (application-specific) driver functions. This way LibSWD is almost standalone and can be easily integrated into existing utilities for low-level access and only requires in return to define driver bridge that controls the physical interface interconnecting host and target. Drivers and other application-specific functions are "extern" and located in external file crafted for that application and its hardware. LibSWD is therefore best way to make your application SWD aware.

How it works

SWD Context

The most important data type in LibSWD is swd_ctx_t structure, a context that represents logical entity of the swd bus (transport layer between host and target) with all its parameters, configuration and command queue. Context is being created with swd_init() function that returns pointer to allocated virgin structure, and it can be destroyed with swd_deinit() function taking the pointer as argument. Context can be set only for one interface-target pair, but there might be many different contexts in use if necessary, so amount of devices in use is not limited.

Functions

All functions in general operates on pointer type and returns number of processed elements on success or negative value with swd_error_code_t on failure. Functions are grouped by functionality that is denoted by function name prefix (ie. swd_bin* are for binary operations, swd_cmdq* deals with command queue, swd_cmd_enqueue* deals with creating commands and attaching them to queue, swd_bus* performs operation on the swd transport system, swd_drv* are the interface drivers, etc).

Standard end-users are encouraged to only use high level functions (swd_bus*, swd_dap*, swd_dp*) to perform operations on the swd transport layer and the target's DAP (Debug Access Port) and its components such as DP (Debug Port) and the AP (Access Port). More advanced users however may use low level functions (swd_cmd*, swd_cmdq*) to group them into new high-level functions that automates some tasks (such as high-level functions does). Functions of type "extern" are the ones to implement in external file by developers that want to incorporate LibSWD into their application. Context structure also has void pointer in the swd_driver_t structure that can hold address of the external driver structure to be passed into internal swd drivers (extern swd_drv* functions) that wouldn't be accessible otherwise.

Commands

Bus operations are split into "commands" represented by swd_cmd_t data type. They form a bidirectional command queue that is part of swd_ctx_t structure. Command type, and so its payload, can be one of: control (user defined 8-bit payload), request (according to the standard), ack, data, parity (data and parity are separate commands!), trn, bitbang and idle (equals to control with zero data). Command type is defined by swd_cmdtype_t and its code can be negative (for MOSI operations) or positive (for MISO operations) - this way bus direction can be easily calculated by multiplying two operation codes (when the result is negative bus will have to change direction), so the libswd "knows" when to put additional TRN command of proper type between enqueued commands.

Payload is stored within union type and its data can be accessed according to payload name, or simply with data8 (char) and data32 (int) fields. Payload for write (MOSI) operations is stored on command creation, but payload for read (MISO) operations becomes available only after command is executed by the interface driver. There are 3 methods of accessing read data - flushing the queue into driver then reading queue directly, single stepping queue execution (flush one-by-one) then reading context log of last executed command results (there are separate fields of type swd_transaction_t in swd_ctx_t's log structure for read and write operations), or providing a double pointer on command creation to have constant access to its data after execution.

After all commands are enqueued with swd_cmd_enqueue* function set, it is time to send them into physical device with swd_cmdq_flush() funtion. According to the swd_operation_t parameter commands can be flushed one-by-one, all of them, only to the selected command or only after selected command. For low level functions all of these options are available, but for high-level functions only two of them can be used - SWD_OPERATION_ENQUEUE (but not send to the driver) and SWD_OPERATION_EXECUTE (all unexecuted commands on the queue are executed by the driver sequentially) - that makes it possible to perform bus operations one after another having their result just at function return, or compose more advanced sequences leading to preferred result at execution time. Because high-level functions provide simple and elegant manner to get the operation result, it is advised to use them instead dealing with low-level functions (implementing memory management, data allocation and queue operation) that exist only to make high-level functions possible.

Drivers

Calling the swd_cmdq_flush() function leads to execution of not yet executed commands from the queue (in a manner specified by the operation parameter) on the SWD bus (transport layer between interface and target, not the bus of the target itself) by swd_drv_transmit() function that use application specific "extern" functions defined in external file (ie. libswd_urjtag.c) to operate on a real hardware using drivers from existing application. LibSWD use only swd_drv_{mosi,miso}_{8,32} (separate for 8-bit char and 32-bit int data cast type) and swd_drv_{mosi,miso}_trn functions to interact with drivers, so it is possible to easily reuse low-level and high-level devices for communications, as they have all information necessary to perform exact actions - number of bits, payload, command type, shift direction and bus direction. It is even possible to send raw bytes on the bus (control command) or bitbang the bus (bitbang command) if necessary. MOSI (Master Output Slave Input) and MISO (Master Input Slave Output) was used to clearly distinguish transfer direction (from master-interface to target-slave), as opposed to ambiguous read/write statements, so after swd_drv_mosi_trn() master should have its buffers set to output and target inputs active. Drivers, as most of the LibSWD functions, works on data pointers instead data copy and returns number of elements processed (bits in this case) or negative error code on failure.

Example

  #include <libswd/libswd.h>
  int main(){
   swd_ctx_t *swdctx;
   int res, *idcode;
   swdctx=swd_init();
   if (swdctx==NULL) return -1;
   //we might need to pass external driver structure to swd_drv* functions 
   //swdctx->driver->device=...
   res=swd_dap_detect(swdctx, SWD_OPERATION_EXECUTE, &idcode);
   if (res<0){
    printf("ERROR: %s\n", swd_error_string(res));
    return res;
   } else printf("IDCODE: 0x%X (%s)\n", *idcode, swd_bin32_string(*idcode));
   swd_deinit(swdctx);
   return idcode;
  }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines