stlink: Implementation of frequency setting.
This commit is contained in:
parent
de26ba6f73
commit
fdc654cfb3
|
@ -109,8 +109,6 @@ void platform_init(int argc, char **argv)
|
||||||
default:
|
default:
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
if (cl_opts.opt_max_swj_frequency)
|
|
||||||
platform_max_frequency_set(cl_opts.opt_max_swj_frequency);
|
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
|
if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
|
||||||
ret = cl_execute(&cl_opts);
|
ret = cl_execute(&cl_opts);
|
||||||
|
@ -124,6 +122,7 @@ void platform_init(int argc, char **argv)
|
||||||
int platform_adiv5_swdp_scan(void)
|
int platform_adiv5_swdp_scan(void)
|
||||||
{
|
{
|
||||||
info.is_jtag = false;
|
info.is_jtag = false;
|
||||||
|
platform_max_frequency_set(cl_opts.opt_max_swj_frequency);
|
||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
case BMP_TYPE_BMP:
|
case BMP_TYPE_BMP:
|
||||||
case BMP_TYPE_LIBFTDI:
|
case BMP_TYPE_LIBFTDI:
|
||||||
|
@ -189,6 +188,7 @@ void platform_add_jtag_dev(int i, const jtag_dev_t *jtag_dev)
|
||||||
int platform_jtag_scan(const uint8_t *lrlens)
|
int platform_jtag_scan(const uint8_t *lrlens)
|
||||||
{
|
{
|
||||||
info.is_jtag = true;
|
info.is_jtag = true;
|
||||||
|
platform_max_frequency_set(cl_opts.opt_max_swj_frequency);
|
||||||
switch (info.bmp_type) {
|
switch (info.bmp_type) {
|
||||||
case BMP_TYPE_BMP:
|
case BMP_TYPE_BMP:
|
||||||
case BMP_TYPE_LIBFTDI:
|
case BMP_TYPE_LIBFTDI:
|
||||||
|
@ -336,6 +336,9 @@ void platform_max_frequency_set(uint32_t freq)
|
||||||
case BMP_TYPE_LIBFTDI:
|
case BMP_TYPE_LIBFTDI:
|
||||||
libftdi_max_frequency_set(freq);
|
libftdi_max_frequency_set(freq);
|
||||||
break;
|
break;
|
||||||
|
case BMP_TYPE_STLINKV2:
|
||||||
|
stlink_max_frequency_set(&info, freq);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
DEBUG_WARN("Setting max SWJ frequency not yet implemented\n");
|
DEBUG_WARN("Setting max SWJ frequency not yet implemented\n");
|
||||||
break;
|
break;
|
||||||
|
@ -352,6 +355,8 @@ uint32_t platform_max_frequency_get(void)
|
||||||
break;
|
break;
|
||||||
case BMP_TYPE_LIBFTDI:
|
case BMP_TYPE_LIBFTDI:
|
||||||
return libftdi_max_frequency_get();
|
return libftdi_max_frequency_get();
|
||||||
|
case BMP_TYPE_STLINKV2:
|
||||||
|
return stlink_max_frequency_get(&info);
|
||||||
default:
|
default:
|
||||||
DEBUG_WARN("Reading max SWJ frequency not yet implemented\n");
|
DEBUG_WARN("Reading max SWJ frequency not yet implemented\n");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -200,7 +200,6 @@ typedef struct {
|
||||||
libusb_context* libusb_ctx;
|
libusb_context* libusb_ctx;
|
||||||
uint16_t vid;
|
uint16_t vid;
|
||||||
uint16_t pid;
|
uint16_t pid;
|
||||||
uint8_t transport_mode;
|
|
||||||
bool srst;
|
bool srst;
|
||||||
uint8_t dap_select;
|
uint8_t dap_select;
|
||||||
uint8_t ep_tx;
|
uint8_t ep_tx;
|
||||||
|
@ -629,44 +628,6 @@ bool stlink_srst_get_val(void)
|
||||||
return Stlink.srst;
|
return Stlink.srst;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool stlink_set_freq_divisor(bmp_info_t *info, uint16_t divisor)
|
|
||||||
{
|
|
||||||
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
|
||||||
STLINK_DEBUG_APIV2_SWD_SET_FREQ,
|
|
||||||
divisor & 0xff, divisor >> 8};
|
|
||||||
uint8_t data[2];
|
|
||||||
send_recv(info->usb_link, cmd, 16, data, 2);
|
|
||||||
if (stlink_usb_error_check(data, false))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool stlink3_set_freq_divisor(bmp_info_t *info, uint16_t divisor)
|
|
||||||
{
|
|
||||||
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
|
||||||
STLINK_APIV3_GET_COM_FREQ,
|
|
||||||
Stlink.transport_mode};
|
|
||||||
uint8_t data[52];
|
|
||||||
send_recv(info->usb_link, cmd, 16, data, 52);
|
|
||||||
stlink_usb_error_check(data, true);
|
|
||||||
int size = data[8];
|
|
||||||
if (divisor > size)
|
|
||||||
divisor = size;
|
|
||||||
uint8_t *p = data + 12 + divisor * sizeof(uint32_t);
|
|
||||||
uint32_t freq = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
|
|
||||||
DEBUG_INFO("Selected %" PRId32 " khz\n", freq);
|
|
||||||
cmd[1] = STLINK_APIV3_SET_COM_FREQ;
|
|
||||||
cmd[2] = Stlink.transport_mode;
|
|
||||||
cmd[3] = 0;
|
|
||||||
p = data + 12 + divisor * sizeof(uint32_t);
|
|
||||||
cmd[4] = p[0];
|
|
||||||
cmd[5] = p[1];
|
|
||||||
cmd[6] = p[2];
|
|
||||||
cmd[7] = p[3];
|
|
||||||
send_recv(info->usb_link, cmd, 16, data, 8);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int stlink_hwversion(void)
|
int stlink_hwversion(void)
|
||||||
{
|
{
|
||||||
return Stlink.ver_stlink;
|
return Stlink.ver_stlink;
|
||||||
|
@ -675,16 +636,10 @@ int stlink_hwversion(void)
|
||||||
static int stlink_enter_debug_jtag(bmp_info_t *info)
|
static int stlink_enter_debug_jtag(bmp_info_t *info)
|
||||||
{
|
{
|
||||||
stlink_leave_state(info);
|
stlink_leave_state(info);
|
||||||
Stlink.transport_mode = STLINK_MODE_JTAG;
|
|
||||||
if (Stlink.ver_stlink == 3)
|
|
||||||
stlink3_set_freq_divisor(info, 4);
|
|
||||||
else
|
|
||||||
stlink_set_freq_divisor(info, 1);
|
|
||||||
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
||||||
STLINK_DEBUG_APIV2_ENTER,
|
STLINK_DEBUG_APIV2_ENTER,
|
||||||
STLINK_DEBUG_ENTER_JTAG_NO_RESET};
|
STLINK_DEBUG_ENTER_JTAG_NO_RESET};
|
||||||
uint8_t data[2];
|
uint8_t data[2];
|
||||||
DEBUG_INFO("Enter JTAG\n");
|
|
||||||
send_recv(info->usb_link, cmd, 16, data, 2);
|
send_recv(info->usb_link, cmd, 16, data, 2);
|
||||||
return stlink_usb_error_check(data, true);
|
return stlink_usb_error_check(data, true);
|
||||||
}
|
}
|
||||||
|
@ -1085,16 +1040,10 @@ void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp)
|
||||||
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp)
|
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp)
|
||||||
{
|
{
|
||||||
stlink_leave_state(info);
|
stlink_leave_state(info);
|
||||||
Stlink.transport_mode = STLINK_MODE_SWD;
|
|
||||||
if (Stlink.ver_stlink == 3)
|
|
||||||
stlink3_set_freq_divisor(info, 2);
|
|
||||||
else
|
|
||||||
stlink_set_freq_divisor(info, 1);
|
|
||||||
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
||||||
STLINK_DEBUG_APIV2_ENTER,
|
STLINK_DEBUG_APIV2_ENTER,
|
||||||
STLINK_DEBUG_ENTER_SWD_NO_RESET};
|
STLINK_DEBUG_ENTER_SWD_NO_RESET};
|
||||||
uint8_t data[2];
|
uint8_t data[2];
|
||||||
DEBUG_INFO("Enter SWD\n");
|
|
||||||
stlink_send_recv_retry(cmd, 16, data, 2);
|
stlink_send_recv_retry(cmd, 16, data, 2);
|
||||||
if (stlink_usb_error_check(data, true))
|
if (stlink_usb_error_check(data, true))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1107,3 +1056,109 @@ int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp)
|
||||||
stlink_dp_error(dp);
|
stlink_dp_error(dp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define V2_USED_SWD_CYCLES 20
|
||||||
|
#define V2_CYCLES_PER_CNT 20
|
||||||
|
#define V2_CLOCK_RATE (72*1000*1000)
|
||||||
|
/* Above values reproduce the known values for V2
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int divs[] = {0, 1,2,3,7,15,31,40,79,158,265,798};
|
||||||
|
for (int i = 0; i < (sizeof(divs) /sizeof(divs[0])); i++) {
|
||||||
|
float ret = 72.0 * 1000 * 1000 / (20 + 20 * divs[i]);
|
||||||
|
printf("%3d: %6.4f MHz\n", divs[i], ret/ 1000000);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int divisor;
|
||||||
|
static unsigned int v3_freq[2];
|
||||||
|
void stlink_max_frequency_set(bmp_info_t *info, uint32_t freq)
|
||||||
|
{
|
||||||
|
if (Stlink.ver_hw == 30) {
|
||||||
|
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
|
||||||
|
STLINK_APIV3_GET_COM_FREQ,
|
||||||
|
info->is_jtag ? STLINK_MODE_JTAG : STLINK_MODE_SWD};
|
||||||
|
uint8_t data[52];
|
||||||
|
send_recv(info->usb_link, cmd, 16, data, 52);
|
||||||
|
stlink_usb_error_check(data, true);
|
||||||
|
volatile uint8_t *p = data + 12;
|
||||||
|
int i;
|
||||||
|
unsigned int last_freq = 0;
|
||||||
|
DEBUG_INFO("Available speed settings: ");
|
||||||
|
for (i = 0; i < STLINK_V3_MAX_FREQ_NB; i++) {
|
||||||
|
unsigned int new_freq = *p++;
|
||||||
|
new_freq |= *p++ << 8;
|
||||||
|
new_freq |= *p++ << 16;
|
||||||
|
new_freq |= *p++ << 24;
|
||||||
|
if (!new_freq)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
last_freq = new_freq;
|
||||||
|
DEBUG_INFO("%s%d", (i)? "/": "", last_freq);
|
||||||
|
if ((freq / 1000) >= last_freq)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DEBUG_INFO(" kHz for %s\n", (info->is_jtag) ? "JTAG" : "SWD");
|
||||||
|
cmd[1] = STLINK_APIV3_SET_COM_FREQ;
|
||||||
|
cmd[3] = 0;
|
||||||
|
cmd[4] = (last_freq >> 0) & 0xff;
|
||||||
|
cmd[5] = (last_freq >> 8) & 0xff;
|
||||||
|
cmd[6] = (last_freq >> 16) & 0xff;
|
||||||
|
cmd[7] = (last_freq >> 24) & 0xff;
|
||||||
|
send_recv(info->usb_link, cmd, 16, data, 8);
|
||||||
|
stlink_usb_error_check(data, true);
|
||||||
|
v3_freq[(info->is_jtag) ? 1 : 0] = last_freq * 1000;
|
||||||
|
} else {
|
||||||
|
uint8_t cmd[16];
|
||||||
|
cmd[0] = STLINK_DEBUG_COMMAND;
|
||||||
|
if (info->is_jtag) {
|
||||||
|
cmd[1] = STLINK_DEBUG_APIV2_JTAG_SET_FREQ;
|
||||||
|
/* V2_CLOCK_RATE / (4, 8, 16, ... 256)*/
|
||||||
|
int div = (V2_CLOCK_RATE + (2 * freq) - 1) / (2 * freq);
|
||||||
|
if (div & (div -1)) {/* Round up */
|
||||||
|
int clz = __builtin_clz(div);
|
||||||
|
divisor = 1 << (32 - clz);
|
||||||
|
} else
|
||||||
|
divisor = div;
|
||||||
|
if (divisor < 4)
|
||||||
|
divisor = 4;
|
||||||
|
else if (divisor > 256)
|
||||||
|
divisor = 256;
|
||||||
|
} else {
|
||||||
|
cmd[1] = STLINK_DEBUG_APIV2_SWD_SET_FREQ;
|
||||||
|
divisor = V2_CLOCK_RATE + freq - 1;
|
||||||
|
divisor /= freq;
|
||||||
|
divisor -= V2_USED_SWD_CYCLES;
|
||||||
|
if (divisor < 0)
|
||||||
|
divisor = 0;
|
||||||
|
divisor /= V2_CYCLES_PER_CNT;
|
||||||
|
}
|
||||||
|
DEBUG_WARN("Divisor for %6.4f MHz is %" PRIu32 "\n",
|
||||||
|
freq/1000000.0, divisor);
|
||||||
|
cmd[2] = divisor & 0xff;
|
||||||
|
cmd[3] = (divisor >> 8) & 0xff;
|
||||||
|
uint8_t data[2];
|
||||||
|
send_recv(info->usb_link, cmd, 16, data, 2);
|
||||||
|
if (stlink_usb_error_check(data, false))
|
||||||
|
DEBUG_WARN("Set frequency failed!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t stlink_max_frequency_get(bmp_info_t *info)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
if (Stlink.ver_hw == 30) {
|
||||||
|
ret = v3_freq[(info->is_jtag) ? STLINK_MODE_JTAG : STLINK_MODE_SWD];
|
||||||
|
} else {
|
||||||
|
ret = V2_CLOCK_RATE;
|
||||||
|
if (info->is_jtag)
|
||||||
|
ret /= (2 * divisor);
|
||||||
|
else
|
||||||
|
ret /= (V2_USED_SWD_CYCLES + (V2_CYCLES_PER_CNT * divisor));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -37,6 +37,8 @@ void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp) {};
|
||||||
int stlink_jtag_dp_init(ADIv5_DP_t *dp) {return false;};
|
int stlink_jtag_dp_init(ADIv5_DP_t *dp) {return false;};
|
||||||
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens) {return 0;};
|
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens) {return 0;};
|
||||||
void stlink_exit_function(bmp_info_t *info) {};
|
void stlink_exit_function(bmp_info_t *info) {};
|
||||||
|
void stlink_max_frequency_set(bmp_info_t *info, uint32_t freq) {};
|
||||||
|
uint32_t stlink_max_frequency_get(bmp_info_t *info) {return 0;};
|
||||||
# pragma GCC diagnostic pop
|
# pragma GCC diagnostic pop
|
||||||
#else
|
#else
|
||||||
int stlink_init(bmp_info_t *info);
|
int stlink_init(bmp_info_t *info);
|
||||||
|
@ -49,5 +51,7 @@ void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp);
|
||||||
int stlink_jtag_dp_init(ADIv5_DP_t *dp);
|
int stlink_jtag_dp_init(ADIv5_DP_t *dp);
|
||||||
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens);
|
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens);
|
||||||
void stlink_exit_function(bmp_info_t *info);
|
void stlink_exit_function(bmp_info_t *info);
|
||||||
|
void stlink_max_frequency_set(bmp_info_t *info, uint32_t freq);
|
||||||
|
uint32_t stlink_max_frequency_get(bmp_info_t *info);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue