Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: SWD delay/frequency calibration #1955

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions src/platforms/common/blackpill-f4/blackpill-f4.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,67 @@ int platform_hwversion(void)
{
return 0;
}

#ifdef PLATFORM_HAS_CUSTOM_COMMANDS

#include "swd.h"
#include "gdb_packet.h"
#include "target_internal.h"
#include <libopencm3/cm3/dwt.h>

static bool cmd_swdptap_calibration(target_s *target, int argc, const char **argv);

const command_s platform_cmd_list[] = {
{"calibrate_swd", cmd_swdptap_calibration, "Calibrate SW-DP TAP timings"},
{NULL, NULL, NULL},
};

static void swdptap_linereset_measured(bool no_delay)
{
const uint32_t ts_pre = dwt_read_cycle_counter();
/* for robustness, we use 60 HIGH cycles and 4 idle cycles */
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0x0fffffffU, 32U);
const uint32_t ts_post = dwt_read_cycle_counter();
const uint32_t cycles_spent = ts_post - ts_pre;
/* Subtract the overhead of function calls */
const uint32_t fncall_corr = no_delay ? (88U) : (140U);
/* Split the *64 into 16*4 for 216-240MHz clocks to not overflow a uint32_t */
const uint32_t freq_measured = rcc_ahb_frequency * 16U / (cycles_spent - fncall_corr) * 4U;
gdb_outf("Estimating %lu Hz (%lu cycles - %ld corr)\n", freq_measured, cycles_spent, fncall_corr);
}

static bool cmd_swdptap_calibration(target_s *target, int argc, const char **argv)
{
(void)argc;
(void)argv;
if (target && target->attached)
target_detach(target);
platform_target_clk_output_enable(true);
if (!swd_proc.seq_out)
swdptap_init();
dwt_enable_cycle_counter();

uint32_t freq = 0;
gdb_outf("Platform core clock %lu\n", rcc_ahb_frequency);

/* Emit a _no_delay waveform */
target_clk_divider = UINT32_MAX;
freq = platform_max_frequency_get();
gdb_outf("Changing frequency to %lu (no_delay)\n", freq);
swdptap_linereset_measured(true);

/* Loop through a few _delay values */
for (uint32_t i = 0; i < 8; i++) {
target_clk_divider = i;
freq = platform_max_frequency_get();
gdb_outf("Changing frequency to %lu (divider=%lu)\n", freq, target_clk_divider);
swdptap_linereset_measured(false);
}

/* Reset frequency to medium */
platform_max_frequency_set(3000000U);
return true;
}

#endif
2 changes: 2 additions & 0 deletions src/platforms/common/blackpill-f4/blackpill-f4.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
extern bool debug_bmp;
#endif

#define PLATFORM_HAS_CUSTOM_COMMANDS

/*
* If the SHIELD macro is passed to make, other macros are defined.
* Build the code using `make PROBE_HOST=blackpill-f4x1cx SHIELD=1` to define the SHIELD macro.
Expand Down
26 changes: 25 additions & 1 deletion src/platforms/common/stm32/timing_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,31 @@ uint32_t platform_time_ms(void)
* per delay loop count with 2 delay loops per clock
*/

#if defined(STM32F4)
/* Values for STM32F411 at 96 MHz */
#define USED_SWD_CYCLES_NODELAY 12
#define USED_SWD_CYCLES 24
#define CYCLES_PER_CNT 12
#elif defined(GD32F1)
/* Values for GD32F103 at 72 MHz */
#define USED_SWD_CYCLES_NODELAY 14
#define USED_SWD_CYCLES 30
#define CYCLES_PER_CNT 14
#elif defined(STM32F1)
/* Values for STM32F103 at 72 MHz */
#define USED_SWD_CYCLES_NODELAY 16
#define USED_SWD_CYCLES 34
#define CYCLES_PER_CNT 17
#elif defined(STM32F0)
/* Values for STM32F072 at 48 MHz */
#define USED_SWD_CYCLES_NODELAY 24
#define USED_SWD_CYCLES 30
#define CYCLES_PER_CNT 17
#else
/* Inherit defaults for other platforms (F3, F7) */
#define USED_SWD_CYCLES 22
#define CYCLES_PER_CNT 10
#endif

void platform_max_frequency_set(const uint32_t frequency)
{
Expand Down Expand Up @@ -200,8 +222,10 @@ uint32_t platform_max_frequency_get(void)
const uint32_t ratio = (target_clk_divider * BITBANG_DIVIDER_FACTOR) + BITBANG_DIVIDER_OFFSET;
return rcc_ahb_frequency / ratio;
#else
if (target_clk_divider == UINT32_MAX)
return rcc_ahb_frequency / USED_SWD_CYCLES_NODELAY;
uint32_t result = rcc_ahb_frequency;
result /= USED_SWD_CYCLES + CYCLES_PER_CNT * target_clk_divider;
result /= USED_SWD_CYCLES + CYCLES_PER_CNT * target_clk_divider * 2U;
return result;
#endif
}
70 changes: 70 additions & 0 deletions src/platforms/stlink/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,73 @@ uint8_t platform_spi_xfer(const spi_bus_e bus, const uint8_t value)
(void)bus;
return value;
}

#ifdef PLATFORM_HAS_CUSTOM_COMMANDS

#include "swd.h"
#include "gdb_packet.h"
#include "target_internal.h"
#include <libopencm3/cm3/dwt.h>

static bool cmd_swdptap_calibration(target_s *target, int argc, const char **argv);

const command_s platform_cmd_list[] = {
{"calibrate_swd", cmd_swdptap_calibration, "Calibrate SW-DP TAP timings"},
{NULL, NULL, NULL},
};

static void swdptap_linereset_measured(bool no_delay)
{
const uint32_t ts_pre = dwt_read_cycle_counter();
/* for robustness, we use 60 HIGH cycles and 4 idle cycles */
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0x0fffffffU, 32U);
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0x0fffffffU, 32U);
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0x0fffffffU, 32U);
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0x0fffffffU, 32U);
const uint32_t ts_post = dwt_read_cycle_counter();
const uint32_t cycles_spent = ts_post - ts_pre;
/* Subtract the overhead of function calls */
const uint32_t fncall_corr = no_delay ? (544U) : (488U);
/* Split the 64*4 into 16*16 for 216-240MHz clocks to not overflow a uint32_t */
const uint32_t freq_measured = rcc_ahb_frequency * 16U / (cycles_spent - fncall_corr) * 16U;
gdb_outf("Estimated %7lu Hz (%5lu cycles - %ld corr)\n", freq_measured, cycles_spent, fncall_corr);
}

static bool cmd_swdptap_calibration(target_s *target, int argc, const char **argv)
{
(void)argc;
(void)argv;
if (target && target->attached)
target_detach(target);
platform_target_clk_output_enable(true);
if (!swd_proc.seq_out)
swdptap_init();
dwt_enable_cycle_counter();

uint32_t freq = 0;
gdb_outf("Platform core clock %lu\n", rcc_ahb_frequency);

/* Emit a _no_delay waveform */
target_clk_divider = UINT32_MAX;
freq = platform_max_frequency_get();
gdb_outf("Changing frequency to %7lu (no_delay)\t", freq);
swdptap_linereset_measured(true);

/* Loop through a few _delay values */
for (uint32_t i = 0; i < 8; i++) {
target_clk_divider = i;
freq = platform_max_frequency_get();
gdb_outf("Changing frequency to %7lu (divider=%lu)\t", freq, target_clk_divider);
swdptap_linereset_measured(false);
}

/* Reset frequency to medium */
platform_max_frequency_set(3000000U);
return true;
}

#endif
2 changes: 2 additions & 0 deletions src/platforms/stlink/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
extern bool debug_bmp;
#endif

#define PLATFORM_HAS_CUSTOM_COMMANDS

#define PLATFORM_IDENT "(ST-Link/v2) "

/* Hardware definitions... */
Expand Down
70 changes: 70 additions & 0 deletions src/platforms/swlink/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,73 @@ uint8_t platform_spi_xfer(const spi_bus_e bus, const uint8_t value)
(void)bus;
return value;
}

#ifdef PLATFORM_HAS_CUSTOM_COMMANDS

#include "swd.h"
#include "gdb_packet.h"
#include "target_internal.h"
#include <libopencm3/cm3/dwt.h>

static bool cmd_swdptap_calibration(target_s *target, int argc, const char **argv);

const command_s platform_cmd_list[] = {
{"calibrate_swd", cmd_swdptap_calibration, "Calibrate SW-DP TAP timings"},
{NULL, NULL, NULL},
};

static void swdptap_linereset_measured(bool no_delay)
{
const uint32_t ts_pre = dwt_read_cycle_counter();
/* for robustness, we use 60 HIGH cycles and 4 idle cycles */
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0x0fffffffU, 32U);
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0x0fffffffU, 32U);
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0x0fffffffU, 32U);
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0x0fffffffU, 32U);
const uint32_t ts_post = dwt_read_cycle_counter();
const uint32_t cycles_spent = ts_post - ts_pre;
/* Subtract the overhead of function calls */
const uint32_t fncall_corr = no_delay ? (243U) : (133U);
/* Split the 64*4 into 16*16 for 216-240MHz clocks to not overflow a uint32_t */
const uint32_t freq_measured = rcc_ahb_frequency * 16U / (cycles_spent - fncall_corr) * 16U;
gdb_outf("Estimated %7lu Hz (%5lu cycles - %ld corr)\n", freq_measured, cycles_spent, fncall_corr);
}

static bool cmd_swdptap_calibration(target_s *target, int argc, const char **argv)
{
(void)argc;
(void)argv;
if (target && target->attached)
target_detach(target);
platform_target_clk_output_enable(true);
if (!swd_proc.seq_out)
swdptap_init();
dwt_enable_cycle_counter();

uint32_t freq = 0;
gdb_outf("Platform core clock %lu\n", rcc_ahb_frequency);

/* Emit a _no_delay waveform */
target_clk_divider = UINT32_MAX;
freq = platform_max_frequency_get();
gdb_outf("Changing frequency to %lu (no_delay)\n", freq);
swdptap_linereset_measured(true);

/* Loop through a few _delay values */
for (uint32_t i = 0; i < 8; i++) {
target_clk_divider = i;
freq = platform_max_frequency_get();
gdb_outf("Changing frequency to %lu (divider=%lu)\n", freq, target_clk_divider);
swdptap_linereset_measured(false);
}

/* Reset frequency to medium */
platform_max_frequency_set(3000000U);
return true;
}

#endif
2 changes: 2 additions & 0 deletions src/platforms/swlink/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
extern bool debug_bmp;
#endif

#define PLATFORM_HAS_CUSTOM_COMMANDS

#define PLATFORM_IDENT "(SWLINK) "

/* Hardware definitions... */
Expand Down
Loading