adiv5_swdp: allow to connect to a sleeping target by pulling SRST
This patch introduces a new command, "connect_srst [enable|disable]" which allows to enable special mode in which SRST would be pulled low before the SWD scan till attaching to a target. Since on Cortex-Mx the SRST signal doesn't gate JTAG and SWD, it's possible to connect to a target while holding reset, ask it to stop at reset vector and only then deassert reset, thus allowing to attach to the kind of firmware that goes immediately to sleep or disables debugging by other means early on start. Tested on an STM32VLDiscovery board with STM32F100 configured to go to STOP mode and executing WFI in the very beginning of main(). Signed-off-by: Paul Fertser <fercerpav@gmail.com>
This commit is contained in:
parent
510d1c0dc8
commit
e0fc21a2a7
|
@ -27,6 +27,7 @@
|
||||||
#include "adiv5.h"
|
#include "adiv5.h"
|
||||||
|
|
||||||
#include "swdptap.h"
|
#include "swdptap.h"
|
||||||
|
#include "jtagtap.h"
|
||||||
|
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
|
||||||
|
@ -53,6 +54,8 @@ int adiv5_swdp_scan(void)
|
||||||
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
|
||||||
|
|
||||||
swdptap_init();
|
swdptap_init();
|
||||||
|
if(connect_assert_srst)
|
||||||
|
jtagtap_srst(true); /* will be deasserted after attach */
|
||||||
/* Read the SW-DP IDCODE register to syncronise */
|
/* Read the SW-DP IDCODE register to syncronise */
|
||||||
/* This could be done with adiv_swdp_low_access(), but this doesn't
|
/* This could be done with adiv_swdp_low_access(), but this doesn't
|
||||||
* allow the ack to be checked here. */
|
* allow the ack to be checked here. */
|
||||||
|
|
|
@ -46,6 +46,7 @@ static bool cmd_jtag_scan(target *t, int argc, char **argv);
|
||||||
static bool cmd_swdp_scan(void);
|
static bool cmd_swdp_scan(void);
|
||||||
static bool cmd_targets(target *t);
|
static bool cmd_targets(target *t);
|
||||||
static bool cmd_morse(void);
|
static bool cmd_morse(void);
|
||||||
|
static bool cmd_connect_srst(target *t, int argc, const char **argv);
|
||||||
#ifdef PLATFORM_HAS_TRACESWO
|
#ifdef PLATFORM_HAS_TRACESWO
|
||||||
static bool cmd_traceswo(void);
|
static bool cmd_traceswo(void);
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,6 +58,7 @@ const struct command_s cmd_list[] = {
|
||||||
{"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" },
|
{"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" },
|
||||||
{"targets", (cmd_handler)cmd_targets, "Display list of available targets" },
|
{"targets", (cmd_handler)cmd_targets, "Display list of available targets" },
|
||||||
{"morse", (cmd_handler)cmd_morse, "Display morse error message" },
|
{"morse", (cmd_handler)cmd_morse, "Display morse error message" },
|
||||||
|
{"connect_srst", (cmd_handler)cmd_connect_srst, "Configure connect under SRST: (enable|disable)" },
|
||||||
#ifdef PLATFORM_HAS_TRACESWO
|
#ifdef PLATFORM_HAS_TRACESWO
|
||||||
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture" },
|
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture" },
|
||||||
#endif
|
#endif
|
||||||
|
@ -209,6 +211,17 @@ bool cmd_morse(void)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool cmd_connect_srst(target *t, int argc, const char **argv)
|
||||||
|
{
|
||||||
|
(void)t;
|
||||||
|
if (argc == 1)
|
||||||
|
gdb_outf("Assert SRST during connect: %s\n",
|
||||||
|
connect_assert_srst ? "enabled" : "disabled");
|
||||||
|
else
|
||||||
|
connect_assert_srst = !strcmp(argv[1], "enable");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef PLATFORM_HAS_TRACESWO
|
#ifdef PLATFORM_HAS_TRACESWO
|
||||||
static bool cmd_traceswo(void)
|
static bool cmd_traceswo(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -385,7 +385,7 @@ cortexm_attach(struct target_s *target)
|
||||||
|
|
||||||
target_halt_request(target);
|
target_halt_request(target);
|
||||||
tries = 10;
|
tries = 10;
|
||||||
while(!target_halt_wait(target) && --tries)
|
while(!connect_assert_srst && !target_halt_wait(target) && --tries)
|
||||||
platform_delay(2);
|
platform_delay(2);
|
||||||
if(!tries)
|
if(!tries)
|
||||||
return false;
|
return false;
|
||||||
|
@ -429,6 +429,9 @@ cortexm_attach(struct target_s *target)
|
||||||
target->clear_hw_wp = cortexm_clear_hw_wp;
|
target->clear_hw_wp = cortexm_clear_hw_wp;
|
||||||
target->check_hw_wp = cortexm_check_hw_wp;
|
target->check_hw_wp = cortexm_check_hw_wp;
|
||||||
|
|
||||||
|
if(connect_assert_srst)
|
||||||
|
jtagtap_srst(false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,7 +549,8 @@ cortexm_reset(struct target_s *target)
|
||||||
{
|
{
|
||||||
ADIv5_AP_t *ap = adiv5_target_ap(target);
|
ADIv5_AP_t *ap = adiv5_target_ap(target);
|
||||||
|
|
||||||
jtagtap_srst();
|
jtagtap_srst(true);
|
||||||
|
jtagtap_srst(false);
|
||||||
|
|
||||||
/* Read DHCSR here to clear S_RESET_ST bit before reset */
|
/* Read DHCSR here to clear S_RESET_ST bit before reset */
|
||||||
adiv5_ap_mem_read(ap, CORTEXM_DHCSR);
|
adiv5_ap_mem_read(ap, CORTEXM_DHCSR);
|
||||||
|
|
|
@ -29,7 +29,7 @@ int jtagtap_init(void);
|
||||||
|
|
||||||
void jtagtap_reset(void);
|
void jtagtap_reset(void);
|
||||||
|
|
||||||
void jtagtap_srst(void);
|
void jtagtap_srst(bool assert);
|
||||||
|
|
||||||
uint8_t jtagtap_next(const uint8_t TMS, const uint8_t TDI);
|
uint8_t jtagtap_next(const uint8_t TMS, const uint8_t TDI);
|
||||||
/* tap_next executes one state transision in the JTAG TAP state machine:
|
/* tap_next executes one state transision in the JTAG TAP state machine:
|
||||||
|
|
|
@ -188,6 +188,7 @@ struct target_command_s {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern target *target_list;
|
extern target *target_list;
|
||||||
|
extern bool connect_assert_srst;
|
||||||
|
|
||||||
target *target_new(unsigned size);
|
target *target_new(unsigned size);
|
||||||
void target_list_free(void);
|
void target_list_free(void);
|
||||||
|
|
|
@ -67,7 +67,7 @@ void jtagtap_reset(void)
|
||||||
jtagtap_soft_reset();
|
jtagtap_soft_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void jtagtap_srst(void)
|
void jtagtap_srst(bool assert)
|
||||||
{
|
{
|
||||||
platform_buffer_flush();
|
platform_buffer_flush();
|
||||||
//ftdi_write_data(ftdic, "\x80\x88\xAB", 3);
|
//ftdi_write_data(ftdic, "\x80\x88\xAB", 3);
|
||||||
|
|
|
@ -50,13 +50,16 @@ void jtagtap_reset(void)
|
||||||
jtagtap_soft_reset();
|
jtagtap_soft_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void jtagtap_srst(void)
|
void jtagtap_srst(bool assert)
|
||||||
{
|
{
|
||||||
#ifdef SRST_PORT
|
(void)assert;
|
||||||
volatile int i;
|
#ifdef SRST_SET_VAL
|
||||||
gpio_set(SRST_PORT, SRST_PIN);
|
SRST_SET_VAL(assert);
|
||||||
for(i = 0; i < 10000; i++) asm("nop");
|
if(assert) {
|
||||||
gpio_clear(SRST_PORT, SRST_PIN);
|
int i;
|
||||||
|
for(i = 0; i < 10000; i++)
|
||||||
|
asm volatile("nop");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
target *target_list = NULL;
|
target *target_list = NULL;
|
||||||
|
bool connect_assert_srst;
|
||||||
|
|
||||||
target *target_new(unsigned size)
|
target *target_new(unsigned size)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue