armv7m: add generic trace support (TPIU, ITM, etc.)
authorPaul Fertser <fercerpav@gmail.com>
Mon, 9 Feb 2015 14:04:52 +0000 (17:04 +0300)
committerSpencer Oliver <spen@spen-soft.co.uk>
Wed, 25 Mar 2015 20:46:43 +0000 (20:46 +0000)
This provides support for various trace-related subsystems in a
generic and expandable way.

Change-Id: I3a27fa7b8cfb111753088bb8c3d760dd12d1395f
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2538
Tested-by: jenkins
17 files changed:
doc/openocd.texi
src/jtag/drivers/stlink_usb.c
src/target/Makefile.am
src/target/armv7m.c
src/target/armv7m.h
src/target/armv7m_trace.c [new file with mode: 0644]
src/target/armv7m_trace.h [new file with mode: 0644]
src/target/cortex_m.c
src/target/cortex_m.h
src/target/hla_target.c
src/target/target.c
src/target/target.h
tcl/target/stm32f1x.cfg
tcl/target/stm32f2x.cfg
tcl/target/stm32f3x.cfg
tcl/target/stm32f4x.cfg
tcl/target/stm32l1.cfg

index 40864373c1e10271065bb02cbb3c59731548861c..f00af7fb8500fbe19eb48b2f7949bbf73949cd84 100644 (file)
@@ -4641,6 +4641,8 @@ when reset disables PLLs needed to use a fast clock.
 @* After all targets have resumed
 @item @b{resumed}
 @* Target has resumed
+@item @b{trace-config}
+@* After target hardware trace configuration was changed
 @end itemize
 
 @node Flash Commands
@@ -7636,6 +7638,93 @@ fix CSW_SPROT from register AP_REG_CSW on selected dap.
 Defaulting to 0.
 @end deffn
 
+@subsection ARMv7-M specific commands
+@cindex tracing
+@cindex SWO
+@cindex SWV
+@cindex TPIU
+@cindex ITM
+@cindex ETM
+
+@deffn Command {tpiu config} (@option{disable} | ((@option{external} | @option{internal @var{filename}}) @
+               (@option{sync @var{port_width}} | ((@option{manchester} | @option{uart}) @var{formatter_enable})) @
+               @var{TRACECLKIN_freq} [@var{trace_freq}]))
+
+ARMv7-M architecture provides several modules to generate debugging
+information internally (ITM, DWT and ETM). Their output is directed
+through TPIU to be captured externally either on an SWO pin (this
+configuration is called SWV) or on a synchronous parallel trace port.
+
+This command configures the TPIU module of the target and, if internal
+capture mode is selected, starts to capture trace output by using the
+debugger adapter features.
+
+Some targets require additional actions to be performed in the
+@b{trace-config} handler for trace port to be activated.
+
+Command options:
+@itemize @minus
+@item @option{disable} disable TPIU handling;
+@item @option{external} configure TPIU to let user capture trace
+output externally (with an additional UART or logic analyzer hardware);
+@item @option{internal @var{filename}} configure TPIU and debug adapter to
+gather trace data and append it to @var{filename} (which can be
+either a regular file or a named pipe);
+@item @option{sync @var{port_width}} use synchronous parallel trace output
+mode, and set port width to @var{port_width};
+@item @option{manchester} use asynchronous SWO mode with Manchester
+coding;
+@item @option{uart} use asynchronous SWO mode with NRZ (same as
+regular UART 8N1) coding;
+@item @var{formatter_enable} is @option{on} or @option{off} to enable
+or disable TPIU formatter which needs to be used when both ITM and ETM
+data is to be output via SWO;
+@item @var{TRACECLKIN_freq} this should be specified to match target's
+current TRACECLKIN frequency (usually the same as HCLK);
+@item @var{trace_freq} trace port frequency. Can be omitted in
+internal mode to let the adapter driver select the maximum supported
+rate automatically.
+@end itemize
+
+Example usage:
+@enumerate
+@item STM32L152 board is programmed with an application that configures
+PLL to provide core clock with 24MHz frequency; to use ITM output it's
+enough to:
+@example
+#include <libopencm3/cm3/itm.h>
+    ...
+       ITM_STIM8(0) = c;
+    ...
+@end example
+(the most obvious way is to use the first stimulus port for printf,
+for that this ITM_STIM8 assignment can be used inside _write(); to make it
+blocking to avoid data loss, add @code{while (!(ITM_STIM8(0) &
+ITM_STIM_FIFOREADY));});
+@item An FT2232H UART is connected to the SWO pin of the board;
+@item Commands to configure UART for 12MHz baud rate:
+@example
+$ setserial /dev/ttyUSB1 spd_cust divisor 5
+$ stty -F /dev/ttyUSB1 38400
+@end example
+(FT2232H's base frequency is 60MHz, spd_cust allows to alias 38400
+baud with our custom divisor to get 12MHz)
+@item @code{itmdump -f /dev/ttyUSB1 -d1}
+@item @code{openocd -f interface/stlink-v2-1.cfg -c "transport select
+hla_swd" -f target/stm32l1.cfg -c "tpiu config external uart off
+24000000 12000000"}
+@end enumerate
+@end deffn
+
+@deffn Command {itm port} @var{port} (@option{0}|@option{1}|@option{on}|@option{off})
+Enable or disable trace output for ITM stimulus @var{port} (counting
+from 0). Port 0 is enabled on target creation automatically.
+@end deffn
+
+@deffn Command {itm ports} (@option{0}|@option{1}|@option{on}|@option{off})
+Enable or disable trace output for all ITM stimulus ports.
+@end deffn
+
 @subsection Cortex-M specific commands
 @cindex Cortex-M
 
index 554ffc1edcbfc2e76e6fe9fd558a3dce37f988b1..331d30b7ba708de2a28083c963bbfcf7c7e902d3 100644 (file)
@@ -1031,16 +1031,16 @@ static int stlink_configure_target_trace_port(void *handle)
        if (res != ERROR_OK)
                goto out;
        /* set the TPI clock prescaler */
-       res = stlink_usb_write_debug_reg(handle, TPI_ACPR, h->trace.prescale);
+       res = stlink_usb_write_debug_reg(handle, TPIU_ACPR, h->trace.prescale);
        if (res != ERROR_OK)
                goto out;
        /* select the pin protocol.  The STLinkv2 only supports asynchronous
         * UART emulation (NRZ) mode, so that's what we pick. */
-       res = stlink_usb_write_debug_reg(handle, TPI_SPPR, 0x02);
+       res = stlink_usb_write_debug_reg(handle, TPIU_SPPR, 0x02);
        if (res != ERROR_OK)
                goto out;
        /* disable continuous formatting */
-       res = stlink_usb_write_debug_reg(handle, TPI_FFCR, (1<<8));
+       res = stlink_usb_write_debug_reg(handle, TPIU_FFCR, (1<<8));
        if (res != ERROR_OK)
                goto out;
 
@@ -1059,7 +1059,7 @@ static int stlink_configure_target_trace_port(void *handle)
        if (res != ERROR_OK)
                goto out;
        /* trace port enable (port 0) */
-       res = stlink_usb_write_debug_reg(handle, ITM_TER, (1<<0));
+       res = stlink_usb_write_debug_reg(handle, ITM_TER0, (1<<0));
        if (res != ERROR_OK)
                goto out;
 
index bf80c64c021aa9ef4e261751ff31a5ec057f9147..c5911036f115782077ed957592404c4e7d11d8ef 100644 (file)
@@ -79,6 +79,7 @@ ARMV6_SRC = \
 
 ARMV7_SRC = \
        armv7m.c \
+       armv7m_trace.c \
        cortex_m.c \
        armv7a.c \
        cortex_a.c
@@ -155,6 +156,7 @@ noinst_HEADERS = \
        armv4_5_cache.h \
        armv7a.h \
        armv7m.h \
+       armv7m_trace.h \
        avrt.h \
        dsp563xx.h \
        dsp563xx_once.h \
index 01fb69ac9358b781c50f8870722b0ece6774e2e9..ccb3e5456e5037abb104b830d0fad151be416f14 100644 (file)
@@ -635,6 +635,9 @@ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
 
        armv7m->common_magic = ARMV7M_COMMON_MAGIC;
        armv7m->fp_feature = FP_NONE;
+       armv7m->trace_config.trace_bus_id = 1;
+       /* Enable stimulus port #0 by default */
+       armv7m->trace_config.itm_ter[0] = 1;
 
        arm->core_type = ARM_MODE_THREAD;
        arm->arch_info = armv7m;
index d28977edf31471d3818b516bc7e2d34195e676ff..19744604e004ffe4a6b607ec881ab25f689f14ec 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "arm_adi_v5.h"
 #include "arm.h"
+#include "armv7m_trace.h"
 
 extern const int armv7m_psp_reg_map[];
 extern const int armv7m_msp_reg_map[];
@@ -153,6 +154,8 @@ struct armv7m_common {
        /* stlink is a high level adapter, does not support all functions */
        bool stlink;
 
+       struct armv7m_trace_config trace_config;
+
        /* Direct processor core register read and writes */
        int (*load_core_reg_u32)(struct target *target, uint32_t num, uint32_t *value);
        int (*store_core_reg_u32)(struct target *target, uint32_t num, uint32_t value);
diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c
new file mode 100644 (file)
index 0000000..b1bbb31
--- /dev/null
@@ -0,0 +1,295 @@
+/***************************************************************************
+ *   Copyright (C) 2015  Paul Fertser <fercerpav@gmail.com>                *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <target/target.h>
+#include <target/armv7m.h>
+#include <target/cortex_m.h>
+#include <target/armv7m_trace.h>
+
+int armv7m_trace_tpiu_config(struct target *target)
+{
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+       struct armv7m_trace_config *trace_config = &armv7m->trace_config;
+       int prescaler;
+       int retval;
+
+       if (!trace_config->trace_freq) {
+               LOG_ERROR("Trace port frequency is 0, can't enable TPIU");
+               return ERROR_FAIL;
+       }
+
+       if (trace_config->traceclkin_freq % trace_config->trace_freq) {
+               LOG_ERROR("Can not calculate an integer divisor to get %u trace port frequency from %u TRACECLKIN frequency",
+                         trace_config->trace_freq, trace_config->traceclkin_freq);
+               return ERROR_FAIL;
+       }
+
+       prescaler = trace_config->traceclkin_freq / trace_config->trace_freq;
+
+       retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u32(target, TPIU_ACPR, prescaler - 1);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u32(target, TPIU_SPPR, trace_config->pin_protocol);
+       if (retval != ERROR_OK)
+               return retval;
+
+       uint32_t ffcr;
+       retval = target_read_u32(target, TPIU_FFCR, &ffcr);
+       if (retval != ERROR_OK)
+               return retval;
+       if (trace_config->formatter)
+               ffcr |= (1 << 1);
+       else
+               ffcr &= ~(1 << 1);
+       retval = target_write_u32(target, TPIU_FFCR, ffcr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG);
+
+       return ERROR_OK;
+}
+
+int armv7m_trace_itm_config(struct target *target)
+{
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+       struct armv7m_trace_config *trace_config = &armv7m->trace_config;
+       int retval;
+
+       retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Enable ITM, TXENA, set TraceBusID and other parameters */
+       retval = target_write_u32(target, ITM_TCR, (1 << 0) | (1 << 3) |
+                                 (trace_config->itm_diff_timestamps << 1) |
+                                 (trace_config->itm_synchro_packets << 2) |
+                                 (trace_config->itm_async_timestamps << 4) |
+                                 (trace_config->itm_ts_prescale << 8) |
+                                 (trace_config->trace_bus_id << 16));
+       if (retval != ERROR_OK)
+               return retval;
+
+       for (unsigned int i = 0; i < 8; i++) {
+               retval = target_write_u32(target, ITM_TER0 + i * 4,
+                                         trace_config->itm_ter[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return ERROR_OK;
+}
+
+static void close_trace_file(struct armv7m_common *armv7m)
+{
+       if (armv7m->trace_config.trace_file)
+               fclose(armv7m->trace_config.trace_file);
+       armv7m->trace_config.trace_file = NULL;
+}
+
+COMMAND_HANDLER(handle_tpiu_config_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+
+       unsigned int cmd_idx = 0;
+
+       if (CMD_ARGC == cmd_idx)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       if (!strcmp(CMD_ARGV[cmd_idx], "disable")) {
+               if (CMD_ARGC == cmd_idx + 1) {
+                       close_trace_file(armv7m);
+
+                       armv7m->trace_config.config_type = DISABLED;
+                       if (CMD_CTX->mode == COMMAND_EXEC)
+                               return armv7m_trace_tpiu_config(target);
+                       else
+                               return ERROR_OK;
+               }
+       } else if (!strcmp(CMD_ARGV[cmd_idx], "external") ||
+                  !strcmp(CMD_ARGV[cmd_idx], "internal")) {
+               close_trace_file(armv7m);
+
+               armv7m->trace_config.config_type = EXTERNAL;
+               if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
+                       cmd_idx++;
+                       if (CMD_ARGC == cmd_idx)
+                               return ERROR_COMMAND_SYNTAX_ERROR;
+
+                       armv7m->trace_config.config_type = INTERNAL;
+                       armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab");
+                       if (!armv7m->trace_config.trace_file) {
+                               LOG_ERROR("Can't open trace destination file");
+                               return ERROR_FAIL;
+                       }
+               }
+               cmd_idx++;
+               if (CMD_ARGC == cmd_idx)
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+
+               if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
+                       armv7m->trace_config.pin_protocol = SYNC;
+
+                       cmd_idx++;
+                       if (CMD_ARGC == cmd_idx)
+                               return ERROR_COMMAND_SYNTAX_ERROR;
+
+                       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size);
+               } else {
+                       if (!strcmp(CMD_ARGV[cmd_idx], "manchester"))
+                               armv7m->trace_config.pin_protocol = ASYNC_MANCHESTER;
+                       else if (!strcmp(CMD_ARGV[cmd_idx], "uart"))
+                               armv7m->trace_config.pin_protocol = ASYNC_UART;
+                       else
+                               return ERROR_COMMAND_SYNTAX_ERROR;
+
+                       cmd_idx++;
+                       if (CMD_ARGC == cmd_idx)
+                               return ERROR_COMMAND_SYNTAX_ERROR;
+
+                       COMMAND_PARSE_ON_OFF(CMD_ARGV[cmd_idx], armv7m->trace_config.formatter);
+               }
+
+               cmd_idx++;
+               if (CMD_ARGC == cmd_idx)
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+
+               COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.traceclkin_freq);
+
+               cmd_idx++;
+               if (CMD_ARGC != cmd_idx) {
+                       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq);
+                       cmd_idx++;
+               } else {
+                       if (armv7m->trace_config.config_type != INTERNAL) {
+                               LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
+                               return ERROR_COMMAND_SYNTAX_ERROR;
+                       }
+                       armv7m->trace_config.trace_freq = 0;
+               }
+
+               if (CMD_ARGC == cmd_idx) {
+                       if (CMD_CTX->mode == COMMAND_EXEC)
+                               return armv7m_trace_tpiu_config(target);
+                       else
+                               return ERROR_OK;
+               }
+       }
+
+       return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(handle_itm_port_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+       unsigned int reg_idx;
+       uint8_t port;
+       bool enable;
+
+       if (CMD_ARGC != 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], port);
+       COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable);
+       reg_idx = port / 32;
+       port = port % 32;
+       if (enable)
+               armv7m->trace_config.itm_ter[reg_idx] |= (1 << port);
+       else
+               armv7m->trace_config.itm_ter[reg_idx] &= ~(1 << port);
+
+       if (CMD_CTX->mode == COMMAND_EXEC)
+               return armv7m_trace_itm_config(target);
+       else
+               return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_itm_ports_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+       bool enable;
+
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
+       memset(armv7m->trace_config.itm_ter, enable ? 0xff : 0,
+              sizeof(armv7m->trace_config.itm_ter));
+
+       if (CMD_CTX->mode == COMMAND_EXEC)
+               return armv7m_trace_itm_config(target);
+       else
+               return ERROR_OK;
+}
+
+static const struct command_registration tpiu_command_handlers[] = {
+       {
+               .name = "config",
+               .handler = handle_tpiu_config_command,
+               .mode = COMMAND_ANY,
+               .help = "Configure TPIU features",
+               .usage = "(disable | "
+               "((external | internal <filename>) "
+               "(sync <port width> | ((manchester | uart) <formatter enable>)) "
+               "<TRACECLKIN freq> [<trace freq>]))",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration itm_command_handlers[] = {
+       {
+               .name = "port",
+               .handler = handle_itm_port_command,
+               .mode = COMMAND_ANY,
+               .help = "Enable or disable ITM stimulus port",
+               .usage = "<port> (0|1|on|off)",
+       },
+       {
+               .name = "ports",
+               .handler = handle_itm_ports_command,
+               .mode = COMMAND_ANY,
+               .help = "Enable or disable all ITM stimulus ports",
+               .usage = "(0|1|on|off)",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration armv7m_trace_command_handlers[] = {
+       {
+               .name = "tpiu",
+               .mode = COMMAND_ANY,
+               .help = "tpiu command group",
+               .usage = "",
+               .chain = tpiu_command_handlers,
+       },
+       {
+               .name = "itm",
+               .mode = COMMAND_ANY,
+               .help = "itm command group",
+               .usage = "",
+               .chain = itm_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h
new file mode 100644 (file)
index 0000000..96c1895
--- /dev/null
@@ -0,0 +1,87 @@
+/***************************************************************************
+ *   Copyright (C) 2015  Paul Fertser <fercerpav@gmail.com>                *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ ***************************************************************************/
+
+#ifndef ARMV7M_TRACE_H
+#define ARMV7M_TRACE_H
+
+#include <command.h>
+
+/**
+ * @file
+ * Holds the interface to TPIU, ITM and DWT configuration functions.
+ */
+
+enum trace_config_type {
+       DISABLED,       /**< tracing is disabled */
+       EXTERNAL,       /**< trace output is captured externally */
+       INTERNAL        /**< trace output is handled by OpenOCD adapter driver */
+};
+
+enum tpio_pin_protocol {
+       SYNC,                   /**< synchronous trace output */
+       ASYNC_MANCHESTER,       /**< asynchronous output with Manchester coding */
+       ASYNC_UART              /**< asynchronous output with NRZ coding */
+};
+
+enum itm_ts_prescaler {
+       ITM_TS_PRESCALE1,       /**< no prescaling for the timestamp counter */
+       ITM_TS_PRESCALE4,       /**< refclock divided by 4 for the timestamp counter */
+       ITM_TS_PRESCALE16,      /**< refclock divided by 16 for the timestamp counter */
+       ITM_TS_PRESCALE64,      /**< refclock divided by 64 for the timestamp counter */
+};
+
+struct armv7m_trace_config {
+       /** Currently active trace capture mode */
+       enum trace_config_type config_type;
+
+       /** Currently active trace output mode */
+       enum tpio_pin_protocol pin_protocol;
+       /** TPIU formatter enable/disable (in async mode) */
+       bool formatter;
+       /** Synchronous output port width */
+       uint32_t port_size;
+
+       /** Bitmask of currenty enabled ITM stimuli */
+       uint32_t itm_ter[8];
+       /** Identifier for multi-source trace stream formatting */
+       unsigned int trace_bus_id;
+       /** Prescaler for the timestamp counter */
+       enum itm_ts_prescaler itm_ts_prescale;
+       /** Enable differential timestamps */
+       bool itm_diff_timestamps;
+       /** Enable async timestamps model */
+       bool itm_async_timestamps;
+       /** Enable synchronisation packet transmission (for sync port only) */
+       bool itm_synchro_packets;
+
+       /** Current frequency of TRACECLKIN (usually matches HCLK) */
+       unsigned int traceclkin_freq;
+       /** Current frequency of trace port */
+       unsigned int trace_freq;
+       /** Handle to output trace data in INTERNAL capture mode */
+       FILE *trace_file;
+};
+
+extern const struct command_registration armv7m_trace_command_handlers[];
+
+/**
+ * Configure hardware accordingly to the current TPIU target settings
+ */
+int armv7m_trace_tpiu_config(struct target *target);
+/**
+ * Configure hardware accordingly to the current ITM target settings
+ */
+int armv7m_trace_itm_config(struct target *target);
+
+#endif
index 4dc92c834e549395f91758a88d99d102c2444fd8..9234824d654b19ae10c4b6690fd572e71ed916dc 100644 (file)
@@ -1932,6 +1932,16 @@ int cortex_m_examine(struct target *target)
                        armv7m->dap.tar_autoincr_block = (1 << 12);
                }
 
+               /* Configure trace modules */
+               retval = target_write_u32(target, DCB_DEMCR, TRCENA | armv7m->demcr);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if (armv7m->trace_config.config_type != DISABLED) {
+                       armv7m_trace_tpiu_config(target);
+                       armv7m_trace_itm_config(target);
+               }
+
                /* NOTE: FPB and DWT are both optional. */
 
                /* Setup FPB */
@@ -2324,6 +2334,9 @@ static const struct command_registration cortex_m_command_handlers[] = {
        {
                .chain = armv7m_command_handlers,
        },
+       {
+               .chain = armv7m_trace_command_handlers,
+       },
        {
                .name = "cortex_m",
                .mode = COMMAND_EXEC,
index 28189e02e978f57690fcf7787b93690262e90ec1..028b4c8d686b15b5ccbab39f22d1b7f4ea11f5fc 100644 (file)
 
 #define SYSTEM_CONTROL_BASE 0x400FE000
 
-#define ITM_TER                0xE0000E00
+#define ITM_TER0       0xE0000E00
 #define ITM_TPR                0xE0000E40
 #define ITM_TCR                0xE0000E80
 #define ITM_LAR                0xE0000FB0
+#define ITM_LAR_KEY    0xC5ACCE55
 
 #define CPUID          0xE000ED00
 /* Debug Control Block */
 #define FPU_FPCAR      0xE000EF38
 #define FPU_FPDSCR     0xE000EF3C
 
-#define TPI_SSPSR      0xE0040000
-#define TPI_CSPSR      0xE0040004
-#define TPI_ACPR       0xE0040010
-#define TPI_SPPR       0xE00400F0
-#define TPI_FFSR       0xE0040300
-#define TPI_FFCR       0xE0040304
-#define TPI_FSCR       0xE0040308
+#define TPIU_SSPSR     0xE0040000
+#define TPIU_CSPSR     0xE0040004
+#define TPIU_ACPR      0xE0040010
+#define TPIU_SPPR      0xE00400F0
+#define TPIU_FFSR      0xE0040300
+#define TPIU_FFCR      0xE0040304
+#define TPIU_FSCR      0xE0040308
 
 /* DCB_DHCSR bit and field definitions */
 #define DBGKEY         (0xA05F << 16)
index a05a99ff5fa83f3ab4b71406a32b14b23d0fd8f1..d0be966c3a056d23d8dace6a73513482d31af0b3 100644 (file)
@@ -772,6 +772,9 @@ static const struct command_registration adapter_command_handlers[] = {
        {
                .chain = arm_command_handlers,
        },
+       {
+               .chain = armv7m_trace_command_handlers,
+       },
        COMMAND_REGISTRATION_DONE
 };
 
index 5c88384d83eb202211dfd328f7b7be99d347cd13..a8d3cba96f1fc536eb364f4f0c5c4998e66b5eba 100644 (file)
@@ -217,6 +217,8 @@ static const Jim_Nvp nvp_target_event[] = {
        { .value = TARGET_EVENT_GDB_FLASH_ERASE_START, .name = "gdb-flash-erase-start" },
        { .value = TARGET_EVENT_GDB_FLASH_ERASE_END  , .name = "gdb-flash-erase-end" },
 
+       { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" },
+
        { .name = NULL, .value = -1 }
 };
 
index fbce19f5194d97622150fe997c80af9d46e5fa15..9382720b9693ef880fc04d9f1c415eb3e40a237b 100644 (file)
@@ -266,6 +266,8 @@ enum target_event {
        TARGET_EVENT_GDB_FLASH_ERASE_END,
        TARGET_EVENT_GDB_FLASH_WRITE_START,
        TARGET_EVENT_GDB_FLASH_WRITE_END,
+
+       TARGET_EVENT_TRACE_CONFIG,
 };
 
 struct target_event_action {
index 6a62992d263097b551284533b8ab280e4a8ecec0..bd02e95b06057953cf4ba54f7ef46ba105f82a58 100644 (file)
@@ -4,6 +4,7 @@
 # stm32 devices support both JTAG and SWD transports.
 #
 source [find target/swj-dp.tcl]
+source [find mem_helper.tcl]
 
 if { [info exists CHIPNAME] } {
    set _CHIPNAME $CHIPNAME
@@ -93,3 +94,16 @@ if {![using_hla]} {
     # perform a soft reset
     cortex_m reset_config sysresetreq
 }
+
+$_TARGETNAME configure -event examine-end {
+       # DBGMCU_CR |= DBG_WWDG_STOP | DBG_IWDG_STOP |
+       #              DBG_STANDBY | DBG_STOP | DBG_SLEEP
+       mmw 0xE0042004 0x00000307 0
+}
+
+$_TARGETNAME configure -event trace-config {
+       # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync
+       # change this value accordingly to configure trace pins
+       # assignment
+       mmw 0xE0042004 0x00000020 0
+}
index 0ac73a519988996a463f7e8c911a790632f47967..0095615d004362ca5a16d3ad04a9b351bb1e8650 100644 (file)
@@ -4,6 +4,7 @@
 # stm32 devices support both JTAG and SWD transports.
 #
 source [find target/swj-dp.tcl]
+source [find mem_helper.tcl]
 
 if { [info exists CHIPNAME] } {
    set _CHIPNAME $CHIPNAME
@@ -77,3 +78,19 @@ if {![using_hla]} {
    # perform a soft reset
    cortex_m reset_config sysresetreq
 }
+
+$_TARGETNAME configure -event examine-end {
+       # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP
+       mmw 0xE0042004 0x00000007 0
+
+       # Stop watchdog counters during halt
+       # DBGMCU_APB1_FZ = DBG_IWDG_STOP | DBG_WWDG_STOP
+       mww 0xE0042008 0x00001800
+}
+
+$_TARGETNAME configure -event trace-config {
+       # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync
+       # change this value accordingly to configure trace pins
+       # assignment
+       mmw 0xE0042004 0x00000020 0
+}
index 7ddf7d0435ad4036cdcb4693c600eb2e279f6cc3..f3c22af7ae2a9a570f7bdd938053c6976ac9c81e 100644 (file)
@@ -118,3 +118,10 @@ proc stm32f3x_default_reset_init {} {
 $_TARGETNAME configure -event examine-end { stm32f3x_default_examine_end }
 $_TARGETNAME configure -event reset-start { stm32f3x_default_reset_start }
 $_TARGETNAME configure -event reset-init { stm32f3x_default_reset_init }
+
+$_TARGETNAME configure -event trace-config {
+       # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync
+       # change this value accordingly to configure trace pins
+       # assignment
+       mmw 0xe0042004 0x00000020 0
+}
index fd5cab6a1c74390839aab7842a29606e6c627a75..51d76e7e5be6382e7bfc6aefa59d3ec984c21141 100644 (file)
@@ -4,6 +4,7 @@
 # stm32 devices support both JTAG and SWD transports.
 #
 source [find target/swj-dp.tcl]
+source [find mem_helper.tcl]
 
 if { [info exists CHIPNAME] } {
    set _CHIPNAME $CHIPNAME
@@ -89,3 +90,19 @@ if {![using_hla]} {
    # perform a soft reset
    cortex_m reset_config sysresetreq
 }
+
+$_TARGETNAME configure -event examine-end {
+       # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP
+       mmw 0xE0042004 0x00000007 0
+
+       # Stop watchdog counters during halt
+       # DBGMCU_APB1_FZ = DBG_IWDG_STOP | DBG_WWDG_STOP
+       mww 0xE0042008 0x00001800
+}
+
+$_TARGETNAME configure -event trace-config {
+       # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync
+       # change this value accordingly to configure trace pins
+       # assignment
+       mmw 0xE0042004 0x00000020 0
+}
index d4673a100c949497e49b1817ad8c1ffff2361b62..7754c84939e4b898aa9b54fa8508b0a7686ab980 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 source [find target/swj-dp.tcl]
+source [find mem_helper.tcl]
 
 if { [info exists CHIPNAME] } {
    set _CHIPNAME $CHIPNAME
@@ -107,3 +108,19 @@ $_TARGETNAME configure -event reset-init {
 $_TARGETNAME configure -event reset-start {
        adapter_khz 300
 }
+
+$_TARGETNAME configure -event examine-end {
+       # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP
+       mmw 0xE0042004 0x00000007 0
+
+       # Stop watchdog counters during halt
+       # DBGMCU_APB1_FZ = DBG_IWDG_STOP | DBG_WWDG_STOP
+       mww 0xE0042008 0x00001800
+}
+
+$_TARGETNAME configure -event trace-config {
+       # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync
+       # change this value accordingly to configure trace pins
+       # assignment
+       mmw 0xE0042004 0x00000020 0
+}