mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-14 10:20:01 +00:00
Delete mos tool and related libraries from dev
Moved to https://github.com/mongoose-os/mos PUBLISHED_FROM=8a0475678dba38fd6e057b8a530e9d08054ff74f
This commit is contained in:
1 parent
747e393a54
commit
b93bc02ab0
10 files changed
-2205
No files matched your search
@@ -1,29 +0,0 @@
|
||||
Copyright (c) 2011 The stlink project (github.com/texane/stlink) contributors.
|
||||
All rights reserved.
|
||||
Copyright (c) 2011 The "Capt'ns Missing Link" Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of Martin Capitanio nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1,869 +0,0 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "stlink.h"
|
||||
#include "usb.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#define O_BINARY 0 //! @todo get rid of this OH MY (@xor-gate)
|
||||
#endif
|
||||
|
||||
/* todo: stm32l15xxx flash memory, pm0062 manual */
|
||||
|
||||
/* stm32f FPEC flash controller interface, pm0063 manual */
|
||||
// TODO - all of this needs to be abstracted out....
|
||||
// STM32F05x is identical, based on RM0091 (DM00031936, Doc ID 018940 Rev 2,
|
||||
// August 2012)
|
||||
#define FLASH_REGS_ADDR 0x40022000
|
||||
#define FLASH_REGS_SIZE 0x28
|
||||
|
||||
#define FLASH_ACR (FLASH_REGS_ADDR + 0x00)
|
||||
#define FLASH_KEYR (FLASH_REGS_ADDR + 0x04)
|
||||
#define FLASH_SR (FLASH_REGS_ADDR + 0x0c)
|
||||
#define FLASH_CR (FLASH_REGS_ADDR + 0x10)
|
||||
#define FLASH_AR (FLASH_REGS_ADDR + 0x14)
|
||||
#define FLASH_OBR (FLASH_REGS_ADDR + 0x1c)
|
||||
#define FLASH_WRPR (FLASH_REGS_ADDR + 0x20)
|
||||
|
||||
// For STM32F05x, the RDPTR_KEY may be wrong, but as it is not used anywhere...
|
||||
#define FLASH_RDPTR_KEY 0x00a5
|
||||
#define FLASH_KEY1 0x45670123
|
||||
#define FLASH_KEY2 0xcdef89ab
|
||||
|
||||
#define FLASH_SR_BSY 0
|
||||
#define FLASH_SR_EOP 5
|
||||
|
||||
#define FLASH_CR_PG 0
|
||||
#define FLASH_CR_PER 1
|
||||
#define FLASH_CR_MER 2
|
||||
#define FLASH_CR_STRT 6
|
||||
#define FLASH_CR_LOCK 7
|
||||
|
||||
// 32L = 32F1 same CoreID as 32F4!
|
||||
#define STM32L_FLASH_REGS_ADDR ((uint32_t) 0x40023c00)
|
||||
#define STM32L_FLASH_ACR (STM32L_FLASH_REGS_ADDR + 0x00)
|
||||
#define STM32L_FLASH_PECR (STM32L_FLASH_REGS_ADDR + 0x04)
|
||||
#define STM32L_FLASH_PDKEYR (STM32L_FLASH_REGS_ADDR + 0x08)
|
||||
#define STM32L_FLASH_PEKEYR (STM32L_FLASH_REGS_ADDR + 0x0c)
|
||||
#define STM32L_FLASH_PRGKEYR (STM32L_FLASH_REGS_ADDR + 0x10)
|
||||
#define STM32L_FLASH_OPTKEYR (STM32L_FLASH_REGS_ADDR + 0x14)
|
||||
#define STM32L_FLASH_SR (STM32L_FLASH_REGS_ADDR + 0x18)
|
||||
#define STM32L_FLASH_OBR (STM32L_FLASH_REGS_ADDR + 0x1c)
|
||||
#define STM32L_FLASH_WRPR (STM32L_FLASH_REGS_ADDR + 0x20)
|
||||
#define FLASH_L1_FPRG 10
|
||||
#define FLASH_L1_PROG 3
|
||||
|
||||
// 32L4 register base is at FLASH_REGS_ADDR (0x40022000)
|
||||
#define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08)
|
||||
#define STM32L4_FLASH_SR (FLASH_REGS_ADDR + 0x10)
|
||||
#define STM32L4_FLASH_CR (FLASH_REGS_ADDR + 0x14)
|
||||
#define STM32L4_FLASH_OPTR (FLASH_REGS_ADDR + 0x20)
|
||||
|
||||
#define STM32L4_FLASH_SR_BSY 16
|
||||
#define STM32L4_FLASH_SR_ERRMASK 0x3f8 /* SR [9:3] */
|
||||
|
||||
#define STM32L4_FLASH_CR_LOCK 31 /* Lock control register */
|
||||
#define STM32L4_FLASH_CR_PG 0 /* Program */
|
||||
#define STM32L4_FLASH_CR_PER 1 /* Page erase */
|
||||
#define STM32L4_FLASH_CR_MER1 2 /* Bank 1 erase */
|
||||
#define STM32L4_FLASH_CR_MER2 15 /* Bank 2 erase */
|
||||
#define STM32L4_FLASH_CR_STRT 16 /* Start command */
|
||||
#define STM32L4_FLASH_CR_BKER 11 /* Bank select for page erase */
|
||||
#define STM32L4_FLASH_CR_PNB 3 /* Page number (8 bits) */
|
||||
// Bits requesting flash operations (useful when we want to clear them)
|
||||
#define STM32L4_FLASH_CR_OPBITS \
|
||||
((1lu << STM32L4_FLASH_CR_PG) | (1lu << STM32L4_FLASH_CR_PER) | \
|
||||
(1lu << STM32L4_FLASH_CR_MER1) | (1lu << STM32L4_FLASH_CR_MER1))
|
||||
// Page is fully specified by BKER and PNB
|
||||
#define STM32L4_FLASH_CR_PAGEMASK (0x1fflu << STM32L4_FLASH_CR_PNB)
|
||||
|
||||
#define STM32L4_FLASH_OPTR_DUALBANK 21
|
||||
|
||||
// STM32L0x flash register base and offsets
|
||||
// same as 32L1 above
|
||||
// RM0090 - DM00031020.pdf
|
||||
#define STM32L0_FLASH_REGS_ADDR ((uint32_t) 0x40022000)
|
||||
#define FLASH_ACR_OFF ((uint32_t) 0x00)
|
||||
#define FLASH_PECR_OFF ((uint32_t) 0x04)
|
||||
#define FLASH_PDKEYR_OFF ((uint32_t) 0x08)
|
||||
#define FLASH_PEKEYR_OFF ((uint32_t) 0x0c)
|
||||
#define FLASH_PRGKEYR_OFF ((uint32_t) 0x10)
|
||||
#define FLASH_OPTKEYR_OFF ((uint32_t) 0x14)
|
||||
#define FLASH_SR_OFF ((uint32_t) 0x18)
|
||||
#define FLASH_OBR_OFF ((uint32_t) 0x1c)
|
||||
#define FLASH_WRPR_OFF ((uint32_t) 0x20)
|
||||
|
||||
// STM32F4
|
||||
#define FLASH_F4_REGS_ADDR ((uint32_t) 0x40023c00)
|
||||
#define FLASH_F4_KEYR (FLASH_F4_REGS_ADDR + 0x04)
|
||||
#define FLASH_F4_OPT_KEYR (FLASH_F4_REGS_ADDR + 0x08)
|
||||
#define FLASH_F4_SR (FLASH_F4_REGS_ADDR + 0x0c)
|
||||
#define FLASH_F4_CR (FLASH_F4_REGS_ADDR + 0x10)
|
||||
#define FLASH_F4_OPT_CR (FLASH_F4_REGS_ADDR + 0x14)
|
||||
#define FLASH_F4_CR_STRT 16
|
||||
#define FLASH_F4_CR_LOCK 31
|
||||
#define FLASH_F4_CR_SER 1
|
||||
#define FLASH_F4_CR_SNB 3
|
||||
#define FLASH_F4_CR_SNB_MASK 0xf8
|
||||
#define FLASH_F4_SR_BSY 16
|
||||
|
||||
#define L1_WRITE_BLOCK_SIZE 0x80
|
||||
#define L0_WRITE_BLOCK_SIZE 0x40
|
||||
|
||||
#define STLINK_REG_CM3_CPUID 0xE000ED00
|
||||
#define STLINK_REG_CM3_FP_CTRL 0xE0002000
|
||||
#define STLINK_REG_CM3_FP_COMP0 0xE0002008
|
||||
|
||||
/* Cortex™-M3 Technical Reference Manual */
|
||||
/* Debug Halting Control and Status Register */
|
||||
#define STLINK_REG_DHCSR 0xe000edf0
|
||||
#define STLINK_REG_DHCSR_DBGKEY 0xa05f0000
|
||||
#define STLINK_REG_DCRSR 0xe000edf4
|
||||
#define STLINK_REG_DCRDR 0xe000edf8
|
||||
|
||||
struct stlink_chipid_params {
|
||||
uint32_t chip_id;
|
||||
char *description;
|
||||
uint32_t flash_size_reg;
|
||||
uint32_t flash_pagesize;
|
||||
uint32_t sram_size;
|
||||
uint32_t bootrom_base;
|
||||
uint32_t bootrom_size;
|
||||
};
|
||||
|
||||
void write_uint32(unsigned char *buf, uint32_t ui) {
|
||||
if (!is_bigendian()) { // le -> le (don't swap)
|
||||
buf[0] = ((unsigned char *) &ui)[0];
|
||||
buf[1] = ((unsigned char *) &ui)[1];
|
||||
buf[2] = ((unsigned char *) &ui)[2];
|
||||
buf[3] = ((unsigned char *) &ui)[3];
|
||||
} else {
|
||||
buf[0] = ((unsigned char *) &ui)[3];
|
||||
buf[1] = ((unsigned char *) &ui)[2];
|
||||
buf[2] = ((unsigned char *) &ui)[1];
|
||||
buf[3] = ((unsigned char *) &ui)[0];
|
||||
}
|
||||
}
|
||||
|
||||
void write_uint16(unsigned char *buf, uint16_t ui) {
|
||||
if (!is_bigendian()) { // le -> le (don't swap)
|
||||
buf[0] = ((unsigned char *) &ui)[0];
|
||||
buf[1] = ((unsigned char *) &ui)[1];
|
||||
} else {
|
||||
buf[0] = ((unsigned char *) &ui)[1];
|
||||
buf[1] = ((unsigned char *) &ui)[0];
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t read_uint32(const unsigned char *c, const int pt) {
|
||||
uint32_t ui;
|
||||
char *p = (char *) &ui;
|
||||
|
||||
if (!is_bigendian()) { // le -> le (don't swap)
|
||||
p[0] = c[pt + 0];
|
||||
p[1] = c[pt + 1];
|
||||
p[2] = c[pt + 2];
|
||||
p[3] = c[pt + 3];
|
||||
} else {
|
||||
p[0] = c[pt + 3];
|
||||
p[1] = c[pt + 2];
|
||||
p[2] = c[pt + 1];
|
||||
p[3] = c[pt + 0];
|
||||
}
|
||||
return ui;
|
||||
}
|
||||
|
||||
static uint32_t __attribute__((unused)) read_flash_rdp(stlink_t *sl) {
|
||||
uint32_t rdp;
|
||||
stlink_read_debug32(sl, FLASH_WRPR, &rdp);
|
||||
return rdp & 0xff;
|
||||
}
|
||||
|
||||
static inline uint32_t read_flash_cr(stlink_t *sl) {
|
||||
uint32_t res;
|
||||
stlink_read_debug32(sl, FLASH_F4_CR, &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline unsigned int is_flash_locked(stlink_t *sl) {
|
||||
/* return non zero for true */
|
||||
uint32_t cr_lock_shift = FLASH_F4_CR_LOCK, cr = read_flash_cr(sl);
|
||||
return cr & (1 << cr_lock_shift);
|
||||
}
|
||||
|
||||
static void unlock_flash(stlink_t *sl) {
|
||||
uint32_t key_reg = FLASH_F4_KEYR;
|
||||
stlink_write_debug32(sl, key_reg, FLASH_KEY1);
|
||||
stlink_write_debug32(sl, key_reg, FLASH_KEY2);
|
||||
}
|
||||
|
||||
static int unlock_flash_if(stlink_t *sl) {
|
||||
/* unlock flash if already locked */
|
||||
|
||||
if (is_flash_locked(sl)) {
|
||||
unlock_flash(sl);
|
||||
if (is_flash_locked(sl)) {
|
||||
printf("Failed to unlock flash!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lock_flash(stlink_t *sl) {
|
||||
uint32_t n;
|
||||
uint32_t cr_reg = FLASH_F4_CR;
|
||||
uint32_t cr_lock_shift = FLASH_F4_CR_LOCK;
|
||||
|
||||
n = read_flash_cr(sl) | (1 << cr_lock_shift);
|
||||
stlink_write_debug32(sl, cr_reg, n);
|
||||
}
|
||||
|
||||
static void set_flash_cr_pg(stlink_t *sl) {
|
||||
uint32_t cr_reg, x;
|
||||
|
||||
x = read_flash_cr(sl);
|
||||
|
||||
cr_reg = FLASH_F4_CR;
|
||||
x |= 1 << FLASH_CR_PG;
|
||||
|
||||
stlink_write_debug32(sl, cr_reg, x);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) clear_flash_cr_pg(stlink_t *sl) {
|
||||
uint32_t cr_reg, n;
|
||||
|
||||
cr_reg = FLASH_F4_CR;
|
||||
|
||||
n = read_flash_cr(sl) & ~(1 << FLASH_CR_PG);
|
||||
stlink_write_debug32(sl, cr_reg, n);
|
||||
}
|
||||
|
||||
static void set_flash_cr_per(stlink_t *sl) {
|
||||
const uint32_t n = 1 << FLASH_CR_PER;
|
||||
stlink_write_debug32(sl, FLASH_CR, n);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) clear_flash_cr_per(stlink_t *sl) {
|
||||
const uint32_t n = read_flash_cr(sl) & ~(1 << FLASH_CR_PER);
|
||||
stlink_write_debug32(sl, FLASH_CR, n);
|
||||
}
|
||||
|
||||
static void set_flash_cr_mer(stlink_t *sl, bool v) {
|
||||
uint32_t val, cr_reg, cr_mer, cr_pg;
|
||||
|
||||
cr_reg = FLASH_F4_CR;
|
||||
cr_mer = 1 << FLASH_CR_MER;
|
||||
cr_pg = 1 << FLASH_CR_PG;
|
||||
|
||||
stlink_read_debug32(sl, cr_reg, &val);
|
||||
if (val & cr_pg) {
|
||||
/* STM32F030 will drop MER bit if PG was set */
|
||||
val &= ~cr_pg;
|
||||
stlink_write_debug32(sl, cr_reg, val);
|
||||
}
|
||||
|
||||
if (v)
|
||||
val |= cr_mer;
|
||||
else
|
||||
val &= ~cr_mer;
|
||||
stlink_write_debug32(sl, cr_reg, val);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) clear_flash_cr_mer(stlink_t *sl) {
|
||||
uint32_t val, cr_reg, cr_mer;
|
||||
|
||||
cr_reg = FLASH_F4_CR;
|
||||
cr_mer = 1 << FLASH_CR_MER;
|
||||
|
||||
stlink_read_debug32(sl, cr_reg, &val);
|
||||
val &= ~cr_mer;
|
||||
stlink_write_debug32(sl, cr_reg, val);
|
||||
}
|
||||
|
||||
static void set_flash_cr_strt(stlink_t *sl) {
|
||||
uint32_t val, cr_reg, cr_strt;
|
||||
|
||||
cr_reg = FLASH_F4_CR;
|
||||
cr_strt = 1 << FLASH_F4_CR_STRT;
|
||||
|
||||
stlink_read_debug32(sl, cr_reg, &val);
|
||||
val |= cr_strt;
|
||||
stlink_write_debug32(sl, cr_reg, val);
|
||||
}
|
||||
|
||||
static inline uint32_t read_flash_sr(stlink_t *sl) {
|
||||
uint32_t res, sr_reg;
|
||||
sr_reg = FLASH_F4_SR;
|
||||
stlink_read_debug32(sl, sr_reg, &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline unsigned int is_flash_busy(stlink_t *sl) {
|
||||
uint32_t sr_busy_shift;
|
||||
sr_busy_shift = FLASH_F4_SR_BSY;
|
||||
return read_flash_sr(sl) & (1 << sr_busy_shift);
|
||||
}
|
||||
|
||||
static void wait_flash_busy(stlink_t *sl) {
|
||||
/* todo: add some delays here */
|
||||
while (is_flash_busy(sl))
|
||||
;
|
||||
}
|
||||
|
||||
static void wait_flash_busy_progress(stlink_t *sl) {
|
||||
while (is_flash_busy(sl)) {
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int is_flash_eop(stlink_t *sl) {
|
||||
return read_flash_sr(sl) & (1 << FLASH_SR_EOP);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) clear_flash_sr_eop(stlink_t *sl) {
|
||||
const uint32_t n = read_flash_sr(sl) & ~(1 << FLASH_SR_EOP);
|
||||
stlink_write_debug32(sl, FLASH_SR, n);
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) wait_flash_eop(stlink_t *sl) {
|
||||
/* todo: add some delays here */
|
||||
while (is_flash_eop(sl) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
static inline void write_flash_ar(stlink_t *sl, uint32_t n) {
|
||||
stlink_write_debug32(sl, FLASH_AR, n);
|
||||
}
|
||||
|
||||
static inline void write_flash_cr_psiz(stlink_t *sl, uint32_t n) {
|
||||
uint32_t x = read_flash_cr(sl);
|
||||
x &= ~(0x03 << 8);
|
||||
x |= (n << 8);
|
||||
stlink_write_debug32(sl, FLASH_F4_CR, x);
|
||||
}
|
||||
|
||||
static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n) {
|
||||
uint32_t x = read_flash_cr(sl);
|
||||
x &= ~FLASH_F4_CR_SNB_MASK;
|
||||
x |= (n << FLASH_F4_CR_SNB);
|
||||
x |= (1 << FLASH_F4_CR_SER);
|
||||
stlink_write_debug32(sl, FLASH_F4_CR, x);
|
||||
}
|
||||
|
||||
static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n) {
|
||||
stlink_write_debug32(sl, STM32L4_FLASH_SR,
|
||||
0xFFFFFFFF & ~(1 << STM32L4_FLASH_SR_BSY));
|
||||
uint32_t x = read_flash_cr(sl);
|
||||
x &= ~STM32L4_FLASH_CR_OPBITS;
|
||||
x &= ~STM32L4_FLASH_CR_PAGEMASK;
|
||||
x &= ~(1 << STM32L4_FLASH_CR_MER1);
|
||||
x &= ~(1 << STM32L4_FLASH_CR_MER2);
|
||||
x |= (n << STM32L4_FLASH_CR_PNB);
|
||||
x |= (1lu << STM32L4_FLASH_CR_PER);
|
||||
stlink_write_debug32(sl, STM32L4_FLASH_CR, x);
|
||||
}
|
||||
|
||||
void stlink_close(stlink_t *sl) {
|
||||
if (!sl) return;
|
||||
_stlink_usb_close(sl);
|
||||
free(sl);
|
||||
}
|
||||
|
||||
int stlink_exit_debug_mode(stlink_t *sl) {
|
||||
int ret;
|
||||
|
||||
ret = stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY);
|
||||
if (ret == -1) return ret;
|
||||
|
||||
return _stlink_usb_exit_debug_mode(sl);
|
||||
}
|
||||
|
||||
int stlink_enter_swd_mode(stlink_t *sl) {
|
||||
return _stlink_usb_enter_swd_mode(sl);
|
||||
}
|
||||
|
||||
// Force the core into the debug mode -> halted state.
|
||||
int stlink_force_debug(stlink_t *sl) {
|
||||
return _stlink_usb_force_debug(sl);
|
||||
}
|
||||
|
||||
int stlink_exit_dfu_mode(stlink_t *sl) {
|
||||
return _stlink_usb_exit_dfu_mode(sl);
|
||||
}
|
||||
|
||||
int stlink_core_id(stlink_t *sl) {
|
||||
int ret;
|
||||
|
||||
ret = _stlink_usb_core_id(sl);
|
||||
if (ret == -1) {
|
||||
printf("Failed to read core_id\n");
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int stlink_chip_id(stlink_t *sl, uint32_t *chip_id) {
|
||||
int ret;
|
||||
|
||||
ret = stlink_read_debug32(sl, 0xE0042000, chip_id);
|
||||
if (ret == -1) return ret;
|
||||
|
||||
if (*chip_id == 0)
|
||||
ret = stlink_read_debug32(
|
||||
sl, 0x40015800,
|
||||
chip_id); // Try Corex M0 DBGMCU_IDCODE register address
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* reads and decodes the flash parameters, as dynamically as possible
|
||||
* @param sl
|
||||
* @return 0 for success, or -1 for unsupported core type.
|
||||
*/
|
||||
static const struct stlink_chipid_params F7_params = {
|
||||
// RM0385 and DS10916 document was used to find these paramaters
|
||||
.chip_id = STLINK_CHIPID_STM32_F7,
|
||||
.description = "F7 device",
|
||||
.flash_size_reg = 0x1ff0f442, // section 41.2
|
||||
.flash_pagesize = 0x800, // No flash pages
|
||||
.sram_size = 0x50000, // "SRAM" byte size in hex from DS Fig 18
|
||||
.bootrom_base =
|
||||
0x00100000, // "System memory" starting address from DS Fig 18
|
||||
.bootrom_size = 0xEDC0 // "System memory" byte size in hex from DS Fig 18
|
||||
};
|
||||
|
||||
int stlink_load_device_params(stlink_t *sl) {
|
||||
const struct stlink_chipid_params *params = &F7_params;
|
||||
stlink_core_id(sl);
|
||||
uint32_t chip_id;
|
||||
uint32_t flash_size;
|
||||
|
||||
stlink_chip_id(sl, &chip_id);
|
||||
sl->chip_id = chip_id & 0xfff;
|
||||
/* Fix chip_id for F4 rev A errata , Read CPU ID, as CoreID is the same for
|
||||
* F2/F4*/
|
||||
if (sl->chip_id == 0x411) {
|
||||
uint32_t cpuid;
|
||||
stlink_read_debug32(sl, 0xE000ED00, &cpuid);
|
||||
if ((cpuid & 0xfff0) == 0xc240) sl->chip_id = 0x413;
|
||||
}
|
||||
|
||||
if (sl->chip_id != STLINK_CHIPID_STM32_F7) {
|
||||
printf("unsupported chip id! %d\n", chip_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// These are fixed...
|
||||
sl->flash_base = STM32_FLASH_BASE;
|
||||
sl->sram_base = STM32_SRAM_BASE;
|
||||
stlink_read_debug32(sl, (params->flash_size_reg) & ~3, &flash_size);
|
||||
if (params->flash_size_reg & 2) flash_size = flash_size >> 16;
|
||||
flash_size = flash_size & 0xffff;
|
||||
|
||||
sl->flash_size = flash_size * 1024;
|
||||
sl->flash_pgsz = params->flash_pagesize;
|
||||
sl->sram_size = params->sram_size;
|
||||
sl->sys_base = params->bootrom_base;
|
||||
sl->sys_size = params->bootrom_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stlink_reset(stlink_t *sl) {
|
||||
return _stlink_usb_reset(sl);
|
||||
}
|
||||
|
||||
int stlink_jtag_reset(stlink_t *sl, int value) {
|
||||
return _stlink_usb_jtag_reset(sl, value);
|
||||
}
|
||||
|
||||
int stlink_run(stlink_t *sl) {
|
||||
return _stlink_usb_run(sl);
|
||||
}
|
||||
|
||||
int stlink_set_swdclk(stlink_t *sl, uint16_t divisor) {
|
||||
return _stlink_usb_set_swdclk(sl, divisor);
|
||||
}
|
||||
|
||||
int stlink_status(stlink_t *sl) {
|
||||
int ret;
|
||||
|
||||
ret = _stlink_usb_status(sl);
|
||||
stlink_core_stat(sl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int stlink_target_voltage(stlink_t *sl) {
|
||||
return _stlink_usb_target_voltage(sl);
|
||||
}
|
||||
|
||||
int stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
|
||||
return _stlink_usb_read_debug32(sl, addr, data);
|
||||
}
|
||||
|
||||
int stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
|
||||
return _stlink_usb_write_debug32(sl, addr, data);
|
||||
}
|
||||
|
||||
int stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
|
||||
if (len % 4 != 0) {
|
||||
fprintf(stderr,
|
||||
"Error: Data length doesn't have a 32 bit alignment: +%d byte.\n",
|
||||
len % 4);
|
||||
abort();
|
||||
}
|
||||
return _stlink_usb_write_mem32(sl, addr, len);
|
||||
}
|
||||
|
||||
int stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
|
||||
if (len % 4 != 0) { // !!! never ever: fw gives just wrong values
|
||||
fprintf(stderr,
|
||||
"Error: Data length doesn't have a 32 bit alignment: +%d byte.\n",
|
||||
len % 4);
|
||||
abort();
|
||||
}
|
||||
return _stlink_usb_read_mem32(sl, addr, len);
|
||||
}
|
||||
|
||||
int stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
|
||||
if (len > 0x40) { // !!! never ever: Writing more then 0x40 bytes gives
|
||||
// unexpected behaviour
|
||||
fprintf(stderr, "Error: Data length > 64: +%d byte.\n", len);
|
||||
abort();
|
||||
}
|
||||
return _stlink_usb_write_mem8(sl, addr, len);
|
||||
}
|
||||
|
||||
int stlink_write_reg(stlink_t *sl, uint32_t reg, int idx) {
|
||||
return _stlink_usb_write_reg(sl, reg, idx);
|
||||
}
|
||||
|
||||
int stlink_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) {
|
||||
if (r_idx > 20 || r_idx < 0) {
|
||||
fprintf(stderr, "Error: register index must be in [0..20]\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _stlink_usb_read_reg(sl, r_idx, regp);
|
||||
}
|
||||
|
||||
bool stlink_is_core_halted(stlink_t *sl) {
|
||||
bool ret = false;
|
||||
|
||||
stlink_status(sl);
|
||||
if (sl->q_buf[0] == STLINK_CORE_HALTED) ret = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int stlink_step(stlink_t *sl) {
|
||||
return _stlink_usb_step(sl);
|
||||
}
|
||||
|
||||
int stlink_current_mode(stlink_t *sl) {
|
||||
return _stlink_usb_current_mode(sl);
|
||||
}
|
||||
|
||||
// End of delegates.... Common code below here...
|
||||
|
||||
// Endianness
|
||||
// http://www.ibm.com/developerworks/aix/library/au-endianc/index.html
|
||||
// const int i = 1;
|
||||
// #define is_bigendian() ( (*(char*)&i) == 0 )
|
||||
|
||||
unsigned int is_bigendian(void) {
|
||||
static volatile const unsigned int i = 1;
|
||||
return *(volatile const char *) &i == 0;
|
||||
}
|
||||
|
||||
uint16_t read_uint16(const unsigned char *c, const int pt) {
|
||||
uint32_t ui;
|
||||
char *p = (char *) &ui;
|
||||
|
||||
if (!is_bigendian()) { // le -> le (don't swap)
|
||||
p[0] = c[pt + 0];
|
||||
p[1] = c[pt + 1];
|
||||
} else {
|
||||
p[0] = c[pt + 1];
|
||||
p[1] = c[pt + 0];
|
||||
}
|
||||
return ui;
|
||||
}
|
||||
|
||||
// same as above with entrypoint.
|
||||
|
||||
void stlink_run_at(stlink_t *sl, stm32_addr_t addr) {
|
||||
stlink_write_reg(sl, addr, 15); /* pc register */
|
||||
|
||||
stlink_run(sl);
|
||||
|
||||
while (stlink_is_core_halted(sl)) usleep(3000000);
|
||||
}
|
||||
|
||||
void stlink_core_stat(stlink_t *sl) {
|
||||
if (sl->q_len <= 0) return;
|
||||
|
||||
switch (sl->q_buf[0]) {
|
||||
case STLINK_CORE_RUNNING:
|
||||
sl->core_stat = STLINK_CORE_RUNNING;
|
||||
return;
|
||||
case STLINK_CORE_HALTED:
|
||||
sl->core_stat = STLINK_CORE_HALTED;
|
||||
return;
|
||||
default:
|
||||
sl->core_stat = STLINK_CORE_STAT_UNKNOWN;
|
||||
fprintf(stderr, " core status: unknown\n");
|
||||
}
|
||||
}
|
||||
|
||||
void stlink_fwrite_finalize(stlink_t *sl, stm32_addr_t addr) {
|
||||
unsigned int val;
|
||||
/* set stack*/
|
||||
stlink_read_debug32(sl, addr, &val);
|
||||
stlink_write_reg(sl, val, 13);
|
||||
/* Set PC to the reset routine*/
|
||||
stlink_read_debug32(sl, addr + 4, &val);
|
||||
stlink_write_reg(sl, val, 15);
|
||||
stlink_run(sl);
|
||||
}
|
||||
|
||||
typedef bool (*save_block_fn)(void *arg, uint8_t *block, ssize_t len);
|
||||
|
||||
static int stlink_read(stlink_t *sl, stm32_addr_t addr, size_t size,
|
||||
save_block_fn fn, void *fn_arg) {
|
||||
int error = -1;
|
||||
|
||||
if (size < 1) size = sl->flash_size;
|
||||
|
||||
if (size > sl->flash_size) size = sl->flash_size;
|
||||
|
||||
size_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz;
|
||||
for (size_t off = 0; off < size; off += cmp_size) {
|
||||
size_t aligned_size;
|
||||
|
||||
/* adjust last page size */
|
||||
if ((off + cmp_size) > size) cmp_size = size - off;
|
||||
|
||||
aligned_size = cmp_size;
|
||||
if (aligned_size & (4 - 1)) aligned_size = (cmp_size + 4) & ~(4 - 1);
|
||||
|
||||
stlink_read_mem32(sl, addr + (uint32_t) off, aligned_size);
|
||||
|
||||
if (!fn(fn_arg, sl->q_buf, aligned_size)) {
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* success */
|
||||
error = 0;
|
||||
|
||||
on_error:
|
||||
return error;
|
||||
}
|
||||
|
||||
int write_buffer_to_sram(stlink_t *sl, flash_loader_t *fl, const uint8_t *buf,
|
||||
size_t size) {
|
||||
/* write the buffer right after the loader */
|
||||
size_t chunk = size & ~0x3;
|
||||
size_t rem = size & 0x3;
|
||||
if (chunk) {
|
||||
memcpy(sl->q_buf, buf, chunk);
|
||||
stlink_write_mem32(sl, fl->buf_addr, chunk);
|
||||
}
|
||||
if (rem) {
|
||||
memcpy(sl->q_buf, buf + chunk, rem);
|
||||
stlink_write_mem8(sl, (fl->buf_addr) + (uint32_t) chunk, rem);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t calculate_F7_sectornum(uint32_t flashaddr) {
|
||||
flashaddr &= ~STM32_FLASH_BASE; // Page now holding the actual flash address
|
||||
if (flashaddr < 0x20000)
|
||||
return (flashaddr / 0x8000);
|
||||
else if (flashaddr < 0x40000)
|
||||
return (4);
|
||||
else
|
||||
return (flashaddr / 0x40000) + 4;
|
||||
}
|
||||
|
||||
uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr) {
|
||||
if (sl->chip_id == STLINK_CHIPID_STM32_F7) {
|
||||
uint32_t sector = calculate_F7_sectornum(flashaddr);
|
||||
if (sector < 4)
|
||||
sl->flash_pgsz = 0x8000;
|
||||
else if (sector < 5)
|
||||
sl->flash_pgsz = 0x20000;
|
||||
else
|
||||
sl->flash_pgsz = 0x40000;
|
||||
}
|
||||
return (uint32_t) sl->flash_pgsz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase a page of flash, assumes sl is fully populated with things like
|
||||
* chip/core ids
|
||||
* @param sl stlink context
|
||||
* @param flashaddr an address in the flash page to erase
|
||||
* @return 0 on success -ve on failure
|
||||
*/
|
||||
int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) {
|
||||
/* wait for ongoing op to finish */
|
||||
wait_flash_busy(sl);
|
||||
|
||||
/* unlock if locked */
|
||||
unlock_flash_if(sl);
|
||||
|
||||
/* select the page to erase */
|
||||
// calculate the actual page from the address
|
||||
uint32_t sector = calculate_F7_sectornum(flashaddr);
|
||||
|
||||
write_flash_cr_snb(sl, sector);
|
||||
|
||||
/* start erase operation */
|
||||
set_flash_cr_strt(sl);
|
||||
|
||||
/* wait for completion */
|
||||
wait_flash_busy(sl);
|
||||
|
||||
/* relock the flash */
|
||||
// todo: fails to program if this is in
|
||||
lock_flash(sl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify addr..addr+len is binary identical to base...base+len
|
||||
* @param sl stlink context
|
||||
* @param address stm device address
|
||||
* @param data host side buffer to check against
|
||||
* @param length how much
|
||||
* @return 0 for success, -ve for failure
|
||||
*/
|
||||
int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data,
|
||||
unsigned length) {
|
||||
size_t off;
|
||||
size_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz;
|
||||
printf("Verifying flash...\n");
|
||||
for (off = 0; off < length; off += cmp_size) {
|
||||
size_t aligned_size;
|
||||
|
||||
/* adjust last page size */
|
||||
if ((off + cmp_size) > length) cmp_size = length - off;
|
||||
|
||||
aligned_size = cmp_size;
|
||||
if (aligned_size & (4 - 1)) aligned_size = (cmp_size + 4) & ~(4 - 1);
|
||||
|
||||
stlink_read_mem32(sl, address + (uint32_t) off, aligned_size);
|
||||
|
||||
if (memcmp(sl->q_buf, data + off, cmp_size)) {
|
||||
printf("Verification of flash failed at offset: %u\n",
|
||||
(unsigned int) off);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
|
||||
uint32_t len, uint8_t eraseonly) {
|
||||
size_t off;
|
||||
flash_loader_t fl;
|
||||
printf("Writing %d (%#x) bytes to stm32 address: %u (%#x)\n", len, len, addr,
|
||||
addr);
|
||||
/* check addr range is inside the flash */
|
||||
stlink_calculate_pagesize(sl, addr);
|
||||
if (addr < sl->flash_base) {
|
||||
printf("addr too low %#x < %#x\n", addr, sl->flash_base);
|
||||
return -1;
|
||||
} else if ((addr + len) < addr) {
|
||||
printf("addr overruns\n");
|
||||
return -1;
|
||||
} else if ((addr + len) > (sl->flash_base + sl->flash_size)) {
|
||||
printf("addr too high\n");
|
||||
return -1;
|
||||
} else if (addr & 1) {
|
||||
printf("unaligned addr 0x%x\n", addr);
|
||||
return -1;
|
||||
} else if (len & 1) {
|
||||
printf("unaligned len 0x%x -- padding with zero\n", len);
|
||||
len += 1;
|
||||
} else if (addr & (sl->flash_pgsz - 1)) {
|
||||
printf("addr not a multiple of pagesize, not supported\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure we've loaded the context with the chip details
|
||||
stlink_core_id(sl);
|
||||
/* erase each page */
|
||||
int page_count = 0;
|
||||
for (off = 0; off < len;
|
||||
off += stlink_calculate_pagesize(sl, addr + (uint32_t) off)) {
|
||||
fprintf(stdout, "Erasing flash page at addr 0x%08X\n", (int) (addr + off));
|
||||
/* addr must be an addr inside the page */
|
||||
if (stlink_erase_flash_page(sl, addr + (uint32_t) off) == -1) {
|
||||
printf("Failed to erase_flash_page(%#zx) == -1\n", addr + off);
|
||||
return -1;
|
||||
}
|
||||
page_count++;
|
||||
}
|
||||
|
||||
if (eraseonly) return 0;
|
||||
|
||||
/* flash loader initialization */
|
||||
if (stlink_flash_loader_init(sl, &fl) == -1) {
|
||||
printf("stlink_flash_loader_init() == -1\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* First unlock the cr */
|
||||
unlock_flash_if(sl);
|
||||
|
||||
/* TODO: Check that Voltage range is 2.7 - 3.6 V */
|
||||
/* set parallelisim to 32 bit*/
|
||||
int voltage = stlink_target_voltage(sl);
|
||||
if (voltage == -1) {
|
||||
printf("Failed to read Target voltage\n");
|
||||
return voltage;
|
||||
} else if (voltage > 2700) {
|
||||
write_flash_cr_psiz(sl, 2);
|
||||
} else {
|
||||
printf(
|
||||
"Target voltage (%d mV) too low for 32-bit flash, using 8-bit "
|
||||
"flash writes\n",
|
||||
voltage);
|
||||
write_flash_cr_psiz(sl, 0);
|
||||
}
|
||||
|
||||
/* set programming mode */
|
||||
set_flash_cr_pg(sl);
|
||||
|
||||
for (off = 0; off < len;) {
|
||||
size_t size = len - off > 0x8000 ? 0x8000 : len - off;
|
||||
printf("Writing %d bytes at 0x%08X\n", (int) size,
|
||||
(int) (addr + (uint32_t) off));
|
||||
if (stlink_flash_loader_run(sl, &fl, addr + (uint32_t) off, base + off,
|
||||
size) == -1) {
|
||||
printf("stlink_flash_loader_run(%#zx) failed! == -1\n", addr + off);
|
||||
return -1;
|
||||
}
|
||||
off += size;
|
||||
}
|
||||
|
||||
/* Relock flash */
|
||||
lock_flash(sl);
|
||||
|
||||
return stlink_verify_write_flash(sl, addr, base, len);
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/* simple wrapper around the stlink_flash_write function */
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "stlink.h"
|
||||
#include "usb.h"
|
||||
|
||||
#define FLASH_ADDRESS 0x8000000
|
||||
|
||||
int stm32_flash(const char *device_name, void *data, int len) {
|
||||
stlink_t *sl = NULL;
|
||||
int err = -1;
|
||||
uint8_t serial[16];
|
||||
|
||||
int j = (int) strlen(device_name);
|
||||
int length = j / 2; // the length of the destination-array
|
||||
if (j % 2 != 0) return -1;
|
||||
|
||||
for (size_t k = 0; j >= 0 && k < sizeof(serial); ++k, j -= 2) {
|
||||
char buffer[3] = {0};
|
||||
memcpy(buffer, device_name + j, 2);
|
||||
serial[length - k] = (uint8_t) strtol(buffer, NULL, 16);
|
||||
}
|
||||
|
||||
sl = stlink_open_usb(1, (char *) serial);
|
||||
|
||||
if (sl == NULL) return -1;
|
||||
|
||||
if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) {
|
||||
if (stlink_exit_dfu_mode(sl)) {
|
||||
printf("Failed to exit DFU mode\n");
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
|
||||
if (stlink_enter_swd_mode(sl)) {
|
||||
printf("Failed to enter SWD mode\n");
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (stlink_jtag_reset(sl, 2)) {
|
||||
printf("Failed to reset JTAG\n");
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if (stlink_reset(sl)) {
|
||||
printf("Failed to reset device\n");
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
// Core must be halted to use RAM based flashloaders
|
||||
if (stlink_force_debug(sl)) {
|
||||
printf("Failed to halt the core\n");
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if (stlink_status(sl)) {
|
||||
printf("Failed to get Core's status\n");
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
|
||||
if ((FLASH_ADDRESS > sl->flash_base + sl->flash_size)) {
|
||||
printf("Unknown memory region\n");
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
err = stlink_write_flash(sl, FLASH_ADDRESS, (uint8_t *) data, len, 0);
|
||||
stlink_fwrite_finalize(sl, FLASH_ADDRESS);
|
||||
|
||||
if (err == -1) {
|
||||
printf("stlink_fwrite_flash() == -1\n");
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
stlink_jtag_reset(sl, 2);
|
||||
stlink_reset(sl);
|
||||
|
||||
err = 0;
|
||||
|
||||
on_error:
|
||||
stlink_exit_debug_mode(sl);
|
||||
stlink_close(sl);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
#include "stlink.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const uint8_t loader_code_stm32f7[] = {
|
||||
0x08, 0x4b, 0x72, 0xb1, 0x04, 0x68, 0x0c, 0x60,
|
||||
0xbf, 0xf3, 0x4f, 0x8f, // DSB Memory barrier for in order flash write
|
||||
0xdc, 0x89, 0x14, 0xf0, 0x01, 0x0f, 0xfb, 0xd1,
|
||||
0x00, 0xf1, 0x04, 0x00, 0x01, 0xf1, 0x04, 0x01,
|
||||
0xa2, 0xf1, 0x01, 0x02, 0xef, 0xe7, 0x00, 0xbe, // bkpt #0x00
|
||||
0x00, 0x3c, 0x02, 0x40,
|
||||
};
|
||||
|
||||
#define WAIT_ROUNDS 10000
|
||||
|
||||
int stlink_flash_loader_init(stlink_t *sl, flash_loader_t *fl) {
|
||||
size_t size;
|
||||
|
||||
/* allocate the loader in sram */
|
||||
if (stlink_flash_loader_write_to_sram(sl, &fl->loader_addr, &size) == -1) {
|
||||
printf("Failed to write flash loader to sram!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allocate a one page buffer in sram right after loader */
|
||||
fl->buf_addr = fl->loader_addr + (uint32_t) size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t *addr,
|
||||
size_t *size) {
|
||||
memcpy(sl->q_buf, loader_code_stm32f7, sizeof(loader_code_stm32f7));
|
||||
stlink_write_mem32(sl, sl->sram_base, sizeof(loader_code_stm32f7));
|
||||
|
||||
*addr = sl->sram_base;
|
||||
*size = sizeof(loader_code_stm32f7);
|
||||
|
||||
/* success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stlink_flash_loader_run(stlink_t *sl, flash_loader_t *fl,
|
||||
stm32_addr_t target, const uint8_t *buf,
|
||||
size_t size) {
|
||||
struct stlink_reg rr;
|
||||
int i = 0;
|
||||
size_t count = 0;
|
||||
|
||||
// FIXME This can never return -1
|
||||
if (write_buffer_to_sram(sl, fl, buf, size) == -1) {
|
||||
// IMPOSSIBLE!
|
||||
printf("write_buffer_to_sram() == -1\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
count = size / sizeof(uint32_t);
|
||||
if (size % sizeof(uint32_t)) ++count;
|
||||
|
||||
/* setup core */
|
||||
stlink_write_reg(sl, fl->buf_addr, 0); /* source */
|
||||
stlink_write_reg(sl, target, 1); /* target */
|
||||
stlink_write_reg(sl, (uint32_t) count, 2); /* count */
|
||||
stlink_write_reg(
|
||||
sl, 0,
|
||||
3); /* flash bank 0 (input), only used on F0, but armless fopr others */
|
||||
stlink_write_reg(sl, fl->loader_addr, 15); /* pc register */
|
||||
|
||||
/* run loader */
|
||||
stlink_run(sl);
|
||||
|
||||
/* wait until done (reaches breakpoint) */
|
||||
for (i = 0; i < WAIT_ROUNDS; i++) {
|
||||
usleep(10);
|
||||
if (stlink_is_core_halted(sl)) break;
|
||||
}
|
||||
|
||||
if (i >= WAIT_ROUNDS) {
|
||||
printf("flash loader run error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check written byte count */
|
||||
stlink_read_reg(sl, 2, &rr);
|
||||
if (rr.r[2] != 0) {
|
||||
printf("write error, count == %u\n", rr.r[2]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* File: stlink.h
|
||||
*
|
||||
* This should contain all the common top level stlink interfaces, regardless
|
||||
* of how the backend does the work....
|
||||
*/
|
||||
#ifndef STLINK_FLASH_LOADER_H_
|
||||
#define STLINK_FLASH_LOADER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "stlink.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int stlink_flash_loader_init(stlink_t *sl, flash_loader_t *fl);
|
||||
int stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t *addr,
|
||||
size_t *size);
|
||||
int stlink_flash_loader_run(stlink_t *sl, flash_loader_t *fl,
|
||||
stm32_addr_t target, const uint8_t *buf,
|
||||
size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* STLINK_FLASH_LOADER_H_ */
|
||||
@@ -1,38 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package stm32
|
||||
|
||||
// #cgo CFLAGS: -I/usr/include/libusb-1.0/
|
||||
// #cgo LDFLAGS: -lusb-1.0
|
||||
// #include "stm32_flash.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"cesanta.com/common/go/fwbundle"
|
||||
"github.com/cesanta/errors"
|
||||
)
|
||||
|
||||
type FlashOpts struct {
|
||||
ShareName string
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
func Flash(fw *fwbundle.FirmwareBundle, opts *FlashOpts) error {
|
||||
data, err := fw.GetPartData("boot")
|
||||
if err != nil {
|
||||
return errors.Annotatef(err, "invalid manifest")
|
||||
}
|
||||
|
||||
flash_res := C.stm32_flash(C.CString(opts.ShareName),
|
||||
unsafe.Pointer(&data[0]),
|
||||
C.int(len(data)))
|
||||
|
||||
if flash_res != 0 {
|
||||
return errors.Errorf("flash failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
* File: stlink.h
|
||||
*
|
||||
* This should contain all the common top level stlink interfaces, regardless
|
||||
* of how the backend does the work....
|
||||
*/
|
||||
#ifndef STLINK_H
|
||||
#define STLINK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define STLINK_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
// Max data transfer size.
|
||||
// 6kB = max mem32_read block, 8kB sram
|
||||
//#define Q_BUF_LEN 96
|
||||
#define Q_BUF_LEN (1024 * 100)
|
||||
|
||||
// STLINK_DEBUG_RESETSYS, etc:
|
||||
#define STLINK_CORE_RUNNING 0x80
|
||||
#define STLINK_CORE_HALTED 0x81
|
||||
#define STLINK_CORE_STAT_UNKNOWN -1
|
||||
|
||||
#define STLINK_GET_VERSION 0xf1
|
||||
#define STLINK_GET_CURRENT_MODE 0xf5
|
||||
#define STLINK_GET_TARGET_VOLTAGE 0xF7
|
||||
|
||||
#define STLINK_DEBUG_COMMAND 0xF2
|
||||
#define STLINK_DFU_COMMAND 0xF3
|
||||
#define STLINK_DFU_EXIT 0x07
|
||||
|
||||
// STLINK_GET_CURRENT_MODE
|
||||
#define STLINK_DEV_DFU_MODE 0x00
|
||||
#define STLINK_DEV_MASS_MODE 0x01
|
||||
#define STLINK_DEV_DEBUG_MODE 0x02
|
||||
#define STLINK_DEV_UNKNOWN_MODE -1
|
||||
|
||||
// TODO - possible poor names...
|
||||
#define STLINK_SWD_ENTER 0x30
|
||||
#define STLINK_SWD_READCOREID 0x32 // TBD
|
||||
#define STLINK_JTAG_WRITEDEBUG_32BIT 0x35
|
||||
#define STLINK_JTAG_READDEBUG_32BIT 0x36
|
||||
#define STLINK_JTAG_DRIVE_NRST 0x3c
|
||||
|
||||
#define STLINK_DEBUG_APIV2_SWD_SET_FREQ 0x43
|
||||
|
||||
/* cortex core ids */
|
||||
// TODO clean this up...
|
||||
#define STM32VL_CORE_ID 0x1ba01477
|
||||
#define STM32F7_CORE_ID 0x5ba02477
|
||||
|
||||
// Constant STM32 memory map figures
|
||||
#define STM32_FLASH_BASE 0x08000000
|
||||
#define STM32_SRAM_BASE 0x20000000
|
||||
|
||||
// Baud rate divisors for SWDCLK
|
||||
#define STLINK_SWDCLK_4MHZ_DIVISOR 0
|
||||
#define STLINK_SWDCLK_1P8MHZ_DIVISOR 1
|
||||
#define STLINK_SWDCLK_1P2MHZ_DIVISOR 2
|
||||
#define STLINK_SWDCLK_950KHZ_DIVISOR 3
|
||||
#define STLINK_SWDCLK_480KHZ_DIVISOR 7
|
||||
#define STLINK_SWDCLK_240KHZ_DIVISOR 15
|
||||
#define STLINK_SWDCLK_125KHZ_DIVISOR 31
|
||||
#define STLINK_SWDCLK_100KHZ_DIVISOR 40
|
||||
#define STLINK_SWDCLK_50KHZ_DIVISOR 79
|
||||
#define STLINK_SWDCLK_25KHZ_DIVISOR 158
|
||||
#define STLINK_SWDCLK_15KHZ_DIVISOR 265
|
||||
#define STLINK_SWDCLK_5KHZ_DIVISOR 798
|
||||
|
||||
#define STLINK_CHIPID_STM32_F7 0x449
|
||||
|
||||
/* Enough space to hold both a V2 command or a V1 command packaged as generic
|
||||
* scsi*/
|
||||
#define C_BUF_LEN 32
|
||||
|
||||
struct stlink_reg {
|
||||
uint32_t r[16];
|
||||
uint32_t s[32];
|
||||
uint32_t xpsr;
|
||||
uint32_t main_sp;
|
||||
uint32_t process_sp;
|
||||
uint32_t rw;
|
||||
uint32_t rw2;
|
||||
uint8_t control;
|
||||
uint8_t faultmask;
|
||||
uint8_t basepri;
|
||||
uint8_t primask;
|
||||
uint32_t fpscr;
|
||||
};
|
||||
|
||||
typedef uint32_t stm32_addr_t;
|
||||
|
||||
typedef struct flash_loader {
|
||||
stm32_addr_t loader_addr; /* loader sram adddr */
|
||||
stm32_addr_t buf_addr; /* buffer sram address */
|
||||
} flash_loader_t;
|
||||
|
||||
typedef struct stlink_version_ {
|
||||
uint32_t stlink_v;
|
||||
uint32_t jtag_v;
|
||||
uint32_t swim_v;
|
||||
uint32_t st_vid;
|
||||
uint32_t stlink_pid;
|
||||
} stlink_version_t;
|
||||
|
||||
typedef struct _stlink stlink_t;
|
||||
|
||||
struct _stlink {
|
||||
void *backend_data;
|
||||
|
||||
// Room for the command header
|
||||
unsigned char c_buf[C_BUF_LEN];
|
||||
// Data transferred from or to device
|
||||
unsigned char q_buf[Q_BUF_LEN];
|
||||
int q_len;
|
||||
|
||||
// transport layer verboseness: 0 for no debug info, 10 for lots
|
||||
uint32_t core_id;
|
||||
uint32_t chip_id;
|
||||
int core_stat;
|
||||
|
||||
char serial[16];
|
||||
int serial_size;
|
||||
|
||||
stm32_addr_t flash_base;
|
||||
size_t flash_size;
|
||||
size_t flash_pgsz;
|
||||
|
||||
/* sram settings */
|
||||
stm32_addr_t sram_base;
|
||||
size_t sram_size;
|
||||
|
||||
// bootloader
|
||||
stm32_addr_t sys_base;
|
||||
size_t sys_size;
|
||||
|
||||
struct stlink_version_ version;
|
||||
};
|
||||
|
||||
int stlink_enter_swd_mode(stlink_t *sl);
|
||||
int stlink_enter_jtag_mode(stlink_t *sl);
|
||||
int stlink_exit_debug_mode(stlink_t *sl);
|
||||
int stlink_exit_dfu_mode(stlink_t *sl);
|
||||
void stlink_close(stlink_t *sl);
|
||||
int stlink_core_id(stlink_t *sl);
|
||||
int stlink_reset(stlink_t *sl);
|
||||
int stlink_jtag_reset(stlink_t *sl, int value);
|
||||
int stlink_run(stlink_t *sl);
|
||||
int stlink_status(stlink_t *sl);
|
||||
int stlink_version(stlink_t *sl);
|
||||
int stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data);
|
||||
int stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
|
||||
int stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data);
|
||||
int stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
|
||||
int stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len);
|
||||
int stlink_read_all_regs(stlink_t *sl, struct stlink_reg *regp);
|
||||
int stlink_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp);
|
||||
int stlink_write_reg(stlink_t *sl, uint32_t reg, int idx);
|
||||
int stlink_step(stlink_t *sl);
|
||||
int stlink_current_mode(stlink_t *sl);
|
||||
int stlink_force_debug(stlink_t *sl);
|
||||
int stlink_target_voltage(stlink_t *sl);
|
||||
int stlink_set_swdclk(stlink_t *sl, uint16_t divisor);
|
||||
int stlink_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data,
|
||||
uint32_t length, uint8_t eraseonly);
|
||||
int stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr);
|
||||
int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data,
|
||||
uint32_t length);
|
||||
int stlink_chip_id(stlink_t *sl, uint32_t *chip_id);
|
||||
int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr);
|
||||
uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr);
|
||||
uint16_t read_uint16(const unsigned char *c, const int pt);
|
||||
void stlink_core_stat(stlink_t *sl);
|
||||
unsigned int is_bigendian(void);
|
||||
uint32_t read_uint32(const unsigned char *c, const int pt);
|
||||
void write_uint32(unsigned char *buf, uint32_t ui);
|
||||
void write_uint16(unsigned char *buf, uint16_t ui);
|
||||
bool stlink_is_core_halted(stlink_t *sl);
|
||||
int write_buffer_to_sram(stlink_t *sl, flash_loader_t *fl, const uint8_t *buf,
|
||||
size_t size);
|
||||
int write_loader_to_sram(stlink_t *sl, stm32_addr_t *addr, size_t *size);
|
||||
int stlink_load_device_params(stlink_t *sl);
|
||||
void stlink_fwrite_finalize(stlink_t *sl, stm32_addr_t addr);
|
||||
|
||||
#include "usb.h"
|
||||
#include "flash_loader.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* STLINK_H */
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef STM32_FLASH_H_
|
||||
#define STM32_FLASH_H_
|
||||
|
||||
int stm32_flash(const char *device_name, void *data, int len);
|
||||
|
||||
#endif
|
||||
@@ -1,773 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <libusb.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "stlink.h"
|
||||
|
||||
enum SCSI_Generic_Direction { SG_DXFER_TO_DEV = 0, SG_DXFER_FROM_DEV = 0x80 };
|
||||
|
||||
enum stlink_debug_commands {
|
||||
STLINK_DEBUG_ENTER_JTAG = 0x00,
|
||||
STLINK_DEBUG_GETSTATUS = 0x01,
|
||||
STLINK_DEBUG_FORCEDEBUG = 0x02,
|
||||
STLINK_DEBUG_RESETSYS = 0x03,
|
||||
STLINK_DEBUG_READALLREGS = 0x04,
|
||||
STLINK_DEBUG_READREG = 0x05,
|
||||
STLINK_DEBUG_WRITEREG = 0x06,
|
||||
STLINK_DEBUG_READMEM_32BIT = 0x07,
|
||||
STLINK_DEBUG_WRITEMEM_32BIT = 0x08,
|
||||
STLINK_DEBUG_RUNCORE = 0x09,
|
||||
STLINK_DEBUG_STEPCORE = 0x0a,
|
||||
STLINK_DEBUG_SETFP = 0x0b,
|
||||
STLINK_DEBUG_WRITEMEM_8BIT = 0x0d,
|
||||
STLINK_DEBUG_CLEARFP = 0x0e,
|
||||
STLINK_DEBUG_WRITEDEBUGREG = 0x0f,
|
||||
STLINK_DEBUG_ENTER = 0x20,
|
||||
STLINK_DEBUG_EXIT = 0x21,
|
||||
STLINK_DEBUG_READCOREID = 0x22,
|
||||
STLINK_DEBUG_ENTER_SWD = 0xa3
|
||||
};
|
||||
|
||||
void _stlink_usb_close(stlink_t *sl) {
|
||||
if (!sl) return;
|
||||
|
||||
struct stlink_libusb *const handle = sl->backend_data;
|
||||
// maybe we couldn't even get the usb device?
|
||||
if (handle != NULL) {
|
||||
if (handle->usb_handle != NULL) {
|
||||
libusb_close(handle->usb_handle);
|
||||
}
|
||||
|
||||
libusb_exit(handle->libusb_ctx);
|
||||
free(handle);
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t send_recv(struct stlink_libusb *handle, int terminate,
|
||||
unsigned char *txbuf, size_t txsize, unsigned char *rxbuf,
|
||||
size_t rxsize) {
|
||||
/* note: txbuf and rxbuf can point to the same area */
|
||||
int res = 0;
|
||||
int t;
|
||||
|
||||
t = libusb_bulk_transfer(handle->usb_handle, handle->ep_req, txbuf,
|
||||
(int) txsize, &res, 3000);
|
||||
if (t) {
|
||||
printf("[!] send_recv send request failed: %s\n", libusb_error_name(t));
|
||||
return -1;
|
||||
} else if ((size_t) res != txsize) {
|
||||
printf("[!] send_recv send request wrote %u bytes (instead of %u).\n",
|
||||
(unsigned int) res, (unsigned int) txsize);
|
||||
}
|
||||
|
||||
if (rxsize != 0) {
|
||||
t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, rxbuf,
|
||||
(int) rxsize, &res, 3000);
|
||||
if (t) {
|
||||
printf("[!] send_recv read reply failed: %s\n", libusb_error_name(t));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((handle->protocoll == 1) && terminate) {
|
||||
/* Read the SG reply */
|
||||
unsigned char sg_buf[13];
|
||||
t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, sg_buf, 13,
|
||||
&res, 3000);
|
||||
if (t) {
|
||||
printf("[!] send_recv read storage failed: %s\n", libusb_error_name(t));
|
||||
return -1;
|
||||
}
|
||||
/* The STLink doesn't seem to evaluate the sequence number */
|
||||
handle->sg_transfer_idx++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int send_only(struct stlink_libusb *handle, int terminate,
|
||||
unsigned char *txbuf, size_t txsize) {
|
||||
return (int) send_recv(handle, terminate, txbuf, txsize, NULL, 0);
|
||||
}
|
||||
|
||||
static int fill_command(stlink_t *sl, enum SCSI_Generic_Direction dir,
|
||||
uint32_t len) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
int i = 0;
|
||||
memset(cmd, 0, sizeof(sl->c_buf));
|
||||
if (slu->protocoll == 1) {
|
||||
cmd[i++] = 'U';
|
||||
cmd[i++] = 'S';
|
||||
cmd[i++] = 'B';
|
||||
cmd[i++] = 'C';
|
||||
write_uint32(&cmd[i], slu->sg_transfer_idx);
|
||||
write_uint32(&cmd[i + 4], len);
|
||||
i += 8;
|
||||
cmd[i++] = (dir == SG_DXFER_FROM_DEV) ? 0x80 : 0;
|
||||
cmd[i++] = 0; /* Logical unit */
|
||||
cmd[i++] = 0xa; /* Command length */
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int _stlink_usb_version(stlink_t *sl) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
uint32_t rep_len = 6;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_GET_VERSION;
|
||||
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_GET_VERSION\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t _stlink_usb_target_voltage(stlink_t *sl) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const rdata = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
uint32_t rep_len = 8;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
uint32_t factor, reading;
|
||||
int voltage;
|
||||
|
||||
cmd[i++] = STLINK_GET_TARGET_VOLTAGE;
|
||||
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_GET_TARGET_VOLTAGE\n");
|
||||
return -1;
|
||||
} else if (size != 8) {
|
||||
printf("[!] wrong length STLINK_GET_TARGET_VOLTAGE\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
factor =
|
||||
(rdata[3] << 24) | (rdata[2] << 16) | (rdata[1] << 8) | (rdata[0] << 0);
|
||||
reading =
|
||||
(rdata[7] << 24) | (rdata[6] << 16) | (rdata[5] << 8) | (rdata[4] << 0);
|
||||
voltage = 2400 * reading / factor;
|
||||
|
||||
return voltage;
|
||||
}
|
||||
|
||||
int _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const rdata = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
const int rep_len = 8;
|
||||
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_JTAG_READDEBUG_32BIT;
|
||||
write_uint32(&cmd[i], addr);
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_JTAG_READDEBUG_32BIT\n");
|
||||
return (int) size;
|
||||
}
|
||||
*data = read_uint32(rdata, 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const rdata = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
const int rep_len = 2;
|
||||
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_JTAG_WRITEDEBUG_32BIT;
|
||||
write_uint32(&cmd[i], addr);
|
||||
write_uint32(&cmd[i + 4], data);
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_JTAG_WRITEDEBUG_32BIT\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
int i, ret;
|
||||
|
||||
i = fill_command(sl, SG_DXFER_TO_DEV, len);
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_WRITEMEM_32BIT;
|
||||
write_uint32(&cmd[i], addr);
|
||||
write_uint16(&cmd[i + 4], len);
|
||||
ret = send_only(slu, 0, cmd, slu->cmd_len);
|
||||
if (ret == -1) return ret;
|
||||
|
||||
ret = send_only(slu, 1, data, len);
|
||||
if (ret == -1) return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
int i, ret;
|
||||
|
||||
i = fill_command(sl, SG_DXFER_TO_DEV, 0);
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_WRITEMEM_8BIT;
|
||||
write_uint32(&cmd[i], addr);
|
||||
write_uint16(&cmd[i + 4], len);
|
||||
ret = send_only(slu, 0, cmd, slu->cmd_len);
|
||||
if (ret == -1) return ret;
|
||||
|
||||
ret = send_only(slu, 1, data, len);
|
||||
if (ret == -1) return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_current_mode(stlink_t *sl) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
ssize_t size;
|
||||
int rep_len = 2;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_GET_CURRENT_MODE;
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_GET_CURRENT_MODE\n");
|
||||
return -1;
|
||||
}
|
||||
return sl->q_buf[0];
|
||||
}
|
||||
|
||||
int _stlink_usb_core_id(stlink_t *sl) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
ssize_t size;
|
||||
int rep_len = 4;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_READCOREID;
|
||||
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DEBUG_READCOREID\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sl->core_id = read_uint32(data, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_status(stlink_t *sl) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
int rep_len = 2;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_GETSTATUS;
|
||||
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DEBUG_GETSTATUS\n");
|
||||
return (int) size;
|
||||
}
|
||||
sl->q_len = (int) size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_force_debug(stlink_t *sl) {
|
||||
struct stlink_libusb *slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
int rep_len = 2;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_FORCEDEBUG;
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DEBUG_FORCEDEBUG\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_enter_swd_mode(stlink_t *sl) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
const int rep_len = 0;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_ENTER;
|
||||
cmd[i++] = STLINK_DEBUG_ENTER_SWD;
|
||||
|
||||
size = send_only(slu, 1, cmd, slu->cmd_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DEBUG_ENTER\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_exit_dfu_mode(stlink_t *sl) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, 0);
|
||||
|
||||
cmd[i++] = STLINK_DFU_COMMAND;
|
||||
cmd[i++] = STLINK_DFU_EXIT;
|
||||
|
||||
size = send_only(slu, 1, cmd, slu->cmd_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DFU_EXIT\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO - not convinced this does anything...
|
||||
* @param sl
|
||||
*/
|
||||
int _stlink_usb_reset(stlink_t *sl) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
int rep_len = 2;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_RESETSYS;
|
||||
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DEBUG_RESETSYS\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_jtag_reset(stlink_t *sl, int value) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
int rep_len = 2;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_JTAG_DRIVE_NRST;
|
||||
cmd[i++] = value;
|
||||
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_JTAG_DRIVE_NRST\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_step(stlink_t *sl) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
int rep_len = 2;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_STEPCORE;
|
||||
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DEBUG_STEPCORE\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This seems to do a good job of restarting things from the beginning?
|
||||
* @param sl
|
||||
*/
|
||||
int _stlink_usb_run(stlink_t *sl) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
int rep_len = 2;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_RUNCORE;
|
||||
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DEBUG_RUNCORE\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_set_swdclk(stlink_t *sl, uint16_t clk_divisor) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
int rep_len = 2;
|
||||
int i;
|
||||
|
||||
// clock speed only supported by stlink/v2 and for firmware >= 22
|
||||
if (sl->version.stlink_v >= 2 && sl->version.jtag_v >= 22) {
|
||||
i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_APIV2_SWD_SET_FREQ;
|
||||
cmd[i++] = clk_divisor & 0xFF;
|
||||
cmd[i++] = (clk_divisor >> 8) & 0xFF;
|
||||
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DEBUG_APIV2_SWD_SET_FREQ\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int _stlink_usb_exit_debug_mode(stlink_t *sl) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, 0);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_EXIT;
|
||||
|
||||
size = send_only(slu, 1, cmd, slu->cmd_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_only STLINK_DEBUG_EXIT\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_READMEM_32BIT;
|
||||
write_uint32(&cmd[i], addr);
|
||||
write_uint16(&cmd[i + 4], len);
|
||||
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DEBUG_READMEM_32BIT\n");
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
sl->q_len = (int) size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
uint32_t r;
|
||||
uint32_t rep_len = 4;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_READREG;
|
||||
cmd[i++] = (uint8_t) r_idx;
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DEBUG_READREG\n");
|
||||
return (int) size;
|
||||
}
|
||||
sl->q_len = (int) size;
|
||||
r = read_uint32(sl->q_buf, 0);
|
||||
|
||||
switch (r_idx) {
|
||||
case 16:
|
||||
regp->xpsr = r;
|
||||
break;
|
||||
case 17:
|
||||
regp->main_sp = r;
|
||||
break;
|
||||
case 18:
|
||||
regp->process_sp = r;
|
||||
break;
|
||||
case 19:
|
||||
regp->rw = r; /* XXX ?(primask, basemask etc.) */
|
||||
break;
|
||||
case 20:
|
||||
regp->rw2 = r; /* XXX ?(primask, basemask etc.) */
|
||||
break;
|
||||
default:
|
||||
regp->r[r_idx] = r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int idx) {
|
||||
struct stlink_libusb *const slu = sl->backend_data;
|
||||
unsigned char *const data = sl->q_buf;
|
||||
unsigned char *const cmd = sl->c_buf;
|
||||
ssize_t size;
|
||||
uint32_t rep_len = 2;
|
||||
int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
|
||||
|
||||
cmd[i++] = STLINK_DEBUG_COMMAND;
|
||||
cmd[i++] = STLINK_DEBUG_WRITEREG;
|
||||
cmd[i++] = idx;
|
||||
write_uint32(&cmd[i], reg);
|
||||
size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
|
||||
if (size == -1) {
|
||||
printf("[!] send_recv STLINK_DEBUG_WRITEREG\n");
|
||||
return (int) size;
|
||||
}
|
||||
sl->q_len = (int) size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
stlink_t *stlink_open_usb(bool reset, char serial[16]) {
|
||||
stlink_t *sl = NULL;
|
||||
struct stlink_libusb *slu = NULL;
|
||||
int ret = -1;
|
||||
int config;
|
||||
|
||||
sl = calloc(1, sizeof(stlink_t));
|
||||
slu = calloc(1, sizeof(struct stlink_libusb));
|
||||
if (sl == NULL) goto on_malloc_error;
|
||||
if (slu == NULL) goto on_malloc_error;
|
||||
|
||||
sl->backend_data = slu;
|
||||
|
||||
sl->core_stat = STLINK_CORE_STAT_UNKNOWN;
|
||||
if (libusb_init(&(slu->libusb_ctx))) {
|
||||
printf("failed to init libusb context, wrong version of libraries?\n");
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
libusb_device **list;
|
||||
/** @todo We should use ssize_t and use it as a counter if > 0. As per libusb
|
||||
* API: ssize_t libusb_get_device_list (libusb_context *ctx, libusb_device
|
||||
* ***list) */
|
||||
int cnt = (int) libusb_get_device_list(slu->libusb_ctx, &list);
|
||||
struct libusb_device_descriptor desc;
|
||||
int devBus = 0;
|
||||
int devAddr = 0;
|
||||
|
||||
/* @TODO: Reading a environment variable in a usb open function is not very
|
||||
nice, this
|
||||
should be refactored and moved into the CLI tools, and instead of giving
|
||||
USB_BUS:USB_ADDR a real stlink
|
||||
serial string should be passed to this function. Probably people are using
|
||||
this but this is very odd because
|
||||
as programmer can change to multiple busses and it is better to detect them
|
||||
based on serial. */
|
||||
char *device = getenv("STLINK_DEVICE");
|
||||
if (device) {
|
||||
char *c = strchr(device, ':');
|
||||
if (c == NULL) {
|
||||
printf("STLINK_DEVICE must be <USB_BUS>:<USB_ADDR> format\n");
|
||||
goto on_error;
|
||||
}
|
||||
devBus = atoi(device);
|
||||
*c++ = 0;
|
||||
devAddr = atoi(c);
|
||||
printf("bus %03d dev %03d\n", devBus, devAddr);
|
||||
}
|
||||
|
||||
while (cnt--) {
|
||||
libusb_get_device_descriptor(list[cnt], &desc);
|
||||
if (desc.idVendor != STLINK_USB_VID_ST) continue;
|
||||
|
||||
if (devBus && devAddr) {
|
||||
if ((libusb_get_bus_number(list[cnt]) != devBus) ||
|
||||
(libusb_get_device_address(list[cnt]) != devAddr)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((desc.idProduct == STLINK_USB_PID_STLINK_32L) ||
|
||||
(desc.idProduct == STLINK_USB_PID_STLINK_NUCLEO)) {
|
||||
struct libusb_device_handle *handle;
|
||||
|
||||
ret = libusb_open(list[cnt], &handle);
|
||||
if (ret) continue;
|
||||
|
||||
sl->serial_size = libusb_get_string_descriptor_ascii(
|
||||
handle, desc.iSerialNumber, (unsigned char *) sl->serial,
|
||||
sizeof(sl->serial));
|
||||
libusb_close(handle);
|
||||
|
||||
if ((serial == NULL) || (*serial == 0)) break;
|
||||
|
||||
if (sl->serial_size < 0) continue;
|
||||
|
||||
if (memcmp(serial, &sl->serial, sl->serial_size) == 0) break;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (desc.idProduct == STLINK_USB_PID_STLINK) {
|
||||
slu->protocoll = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt < 0) {
|
||||
printf("Couldn't find %s ST-Link/V2 devices\n",
|
||||
(devBus && devAddr) ? "matched" : "any");
|
||||
goto on_error;
|
||||
} else {
|
||||
ret = libusb_open(list[cnt], &slu->usb_handle);
|
||||
if (ret != 0) {
|
||||
printf("Error %d (%s) opening ST-Link/V2 device %03d:%03d\n", ret,
|
||||
strerror(errno), libusb_get_bus_number(list[cnt]),
|
||||
libusb_get_device_address(list[cnt]));
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
|
||||
libusb_free_device_list(list, 1);
|
||||
|
||||
if (libusb_kernel_driver_active(slu->usb_handle, 0) == 1) {
|
||||
ret = libusb_detach_kernel_driver(slu->usb_handle, 0);
|
||||
if (ret < 0) {
|
||||
printf("libusb_detach_kernel_driver(() error %s\n", strerror(-ret));
|
||||
goto on_libusb_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (libusb_get_configuration(slu->usb_handle, &config)) {
|
||||
/* this may fail for a previous configured device */
|
||||
printf("libusb_get_configuration()\n");
|
||||
goto on_libusb_error;
|
||||
}
|
||||
|
||||
if (config != 1) {
|
||||
printf("setting new configuration (%d -> 1)\n", config);
|
||||
if (libusb_set_configuration(slu->usb_handle, 1)) {
|
||||
/* this may fail for a previous configured device */
|
||||
printf("libusb_set_configuration() failed\n");
|
||||
goto on_libusb_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (libusb_claim_interface(slu->usb_handle, 0)) {
|
||||
printf(
|
||||
"Stlink usb device found, but unable to claim (probably already in "
|
||||
"use?)\n");
|
||||
goto on_libusb_error;
|
||||
}
|
||||
|
||||
// TODO - could use the scanning techniq from stm8 code here...
|
||||
slu->ep_rep = 1 /* ep rep */ | LIBUSB_ENDPOINT_IN;
|
||||
if (desc.idProduct == STLINK_USB_PID_STLINK_NUCLEO) {
|
||||
slu->ep_req = 1 /* ep req */ | LIBUSB_ENDPOINT_OUT;
|
||||
} else {
|
||||
slu->ep_req = 2 /* ep req */ | LIBUSB_ENDPOINT_OUT;
|
||||
}
|
||||
|
||||
slu->sg_transfer_idx = 0;
|
||||
// TODO - never used at the moment, always CMD_SIZE
|
||||
slu->cmd_len = (slu->protocoll == 1) ? STLINK_SG_SIZE : STLINK_CMD_SIZE;
|
||||
|
||||
if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) {
|
||||
printf("-- exit_dfu_mode\n");
|
||||
stlink_exit_dfu_mode(sl);
|
||||
}
|
||||
|
||||
if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
|
||||
stlink_enter_swd_mode(sl);
|
||||
}
|
||||
|
||||
sl->version.stlink_v = 2;
|
||||
|
||||
if (reset) {
|
||||
if (sl->version.stlink_v > 1) stlink_jtag_reset(sl, 2);
|
||||
stlink_reset(sl);
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
ret = stlink_load_device_params(sl);
|
||||
|
||||
// Set the stlink clock speed (default is 1800kHz)
|
||||
stlink_set_swdclk(sl, STLINK_SWDCLK_1P8MHZ_DIVISOR);
|
||||
|
||||
on_libusb_error:
|
||||
if (ret == -1) {
|
||||
stlink_close(sl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sl;
|
||||
|
||||
on_error:
|
||||
if (slu->libusb_ctx) libusb_exit(slu->libusb_ctx);
|
||||
|
||||
on_malloc_error:
|
||||
if (sl != NULL) free(sl);
|
||||
if (slu != NULL) free(slu);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* File: stlink/usb.h
|
||||
* Author: karl
|
||||
*
|
||||
* Created on October 1, 2011, 11:29 PM
|
||||
*/
|
||||
|
||||
#ifndef STLINK_USB_H
|
||||
#define STLINK_USB_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "stlink.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define STLINK_USB_VID_ST 0x0483
|
||||
#define STLINK_USB_PID_STLINK 0x3744
|
||||
#define STLINK_USB_PID_STLINK_32L 0x3748
|
||||
#define STLINK_USB_PID_STLINK_NUCLEO 0x374b
|
||||
|
||||
#define STLINK_SG_SIZE 31
|
||||
#define STLINK_CMD_SIZE 16
|
||||
|
||||
struct stlink_libusb {
|
||||
libusb_context *libusb_ctx;
|
||||
libusb_device_handle *usb_handle;
|
||||
unsigned int ep_req;
|
||||
unsigned int ep_rep;
|
||||
int protocoll;
|
||||
unsigned int sg_transfer_idx;
|
||||
unsigned int cmd_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* Open a stlink
|
||||
* @param verbose Verbosity loglevel
|
||||
* @param reset Reset stlink programmer
|
||||
* @param serial Serial number to search for, when NULL the first stlink found
|
||||
* is opened (binary format)
|
||||
* @retval NULL Error while opening the stlink
|
||||
* @retval !NULL Stlink found and ready to use
|
||||
*/
|
||||
stlink_t *stlink_open_usb(bool reset, char serial[16]);
|
||||
|
||||
void _stlink_usb_close(stlink_t *sl);
|
||||
int _stlink_usb_version(stlink_t *sl);
|
||||
int32_t _stlink_usb_target_voltage(stlink_t *sl);
|
||||
int _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data);
|
||||
int _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data);
|
||||
int _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
|
||||
int _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len);
|
||||
int _stlink_usb_current_mode(stlink_t *sl);
|
||||
int _stlink_usb_core_id(stlink_t *sl);
|
||||
int _stlink_usb_status(stlink_t *sl);
|
||||
int _stlink_usb_force_debug(stlink_t *sl);
|
||||
int _stlink_usb_enter_swd_mode(stlink_t *sl);
|
||||
int _stlink_usb_exit_dfu_mode(stlink_t *sl);
|
||||
int _stlink_usb_reset(stlink_t *sl);
|
||||
int _stlink_usb_jtag_reset(stlink_t *sl, int value);
|
||||
int _stlink_usb_step(stlink_t *sl);
|
||||
int _stlink_usb_run(stlink_t *sl);
|
||||
int _stlink_usb_set_swdclk(stlink_t *sl, uint16_t clk_divisor);
|
||||
int _stlink_usb_exit_debug_mode(stlink_t *sl);
|
||||
int _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
|
||||
int _stlink_usb_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp);
|
||||
int _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int idx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* STLINK_USB_H */
|
||||
Reference in new issue
Block a user