diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.c b/src/platforms/common/blackpill-f4/blackpill-f4.c index 1e26b875770..2a64e6efc17 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.c +++ b/src/platforms/common/blackpill-f4/blackpill-f4.c @@ -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 + +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 diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.h b/src/platforms/common/blackpill-f4/blackpill-f4.h index 7a55fc3c20f..30545866363 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.h +++ b/src/platforms/common/blackpill-f4/blackpill-f4.h @@ -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. diff --git a/src/platforms/common/stm32/timing_stm32.c b/src/platforms/common/stm32/timing_stm32.c index 67688f0196c..0bb07177c96 100644 --- a/src/platforms/common/stm32/timing_stm32.c +++ b/src/platforms/common/stm32/timing_stm32.c @@ -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) { @@ -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 } diff --git a/src/platforms/stlink/platform.c b/src/platforms/stlink/platform.c index 4a423ff6039..17391f3f969 100644 --- a/src/platforms/stlink/platform.c +++ b/src/platforms/stlink/platform.c @@ -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 + +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 diff --git a/src/platforms/stlink/platform.h b/src/platforms/stlink/platform.h index 8068c717d2a..839f57d6da1 100644 --- a/src/platforms/stlink/platform.h +++ b/src/platforms/stlink/platform.h @@ -40,6 +40,8 @@ extern bool debug_bmp; #endif +#define PLATFORM_HAS_CUSTOM_COMMANDS + #define PLATFORM_IDENT "(ST-Link/v2) " /* Hardware definitions... */ diff --git a/src/platforms/swlink/platform.c b/src/platforms/swlink/platform.c index bff34040943..881346ac8e6 100644 --- a/src/platforms/swlink/platform.c +++ b/src/platforms/swlink/platform.c @@ -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 + +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 diff --git a/src/platforms/swlink/platform.h b/src/platforms/swlink/platform.h index 65d774b74a6..ca1fc358153 100644 --- a/src/platforms/swlink/platform.h +++ b/src/platforms/swlink/platform.h @@ -35,6 +35,8 @@ extern bool debug_bmp; #endif +#define PLATFORM_HAS_CUSTOM_COMMANDS + #define PLATFORM_IDENT "(SWLINK) " /* Hardware definitions... */