From 2dc3245deb212ceaf16e5ed60f89490579e6cef8 Mon Sep 17 00:00:00 2001 From: ALTracer Date: Sat, 12 Oct 2024 12:05:50 +0300 Subject: [PATCH 1/5] blackpill-f4: Implement SWCLK self-measurement as a platform command --- .../common/blackpill-f4/blackpill-f4.c | 64 +++++++++++++++++++ .../common/blackpill-f4/blackpill-f4.h | 2 + 2 files changed, 66 insertions(+) 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. From 102e70532f740aed893e072aa57f2c335a50e641 Mon Sep 17 00:00:00 2001 From: ALTracer Date: Sat, 12 Oct 2024 12:09:30 +0300 Subject: [PATCH 2/5] swlink: Implement SWCLK self-measurement as a platform command --- src/platforms/swlink/platform.c | 64 +++++++++++++++++++++++++++++++++ src/platforms/swlink/platform.h | 2 ++ 2 files changed, 66 insertions(+) diff --git a/src/platforms/swlink/platform.c b/src/platforms/swlink/platform.c index bff34040943..a2ea4aafdaf 100644 --- a/src/platforms/swlink/platform.c +++ b/src/platforms/swlink/platform.c @@ -215,3 +215,67 @@ 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); + 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/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... */ From a3b4d172e1359b4807cc1aabdd06502ef16d39e6 Mon Sep 17 00:00:00 2001 From: ALTracer Date: Sat, 12 Oct 2024 12:57:40 +0300 Subject: [PATCH 3/5] stlink: Implement SWCLK self-measurement as a platform command --- src/platforms/stlink/platform.c | 70 +++++++++++++++++++++++++++++++++ src/platforms/stlink/platform.h | 2 + 2 files changed, 72 insertions(+) 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... */ From 7f22531869d5c0c0d2212859c0abcd1e340c924c Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sat, 12 Oct 2024 14:04:43 +0300 Subject: [PATCH 4/5] common/stm32/timing: Treat _no_delay frequency specially * Current _clk_delay strategy is better approximated by a proportional law, but _no_delay does not fit into that nicely. * Also update delay macros with values obtained from calibration. --- src/platforms/common/stm32/timing_stm32.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/platforms/common/stm32/timing_stm32.c b/src/platforms/common/stm32/timing_stm32.c index 67688f0196c..f4ef0a67159 100644 --- a/src/platforms/common/stm32/timing_stm32.c +++ b/src/platforms/common/stm32/timing_stm32.c @@ -146,9 +146,26 @@ 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(STM32F1) /* Values for STM32F103 at 72 MHz */ +#define USED_SWD_CYCLES_NODELAY 14 +#define USED_SWD_CYCLES 30 +#define CYCLES_PER_CNT 14 +#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 +217,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 } From d2e78a78bc7e7cc4c5d0b9f994eae75ce21eb48c Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Tue, 29 Oct 2024 22:01:31 +0300 Subject: [PATCH 5/5] swlink: timing: Update routines for stm32f103 flash --- src/platforms/common/stm32/timing_stm32.c | 9 +++++++-- src/platforms/swlink/platform.c | 14 ++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/platforms/common/stm32/timing_stm32.c b/src/platforms/common/stm32/timing_stm32.c index f4ef0a67159..0bb07177c96 100644 --- a/src/platforms/common/stm32/timing_stm32.c +++ b/src/platforms/common/stm32/timing_stm32.c @@ -151,11 +151,16 @@ uint32_t platform_time_ms(void) #define USED_SWD_CYCLES_NODELAY 12 #define USED_SWD_CYCLES 24 #define CYCLES_PER_CNT 12 -#elif defined(STM32F1) -/* Values for STM32F103 at 72 MHz */ +#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 diff --git a/src/platforms/swlink/platform.c b/src/platforms/swlink/platform.c index a2ea4aafdaf..881346ac8e6 100644 --- a/src/platforms/swlink/platform.c +++ b/src/platforms/swlink/platform.c @@ -236,13 +236,19 @@ static void swdptap_linereset_measured(bool no_delay) /* 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 ? (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); + 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)