├── .gitignore ├── srec.h ├── utils.h ├── try.h ├── INSTALL ├── error.h ├── byte_utils.h ├── stlinkv2.h ├── byte_utils.c ├── espstlink.h ├── stm8.h ├── LICENSE-CHANGE ├── stlink.h ├── pgm.h ├── libespstlink.h ├── ihex.h ├── Makefile ├── espstlink.c ├── README.md ├── ihex.c ├── srec.c ├── libespstlink.c ├── stlink.c ├── COPYING ├── stlinkv2.c ├── main.c └── stm8.c /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | *.o 3 | *.bin 4 | *.ihx 5 | *.hex 6 | *.exe 7 | *.gch 8 | tags 9 | -------------------------------------------------------------------------------- /srec.h: -------------------------------------------------------------------------------- 1 | #ifndef __SREC_H 2 | #define __SREC_H 3 | 4 | int srec_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end); 5 | 6 | void srec_write(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_H 2 | #define __UTILS_H 3 | 4 | #if DEBUG 5 | #define DEBUG_PRINT(...) do{ fprintf( stderr, __VA_ARGS__ ); fflush(stderr); } while( false ) 6 | #else 7 | #define DEBUG_PRINT(...) do{ } while ( false ) 8 | #endif 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /try.h: -------------------------------------------------------------------------------- 1 | #include "error.h" 2 | 3 | #define TRY(times, statement) do { \ 4 | int c = (times); \ 5 | while(c > 0) { \ 6 | usleep(10000); \ 7 | if((statement)) break; \ 8 | c--; \ 9 | } \ 10 | if(!c) { \ 11 | ERROR("Tries exceeded"); \ 12 | } \ 13 | } while(0) 14 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | 1) Ensure the necessary dependencies are installed, in particular pkg-config and libusb: 2 | E.g. on Debian or Ubuntu (as root or via sudo): apt-get install pkg-config libusb-1.0-0-dev 3 | 4 | 2) Build it: 5 | make 6 | 7 | 3) Install it: 8 | (as root or sudo): make install 9 | 10 | -------------------------------------------------------------------------------- /error.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Fixes warning 4 | #undef ERROR 5 | 6 | #define ERROR(s) do { fprintf(stderr, "%s\n", (s)); exit(-1); } while(0) 7 | #define ERROR2(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while(0) 8 | #define PERROR(s) do { perror((s)); exit(-1); } while(0) 9 | #define USAGE_ERROR(s) do { fprintf(stderr, "%s\n", (s)); print_help_and_exit(argv[0]); } while(0) 10 | -------------------------------------------------------------------------------- /byte_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __BYTE_UTILS_H 2 | #define __BYTE_UTILS_H 3 | 4 | #define MP_LITTLE_ENDIAN 0 5 | #define MP_BIG_ENDIAN 1 6 | 7 | #define EH(x) ((unsigned)((x) & 0xff000000) >> 24) 8 | #define EX(x) (((x) & 0xff0000) >> 16) 9 | #define HI(x) (((x) & 0xff00) >> 8) 10 | #define LO(x) ((x) & 0xff) 11 | 12 | void format_int(unsigned char *out, unsigned int in, unsigned char length, unsigned char endianess); 13 | int load_int(unsigned char *buf, unsigned char length, unsigned char endianess); 14 | 15 | #endif 16 | 17 | -------------------------------------------------------------------------------- /stlinkv2.h: -------------------------------------------------------------------------------- 1 | #ifndef __STLINKV2_H 2 | #define __STLINKV2_H 3 | 4 | #include "pgm.h" 5 | 6 | bool stlink2_open(programmer_t *pgm); 7 | void stlink2_close(programmer_t *pgm); 8 | void stlink2_srst(programmer_t *pgm); 9 | int stlink2_swim_read_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length); 10 | int stlink2_swim_write_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /byte_utils.c: -------------------------------------------------------------------------------- 1 | #include "byte_utils.h" 2 | 3 | void format_int(unsigned char *out, unsigned int in, unsigned char length, unsigned char endianess) { 4 | int i, idx; 5 | for(i = 0; i < length; i++) { 6 | idx = endianess == MP_LITTLE_ENDIAN ? i : length - 1 - i; 7 | out[i] = (in & 0xFF << idx*8) >> idx*8; 8 | } 9 | } 10 | 11 | int load_int(unsigned char *buf, unsigned char length, unsigned char endianess) { 12 | int i, idx, result = 0; 13 | for(i = 0; i < length; i++) { 14 | idx = endianess == MP_LITTLE_ENDIAN ? i : length - 1 - i; 15 | result |= (buf[i] << idx*8); 16 | } 17 | return(result); 18 | } 19 | -------------------------------------------------------------------------------- /espstlink.h: -------------------------------------------------------------------------------- 1 | #ifndef __ESPSTLINKV_H 2 | #define __ESPSTLINKV_H 3 | 4 | #include 5 | #include "pgm.h" 6 | 7 | int espstlink_swim_read_range(programmer_t *pgm, const stm8_device_t *device, 8 | unsigned char *buffer, unsigned int start, 9 | unsigned int length); 10 | int espstlink_swim_write_range(programmer_t *pgm, const stm8_device_t *device, 11 | unsigned char *buffer, unsigned int start, 12 | unsigned int length, const memtype_t memtype); 13 | void espstlink_srst(programmer_t *pgm); 14 | bool espstlink_pgm_open(programmer_t *pgm); 15 | void espstlink_pgm_close(programmer_t *pgm); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /stm8.h: -------------------------------------------------------------------------------- 1 | #ifndef __STM8_H 2 | #define __STM8_H 3 | 4 | /* This header file contains the generic information 5 | about supported STM8 devices */ 6 | 7 | typedef struct stm8_regs { 8 | unsigned int CLK_CKDIVR; 9 | unsigned int FLASH_PUKR; 10 | unsigned int FLASH_DUKR; 11 | unsigned int FLASH_IAPSR; 12 | unsigned int FLASH_CR2; 13 | unsigned int FLASH_NCR2; 14 | unsigned int FLASH_DM_CSR2; 15 | } stm8_regs_t; 16 | 17 | 18 | typedef enum { 19 | ROP_UNKNOWN, 20 | ROP_STM8S, // Disable ROP = 0x00 and reset. Option bytes are written noninverted and inverted. 21 | ROP_STM8L, // Disable ROP = 0xaa, read EOP, ROP = 0xaa, read EOP. Option bytes are written noninverted. 22 | } ROP_type_t; 23 | 24 | typedef struct stm8_device { 25 | const char *name; 26 | unsigned int ram_start; 27 | unsigned int ram_size; 28 | unsigned int eeprom_start; 29 | unsigned int eeprom_size; 30 | unsigned int flash_start; 31 | unsigned int flash_size; 32 | unsigned int flash_block_size; 33 | unsigned int option_bytes_size; 34 | ROP_type_t read_out_protection_mode; 35 | stm8_regs_t regs; 36 | } stm8_device_t; 37 | 38 | extern const stm8_device_t stm8_devices[]; 39 | 40 | #endif 41 | 42 | -------------------------------------------------------------------------------- /LICENSE-CHANGE: -------------------------------------------------------------------------------- 1 | stm8link was historically licensed under the GPL, version 2, without the "or later" clause. 2 | But some newer parts were licensed under GPLv3. These licenses are incompatible. Moving to 3 | GPLv2 with the "or later" clause fixed this. 4 | The license change to "GPLv2 or later" has happened. This file now remains for documentation only. 5 | 6 | Authors that have agreed to change from "GPLv2 only" or "GPLv3" to "GPLv2 or later": 7 | 8 | Philipp Klaus Krause 9 | Ryan Pavlik 10 | Hagen Fritsch 11 | Lukasz Kordowski 12 | Janne Virsunen 13 | Aram Verstegen 14 | Valentin Dudouyt 15 | Tim Cameron Ryan 16 | Miklós Márton 17 | Jan Szumiec 18 | Tim 19 | Bill Lash 20 | Erno Szabados 21 | Vladimir Koutny 22 | Mario Cianciolo 23 | Ivan A-R / plumbum 24 | Nguyen Huu Hoa 25 | Stefaan De Smet 26 | janezNov / Žiga Stegu 27 | 28 | Authors that have not agreed: 29 | 30 | (none) 31 | 32 | No reply yet: 33 | 34 | (none) 35 | 36 | Those that need to be contacted (or checked if their contribution does not raise to the standard for being copyrightable): 37 | 38 | (none) 39 | 40 | -------------------------------------------------------------------------------- /stlink.h: -------------------------------------------------------------------------------- 1 | /* stlink/v2 device driver 2 | (c) Valentin Dudouyt, 2012 */ 3 | 4 | #ifndef __STLINK_H 5 | #define __STLINK_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include "pgm.h" 11 | 12 | typedef struct stlink_context_s { 13 | libusb_device_handle *dev_handle; 14 | libusb_context *ctx; 15 | unsigned int debug; 16 | } stlink_context_t; 17 | 18 | typedef enum { 19 | STLK_OK = 0, 20 | STLK_USB_ERROR, 21 | STLK_SWIM_ERROR 22 | } stlink_status_t; 23 | 24 | /* stlinkv1 uses the USB-TO-ATA protocol to communicate (same as your 25 | USB flash drive), with exception that some additional commands are 26 | supported */ 27 | #define USB_CBW_SIGNATURE 0x55534243 28 | #define USB_CBW_SIZE 31 29 | typedef struct _scsi_usb_cbw { 30 | // Command block warper 31 | uint32_t signature; // Always 0x55534243 32 | uint32_t tag; // Arbitrary value 33 | uint32_t transfer_length; 34 | unsigned char flags; 35 | unsigned char LUN; // SCSI drive identificator (always 0 here) 36 | unsigned char cblength; 37 | unsigned char cb[16]; // Raw command 38 | } scsi_usb_cbw; 39 | 40 | #define USB_CSW_SIZE 13 41 | typedef struct _scsi_usb_csw { 42 | // Command status warper 43 | uint32_t signature; // Always 0x55534243 44 | uint32_t tag; // Same as passed with CBW 45 | uint32_t data_residue; // cbw.transfer_length - actual handled 46 | unsigned char status; 47 | } scsi_usb_csw; 48 | 49 | bool stlink_open(programmer_t *pgm); 50 | void stlink_close(programmer_t *pgm); 51 | void stlink_swim_srst(programmer_t *pgm); 52 | int stlink_swim_read_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length); 53 | int stlink_swim_write_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /pgm.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGM_H 2 | #define __PGM_H 3 | 4 | #if defined(WIN32) || defined(__CYGWIN__) 5 | #include 6 | #else 7 | #include 8 | #endif 9 | 10 | #include "stm8.h" 11 | #include "libespstlink.h" 12 | 13 | typedef enum { 14 | UNKNOWN, 15 | RAM, 16 | EEPROM, 17 | FLASH, 18 | OPT, 19 | } memtype_t; 20 | 21 | typedef enum { 22 | NONE = 0, 23 | READ, 24 | WRITE, 25 | VERIFY, 26 | RESET, 27 | UNLOCK 28 | } action_t; 29 | 30 | typedef enum { 31 | STLinkV1, 32 | STLinkV2, 33 | STLinkV21, 34 | STLinkV3, 35 | ESP_STLink 36 | } programmer_type_t; 37 | 38 | typedef struct programmer_s { 39 | /* Info */ 40 | const char *name; 41 | programmer_type_t type; 42 | unsigned int usb_vid; 43 | unsigned int usb_pid; 44 | 45 | /* Methods */ 46 | bool (*open) (struct programmer_s *pgm); 47 | void (*close) (struct programmer_s *pgm); 48 | void (*reset) (struct programmer_s *pgm); 49 | int (*read_range) (struct programmer_s *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length); 50 | int (*write_range) (struct programmer_s *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype); 51 | 52 | /* Private */ 53 | libusb_device_handle *dev_handle; 54 | libusb_context *ctx; 55 | 56 | unsigned int msg_count; // debugging only 57 | unsigned int out_msg_size; // stlink/stlinkv2 58 | 59 | /* Data for espstlink module. */ 60 | espstlink_t * espstlink; 61 | const char *port; 62 | } programmer_t; 63 | 64 | typedef bool (*pgm_open_cb)(programmer_t *); 65 | typedef void (*pgm_close_cb)(programmer_t *); 66 | typedef int (*pgm_read_range_cb)(programmer_t *, unsigned char *, unsigned int, unsigned int); 67 | typedef int (*pgm_write_range_cb)(programmer_t *, unsigned char *, unsigned int, unsigned int); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /libespstlink.h: -------------------------------------------------------------------------------- 1 | /** 2 | * libespstlink provides low level access to the STM8 SWIM protocol using 3 | * the espstlink hardware (https://github.com/rumpeltux/esp-stlink) 4 | */ 5 | #ifndef __LIBESPSTLINKV_H 6 | #define __LIBESPSTLINKV_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | typedef struct _espstlink_t { 13 | int fd; 14 | int version; 15 | } espstlink_t; 16 | 17 | typedef struct _esplink_error_t { 18 | int code; 19 | char *message; 20 | char data[256]; 21 | size_t data_len; 22 | int device_code; 23 | } espstlink_error_t; 24 | 25 | #define ESPSTLINK_ERROR_READ 1 26 | #define ESPSTLINK_ERROR_DATA 2 27 | #define ESPSTLINK_ERROR_COMM 3 28 | #define ESPSTLINK_ERROR_VERSION 4 29 | 30 | #define ESPSTLINK_SWIM_ERROR_READ_BIT_TIMEOUT -1 31 | #define ESPSTLINK_SWIM_ERROR_INVALID_TARGET_ID -2 32 | #define ESPSTLINK_SWIM_ERROR_PARITY -3 33 | #define ESPSTLINK_SWIM_ERROR_NACK -4 34 | #define ESPSTLINK_SWIM_ERROR_SYNC_TIMEOUT_1 -5 35 | #define ESPSTLINK_SWIM_ERROR_SYNC_TIMEOUT_2 -6 36 | 37 | espstlink_error_t *espstlink_get_last_error(); 38 | 39 | espstlink_t *espstlink_open(const char *device); 40 | void espstlink_close(espstlink_t *pgm); 41 | bool espstlink_fetch_version(espstlink_t *pgm); 42 | 43 | bool espstlink_swim_entry(const espstlink_t *pgm); 44 | bool espstlink_swim_srst(const espstlink_t *pgm); 45 | bool espstlink_swim_read(const espstlink_t *pgm, uint8_t *buffer, 46 | unsigned int addr, size_t size); 47 | bool espstlink_swim_write(const espstlink_t *pgm, const uint8_t *buffer, 48 | unsigned int addr, size_t size); 49 | 50 | /** 51 | * Switch the reset pin. 52 | * If `input`, the pin is used as an input pin with a pull-up resistor. 53 | * Otherwise, the pin is used as an output pin as follows: 54 | * value == 0: DEFAULT, sets the pin HIGH 55 | * value == 1: RESET, sets the pin LOW 56 | */ 57 | bool espstlink_reset(const espstlink_t *pgm, bool input, bool enable_reset); 58 | #endif 59 | -------------------------------------------------------------------------------- /ihex.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Intel hex read and write utility functions * 3 | * * 4 | * Copyright (c) Valentin Dudouyt, 2004 2012 - 2014 * 5 | * Copyright (c) Philipp Klaus Krause, 2021 * 6 | * * 7 | * This program is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU General Public License as published by * 9 | * the Free Software Foundation; either version 2 of the License, or * 10 | * (at your option) any later version. * 11 | * * 12 | * This program is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU General Public License * 18 | * along with this program; if not, write to the * 19 | * Free Software Foundation, Inc., * 20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 21 | ***************************************************************************/ 22 | 23 | #ifndef IHEX_H 24 | #define IHEX_H 25 | 26 | // Read Intel hex file. 27 | // Returns number of bytes read on success, -1 otherwise. 28 | int ihex_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end); 29 | 30 | // Write Intel hex file. 31 | // Returns 0 on success, -1 otherwise. 32 | int ihex_write(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end); 33 | 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # stm8flash makefile 2 | # 3 | # Multiplatform support 4 | # - Linux (x86, Raspian) 5 | # - MacOS (Darwin) 6 | # - Windows (e.g. mingw-w64-x86 with libusb1.0) 7 | 8 | 9 | PKG_CONFIG ?= pkg-config 10 | PLATFORM=$(shell uname -s) 11 | DEBUG=0 12 | 13 | # Pass RELEASE=anything to build without debug symbols 14 | ifneq (,$(strip $(RELEASE))) 15 | BASE_CFLAGS := -O1 16 | else 17 | BASE_CFLAGS := -g -O0 -DDEBUG=$(DEBUG) 18 | endif 19 | 20 | # Pass LIBUSB_QUIET=anything to Make to silence debug output from libusb. 21 | ifneq (,$(strip $(LIBUSB_QUIET))) 22 | BASE_CFLAGS += -DSTM8FLASH_LIBUSB_QUIET 23 | endif 24 | 25 | BASE_CFLAGS += --std=gnu99 --pedantic -Wall 26 | 27 | ifeq ($(PLATFORM),Linux) 28 | LIBS = `$(PKG_CONFIG) --libs libusb-1.0` 29 | LIBUSB_CFLAGS = `$(PKG_CONFIG) --cflags libusb-1.0` 30 | else ifeq ($(PLATFORM),Darwin) 31 | LIBS = $(shell $(PKG_CONFIG) --libs libusb-1.0) 32 | LIBUSB_CFLAGS = $(shell $(PKG_CONFIG) --cflags libusb-1.0) 33 | #MacOSSDK=$(shell xcrun --show-sdk-path) 34 | #BASE_CFLAGS += -I$(MacOSSDK)/usr/include/ -I$(MacOSSDK)/usr/include/sys -I$(MacOSSDK)/usr/include/machine 35 | else ifeq ($(PLATFORM),FreeBSD) 36 | LIBS = `$(PKG_CONFIG) --libs libusb-1.0` 37 | LIBUSB_CFLAGS = `$(PKG_CONFIG) --cflags libusb-1.0` 38 | else 39 | # Generic case is Windows 40 | 41 | LIBS = -lusb-1.0 42 | LIBUSB_CFLAGS = 43 | CC ?= GCC 44 | BIN_SUFFIX =.exe 45 | endif 46 | 47 | # Respect user-supplied cflags, if any - just put ours in front. 48 | override CFLAGS := $(BASE_CFLAGS) $(LIBUSB_CFLAGS) $(CFLAGS) 49 | 50 | # Check if install DESTDIR is undefined 51 | ifndef DESTDIR 52 | DESTDIR=/usr/local 53 | endif 54 | 55 | BIN =stm8flash 56 | OBJECTS =stlink.o stlinkv2.o espstlink.o main.o byte_utils.o ihex.o srec.o stm8.o libespstlink.o 57 | 58 | 59 | .PHONY: all clean install 60 | 61 | $(BIN)$(BIN_SUFFIX): $(OBJECTS) 62 | $(CC) $(CFLAGS) $(OBJECTS) $(LIBS) -o $(BIN)$(BIN_SUFFIX) 63 | 64 | all: $(BIN)$(BIN_SUFFIX) 65 | 66 | $(OBJECTS): $(wildcard *.h) 67 | 68 | libespstlink.so: libespstlink.c libespstlink.h 69 | $(CC) -shared $(CFLAGS) -fPIC $< -o $@ 70 | 71 | clean: 72 | -rm -f $(OBJECTS) $(BIN)$(BIN_SUFFIX) 73 | 74 | install: $(BIN)$(BIN_SUFFIX) 75 | mkdir -p $(DESTDIR)/bin/ 76 | cp $(BIN)$(BIN_SUFFIX) $(DESTDIR)/bin/ 77 | 78 | -------------------------------------------------------------------------------- /espstlink.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Hagen Fritsch 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "libespstlink.h" 29 | #include "pgm.h" 30 | #include "try.h" 31 | 32 | #define DM_CSR2 0x7F99 33 | 34 | static int espstlink_read_byte(programmer_t *pgm, unsigned int addr) { 35 | uint8_t byte; 36 | if (!espstlink_swim_read(pgm->espstlink, &byte, addr, 1)) return -1; 37 | return byte; 38 | } 39 | 40 | static bool espstlink_write_byte(programmer_t *pgm, uint8_t byte, 41 | unsigned int addr) { 42 | return espstlink_swim_write(pgm->espstlink, &byte, addr, 1); 43 | } 44 | 45 | static bool espstlink_swim_reconnect(programmer_t *pgm) { 46 | int version = pgm->espstlink->version; 47 | 48 | // Enter reset state, if the programmer firmware supports this. 49 | if (version > 0 && !espstlink_reset(pgm->espstlink, /*input=*/0, 1)) return 0; 50 | 51 | if (!espstlink_swim_entry(pgm->espstlink)) return 0; 52 | 53 | // Put the reset pin back into pullup state. 54 | if (version > 0 && !espstlink_reset(pgm->espstlink, /*input=*/1, 0)) return 0; 55 | 56 | if (!espstlink_swim_srst(pgm->espstlink)) return 0; 57 | usleep(1); 58 | return espstlink_write_byte(pgm, 0xA0, 0x7f80); // Init the SWIM_CSR. 59 | } 60 | 61 | // Set / Unsets the STALL bit in the DM_CSR2 register. Stops / Resumes the CPU. 62 | static bool espstlink_stall(programmer_t *pgm, bool stall) { 63 | // Set the STALL bit in DM_CSR2, to stop any code from executing. 64 | int csr = espstlink_read_byte(pgm, DM_CSR2); 65 | if (csr == -1) return 0; 66 | return espstlink_write_byte(pgm, stall ? csr | 8 : csr & ~8, DM_CSR2); 67 | } 68 | 69 | static bool espstlink_prepare_for_flash(programmer_t *pgm, 70 | const stm8_device_t *device, 71 | const memtype_t memtype) { 72 | if (!espstlink_stall(pgm, true)) return 0; 73 | 74 | // Unlock MASS 75 | if (memtype == FLASH) { 76 | if (!espstlink_write_byte(pgm, 0x56, device->regs.FLASH_PUKR)) return 0; 77 | if (!espstlink_write_byte(pgm, 0xae, device->regs.FLASH_PUKR)) return 0; 78 | } 79 | if (memtype == EEPROM || memtype == OPT) { 80 | if (!espstlink_write_byte(pgm, 0xae, device->regs.FLASH_DUKR)) return 0; 81 | if (!espstlink_write_byte(pgm, 0x56, device->regs.FLASH_DUKR)) return 0; 82 | } 83 | 84 | // Set the PRG bit in FLASH_CR2 and reset it in FLASH_NCR2. 85 | uint8_t mode = 0x01; 86 | uint8_t flash_cr2[] = {mode, ~mode}; 87 | return espstlink_swim_write(pgm->espstlink, flash_cr2, device->regs.FLASH_CR2, 88 | 2); 89 | } 90 | 91 | static void espstlink_wait_until_transfer_completes( 92 | programmer_t *pgm, const stm8_device_t *device) { 93 | // wait until the EOP bit is set. 94 | TRY(8, espstlink_read_byte(pgm, device->regs.FLASH_IAPSR) & 0x4); 95 | } 96 | 97 | int espstlink_swim_read_range(programmer_t *pgm, const stm8_device_t *device, 98 | unsigned char *buffer, unsigned int start, 99 | unsigned int length) { 100 | size_t i = 0; 101 | for (; i < length;) { 102 | int current_size = length - i; 103 | if (current_size > 255) 104 | current_size = 255; 105 | if (!espstlink_swim_read(pgm->espstlink, buffer + i, start + i, 106 | current_size)) 107 | return i; 108 | i += current_size; 109 | } 110 | return i; 111 | } 112 | 113 | int espstlink_swim_write_range(programmer_t *pgm, const stm8_device_t *device, 114 | unsigned char *buffer, unsigned int start, 115 | unsigned int length, const memtype_t memtype) { 116 | espstlink_prepare_for_flash(pgm, device, memtype); 117 | 118 | size_t i = 0; 119 | for (; i < length;) { 120 | // Write one block (128 bytes) at a time. 121 | int current_size = length - i; 122 | if (current_size > 128) 123 | current_size = 128; 124 | if (!espstlink_swim_write(pgm->espstlink, buffer + i, start + i, 125 | current_size)) 126 | return i; 127 | i += current_size; 128 | 129 | espstlink_wait_until_transfer_completes(pgm, device); 130 | // TODO: Check the WR_PG_DIS bit in FLASH_IAPSR to verify if the block you 131 | // attempted to program was not write protected (optional) 132 | } 133 | return i; 134 | } 135 | 136 | void espstlink_srst(programmer_t *pgm) { 137 | espstlink_swim_srst(pgm->espstlink); 138 | espstlink_stall(pgm, false); 139 | } 140 | 141 | bool espstlink_pgm_open(programmer_t *pgm) { 142 | pgm->espstlink = espstlink_open(pgm->port); 143 | return pgm->espstlink != NULL && espstlink_fetch_version(pgm->espstlink) && 144 | espstlink_swim_reconnect(pgm); 145 | } 146 | 147 | void espstlink_pgm_close(programmer_t *pgm) { 148 | espstlink_close(pgm->espstlink); 149 | pgm->espstlink = NULL; 150 | } 151 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | stm8flash 2 | ========= 3 | 4 | This is free and opensource software distributed under the terms of the GNU General Public License, 5 | either version 2 of the License, or (at your option) any later version. 6 | 7 | For years, it was the only program that's able to communicate through the SWIM interface of ST-LINKs under Linux. 8 | 9 | Since 2018, OpenOCD also offers the basic functionality, and also has support for on-target debugging. 10 | As of early 2018, stm8flash has wider device support, and better support for memory read/write operations. 11 | 12 | 13 | Synopsis 14 | -------- 15 | 16 | ``` 17 | stm8flash -c -p [-s flash|eeprom|0x8000] [-r|-w|-v] 18 | ``` 19 | 20 | The supported file types are Intel Hex, Motorola S-Record and Raw Binary. The type is detected by the file extension. 21 | 22 | Flash examples: 23 | ```nohighlight 24 | ./stm8flash -c stlink -p stm8s003f3 -w blinky.bin 25 | ./stm8flash -c stlink -p stm8s003f3 -w blinky.ihx 26 | ./stm8flash -c stlinkv2 -p stm8s003f3 -w blinky.ihx 27 | ./stm8flash -c stlink -p stm8s105c6 -w blinky.bin 28 | ./stm8flash -c stlinkv2 -p stm8l150 -w blinky.bin 29 | ``` 30 | 31 | EEPROM examples: 32 | ```nohighlight 33 | ./stm8flash -c stlinkv2 -p stm8s003f3 -s eeprom -r ee.bin 34 | ./stm8flash -c stlinkv2 -p stm8s003f3 -s eeprom -w ee.bin 35 | ./stm8flash -c stlinkv2 -p stm8s003f3 -s eeprom -v ee.bin 36 | ``` 37 | 38 | Support table 39 | ------------- 40 | 41 | * ST-Link V1: flash/eeprom/opt 42 | * flash2/eeprom2/opt2: ST-LINK/V2, ST-LINK/V2-1 and STLINK-V3 43 | 44 | | MCU | flash | eeprom | opt | flash2 | eeprom2 | opt2 | 45 | |-------------|-------|--------|------|--------|---------|-------| 46 | | stlux385 | ? | ? | ? | ? | ? | ? | 47 | | stlux???a | ? | ? | ? | ok | ok | ? | 48 | | stm8af526? | ? | ? | ? | ? | ? | ? | 49 | | stm8af528? | ? | ? | ? | ok | ? | ? | 50 | | stm8af52a? | ? | ? | ? | ok | ? | ? | 51 | | stm8af6213 | ? | ? | ? | ? | ? | ? | 52 | | stm8af6223 | ? | ? | ? | ? | ? | ? | 53 | | stm8af6223a | ? | ? | ? | ? | ? | ? | 54 | | stm8af6226 | ? | ? | ? | ? | ? | ? | 55 | | stm8af624? | ? | ? | ? | ? | ? | ? | 56 | | stm8af6266 | ? | ? | ? | ? | ? | ? | 57 | | stm8af6268 | ? | ? | ? | ? | ? | ? | 58 | | stm8af6269 | ? | ? | ? | ? | ? | ? | 59 | | stm8af628? | ? | ? | ? | ? | ? | ? | 60 | | stm8af62a? | ? | ? | ? | ? | ? | ? | 61 | | stm8al313? | ? | ? | ? | ? | ? | ? | 62 | | stm8al314? | ? | ? | ? | ? | ? | ? | 63 | | stm8al316? | ? | ? | ? | ? | ? | ? | 64 | | stm8al318? | ? | ? | ? | ? | ? | ? | 65 | | stm8al31e8? | ? | ? | ? | ? | ? | ? | 66 | | stm8al3l4? | ? | ? | ? | ? | ? | ? | 67 | | stm8al3l6? | ? | ? | ? | ok | ok | ok | 68 | | stm8al3l8? | ? | ? | ? | ? | ? | ? | 69 | | stm8al3le8? | ? | ? | ? | ? | ? | ? | 70 | | stm8l001j3 | ? | ? | ? | ? | ? | ? | 71 | | stm8l050j3 | ok | ? | ok | ok | ok | ok | 72 | | stm8l051f3 | ok | ? | ? | ? | ? | ? | 73 | | stm8l052c6 | ok | ? | ? | ok | ? | ? | 74 | | stm8l052r8 | ok | ? | ? | ? | ? | ? | 75 | | stm8l101f1 | ? | no | ? | ? | no | ? | 76 | | stm8l101?2 | ? | no | ? | ? | no | ? | 77 | | stm8l101?3 | ? | no | ? | ok | no | ? | 78 | | stm8l151?2 | ? | ? | ? | ? | ? | ? | 79 | | stm8l151?3 | ? | ? | ? | ? | ? | ? | 80 | | stm8l151?4 | ok | ? | ? | ok | ? | ? | 81 | | stm8l151?6 | ? | ? | ? | ? | ? | ? | 82 | | stm8l151?8 | ok | ? | ? | ok | ? | ? | 83 | | stm8l152?4 | ? | ? | ? | ? | ? | ? | 84 | | stm8l152?6 | ok | FAIL | ? | ok | ok | ? | 85 | | stm8l152?8 | ? | ? | ? | ok | ? | ? | 86 | | stm8l162?8 | ? | ? | ? | ? | ? | ? | 87 | | stm8s001j3 | ? | ? | ? | ok | ok | ? | 88 | | stm8s003?3 | ok | FAIL | ? | ok | ok | ok | 89 | | stm8s005?6 | ok | ? | ok | ok | ok | ok | 90 | | stm8s007c8 | ? | ? | ? | ? | ? | ? | 91 | | stm8s103f2 | ? | ? | ? | ? | ? | ? | 92 | | stm8s103?3 | ok | ? | ? | ok | ? | ok | 93 | | stm8s105?4 | ok | FAIL | ? | ok | ok | ok | 94 | | stm8s105?6 | ok | ? | ? | ok | ? | ? | 95 | | stm8s207c8 | ? | ? | ? | ? | ? | ? | 96 | | stm8s207cb | ? | ? | ? | ? | ? | ? | 97 | | stm8s207k8 | ? | ? | ? | ? | ? | ? | 98 | | stm8s207m8 | ? | ? | ? | ? | ? | ? | 99 | | stm8s207mb | ? | ? | ? | ? | ? | ? | 100 | | stm8s207r8 | ? | ? | ? | ok | ? | ? | 101 | | stm8s207rb | ? | ? | ? | ? | ? | ? | 102 | | stm8s207s8 | ? | ? | ? | ? | ? | ? | 103 | | stm8s207sb | ? | ? | ? | ? | ? | ? | 104 | | stm8s207?6 | ? | ? | ? | ? | ? | ? | 105 | | stm8s208c6 | ? | ? | ? | ok | ? | ? | 106 | | stm8s208r6 | ? | ? | ? | ? | ? | ? | 107 | | stm8s208s6 | ? | ? | ? | ? | ? | ? | 108 | | stm8s208?8 | ? | ? | ? | ? | ? | ? | 109 | | stm8s208?b | ? | ? | ? | ok | ? | ok | 110 | | stm8s903?3 | ? | ? | ? | ok | ok | ok | 111 | | stm8splnb1 | ? | ? | ? | ? | ? | ? | 112 | | stm8tl5??4 | ? | no | ? | ? | no | ? | 113 | | stnrg???a | ? | ? | ? | ok | ok | ? | 114 | 115 | Legend: 116 | 117 | * `ok` - Fully supported. 118 | * `no` - Not supported. 119 | * `?` - Not tested. 120 | * `FAIL` - Not working. Needs fix. 121 | 122 | -------------------------------------------------------------------------------- /ihex.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Intel hex read and write utility functions * 3 | * * 4 | * Copyright (c) Valentin Dudouyt, 2004 2012 - 2014 * 5 | * Copyright (c) Philipp Klaus Krause, 2021 * 6 | * * 7 | * This program is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU General Public License as published by * 9 | * the Free Software Foundation; either version 2 of the License, or * 10 | * (at your option) any later version. * 11 | * * 12 | * This program is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU General Public License * 18 | * along with this program; if not, write to the * 19 | * Free Software Foundation, Inc., * 20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 21 | ***************************************************************************/ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "ihex.h" 27 | 28 | #define HI(x) (((x) & 0xff00) >> 8) 29 | #define LO(x) ((x) & 0xff) 30 | 31 | static unsigned char checksum(unsigned char *buf, unsigned int length, int chunk_len, int chunk_addr, int chunk_type) { 32 | int sum = chunk_len + (LO(chunk_addr)) + (HI(chunk_addr)) + chunk_type; 33 | int i; 34 | for(i = 0; i < length; i++) { 35 | sum += buf[i]; 36 | } 37 | 38 | int complement = (~sum + 1); 39 | return(complement & 0xff); 40 | } 41 | 42 | int ihex_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { 43 | // a record in intel hex looks like 44 | // :LLXXXXTTDDDD....DDCC 45 | // Where LL is the length of the data field and can be as large as 255. So the maximum size of a record is 9 characters for the 46 | // header, 255 * 2 characters for the data, 2 characters for the Checksum, and an additional 2 characters (possibly a Carriage 47 | // Return and linefeed. This is then a total an 9 + 510 + 2 + 2 = 523. 48 | static char line[523]; 49 | 50 | fseek(pFile, 0, SEEK_SET); 51 | 52 | unsigned int chunk_len, chunk_addr, chunk_type, i, byte, line_no = 0, greatest_addr = 0, offset = 0; 53 | 54 | while(fgets(line, sizeof(line), pFile)) { 55 | line_no++; 56 | 57 | // Strip off Carriage Return at end of line if it exists. 58 | if (line[strlen(line)] == '\r') 59 | { 60 | line[strlen(line)] = 0; 61 | } 62 | 63 | // Reading chunk header 64 | if(sscanf(line, ":%02x%04x%02x", &chunk_len, &chunk_addr, &chunk_type) != 3) { 65 | free(buf); 66 | fprintf(stderr, "Error while parsing IHEX at line %d\n", line_no); 67 | return(-1); 68 | } 69 | // Reading chunk data 70 | if(chunk_type == 2) // Extended Segment Address 71 | { 72 | unsigned int esa; 73 | if(sscanf(&line[9],"%04x",&esa) != 1) { 74 | free(buf); 75 | fprintf(stderr, "Error while parsing IHEX at line %d\n", line_no); 76 | return(-1); 77 | } 78 | offset = esa * 16; 79 | } 80 | if(chunk_type == 4) // Extended Linear Address 81 | { 82 | unsigned int ela; 83 | if(sscanf(&line[9],"%04x",&ela) != 1) { 84 | free(buf); 85 | fprintf(stderr, "Error while parsing IHEX at line %d\n", line_no); 86 | return(-1); 87 | } 88 | offset = ela * 65536; 89 | } 90 | 91 | for(i = 9; i < strlen(line) - 1; i +=2) { 92 | if(sscanf(&(line[i]), "%02x", &byte) != 1) { 93 | free(buf); 94 | fprintf(stderr, "Error while parsing IHEX at line %d byte %d\n", line_no, i); 95 | return(-1); 96 | } 97 | if(chunk_type != 0x00) { 98 | // The only data records have to be processed 99 | break; 100 | } 101 | if((i - 9) / 2 >= chunk_len) { 102 | // Respect chunk_len and do not capture checksum as data 103 | break; 104 | } 105 | if((chunk_addr + offset) < start) { 106 | free(buf); 107 | fprintf(stderr, "Address %04x is out of range at line %d\n", chunk_addr, line_no); 108 | return(-1); 109 | } 110 | if(chunk_addr + offset + chunk_len > end) { 111 | free(buf); 112 | fprintf(stderr, "Address %04x + %d is out of range at line %d\n", chunk_addr, chunk_len, line_no); 113 | return(-1); 114 | } 115 | if(chunk_addr + offset + chunk_len > greatest_addr) { 116 | greatest_addr = chunk_addr + offset + chunk_len; 117 | } 118 | buf[chunk_addr + offset - start + (i - 9) / 2] = byte; 119 | } 120 | } 121 | 122 | return(greatest_addr - start); 123 | } 124 | 125 | int ihex_write(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { 126 | unsigned int chunk_len, chunk_start, i; 127 | int cur_ela = 0; 128 | // If any address is above the first 64k, cause an initial ELA record to be written 129 | if (end > 65535) 130 | { 131 | cur_ela = -1; 132 | } 133 | chunk_start = start; 134 | while(chunk_start < end) 135 | { 136 | // Assume the rest of the bytes will be written in this chunk 137 | chunk_len = end - chunk_start; 138 | // Limit the length to 32 bytes per chunk 139 | if (chunk_len > 32) 140 | { 141 | chunk_len = 32; 142 | } 143 | // Check if length would go past the end of the current 64k block 144 | if (((chunk_start & 0xffff) + chunk_len) > 0xffff) 145 | { 146 | // If so, reduce the length to go only to the end of the block 147 | chunk_len = 0x10000 - (chunk_start & 0xffff); 148 | } 149 | 150 | // See if the last ELA record that was written matches the current block 151 | if (cur_ela != (chunk_start >> 16)) 152 | { 153 | // If not, write an ELA record 154 | unsigned char ela_bytes[2]; 155 | cur_ela = chunk_start >> 16; 156 | ela_bytes[0] = HI(cur_ela); 157 | ela_bytes[1] = LO(cur_ela); 158 | if(fprintf(pFile, ":02000004%04X%02X\n",cur_ela,checksum(ela_bytes,2,2,0,4)) < 0) 159 | { 160 | fprintf(stderr, "I/O error during IHEX write\n"); 161 | return(-1); 162 | } 163 | } 164 | // Write the data record 165 | fprintf(pFile, ":%02X%04X00",chunk_len,chunk_start & 0xffff); 166 | for(i = chunk_start - start; i < (chunk_start + chunk_len - start); i++) 167 | if(fprintf(pFile, "%02X",buf[i]) < 0) 168 | { 169 | fprintf(stderr, "I/O error during IHEX write\n"); 170 | return(-1); 171 | } 172 | if(fprintf(pFile, "%02X\n", checksum( &buf[chunk_start - start], chunk_len, chunk_len, chunk_start, 0)) < 0) 173 | { 174 | fprintf(stderr, "I/O error during IHEX write\n"); 175 | return(-1); 176 | } 177 | 178 | 179 | chunk_start += chunk_len; 180 | } 181 | // Add the END record 182 | if(fprintf(pFile,":00000001FF\n") < 0) 183 | { 184 | fprintf(stderr, "I/O error during IHEX write\n"); 185 | return(-1); 186 | } 187 | 188 | return(0); 189 | } 190 | 191 | -------------------------------------------------------------------------------- /srec.c: -------------------------------------------------------------------------------- 1 | /* stlink/v2 stm8 memory programming utility 2 | (c) Valentin Dudouyt, 2012 - 2014 */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "srec.h" 9 | #include "error.h" 10 | #include "byte_utils.h" 11 | 12 | /* 13 | * Checksum for SRECORD. Add all the bytes from the record length field through the data, and take 14 | * the ones complement. This includes the address field, which for SRECORDs can be 2 bytes, 3 bytes or 15 | * 4 bytes. In this case, since the upper bytes of the address will be 0 for records of the smaller sizes, 16 | * just add all 4 bytes of the address in all cases. 17 | * 18 | * The arguments are: 19 | * 20 | * buf a pointer to the beginning of the data for the record 21 | * length the length of the data portion of the record 22 | * chunk_len the length of the record starting at the address and including the checksum 23 | * chunk_addr starting address for the data in the record 24 | * 25 | * Returns an unsigned char with the checksum 26 | */ 27 | static unsigned char srec_csum(unsigned char *buf, unsigned int length, int chunk_len, int chunk_addr) { 28 | int sum = chunk_len + (LO(chunk_addr)) + (HI(chunk_addr)) + (EX(chunk_addr)) + (EH(chunk_addr)); 29 | unsigned int i; 30 | for(i = 0; i < length; i++) { 31 | sum += buf[i]; 32 | } 33 | return ~sum & 0xff; 34 | } 35 | 36 | 37 | static bool is_data_type(unsigned int chunk_type) 38 | { 39 | return (chunk_type == 0x01 || chunk_type == 0x02 || chunk_type == 0x03); 40 | } 41 | 42 | 43 | 44 | int srec_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { 45 | // A SRECORD has one of the following formats 46 | // SXLLAAAADDDD....DDCC 47 | // SXLLAAAAAADDDD....DDCC 48 | // SXLLAAAAAAAADDDD....DDCC 49 | // Where S is the letter 'S', X is a single digit indicating the record type, LL is the length of the 50 | // record from the start of the address field through the checksum (i.e. the length of the rest of the 51 | // record), AAAA[AA[AA]] is the address field and can be 16, 24 or 32 bits depending on the record type, 52 | // DD is the data for the record (and optional for an S0 record, and not present in some other records), 53 | // anc CC is the ones complement chechsum of the bytes starting at LL up to the last DD byte. 54 | // The maximum value for LL is 0xFF, indication a length from the first AA byte through CC byte of 255. 55 | // The maximum total length in characters would then be 4 (for the SXLL characters) plus 255 * 2 plus a 56 | // possible carriage return and line feed. This would then be 4+510+2, or 516 characters. 57 | static char line[516]; 58 | 59 | fseek(pFile, 0, SEEK_SET); 60 | 61 | unsigned int chunk_len, chunk_addr, chunk_type, i, byte, line_no = 0, greatest_addr = 0; 62 | unsigned int number_of_records = 0; 63 | 64 | bool data_record = false; 65 | bool found_S5_rec = false; 66 | unsigned int expected_data_records = 0; 67 | unsigned int data_len = 0; 68 | unsigned char temp = ' '; 69 | unsigned int checksum; 70 | 71 | while(fgets(line, sizeof(line), pFile)) { 72 | data_record = false; 73 | line_no++; 74 | 75 | // Reading chunk header 76 | if(sscanf(line, "S%01x%02x%08x", &chunk_type, &chunk_len, &chunk_addr) != 3) { 77 | sscanf(line, "%c",&temp); 78 | if(temp != 'S') 79 | { 80 | continue; 81 | } 82 | free(buf); 83 | ERROR2("Error while parsing SREC at line %d\n", line_no); 84 | } 85 | 86 | if(chunk_type == 0x00 || chunk_type == 0x04) //Header type record or reserved. Skip! 87 | { 88 | continue; 89 | } 90 | else if(chunk_type == 0x05) 91 | { //This will contain the total expected number of data records. Save for error checking later 92 | found_S5_rec = true; 93 | if (chunk_len != 3) { // Length field must contain a 3 to be a valid S5 record. 94 | ERROR2("Error while parsing S5 Record at line %d\n", line_no); 95 | } 96 | //The expected total number of data records is saved in S503 field. 97 | //Address is only 2 byte long and checksum is also read as part of the address, so we need to strip it. 98 | chunk_type = 1; 99 | chunk_addr = chunk_addr >> 8; 100 | expected_data_records = chunk_addr; 101 | data_len = 0; 102 | } 103 | else if(is_data_type(chunk_type)) 104 | { 105 | data_record = true; 106 | chunk_addr = chunk_addr >> (8*(3-chunk_type)); 107 | data_len = chunk_len - chunk_type - 2; // See https://en.wikipedia.org/wiki/SREC_(file_format)#Record_types 108 | } 109 | else 110 | { 111 | continue; 112 | } 113 | 114 | checksum = chunk_len; 115 | checksum += (chunk_addr >> 0) & 0xFF; 116 | checksum += (chunk_addr >> 8) & 0xFF; 117 | checksum += (chunk_addr >> 16) & 0xFF; 118 | checksum += (chunk_addr >> 24) & 0xFF; 119 | 120 | // Reading chunk data 121 | for(i = 2*(chunk_type+3); i < 2*(chunk_type+3+data_len); i +=2) { 122 | if(sscanf(&(line[i]), "%02x", &byte) != 1) { 123 | free(buf); 124 | ERROR2("Error while parsing SREC at line %d byte %d\n", line_no, i); 125 | } 126 | checksum += byte; 127 | 128 | if(!data_record) { 129 | // The only data records have to be processed 130 | continue; 131 | } 132 | 133 | if(chunk_addr < start) { 134 | free(buf); 135 | ERROR2("Address %08x is out of range at line %d\n", chunk_addr, line_no); 136 | } 137 | if(chunk_addr + data_len > end) { 138 | free(buf); 139 | ERROR2("Address %08x + %d is out of range at line %d\n", chunk_addr, data_len, line_no); 140 | } 141 | if(chunk_addr + data_len > greatest_addr) { 142 | greatest_addr = chunk_addr + data_len; 143 | } 144 | buf[chunk_addr - start + (i - 8) / 2] = byte; 145 | } 146 | if(data_record) { //We found a data record. Remember this. 147 | number_of_records++; 148 | } 149 | 150 | i = 2*(chunk_type+3+data_len); 151 | if(sscanf(&(line[i]), "%02x", &byte) != 1) { 152 | free(buf); 153 | ERROR2("Error while reading checksum at line %d byte %d\n", line_no, i); 154 | } 155 | checksum += byte; 156 | 157 | if ((checksum & 0xFF) != 0xFF) { 158 | ERROR2("Invalid checksum at line %d\n", line_no); 159 | } 160 | } 161 | 162 | //Check to see if the number of data records expected is the same as we actually read. 163 | if(found_S5_rec && number_of_records != expected_data_records) { 164 | ERROR2("Error while comparing S5 record (number of data records: %d) with the number actually read: %d\n", expected_data_records, number_of_records); 165 | } 166 | 167 | return(greatest_addr - start); 168 | 169 | } 170 | 171 | 172 | void srec_write(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { 173 | int data_rectype = 1; // Use S1 records if possible 174 | unsigned int chunk_len, chunk_start, i, addr_width; 175 | unsigned int num_records = 0; 176 | 177 | addr_width = 4; 178 | if(end >= 1<<16) 179 | { 180 | if(end >= 1<<24) 181 | { 182 | data_rectype = 3; // addresses greater than 24 bit, use S3 records 183 | addr_width = 8; 184 | } 185 | else 186 | { 187 | data_rectype = 2; // addresses greater than 16 bits, but not greater than 24 bits, use S2 records 188 | addr_width = 6; 189 | } 190 | } 191 | fprintf(pFile, "S0030000FC\n"); // Start with an S0 record 192 | chunk_start = start; 193 | while(chunk_start < end) { 194 | // Assume the rest of the bytes will be written in this chunk 195 | chunk_len = end - chunk_start; 196 | // Limit the length to 32 bytes per chunk 197 | if (chunk_len > 32) 198 | { 199 | chunk_len = 32; 200 | } 201 | // Write the data record 202 | fprintf(pFile, "S%1X%02X%0*X",data_rectype,chunk_len + addr_width/2 + 1,addr_width,chunk_start); 203 | for(i = chunk_start - start; i < (chunk_start + chunk_len - start); i++) 204 | { 205 | fprintf(pFile, "%02X",buf[i]); 206 | } 207 | fprintf(pFile, "%02X\n", srec_csum( &buf[chunk_start - start], chunk_len, chunk_len + addr_width/2 + 1, chunk_start)); 208 | num_records++; 209 | chunk_start += chunk_len; 210 | } 211 | 212 | // Add S5 record, for count of data records 213 | fprintf(pFile, "S503%04X", num_records & 0xffff); 214 | fprintf(pFile, "%02X\n", srec_csum(buf, 0, 3, num_records & 0xffff)); 215 | // Add End record. S9 terminates S1, S8 terminates S2 and S7 terminates S3 records 216 | fprintf(pFile, "S%1X%02X%0*X",10-data_rectype, addr_width/2 + 1, addr_width, 0); 217 | fprintf(pFile, "%02X\n", srec_csum(buf, 0, addr_width/2 + 1, 0)); 218 | 219 | 220 | } 221 | -------------------------------------------------------------------------------- /libespstlink.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Hagen Fritsch 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "libespstlink.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | static espstlink_error_t error = {0, NULL}; 33 | 34 | espstlink_error_t *espstlink_get_last_error() { return &error; } 35 | 36 | /** Set the error message based on a format string. */ 37 | static void set_error(int code, char *format, ...) { 38 | // Free an old message. 39 | if (error.message != NULL) free(error.message); 40 | 41 | memset(&error, 0, sizeof(error)); 42 | 43 | // Calculate required memory size 44 | va_list arglist; 45 | va_start(arglist, format); 46 | size_t size = vsnprintf(NULL, 0, format, arglist); 47 | va_end(arglist); 48 | 49 | // Store actual message. 50 | error.message = malloc(size); 51 | va_start(arglist, format); 52 | vsnprintf(error.message, size, format, arglist); 53 | va_end(arglist); 54 | 55 | fprintf(stderr, "%s\n", error.message); 56 | } 57 | 58 | espstlink_t *espstlink_open(const char *device) { 59 | struct termios tty; 60 | memset(&tty, 0, sizeof tty); 61 | 62 | int fd = open(device == NULL ? "/dev/ttyUSB0" : device, O_RDWR | O_NOCTTY); 63 | if (fd < 0) { 64 | perror("Couldn't open tty"); 65 | return NULL; 66 | } 67 | 68 | /* Error Handling */ 69 | if (tcgetattr(fd, &tty) != 0) { 70 | perror("Couldn't open tty"); 71 | return NULL; 72 | } 73 | 74 | /* Set Baud Rate */ 75 | cfsetospeed(&tty, (speed_t)B115200); 76 | cfsetispeed(&tty, (speed_t)B115200); 77 | 78 | /* Setting other Port Stuff */ 79 | tty.c_cc[VMIN] = 0; // read does block 80 | tty.c_cc[VTIME] = 1; // 0.1 seconds read timeout 81 | tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines 82 | 83 | /* Make raw */ 84 | cfmakeraw(&tty); 85 | 86 | /* Flush Port, then applies attributes */ 87 | tcflush(fd, TCIFLUSH); 88 | if (tcsetattr(fd, TCSANOW, &tty) != 0) { 89 | perror("Setting tty attributes failed"); 90 | return NULL; 91 | } 92 | espstlink_t *pgm = malloc(sizeof(espstlink_t)); 93 | pgm->fd = fd; 94 | return pgm; 95 | } 96 | 97 | static const char *command_name(uint8_t command) { 98 | switch (command) { 99 | case 0: 100 | return "SOFT_RESET"; 101 | case 1: 102 | return "READ"; 103 | case 2: 104 | return "WRITE"; 105 | case 0xFD: 106 | return "HARD_RESET"; 107 | case 0xFE: 108 | return "SWIM_ENTRY"; 109 | case 0xFF: 110 | return "GET_VERSION"; 111 | default: 112 | return "unknown (invalid)"; 113 | } 114 | } 115 | 116 | static const char *swim_error_name(int code) { 117 | switch (-code) { 118 | case ESPSTLINK_SWIM_ERROR_READ_BIT_TIMEOUT: 119 | return "READ_BIT_TIMEOUT"; 120 | case ESPSTLINK_SWIM_ERROR_INVALID_TARGET_ID: 121 | return "INVALID_TARGET_ID"; 122 | case ESPSTLINK_SWIM_ERROR_PARITY: 123 | return "PARITY"; 124 | case ESPSTLINK_SWIM_ERROR_NACK: 125 | return "NACK"; 126 | case ESPSTLINK_SWIM_ERROR_SYNC_TIMEOUT_1: 127 | return "SYNC_TIMEOUT_1"; 128 | case ESPSTLINK_SWIM_ERROR_SYNC_TIMEOUT_2: 129 | return "SYNC_TIMEOUT_2"; 130 | default: 131 | return "unknown (invalid)"; 132 | } 133 | } 134 | 135 | static bool error_check(int fd, uint8_t command, uint8_t *resp_buf, 136 | size_t size) { 137 | uint8_t buf[4]; 138 | int len = read(fd, buf, 1); 139 | if (len < 1) { 140 | set_error(ESPSTLINK_ERROR_READ, 141 | "Didn't get a response from the device: %s\n", strerror(errno)); 142 | return 0; 143 | } 144 | if (buf[0] != command) { 145 | set_error(ESPSTLINK_ERROR_DATA, "Unexpected data: %02x\n", buf[0]); 146 | error.data[0] = buf[0]; 147 | error.data_len = 1 + read(fd, &error.data[1], sizeof(error.data) - 1); 148 | return 0; 149 | } 150 | len = read(fd, buf + 1, 1); 151 | if (len < 1) { 152 | set_error(ESPSTLINK_ERROR_DATA, 153 | "Device didn't finish command 0x%02x (%s): %s\n", buf[0], 154 | command_name(buf[0]), strerror(errno)); 155 | return 0; 156 | } 157 | if (buf[1] == 0) { 158 | if (resp_buf && size) { 159 | size_t total = 0; 160 | while (total < size) { 161 | len = read(fd, resp_buf + total, size); 162 | if (len < 1) { 163 | set_error( 164 | ESPSTLINK_ERROR_DATA, 165 | "Incomplete response for command 0x%02x (%s): expected %d bytes, " 166 | "but got %d bytes (%s)\n", 167 | buf[0], command_name(buf[0]), size, len, strerror(errno)); 168 | return 0; 169 | } 170 | total += len; 171 | } 172 | } 173 | return 1; 174 | } 175 | if (buf[1] == 0xFF) { 176 | len = read(fd, buf + 2, 2); 177 | if (len < 2) { 178 | set_error(ESPSTLINK_ERROR_DATA, 179 | "Device didn't finish sending error code for command 0x%02x " 180 | "(%s): %s\n", 181 | buf[0], command_name(buf[0]), strerror(errno)); 182 | return 0; 183 | } 184 | int code = buf[2] << 8 | buf[3]; 185 | set_error(ESPSTLINK_ERROR_COMM, 186 | "Command 0x%02x (%s) failed with code: 0x%02x (%s)\n", buf[0], 187 | command_name(buf[0]), code, swim_error_name(code)); 188 | error.device_code = code; 189 | } else { 190 | set_error(ESPSTLINK_ERROR_DATA, 191 | "Unexpected error code for command 0x%02x (%s): 0x%02x\n", buf[0], 192 | command_name(buf[0]), buf[1]); 193 | error.data[0] = buf[0]; 194 | error.data[1] = buf[1]; 195 | error.data_len = 2 + read(fd, &error.data[2], sizeof(error.data) - 2); 196 | } 197 | return 0; 198 | } 199 | 200 | bool espstlink_fetch_version(espstlink_t *pgm) { 201 | uint8_t cmd[] = {0xFF}; 202 | uint8_t resp_buf[2]; 203 | 204 | write(pgm->fd, cmd, 1); 205 | if (!error_check(pgm->fd, cmd[0], resp_buf, 2)) return 0; 206 | 207 | int version = resp_buf[0] << 8 | resp_buf[1]; 208 | if (version > 1) { 209 | set_error(ESPSTLINK_ERROR_VERSION, "Unsupported target version: %d.\n", 210 | version); 211 | error.device_code = version; 212 | return 0; 213 | } 214 | pgm->version = version; 215 | return 1; 216 | } 217 | 218 | bool espstlink_swim_entry(const espstlink_t *pgm) { 219 | uint8_t cmd[] = {0xFE}; 220 | uint8_t resp_buf[2]; 221 | 222 | write(pgm->fd, cmd, 1); 223 | if (!error_check(pgm->fd, cmd[0], resp_buf, 2)) return 0; 224 | 225 | int duration = resp_buf[0] << 8 | resp_buf[1]; 226 | if (duration < 1200 || duration > 1360) { 227 | fprintf(stderr, 228 | "Warning: remote device took %d cycles (%d us) (expected: %d us)\n", 229 | duration, duration / 80, 128 / 8); 230 | } 231 | return 1; 232 | } 233 | 234 | bool espstlink_reset(const espstlink_t *pgm, bool input, bool enable_reset) { 235 | uint8_t cmd[] = {0xFD, input ? 0xFF : enable_reset}; 236 | 237 | write(pgm->fd, cmd, 2); 238 | return error_check(pgm->fd, cmd[0], NULL, 0); 239 | } 240 | 241 | bool espstlink_swim_srst(const espstlink_t *pgm) { 242 | uint8_t cmd[] = {0}; 243 | 244 | write(pgm->fd, cmd, 1); 245 | return error_check(pgm->fd, cmd[0], NULL, 0); 246 | } 247 | 248 | bool espstlink_swim_read(const espstlink_t *pgm, uint8_t *buffer, 249 | unsigned int addr, size_t size) { 250 | uint8_t cmd[] = {1, size, addr >> 16, addr >> 8, addr}; 251 | uint8_t resp_buf[512]; 252 | write(pgm->fd, cmd, 5); 253 | if (!error_check(pgm->fd, cmd[0], resp_buf, cmd[1] + 4)) return 0; 254 | // there's 4 non data bytes in the response: len, 3*address 255 | memcpy(buffer, resp_buf + 4, size); 256 | return 1; 257 | } 258 | 259 | bool espstlink_swim_write(const espstlink_t *pgm, const uint8_t *buffer, 260 | unsigned int addr, size_t size) { 261 | uint8_t cmd[] = {2, size, addr >> 16, addr >> 8, addr}; 262 | write(pgm->fd, cmd, 5); 263 | write(pgm->fd, buffer, cmd[1]); 264 | 265 | uint8_t resp_buf[4]; 266 | return error_check(pgm->fd, cmd[0], resp_buf, 4); 267 | } 268 | 269 | void espstlink_close(espstlink_t *pgm) { 270 | close(pgm->fd); 271 | free(pgm); 272 | } 273 | -------------------------------------------------------------------------------- /stlink.c: -------------------------------------------------------------------------------- 1 | /* stlink common and stlink-v1 specific functions 2 | (c) Valentin Dudouyt, 2012-2013 */ 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __linux__ 8 | #include 9 | #endif 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "stm8.h" 17 | #include "pgm.h" 18 | #include "stlink.h" 19 | #include "utils.h" 20 | 21 | #define STLK_FLAG_ERR 0x01 22 | #define STLK_FLAG_BUFFER_FULL 0x04 23 | #define STLK_READ_BUFFER_SIZE 6144 24 | #define STLK_MAX_WRITE 512 25 | 26 | unsigned int stlink_swim_get_status(programmer_t *pgm); 27 | int stlink_swim_read_byte(programmer_t *pgm, unsigned char byte, unsigned int start); 28 | int stlink_swim_write_byte(programmer_t *pgm, unsigned char byte, unsigned int start); 29 | 30 | void stlink_send_message(programmer_t *pgm, int count, ...) { 31 | va_list ap; 32 | unsigned char data[32]; 33 | int i, r, actual; 34 | 35 | va_start(ap, count); 36 | assert(pgm->out_msg_size < sizeof(data)); 37 | assert(count <= pgm->out_msg_size); 38 | memset(data, 0, pgm->out_msg_size); 39 | for(i = 0; i < count; i++) 40 | data[i] = va_arg(ap, int); 41 | r = libusb_bulk_transfer(pgm->dev_handle, (2 | LIBUSB_ENDPOINT_OUT), data, pgm->out_msg_size, &actual, 0); 42 | assert(r == 0); 43 | pgm->msg_count++; 44 | return; 45 | } 46 | 47 | int stlink_read(programmer_t *pgm, unsigned char *buffer, int count) { 48 | int r, recv; 49 | r = libusb_bulk_transfer(pgm->dev_handle, (1 | LIBUSB_ENDPOINT_IN), buffer, count, &recv, 0); 50 | assert(r==0); 51 | return(recv); 52 | } 53 | 54 | int stlink_read1(programmer_t *pgm, int count) { 55 | unsigned char buf[16]; 56 | return(stlink_read(pgm, buf, count)); 57 | } 58 | 59 | int stlink_read_and_cmp(programmer_t *pgm, int count, ...) { 60 | va_list ap; 61 | unsigned char buf[16]; 62 | stlink_read(pgm, buf, count); 63 | int i, ret = 0; 64 | va_start(ap, count); 65 | for(i = 0; i < count; i++) { 66 | if(buf[i] != va_arg(ap, int)) 67 | ret++; 68 | } 69 | return(ret); 70 | } 71 | 72 | unsigned char *pack_int16(uint16_t word, unsigned char *out) { 73 | // Filling with bytes in big-endian order 74 | out[0] = (word & 0xff00) >> 8; 75 | out[1] = (word & 0x00ff); 76 | return(out+2); 77 | } 78 | 79 | uint16_t unpack_int16_le(unsigned char *block) { 80 | uint32_t ret; 81 | ret = *(block + 1) << 8; 82 | ret += *(block + 0); 83 | return(ret); 84 | } 85 | 86 | uint16_t unpack_int16(unsigned char *block) { 87 | uint32_t ret; 88 | ret = *(block + 0) << 8; 89 | ret += *(block + 1); 90 | return(ret); 91 | } 92 | 93 | unsigned char *pack_int32(uint32_t word, unsigned char *out) { 94 | out[0] = (word & 0xff000000) >> 24; 95 | out[1] = (word & 0x00ff0000) >> 16; 96 | out[2] = (word & 0x0000ff00) >> 8; 97 | out[3] = (word & 0x000000ff); 98 | return(out+4); 99 | } 100 | 101 | unsigned char *pack_int32_le(uint32_t word, unsigned char *out) { 102 | // Filling with bytes in little-endian order 103 | out[0] = (word & 0x000000ff); 104 | out[1] = (word & 0x0000ff00) >> 8; 105 | out[2] = (word & 0x00ff0000) >> 16; 106 | out[3] = (word & 0xff000000) >> 24; 107 | return(out+4); 108 | } 109 | 110 | uint32_t unpack_int32(unsigned char *block) { 111 | uint32_t ret; 112 | ret = *(block + 0) << 24; 113 | ret += *(block + 1) << 16; 114 | ret += *(block + 2) << 8; 115 | ret += *(block + 3); 116 | return(ret); 117 | } 118 | 119 | uint32_t unpack_int32_le(unsigned char *block) { 120 | uint32_t ret; 121 | ret = *(block + 3) << 24; 122 | ret += *(block + 2) << 16; 123 | ret += *(block + 1) << 8; 124 | ret += *(block + 0); 125 | return(ret); 126 | } 127 | 128 | void pack_usb_cbw(scsi_usb_cbw *cbw, unsigned char *out) { 129 | unsigned char *offset = out; 130 | offset = pack_int32(cbw->signature, offset); 131 | offset = pack_int32(cbw->tag, offset); 132 | offset = pack_int32_le(cbw->transfer_length, offset); 133 | offset[0] = cbw->flags; 134 | offset[1] = cbw->LUN; 135 | offset[2] = cbw->cblength; 136 | offset += 3; 137 | memcpy(offset, cbw->cb, sizeof(cbw->cb)); 138 | offset += sizeof(cbw->cb); 139 | assert(offset - out == USB_CBW_SIZE); 140 | } 141 | 142 | void unpack_usb_csw(unsigned char *block, scsi_usb_csw *out) { 143 | out->signature = unpack_int32(block); 144 | out->tag = unpack_int32(block + 4); 145 | out->data_residue = unpack_int32_le(block + 8); 146 | out->status = block[12]; 147 | } 148 | 149 | int stlink_send_cbw(libusb_device_handle *dev_handle, scsi_usb_cbw *cbw) { 150 | unsigned char buf[USB_CBW_SIZE]; 151 | cbw->signature = USB_CBW_SIGNATURE; 152 | cbw->tag = 0x707ec281; 153 | pack_usb_cbw(cbw, buf); 154 | int actual; 155 | int r = libusb_bulk_transfer(dev_handle, 156 | (2 | LIBUSB_ENDPOINT_OUT), 157 | buf, 158 | USB_CBW_SIZE, 159 | &actual, 160 | 0); 161 | assert(actual == USB_CBW_SIZE); 162 | return(r); 163 | } 164 | 165 | int stlink_read_csw(libusb_device_handle *dev_handle, scsi_usb_csw *csw) { 166 | unsigned char buf[USB_CSW_SIZE]; 167 | int recv; 168 | int r = libusb_bulk_transfer(dev_handle, 169 | (1 | LIBUSB_ENDPOINT_IN), 170 | buf, 171 | USB_CSW_SIZE, 172 | &recv, 173 | 0); 174 | assert(recv == USB_CSW_SIZE); 175 | unpack_usb_csw(buf, csw); 176 | return(r); 177 | } 178 | 179 | scsi_usb_cbw cbw; 180 | scsi_usb_csw csw; 181 | 182 | int stlink_test_unit_ready(programmer_t *pgm) { 183 | // This is a default SCSI command 184 | memset(&cbw, 0, sizeof(scsi_usb_cbw)); 185 | cbw.cblength = 0x06; 186 | int r; 187 | r = stlink_send_cbw(pgm->dev_handle, &cbw); 188 | assert(r == 0); 189 | r = stlink_read_csw(pgm->dev_handle, &csw); 190 | assert(r == 0); 191 | return(csw.status == 0); 192 | } 193 | 194 | int stlink_cmd(programmer_t *pgm, int transfer_length, unsigned char *transfer_out, unsigned char flags, 195 | int cblength, ...) { 196 | va_list ap; 197 | memset(&cbw, 0, sizeof(scsi_usb_cbw)); 198 | cbw.transfer_length = transfer_length; 199 | cbw.flags = flags; 200 | cbw.cblength = cblength; 201 | va_start(ap, cblength); 202 | int i; 203 | for(i = 0; i < cblength; i++) { 204 | cbw.cb[i] = va_arg(ap, int); 205 | } 206 | assert( stlink_send_cbw(pgm->dev_handle, &cbw) == 0); 207 | if(transfer_length) { 208 | // Transfer expected, read some raw data 209 | if(transfer_out) 210 | stlink_read(pgm, transfer_out, transfer_length); 211 | else 212 | stlink_read1(pgm, transfer_length); 213 | } 214 | // Reading status 215 | stlink_read_csw(pgm->dev_handle, &csw); 216 | return(csw.status == 0); 217 | } 218 | 219 | int stlink_cmd_swim_read(programmer_t *pgm, uint16_t length, uint16_t start) { 220 | memset(&cbw, 0, sizeof(scsi_usb_cbw)); 221 | cbw.transfer_length = length; 222 | cbw.flags = 0x80; 223 | cbw.cblength = 0x0a; 224 | cbw.cb[0] = 0xf4; 225 | cbw.cb[1] = 0x0c; 226 | pack_int16(length, cbw.cb+2); 227 | pack_int16(start, cbw.cb+6); 228 | return 0; 229 | } 230 | 231 | void stlink_init_session(programmer_t *pgm) { 232 | int i; 233 | char f4_cmd_arg1[] = { 0x07, 234 | 0x07, 235 | 0x08, 236 | 0x07, 237 | 0x04, 238 | }; 239 | for(i = 0; i < sizeof(f4_cmd_arg1); i++) { 240 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 241 | 0xf4, f4_cmd_arg1[i], 242 | 0x01, 0x00, 243 | 0x00, 0x00, 244 | 0x00, 0x00, 245 | 0x00, 0x00); 246 | stlink_swim_get_status(pgm); 247 | } 248 | do { 249 | usleep(10000); 250 | } while ((stlink_swim_get_status(pgm) & 1) != 0); 251 | stlink_cmd(pgm, 0, NULL, 0x00, 0x03, 252 | 0xf4, 0x03, 253 | 0x00, 0x00, 254 | 0x00, 0x00, 255 | 0x00, 0x00, 256 | 0x00, 0x00); 257 | stlink_swim_get_status(pgm); 258 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 259 | 0xf4, 0x05, 260 | 0x00, 0x00, 261 | 0x00, 0x00, 262 | 0x00, 0x00, 263 | 0x00, 0x00); 264 | stlink_swim_get_status(pgm); 265 | 266 | stlink_swim_write_byte(pgm, 0xa0, 0x7f80); // mov 0x0a, SWIM_CSR2 ;; Init SWIM 267 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 268 | 0xf4, 0x08, 269 | 0x00, 0x01, 270 | 0x00, 0x00, 271 | 0x7f, 0x80, 272 | 0xa0, 0x00); 273 | stlink_swim_get_status(pgm); 274 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 275 | 0xf4, 0x06, 276 | 0x00, 0x01, 277 | 0x00, 0x00, 278 | 0x7f, 0x99, 279 | 0xa0, 0x00); 280 | stlink_swim_get_status(pgm); 281 | stlink_swim_write_byte(pgm, 0xb0, 0x7f80); 282 | stlink_cmd(pgm, 0, NULL, 0x00, 0x03, // Elsewise, only zeroes will be received 283 | 0xf4, 0x03, 284 | 0x01); 285 | stlink_swim_get_status(pgm); 286 | stlink_swim_write_byte(pgm, 0xb4, 0x7f80); 287 | } 288 | 289 | void stlink_finish_session(programmer_t *pgm) { 290 | stlink_swim_write_byte(pgm, 0xb6, 0x7f80); 291 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 292 | 0xf4, 0x05, 293 | 0x00, 0x01, 294 | 0x00, 0x00, 295 | 0x7f, 0x80, 296 | 0xb6, 0x00); 297 | stlink_swim_get_status(pgm); 298 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 299 | 0xf4, 0x07, 300 | 0x00, 0x01, 301 | 0x00, 0x00, 302 | 0x7f, 0x80, 303 | 0xb6, 0x00); 304 | stlink_swim_get_status(pgm); 305 | stlink_cmd(pgm, 0, NULL, 0x00, 0x03, 306 | 0xf4, 0x03, 307 | 0x01); 308 | stlink_swim_get_status(pgm); 309 | } 310 | 311 | unsigned int stlink_swim_get_status(programmer_t *pgm) { 312 | unsigned char buf[4]; 313 | stlink_cmd(pgm, 4, buf, 0x80, 0x0a, 314 | 0xf4, 0x09, 315 | 0x01, 0x00, 316 | 0x00, 0x00, 317 | 0x00, 0x00, 318 | 0x00, 0x00); 319 | return(unpack_int32_le(buf)); 320 | } 321 | 322 | bool stlink_open(programmer_t *pgm) { 323 | unsigned char buf[18]; 324 | pgm->out_msg_size = 31; 325 | stlink_test_unit_ready(pgm); 326 | stlink_cmd(pgm, 0x06, buf, 0x80, 6, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x00); 327 | stlink_test_unit_ready(pgm); 328 | stlink_cmd(pgm, 0x12, buf, 0x80, 6, 0x12, 0x80, 0x00, 0x00, 0x20); 329 | stlink_test_unit_ready(pgm); 330 | stlink_cmd(pgm, 2, buf, 0x80, 2, 0xf5, 0x00); // Reading status 331 | stlink_test_unit_ready(pgm); 332 | int status = unpack_int16_le(buf); 333 | switch(status) { 334 | case 0x0000: // Ok 335 | stlink_cmd(pgm, 0, NULL, 0x80, 2, 0xf3, 0x07); // Start initializing sequence 336 | stlink_cmd(pgm, 0, NULL, 0x00, 2, 0xf4, 0x00); // Turn the lights on 337 | stlink_cmd(pgm, 2, buf, 0x80, 2, 0xf4, 0x0d); 338 | stlink_cmd(pgm, 8, buf, 0x80, 3, 0xf4, 0x02, 0x01); // End init 339 | case 0x0003: // Already initialized 340 | return(true); 341 | case 0x0001: // Busy 342 | break; 343 | default: 344 | fprintf(stderr, "Unknown status: %x\n", status); 345 | } 346 | return(false); 347 | } 348 | 349 | void stlink_close(programmer_t *pgm) { 350 | } 351 | 352 | void stlink_swim_srst(programmer_t *pgm) { 353 | // Ready bytes count (always 1 here) 354 | stlink_cmd(pgm, 0, NULL, 0x80, 0x0a, 355 | 0xf4, 0x08, 356 | 0x00, 0x01, 357 | 0x00, 0x00, 358 | 0x00, 0x00, 359 | 0x00, 0x00); 360 | stlink_swim_get_status(pgm); 361 | } 362 | 363 | int stlink_swim_write_byte(programmer_t *pgm, unsigned char byte, unsigned int start) { 364 | unsigned char buf[4], start2[2]; 365 | int result, tries = 0; 366 | pack_int16(start, start2); 367 | DEBUG_PRINT("stlink_swim_write_byte\n"); 368 | do { 369 | stlink_cmd(pgm, 0, NULL, 0x00, 0x10, 370 | 0xf4, 0x0a, 371 | 0x00, 0x01, 372 | 0x00, 0x00, 373 | start2[0], start2[1], 374 | byte, 0x00, 375 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 376 | usleep(2000); 377 | // Ready bytes count (always 1 here) 378 | stlink_cmd(pgm, 4, buf, 0x80, 0x0a, 379 | 0xf4, 0x09, 380 | 0x00, 0x01, 381 | 0x00, 0x00, 382 | start2[0], start2[1], 383 | byte, 0x00); 384 | result = unpack_int16_le(buf); 385 | tries++; 386 | if(result & STLK_FLAG_BUFFER_FULL) { 387 | usleep(4000); // Chill out 388 | DEBUG_PRINT("retry\n"); 389 | continue; 390 | } 391 | if(result & STLK_FLAG_ERR) 392 | break; 393 | } while(result & STLK_FLAG_ERR && tries < 5); 394 | return(result); 395 | } 396 | 397 | int stlink_swim_read_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length) { 398 | DEBUG_PRINT("stlink_swim_read_range\n"); 399 | stlink_init_session(pgm); 400 | stlink_swim_write_byte(pgm, 0x00, device->regs.CLK_CKDIVR); // mov 0x00, CLK_DIVR 401 | int i; 402 | for(i = 0; i < length; i += STLK_READ_BUFFER_SIZE) { 403 | unsigned char block_start2[2], block_size2[2]; 404 | int block_start = start + i; 405 | // Determining block size 406 | int block_size = length - i; 407 | if(block_size > STLK_READ_BUFFER_SIZE) 408 | block_size = STLK_READ_BUFFER_SIZE; 409 | DEBUG_PRINT("Reading %d bytes from %x\n", block_size, block_start); 410 | // Starting SWIM transfer 411 | pack_int16(block_start, block_start2); 412 | pack_int16(block_size, block_size2); 413 | stlink_cmd(pgm, 0, NULL, 0x80, 0x0a, 414 | 0xf4, 0x0b, 415 | block_size2[0], block_size2[1], 416 | 0x00, 0x00, 417 | block_start2[0], block_start2[1], 418 | 0x00, 0x00); 419 | // Waiting until the data becomes ready 420 | int result; 421 | do { 422 | usleep(2000); 423 | result = stlink_swim_get_status(pgm); 424 | } while(result & 1); 425 | // Downloading bytes from stlink 426 | stlink_cmd(pgm, block_size, &(buffer[i]), 0x80, 0x0a, 427 | 0xf4, 0x0c, 428 | block_size2[0], block_size2[1], 429 | 0x00, 0x00, 430 | block_start2[0], block_start2[1], 431 | 0x00, 0x00); 432 | } 433 | stlink_finish_session(pgm); 434 | return(length); 435 | } 436 | 437 | int stlink_swim_wait(programmer_t *pgm) { 438 | int result; 439 | do { 440 | usleep(3000); 441 | result = stlink_swim_get_status(pgm); 442 | } while(result & 1); 443 | return(result); 444 | } 445 | 446 | int stlink_swim_write_block(programmer_t *pgm, unsigned char *buffer, 447 | unsigned int start, 448 | unsigned int length, 449 | unsigned int padding 450 | ) { 451 | int length1 = 8 - padding; // Amount to be transferred with CBW 452 | int length2 = length - 8 + padding; // Amount to be transferred with additional transfer 453 | if (length2 < 0) length2 = 0; 454 | unsigned char block_size2[2], block_start2[2]; 455 | pack_int16(start, block_start2); 456 | pack_int16(length, block_size2); 457 | // Some logical checks 458 | assert(padding >= 0 && padding <= 1); 459 | assert(length1 + length2 == length); 460 | assert(length1 + padding <= 8); 461 | assert(length2 < STLK_MAX_WRITE - 6); 462 | assert(length1 > 0); 463 | assert(length2 > 0); 464 | // Filling CBW 465 | memset(&cbw, 0, sizeof(scsi_usb_cbw)); 466 | cbw.transfer_length = length2 + padding; 467 | cbw.flags = 0x00; 468 | cbw.cblength = 0x10; 469 | cbw.cb[0] = 0xf4; 470 | cbw.cb[1] = 0x0a; 471 | memcpy(cbw.cb+2, block_size2, 2); 472 | memcpy(cbw.cb+6, block_start2, 2); 473 | memcpy(cbw.cb+8+padding, buffer, length1); 474 | if(padding) cbw.cb[8] = '\0'; 475 | assert( stlink_send_cbw(pgm->dev_handle, &cbw) == 0); 476 | usleep(3000); 477 | if(length2) { 478 | // Sending the rest 479 | unsigned char tail[STLK_MAX_WRITE-6]; 480 | memcpy(tail, buffer + length1, length2); 481 | if(padding) tail[length2] = '\1'; 482 | int actual; 483 | int r = libusb_bulk_transfer(pgm->dev_handle, 484 | (2 | LIBUSB_ENDPOINT_OUT), 485 | tail, 486 | length2 + padding, 487 | &actual, 488 | 0); 489 | assert(r == 0); 490 | assert(actual == length2 + padding); 491 | } 492 | // Reading status 493 | stlink_read_csw(pgm->dev_handle, &csw); 494 | assert(csw.status == 0); 495 | memset(cbw.cb+8, 0, 8); 496 | cbw.cb[8] = 0x01; 497 | cbw.cb[9] = 0x02; 498 | int result = stlink_swim_wait(pgm); 499 | return(result); 500 | } 501 | 502 | int stlink_swim_write_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype) { 503 | int i; 504 | stlink_init_session(pgm); 505 | stlink_swim_write_byte(pgm, 0x00, device->regs.CLK_CKDIVR); 506 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 507 | stlink_swim_write_byte(pgm, 0x00, device->regs.FLASH_IAPSR); 508 | } 509 | if(memtype == FLASH) { 510 | stlink_swim_write_byte(pgm, 0x56, device->regs.FLASH_PUKR); 511 | stlink_swim_write_byte(pgm, 0xae, device->regs.FLASH_PUKR); 512 | } 513 | if(memtype == EEPROM || memtype == OPT) { 514 | stlink_swim_write_byte(pgm, 0xae, device->regs.FLASH_DUKR); 515 | stlink_swim_write_byte(pgm, 0x56, device->regs.FLASH_DUKR); 516 | } 517 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 518 | stlink_swim_write_byte(pgm, 0x56, device->regs.FLASH_IAPSR); 519 | } 520 | int flash_block_size = device->flash_block_size; 521 | for(i = 0; i < length; i+=flash_block_size) { 522 | unsigned char block[128]; 523 | memset(block, 0, sizeof(block)); 524 | int block_size = length - i; 525 | if(block_size > flash_block_size) 526 | block_size = flash_block_size; 527 | DEBUG_PRINT("Writing block %04x with size %d\n", start+i, block_size); 528 | memcpy(block, buffer+i, block_size); 529 | if(block_size < flash_block_size) { 530 | DEBUG_PRINT("Padding block %04x with %d zeroes\n", 531 | start+i, 532 | flash_block_size - block_size); 533 | block_size = flash_block_size; 534 | } 535 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 536 | stlink_swim_write_byte(pgm, 0x01, device->regs.FLASH_CR2); 537 | if(device->regs.FLASH_NCR2 != 0) { // Device have FLASH_NCR2 register 538 | stlink_swim_write_byte(pgm, 0xFE, device->regs.FLASH_NCR2); 539 | } 540 | } 541 | int result = stlink_swim_write_block(pgm, block, start + i, block_size, 0); 542 | if(result & STLK_FLAG_ERR) 543 | fprintf(stderr, "Write error\n"); 544 | } 545 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 546 | stlink_swim_write_byte(pgm, 0x56, device->regs.FLASH_IAPSR); 547 | } 548 | stlink_finish_session(pgm); 549 | return(length); 550 | } 551 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /stlinkv2.c: -------------------------------------------------------------------------------- 1 | /* stlink-v2 specific functions 2 | (c) Valentin Dudouyt, 2012-2013 */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "stlinkv2.h" 11 | #include "error.h" 12 | #include "try.h" 13 | #include "byte_utils.h" 14 | #include "stlinkv2.h" 15 | #include "utils.h" 16 | 17 | 18 | /* Use high speed SWIM mode. 19 | * This changes the ratio used in bit signalling from 2:20 to 2:8. Since it neither 20 | * changes the clock rate nor changes the smallest interval between edges there 21 | * seems little reason not to always use it. 22 | */ 23 | #define USE_HIGH_SPEED 1 24 | 25 | /* Only write differences to the target. 26 | * If set to 1 then a write operation first reads the relevant memory from the 27 | * target then only writes back those blocks that contain actual changes thus 28 | * sparing flash from unnecessary erase-and-rewrite cycles. 29 | */ 30 | #define ONLY_WRITE_DIFFS 1 31 | 32 | 33 | #define MAX_SWIM_ERRORS 8 34 | 35 | #define STLINK_SWIM_OK 0x00 36 | #define STLINK_SWIM_BUSY 0x01 37 | #define STLINK_SWIM_NO_RESPONSE 0x04 // Target did not respond. SWIM not active? 38 | #define STLINK_SWIM_BAD_STATE 0x05 // ?? 39 | 40 | #define STLINK_MODE_DFU 0x00 41 | #define STLINK_MODE_MASS 0x01 42 | #define STLINK_MODE_DEBUG 0x02 43 | #define STLINK_MODE_SWIM 0x03 44 | #define STLINK_MODE_BOOTLOADER 0x04 45 | 46 | #define STLINK_GET_VERSION 0xf1 47 | #define STLINK_DEBUG 0xf2 48 | #define STLINK_DFU 0xf3 49 | #define STLINK_SWIM 0xf4 50 | #define STLINK_GET_CURRENT_MODE 0xf5 51 | #define STLINK_GET_VDD 0xf7 52 | 53 | #define DEBUG_EXIT 0x21 54 | #define DFU_EXIT 0x07 55 | 56 | #define SWIM_ENTER 0x00 57 | #define SWIM_EXIT 0x01 58 | #define SWIM_READ_CAP 0x02 59 | #define SWIM_SPEED 0x03 60 | #define SWIM_ENTER_SEQ 0x04 61 | #define SWIM_GEN_RST 0x05 62 | #define SWIM_RESET 0x06 63 | #define SWIM_ASSERT_RESET 0x07 64 | #define SWIM_DEASSERT_RESET 0x08 65 | #define SWIM_READSTATUS 0x09 66 | #define SWIM_WRITEMEM 0x0a 67 | #define SWIM_READMEM 0x0b 68 | #define SWIM_READBUF 0x0c 69 | #define SWIM_READBUFSIZE 0x0d 70 | 71 | #if DEBUG 72 | #undef nSTR 73 | #define nSTR(name) [name] = #name + 6 74 | static const char * const debug_cmd_map[] = { 75 | nSTR(DEBUG_EXIT), 76 | }; 77 | 78 | #undef nSTR 79 | #define nSTR(name) [name] = #name + 4 80 | static const char * const dfu_cmd_map[] = { 81 | nSTR(DFU_EXIT), 82 | }; 83 | 84 | #undef nSTR 85 | #define nSTR(name) [name] = #name + 5 86 | static const char * const swim_cmd_map[] = { 87 | nSTR(SWIM_ENTER), 88 | nSTR(SWIM_EXIT), 89 | nSTR(SWIM_READ_CAP), 90 | nSTR(SWIM_SPEED), 91 | nSTR(SWIM_ENTER_SEQ), 92 | nSTR(SWIM_GEN_RST), 93 | nSTR(SWIM_RESET), 94 | nSTR(SWIM_ASSERT_RESET), 95 | nSTR(SWIM_DEASSERT_RESET), 96 | nSTR(SWIM_READSTATUS), 97 | nSTR(SWIM_WRITEMEM), 98 | nSTR(SWIM_READMEM), 99 | nSTR(SWIM_READBUF), 100 | nSTR(SWIM_READBUFSIZE), 101 | }; 102 | 103 | #undef nSTR 104 | #define nSTR(name) [name - STLINK_GET_VERSION] = #name + 7 105 | static const char * const stlink_cmd_map[] = { 106 | nSTR(STLINK_GET_VERSION), 107 | nSTR(STLINK_DEBUG), 108 | nSTR(STLINK_DFU), 109 | nSTR(STLINK_SWIM), 110 | nSTR(STLINK_GET_CURRENT_MODE), 111 | nSTR(STLINK_GET_VDD), 112 | }; 113 | 114 | static const char * const cmd_to_str(unsigned int cmd) { 115 | static char buf[3]; 116 | 117 | cmd -= STLINK_GET_VERSION; 118 | if (cmd < sizeof(stlink_cmd_map)/sizeof(stlink_cmd_map[0]) && stlink_cmd_map[cmd]) 119 | return stlink_cmd_map[cmd]; 120 | 121 | sprintf(buf, "%02x", cmd + STLINK_GET_VERSION); 122 | return buf; 123 | } 124 | 125 | 126 | static const struct { 127 | const char * const * cmd_to_str; 128 | size_t size; 129 | } stlink_subcmd_map[] = { 130 | [STLINK_GET_VERSION - STLINK_GET_VERSION] = { NULL, 0 }, 131 | [STLINK_DEBUG - STLINK_GET_VERSION] = { debug_cmd_map, sizeof(debug_cmd_map) / sizeof(debug_cmd_map[0]) }, 132 | [STLINK_DFU - STLINK_GET_VERSION] = { dfu_cmd_map, sizeof(dfu_cmd_map) / sizeof(dfu_cmd_map[0]) }, 133 | [STLINK_SWIM - STLINK_GET_VERSION] = { swim_cmd_map, sizeof(swim_cmd_map) / sizeof(swim_cmd_map[0]) }, 134 | [STLINK_GET_CURRENT_MODE - STLINK_GET_VERSION] = { NULL, 0 }, 135 | [STLINK_GET_VDD - STLINK_GET_VERSION] = { NULL, 0 }, 136 | }; 137 | 138 | static const char * const subcmd_to_str(unsigned int cmd, unsigned int subcmd) { 139 | static char buf[3]; 140 | 141 | cmd -= STLINK_GET_VERSION; 142 | if (cmd < sizeof(stlink_subcmd_map)/sizeof(stlink_subcmd_map[0]) && subcmd < stlink_subcmd_map[cmd].size) 143 | return stlink_subcmd_map[cmd].cmd_to_str[subcmd]; 144 | 145 | sprintf(buf, "%02x", subcmd); 146 | return buf; 147 | } 148 | #endif 149 | 150 | unsigned char *pack_int16(uint16_t word, unsigned char *out); 151 | 152 | unsigned int read_buf_size = 6144; 153 | 154 | static void swim_write_byte(programmer_t *pgm, unsigned char byte, unsigned int start); 155 | static int swim_read_byte(programmer_t *pgm, unsigned int addr); 156 | 157 | static unsigned int msg_transfer(programmer_t *pgm, unsigned char *buf, unsigned int length, int direction) { 158 | int bytes_transferred = 0; 159 | int ep = (direction == LIBUSB_ENDPOINT_OUT) ? 2 : 1; 160 | if (pgm->type == STLinkV21 || pgm->type == STLinkV3) 161 | ep = 1; 162 | libusb_bulk_transfer(pgm->dev_handle, ep | direction, buf, length, &bytes_transferred, 0); 163 | if(bytes_transferred != length) ERROR2("IO error: expected %d bytes but %d bytes transferred\n", length, bytes_transferred); 164 | return bytes_transferred; 165 | } 166 | 167 | static void msg_send(programmer_t *pgm, unsigned char *buf, unsigned int length) { 168 | while (length > 0) { 169 | int n = msg_transfer(pgm, buf, length, LIBUSB_ENDPOINT_OUT); 170 | 171 | length -= n; 172 | buf += n; 173 | 174 | if (length > 0) { 175 | DEBUG_PRINT(" short write - %d bytes still to go\n", length); 176 | usleep(1000000); 177 | } 178 | } 179 | } 180 | 181 | static void msg_recv(programmer_t *pgm, unsigned char *buf, unsigned int length) { 182 | int n; 183 | 184 | while (length > 0) { 185 | n = msg_transfer(pgm, buf, length, LIBUSB_ENDPOINT_IN); 186 | length -= n; 187 | buf += n; 188 | 189 | if (length > 0) { 190 | DEBUG_PRINT(" short read - %d bytes more needed\n", length); 191 | usleep(1000000); 192 | } 193 | } 194 | } 195 | 196 | static unsigned int msg_recv_int(programmer_t *pgm, unsigned int length) { 197 | unsigned char buf[4] = { 0x00, 0x01, 0x02, 0x03 }; 198 | msg_recv(pgm, buf, length); 199 | unsigned int ret = load_int(buf, length, MP_LITTLE_ENDIAN); 200 | DEBUG_PRINT(" -> 0x%x\n", ret); 201 | return ret; 202 | } 203 | 204 | static unsigned int msg_recv_int8(programmer_t *pgm) { return msg_recv_int(pgm, 1); } 205 | static unsigned int msg_recv_int16(programmer_t *pgm) { return msg_recv_int(pgm, 2); } 206 | 207 | static void stlink2_cmd_internal(programmer_t *pgm, unsigned char *buf, unsigned int buf_len, unsigned int length, va_list ap) { 208 | unsigned char cmd_buf[16]; 209 | int i, j; 210 | 211 | // Preparing 212 | memset(cmd_buf, 0, sizeof(cmd_buf)); 213 | for(i = 0; i < length; i++) { 214 | int arg = va_arg(ap, int); 215 | cmd_buf[i] = arg; 216 | } 217 | 218 | while (buf_len > 0 && i < sizeof(cmd_buf)) { 219 | cmd_buf[i++] = *(buf++); 220 | buf_len--; 221 | } 222 | 223 | DEBUG_PRINT(" %s", cmd_to_str(cmd_buf[0])); 224 | if (i > 1) 225 | DEBUG_PRINT(" %s", subcmd_to_str(cmd_buf[0], cmd_buf[1])); 226 | for (j = 2; j < i; j++) 227 | DEBUG_PRINT(" %02x", cmd_buf[j]); 228 | if (buf_len > 0) 229 | DEBUG_PRINT(" + %d more bytes", buf_len); 230 | DEBUG_PRINT("\n"); 231 | 232 | // Triggering USB transfer 233 | msg_send(pgm, cmd_buf, sizeof(cmd_buf)); 234 | if (buf_len) 235 | msg_send(pgm, buf, buf_len); 236 | } 237 | 238 | static void stlink2_cmd(programmer_t *pgm, unsigned int length, ...) { 239 | va_list ap; 240 | 241 | va_start(ap, length); 242 | stlink2_cmd_internal(pgm, NULL, 0, length, ap); 243 | va_end(ap); 244 | } 245 | 246 | static void swim_cmd_internal(programmer_t *pgm, unsigned char *buf, unsigned int buf_len, unsigned int length, va_list ap) { 247 | int stalls = 0; 248 | unsigned char status[2][4]; 249 | int set = 0; 250 | 251 | stlink2_cmd_internal(pgm, buf, buf_len, length, ap); 252 | 253 | while (stalls < 4) { 254 | 255 | stlink2_cmd(pgm,2,STLINK_SWIM,SWIM_READSTATUS); 256 | msg_recv(pgm, status[set], 4); 257 | DEBUG_PRINT(" status %02x %02x %02x %02x\n", status[set][0], status[set][1], status[set][2], status[set][3]); 258 | 259 | if (status[set][0] == STLINK_SWIM_OK) { 260 | // We're done! 261 | return; 262 | } 263 | 264 | // Still waiting... 265 | if (memcmp(status[0], status[1], 4)) 266 | stalls = 0; 267 | else 268 | stalls++; 269 | 270 | set ^= 1; 271 | usleep(10000); 272 | //usleep(100); 273 | } 274 | ERROR2("SWIM error 0x%02x\n", status[set][0]); 275 | } 276 | 277 | static void swim_cmd(programmer_t *pgm, unsigned int length, ...) { 278 | va_list ap; 279 | 280 | va_start(ap, length); 281 | swim_cmd_internal(pgm, NULL, 0, length, ap); 282 | va_end(ap); 283 | } 284 | 285 | static void swim_cmd_with_data(programmer_t *pgm, unsigned char *buf, unsigned int buf_len, unsigned int length, ...) { 286 | va_list ap; 287 | 288 | va_start(ap, length); 289 | swim_cmd_internal(pgm, buf, buf_len, length, ap); 290 | va_end(ap); 291 | } 292 | 293 | #if USE_HIGH_SPEED 294 | // Switch to high speed SWIM format (UM0470: 3.3) 295 | static void stlink2_high_speed(programmer_t *pgm) { 296 | unsigned char csr; 297 | 298 | // Wait for HSIT to be set in SWIM_CSR 299 | // avoid hanging when HSIT doesn't become 1 300 | unsigned char retries = 10; 301 | while (!((csr = swim_read_byte(pgm, 0x7f80)) & 0x02) && (retries-- != 0)) 302 | usleep(500); 303 | 304 | // Do a SWIM_RESET to resync clocking 305 | swim_cmd(pgm, 2, STLINK_SWIM, SWIM_RESET); 306 | 307 | if (csr & 0x02) { 308 | // Set HS in SWIM_CSR 309 | swim_write_byte(pgm, csr | 0x10, 0x7f80); 310 | 311 | // Finally, tell the stlinkv2 to use high speed format. 312 | swim_cmd(pgm, 3, STLINK_SWIM, SWIM_SPEED, 1); 313 | DEBUG_PRINT("continuing in high speed swim\n"); 314 | } 315 | else { 316 | DEBUG_PRINT("continuing in low speed swim\n"); 317 | } 318 | } 319 | #endif 320 | 321 | bool stlink2_open(programmer_t *pgm) { 322 | unsigned char buf[8]; 323 | unsigned int v; 324 | 325 | stlink2_cmd(pgm, 1, STLINK_GET_VERSION); 326 | msg_recv(pgm, buf, 6); 327 | v = (buf[0] << 8) | buf[1]; 328 | fprintf(stderr, "STLink: v%d, JTAG: v%d, SWIM: v%d, VID: %02x%02x, PID: %02x%02x\n", 329 | (v >> 12) & 0x3f, (v >> 6) & 0x3f, v & 0x3f, buf[2], buf[3], buf[4], buf[5]); 330 | 331 | #if 0 332 | // This does not appear to work on all ST-Link V2 clones even if the JTAG 333 | // version is high enough? 334 | if (((v >> 6) & 0x3f) >= 13) { 335 | stlink2_cmd(pgm, 1, STLINK_GET_VDD); 336 | msg_recv(pgm, buf, 8); 337 | if ((v = load_int(buf, 4, MP_LITTLE_ENDIAN))) 338 | fprintf(stderr, "Target voltage: %.2fV\n", 2.0 * (load_int(buf+4, 4, MP_LITTLE_ENDIAN) * (1.2 / v))); 339 | } 340 | #endif 341 | 342 | stlink2_cmd(pgm, 1, STLINK_GET_CURRENT_MODE); 343 | msg_recv(pgm, buf, 2); 344 | DEBUG_PRINT(" -> %02x %02x\n", buf[0], buf[1]); 345 | 346 | switch (buf[0]) { 347 | case STLINK_MODE_DEBUG: 348 | stlink2_cmd(pgm, 2, STLINK_DEBUG, DEBUG_EXIT); 349 | break; 350 | 351 | case STLINK_MODE_BOOTLOADER: 352 | case STLINK_MODE_DFU: 353 | case STLINK_MODE_MASS: 354 | stlink2_cmd(pgm, 2, STLINK_DFU, DFU_EXIT); 355 | break; 356 | 357 | default: 358 | break; 359 | } 360 | 361 | if (buf[0] != STLINK_MODE_SWIM) 362 | stlink2_cmd(pgm, 2, STLINK_SWIM, SWIM_ENTER); 363 | 364 | stlink2_cmd(pgm, 2, STLINK_SWIM, SWIM_READBUFSIZE); 365 | read_buf_size = msg_recv_int16(pgm); 366 | 367 | stlink2_cmd(pgm, 3, STLINK_SWIM, SWIM_READ_CAP, 0x01); 368 | msg_recv(pgm, buf, 8); 369 | DEBUG_PRINT(" -> %02x %02x %02x %02x %02x %02x %02x %02x\n", 370 | buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); 371 | 372 | swim_cmd(pgm, 2, STLINK_SWIM, SWIM_ASSERT_RESET); 373 | 374 | swim_cmd(pgm, 2, STLINK_SWIM, SWIM_ENTER_SEQ); 375 | 376 | // Mask internal interrupt sources, enable access to whole of memory, 377 | // prioritize SWIM and stall the CPU. 378 | swim_write_byte(pgm, 0xa1, 0x7f80); 379 | 380 | swim_cmd(pgm, 2, STLINK_SWIM, SWIM_DEASSERT_RESET); 381 | usleep(1000); 382 | 383 | #if USE_HIGH_SPEED 384 | stlink2_high_speed(pgm); 385 | #endif 386 | 387 | return(true); 388 | } 389 | 390 | void stlink2_srst(programmer_t *pgm) { 391 | swim_write_byte(pgm, swim_read_byte(pgm, 0x7f80) | 0x4, 0x7f80); // set SWIM_CSR.RST 392 | // alt : remove stall bit after reset (like libespstlink) 393 | swim_cmd(pgm, 2, STLINK_SWIM, SWIM_GEN_RST); 394 | usleep(1000); 395 | } 396 | 397 | void stlink2_close(programmer_t *pgm) { 398 | stlink2_cmd(pgm, 2, STLINK_SWIM, SWIM_EXIT); 399 | } 400 | 401 | static void swim_write_byte(programmer_t *pgm, unsigned char byte, unsigned int start) { 402 | swim_cmd(pgm, 9, STLINK_SWIM, SWIM_WRITEMEM, 403 | 0x00, 0x01, 404 | 0x00, EX(start), 405 | HI(start), LO(start), 406 | byte); 407 | } 408 | 409 | #if 0 410 | static void stlink2_write_word(programmer_t *pgm, unsigned int word, unsigned int start) { 411 | swim_cmd(pgm, 10, STLINK_SWIM, SWIM_WRITEMEM, 412 | 0x00, 0x02, 413 | 0x00, EX(start), 414 | HI(start), LO(start), 415 | HI(word), LO(word)); 416 | } 417 | #endif 418 | 419 | static int swim_read_byte(programmer_t *pgm, unsigned int addr) { 420 | swim_cmd(pgm, 8, STLINK_SWIM, SWIM_READMEM, 421 | 0x00, 0x01, 422 | 0x00, EX(addr), 423 | HI(addr), LO(addr)); 424 | 425 | stlink2_cmd(pgm, 2, STLINK_SWIM, SWIM_READBUF); 426 | return(msg_recv_int8(pgm)); 427 | } 428 | 429 | int stlink2_swim_read_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length) { 430 | DEBUG_PRINT("read range\n"); 431 | 432 | unsigned int remaining = length; 433 | 434 | while (remaining > 0) { 435 | unsigned int size = (remaining > read_buf_size ? read_buf_size : remaining); 436 | 437 | DEBUG_PRINT("read 0x%04x to 0x%04x\n", start, start + size); 438 | 439 | swim_cmd(pgm, 8, STLINK_SWIM, SWIM_READMEM, 440 | HI(size), LO(size), 441 | 0x00, EX(start), HI(start), LO(start)); 442 | 443 | stlink2_cmd(pgm, 2, STLINK_SWIM, SWIM_READBUF); 444 | msg_recv(pgm, buffer, size); 445 | 446 | buffer += size; 447 | start += size; 448 | remaining -= size; 449 | } 450 | 451 | return length; 452 | } 453 | 454 | int stlink2_swim_write_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype) { 455 | unsigned int iapsr; 456 | 457 | DEBUG_PRINT("write range: setup\n"); 458 | 459 | swim_write_byte(pgm, 0x00, device->regs.CLK_CKDIVR); 460 | 461 | // Unlock MASS 462 | if (memtype == FLASH) { 463 | DEBUG_PRINT("write range: unlock FLASH\n"); 464 | swim_write_byte(pgm, 0x56, device->regs.FLASH_PUKR); 465 | swim_write_byte(pgm, 0xae, device->regs.FLASH_PUKR); 466 | } else if (memtype == EEPROM || memtype == OPT) { 467 | DEBUG_PRINT("write range: unlock EEPROM\n"); 468 | swim_write_byte(pgm, 0xae, device->regs.FLASH_DUKR); 469 | swim_write_byte(pgm, 0x56, device->regs.FLASH_DUKR); 470 | } 471 | 472 | if (memtype == OPT) { 473 | // Option programming mode 474 | swim_write_byte(pgm, 0x80, device->regs.FLASH_CR2); 475 | if (device->regs.FLASH_NCR2 != 0) { 476 | swim_write_byte(pgm, 0x7F, device->regs.FLASH_NCR2); 477 | } 478 | 479 | for (unsigned int i = 0; i < length; i++) { 480 | swim_write_byte(pgm, *(buffer++), start++); 481 | // Wait for EOP to be set in FLASH_IAPSR 482 | usleep(6000); // t_prog per the datasheets is 6ms typ, 6.6ms max 483 | TRY(5,swim_read_byte(pgm, device->regs.FLASH_IAPSR) & 0x04); 484 | } 485 | 486 | } else { 487 | // NOTE : RAM is also written in flash_block_size chunks here; just for convenience 488 | unsigned int rounded_size = ((length - 1) / device->flash_block_size + 1) * device->flash_block_size; 489 | unsigned char *current = alloca(rounded_size); 490 | int i; 491 | 492 | #if ONLY_WRITE_DIFFS 493 | stlink2_swim_read_range(pgm, device, current, start, rounded_size); 494 | memcpy(buffer + length, current + length, rounded_size - length); 495 | #endif 496 | 497 | DEBUG_PRINT("write range: block program with block size = %d\n", device->flash_block_size); 498 | 499 | for (i = 0; i < length; i += device->flash_block_size) { 500 | // BUG HERE : can read beyond buffer[] array boundary, because buffer is not always a multiple of flash_block_size 501 | if (ONLY_WRITE_DIFFS && !memcmp(current + i, buffer + i, device->flash_block_size)) { 502 | DEBUG_PRINT("no change 0x%04x to 0x%04x\n", start + i, start + i + device->flash_block_size); 503 | } else { 504 | int prgmode; 505 | /* 506 | * Use fast block programming (prgmode = 0x10) only if we have 507 | * read the flash block and verified that it is empty (all its 508 | * bytes are 0x00). 509 | */ 510 | #if ONLY_WRITE_DIFFS 511 | prgmode = 0x10; 512 | for (int j = 0; j < device->flash_block_size; j++) { 513 | if (current[i + j]) { 514 | prgmode = 0x01; 515 | break; 516 | } 517 | } 518 | #else 519 | prgmode = 0x01; 520 | #endif 521 | 522 | DEBUG_PRINT("%swrite 0x%04x to 0x%04x\n", (prgmode == 0x10 ? "fast " : ""), start + i, start + i + device->flash_block_size); 523 | 524 | if (memtype == FLASH || memtype == EEPROM) { 525 | // Stall the CPU before entering block programming mode 526 | // If the CPU keeps running and executes a software reset 527 | // (e.g. due to an invalid instruction) programming fails. 528 | int csr = swim_read_byte(pgm, device->regs.FLASH_DM_CSR2); 529 | swim_write_byte(pgm, csr | 8, device->regs.FLASH_DM_CSR2); 530 | 531 | // Block programming mode 532 | swim_write_byte(pgm, prgmode, device->regs.FLASH_CR2); 533 | if(device->regs.FLASH_NCR2 != 0) { 534 | swim_write_byte(pgm, ~prgmode, device->regs.FLASH_NCR2); 535 | } 536 | } 537 | 538 | // Page-based writing 539 | // The first 8 packet bytes are transmitted in the same USB bulk transfer 540 | // as the command itself with the rest following. 541 | // BUG HERE : only works correctly if start is on flash block boundary 542 | swim_cmd_with_data(pgm, buffer + i, device->flash_block_size, 8, STLINK_SWIM, SWIM_WRITEMEM, 543 | HI(device->flash_block_size), LO(device->flash_block_size), 544 | EH(start + i), EX(start + i), HI(start + i), LO(start + i)); 545 | 546 | if (memtype == FLASH || memtype == EEPROM) { 547 | // Wait for EOP to be set in FLASH_IAPSR 548 | // t_prog per the datasheets is 6ms typ, 6.6ms max, fast mode is twice as fast 549 | usleep(prgmode == 0x10 ? 3000 : 6000); 550 | //TRY(5,swim_read_byte(pgm, device->regs.FLASH_IAPSR) & 0x04); 551 | // provide a better error message than 'tries exceeded' 552 | do { 553 | int retries = 5; 554 | int iapsr; 555 | while (retries > 0) { 556 | iapsr = swim_read_byte(pgm, device->regs.FLASH_IAPSR); 557 | if (iapsr & 0x04) break; 558 | if (iapsr & 0x01) { 559 | ERROR("target page is write protected (UBC) or read-out protection is enabled"); 560 | } 561 | retries--; 562 | usleep(10000); 563 | } 564 | } while (0); 565 | } 566 | } 567 | } 568 | } 569 | 570 | if (memtype == FLASH || memtype == EEPROM || memtype == OPT) { 571 | // Reset DUL and PUL in IAPSR to disable flash and data writes. 572 | iapsr = swim_read_byte(pgm, device->regs.FLASH_IAPSR); 573 | swim_write_byte(pgm, iapsr & (~0x0a), device->regs.FLASH_IAPSR); 574 | } 575 | 576 | return(length); 577 | } 578 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* stlink/v2 stm8 memory programming utility 2 | (c) Valentin Dudouyt, 2012 - 2014 */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "pgm.h" 15 | #include "espstlink.h" 16 | #include "stlink.h" 17 | #include "stlinkv2.h" 18 | #include "stm8.h" 19 | #include "ihex.h" 20 | #include "srec.h" 21 | 22 | typedef enum { 23 | INTEL_HEX = 0, 24 | MOTOROLA_S_RECORD, 25 | RAW_BINARY 26 | } fileformat_t; 27 | 28 | #ifdef __APPLE__ 29 | extern char *optarg; 30 | extern int optind; 31 | extern int optopt; 32 | extern int opterr; 33 | extern int optreset; 34 | #endif 35 | 36 | #define VERSION_RELASE_DATE "20170616" 37 | #define VERSION "1.1" 38 | #define VERSION_NOTES "" 39 | 40 | programmer_t pgms[] = { 41 | { "stlink", 42 | STLinkV1, 43 | 0x0483, // USB vid 44 | 0x3744, // USB pid 45 | stlink_open, 46 | stlink_close, 47 | stlink_swim_srst, 48 | stlink_swim_read_range, 49 | stlink_swim_write_range, 50 | }, 51 | { 52 | "stlinkv2", 53 | STLinkV2, 54 | 0x0483, 55 | 0x3748, 56 | stlink2_open, 57 | stlink2_close, 58 | stlink2_srst, 59 | stlink2_swim_read_range, 60 | stlink2_swim_write_range, 61 | }, 62 | { 63 | "stlinkv21", 64 | STLinkV21, 65 | 0x0483, 66 | 0x374b, 67 | stlink2_open, 68 | stlink_close, 69 | stlink2_srst, 70 | stlink2_swim_read_range, 71 | stlink2_swim_write_range, 72 | }, 73 | { 74 | "stlinkv3", 75 | STLinkV3, 76 | 0x0483, 77 | 0x374f, 78 | stlink2_open, 79 | stlink_close, 80 | stlink2_srst, 81 | stlink2_swim_read_range, 82 | stlink2_swim_write_range, 83 | }, 84 | { 85 | "espstlink", 86 | ESP_STLink, 87 | 0, 88 | 0, 89 | espstlink_pgm_open, 90 | espstlink_pgm_close, 91 | espstlink_srst, 92 | espstlink_swim_read_range, 93 | espstlink_swim_write_range, 94 | }, 95 | { NULL }, 96 | }; 97 | 98 | void print_help_and_exit(const char *name, bool err) { 99 | int i = 0; 100 | FILE *stream = err ? stderr : stdout; 101 | fprintf(stream, "Usage: %s [-c programmer] [-S serialno] [-p partno] [-s memtype] [-b bytes] [-r|-w|-v] \n", name); 102 | fprintf(stream, "Usage: %s [-c programmer] [-S serialno] [-p partno] -R\n", name); 103 | fprintf(stream, "Options:\n"); 104 | fprintf(stream, "\t-h Display this help\n"); 105 | fprintf(stream, "\t-c programmer Specify programmer used ("); 106 | while (1) { 107 | if (pgms[i].name == NULL) 108 | break; 109 | 110 | if (i) { 111 | if (pgms[i+1].name == NULL) 112 | fprintf(stream, " or "); 113 | else 114 | fprintf(stream, ", "); 115 | } 116 | 117 | fprintf(stream, "%s", pgms[i].name); 118 | i++; 119 | } 120 | fprintf(stream, ")\n"); 121 | fprintf(stream, "\t-S serialno Specify programmer's serial number. If not given and more than one programmer is available, they'll be listed.\n"); 122 | fprintf(stream, "\t-d port Specify the serial device for espstlink (default: /dev/ttyUSB0)\n"); 123 | fprintf(stream, "\t-p partno Specify STM8 device\n"); 124 | fprintf(stream, "\t-l List supported STM8 devices\n"); 125 | fprintf(stream, "\t-s memtype Specify memory type (flash, eeprom, ram, opt or explicit address)\n"); 126 | fprintf(stream, "\t-b bytes Specify number of bytes\n"); 127 | fprintf(stream, "\t-r Read data from device to file\n"); 128 | fprintf(stream, "\t-w Write data from file to device\n"); 129 | fprintf(stream, "\t-v Verify data in device against file\n"); 130 | fprintf(stream, "\t-R Reset the device only\n"); 131 | fprintf(stream, "\t-L List attached ST-LINK compatible programmers and their serial numbers\n"); 132 | fprintf(stream, "\t-V Print Date(YearMonthDay-Version) and Version format is IE: 20171204-1.0\n"); 133 | fprintf(stream, "\t-u Unlock. Reset option bytes to factory default to remove write protection.\n"); 134 | exit(-err); 135 | } 136 | 137 | void print_version_and_exit( bool err) { 138 | FILE *stream = err ? stderr : stdout; 139 | fprintf(stream, "%s-%s\n%s",VERSION_RELASE_DATE, VERSION, VERSION_NOTES ); 140 | exit(-err); 141 | } 142 | 143 | 144 | void spawn_error(const char *msg) { 145 | fprintf(stderr, "%s\n", msg); 146 | exit(-1); 147 | } 148 | 149 | void dump_pgms(programmer_t *pgms) { 150 | // Dump programmers list in stderr 151 | int i; 152 | for(i = 0; pgms[i].name; i++) 153 | fprintf(stderr, "%s\n", pgms[i].name); 154 | } 155 | 156 | bool is_ext(const char *filename, const char *ext) { 157 | char *ext_begin = strrchr(filename, '.'); 158 | return(ext_begin && strcmp(ext_begin, ext) == 0); 159 | } 160 | 161 | void serialno_to_hex(const char *serialno, const int length, char *serialno_hex) { 162 | const char lk[] = "0123456789ABCDEF"; 163 | for(int i=0;i>4)&0x0f]; 166 | serialno_hex[i*2+1] = lk[(serialno[i]>>0)&0x0f]; 167 | } 168 | if (!strncmp (serialno_hex, "303030303030303030303031", 2 * length)) 169 | fprintf (stderr, "WARNING: Serial Number 303030303030303030303031 is most likely an invalid number reported due to a bug in older programmer firmware versions.\n"); 170 | } 171 | 172 | bool usb_init(programmer_t *pgm, bool pgm_serialno_specified, char *pgm_serialno) { 173 | if (!pgm->usb_vid && !pgm->usb_pid) return(true); 174 | 175 | libusb_device **devs; 176 | libusb_context *ctx = NULL; 177 | int numOfProgrammers = 0; 178 | char vendor[32]; 179 | char device[32]; 180 | char serialno[32]; 181 | char serialno_hex[64 + 1] = {0}; 182 | 183 | 184 | int r; 185 | ssize_t cnt; 186 | r = libusb_init(&ctx); 187 | if(r < 0) return(false); 188 | 189 | { 190 | #ifdef STM8FLASH_LIBUSB_QUIET 191 | const int usb_debug_level = 0; 192 | #else 193 | const int usb_debug_level = 3; 194 | #endif 195 | #if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000106) 196 | libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, usb_debug_level); 197 | #else 198 | libusb_set_debug(ctx, usb_debug_level); 199 | #endif 200 | } 201 | 202 | cnt = libusb_get_device_list(ctx, &devs); 203 | if(cnt < 0) return(false); 204 | 205 | // count available programmers 206 | for(int i=0; iusb_vid && desc.idProduct == pgm->usb_pid) { 210 | numOfProgrammers++; 211 | } 212 | 213 | } 214 | 215 | if(numOfProgrammers > 1 || pgm_serialno_specified){ 216 | 217 | // no serialno given 218 | if(!pgm_serialno_specified) { 219 | fprintf(stderr, "WARNING: More than one programmer found but no serial number given. Programmer 1 will be used:\n"); 220 | pgm->dev_handle = libusb_open_device_with_vid_pid(ctx, pgm->usb_vid, pgm->usb_pid); 221 | } 222 | 223 | numOfProgrammers = 0; 224 | int i=0; 225 | for(i=0; iusb_vid && desc.idProduct == pgm->usb_pid) { 231 | numOfProgrammers++; 232 | 233 | if (libusb_open(devs[i], &tempHandle)) 234 | continue; 235 | 236 | libusb_get_string_descriptor_ascii(tempHandle, desc.iManufacturer, (unsigned char*)vendor, sizeof(vendor)); 237 | libusb_get_string_descriptor_ascii(tempHandle, desc.iProduct, (unsigned char*)device, sizeof(device)); 238 | int serialno_length = libusb_get_string_descriptor_ascii(tempHandle, desc.iSerialNumber, (unsigned char*)serialno, sizeof(serialno)); 239 | if (serialno_length > 32) serialno_length = 32; 240 | serialno_to_hex(serialno, serialno_length, serialno_hex); 241 | 242 | // print programmer data if no serial number specified 243 | if(!pgm_serialno_specified) { 244 | fprintf(stderr, "Programmer %d: %s %s, Serial Number: %.*s\n", numOfProgrammers, vendor, device, 2*serialno_length, serialno_hex); 245 | } 246 | else 247 | { 248 | // otherwise check if it's the correct one 249 | if(0==strcmp(serialno_hex, pgm_serialno)) { 250 | pgm->dev_handle = tempHandle; 251 | break; 252 | } 253 | } 254 | libusb_close(tempHandle); 255 | } 256 | 257 | } 258 | if(pgm_serialno_specified && i==cnt) { 259 | fprintf(stderr, "ERROR: No programmer with serial number %s found.\n", pgm_serialno); 260 | return(false); 261 | } 262 | } 263 | else 264 | { 265 | pgm->dev_handle = libusb_open_device_with_vid_pid(ctx, pgm->usb_vid, pgm->usb_pid); 266 | } 267 | 268 | 269 | 270 | 271 | pgm->ctx = ctx; 272 | if (!pgm->dev_handle) spawn_error("Could not open USB device."); 273 | // assert(pgm->dev_handle); 274 | 275 | libusb_free_device_list(devs, 1); //free the list, unref the devices in it 276 | 277 | if(libusb_kernel_driver_active(pgm->dev_handle, 0) == 1) { //find out if kernel driver is attached 278 | int r = libusb_detach_kernel_driver(pgm->dev_handle, 0); 279 | assert(r == 0); 280 | } 281 | 282 | r = libusb_claim_interface(pgm->dev_handle, 0); 283 | assert(r == 0); 284 | 285 | return(true); 286 | } 287 | 288 | static bool is_interesting_usb(const uint16_t vid, const uint16_t pid) { 289 | for (int i = 0; i < (sizeof(pgms) / sizeof(pgms[0])); i++) { 290 | if ((pgms[i].usb_pid == pid) && (pgms[i].usb_vid == vid)) { 291 | return true; 292 | } 293 | } 294 | return false; 295 | } 296 | 297 | void dump_stlink_programmers(void) { 298 | libusb_device **devs; 299 | libusb_context *ctx = NULL; 300 | char vendor[32]; 301 | char device[32]; 302 | char serialno[32]; 303 | char serialno_hex[64]; 304 | 305 | int r; 306 | r = libusb_init(&ctx); 307 | if(r < 0) return; 308 | 309 | { 310 | #ifdef STM8FLASH_LIBUSB_QUIET 311 | const int usb_debug_level = 0; 312 | #else 313 | const int usb_debug_level = 3; 314 | #endif 315 | #if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000106) 316 | libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, usb_debug_level); 317 | #else 318 | libusb_set_debug(ctx, usb_debug_level); 319 | #endif 320 | } 321 | 322 | const int cnt = libusb_get_device_list(ctx, &devs); 323 | if(cnt < 0) return; 324 | 325 | int numOfProgrammers = 0; 326 | // count available programmers 327 | for (int i = 0; i < cnt; i++) { 328 | struct libusb_device_descriptor desc; 329 | libusb_device_handle *tempHandle; 330 | libusb_get_device_descriptor(devs[i], &desc); 331 | 332 | if (is_interesting_usb(desc.idVendor, desc.idProduct)) { 333 | if (libusb_open(devs[i], &tempHandle)) 334 | continue; 335 | 336 | libusb_get_string_descriptor_ascii(tempHandle, desc.iManufacturer, (unsigned char*)vendor, sizeof(vendor)); 337 | libusb_get_string_descriptor_ascii(tempHandle, desc.iProduct, (unsigned char*)device, sizeof(device)); 338 | const int serialno_length = libusb_get_string_descriptor_ascii(tempHandle, desc.iSerialNumber, (unsigned char*)serialno, sizeof(serialno)); 339 | serialno_to_hex(serialno, serialno_length, serialno_hex); 340 | 341 | // print programmer data if no serial number specified 342 | fprintf(stdout, "Programmer %d: %s %s, Serial Number: %.*s\n", numOfProgrammers, vendor, device, 2*serialno_length, serialno_hex); 343 | libusb_close(tempHandle); 344 | numOfProgrammers++; 345 | } 346 | } 347 | 348 | libusb_free_device_list(devs, 1); 349 | libusb_exit(ctx); 350 | } 351 | 352 | const stm8_device_t *get_part(const char *name) 353 | { 354 | for(unsigned int i = 0; stm8_devices[i].name; i++) 355 | { 356 | const char *e = stm8_devices[i].name; 357 | const char *s = name; 358 | for(e = stm8_devices[i].name, s = name; *s && (*e == *s || toupper(*e) == *s || *e == '?'); e++, s++); 359 | if(!*e) 360 | return(&stm8_devices[i]); 361 | } 362 | return(0); 363 | } 364 | 365 | int main(int argc, char **argv) { 366 | unsigned int start; 367 | int bytes_count = 0; 368 | char filename[256]; 369 | memset(filename, 0, sizeof(filename)); 370 | bool need_file = true; 371 | char pgm_serialno[64]; 372 | memset(pgm_serialno, 0, sizeof(pgm_serialno)); 373 | // Parsing command line 374 | char c; 375 | action_t action = NONE; 376 | fileformat_t fileformat = RAW_BINARY; 377 | bool start_addr_specified = false, 378 | pgm_specified = false, 379 | pgm_serialno_specified = false, 380 | part_specified = false, 381 | bytes_count_specified = false; 382 | memtype_t memtype = FLASH; 383 | const char * port = NULL; 384 | int i; 385 | programmer_t *pgm = NULL; 386 | const stm8_device_t *part = NULL; 387 | 388 | setbuf (stderr, 0); // Make stderr unbuffered (which is the default on POSIX anyway, but not on Windows). 389 | setbuf (stdout, 0); // Also make stdout unbuffered (performance doesn't matter much here, bug quick progress display is useful). 390 | 391 | while((c = getopt(argc, argv, "r:w:v:c:S:p:d:s:b:hluVLR")) != (char)-1) { 392 | switch(c) { 393 | case 'c': 394 | pgm_specified = true; 395 | for(i = 0; pgms[i].name; i++) { 396 | if(!strcmp(optarg, pgms[i].name)) 397 | pgm = &pgms[i]; 398 | } 399 | break; 400 | case 'S': 401 | pgm_serialno_specified = true; 402 | if(NULL != optarg) 403 | strncpy(pgm_serialno, optarg, sizeof(pgm_serialno)); 404 | break; 405 | case 'p': 406 | part_specified = true; 407 | part = get_part(optarg); 408 | break; 409 | case 'd': 410 | port = strdup(optarg); 411 | break; 412 | case 'L': 413 | dump_stlink_programmers(); 414 | exit(0); 415 | case 'l': 416 | for(i = 0; stm8_devices[i].name; i++) 417 | printf("%s ", stm8_devices[i].name); 418 | printf("\n"); 419 | exit(0); 420 | case 'r': 421 | action = READ; 422 | strcpy(filename, optarg); 423 | break; 424 | case 'w': 425 | action = WRITE; 426 | strcpy(filename, optarg); 427 | break; 428 | case 'v': 429 | action = VERIFY; 430 | strcpy(filename, optarg); 431 | break; 432 | case 'u': 433 | action = UNLOCK; 434 | start = 0x4800; 435 | memtype = OPT; 436 | strcpy(filename, "Workaround"); 437 | break; 438 | case 's': 439 | // Start addr is depending on MCU type 440 | if(strcasecmp(optarg, "flash") == 0) { 441 | memtype = FLASH; 442 | } else if(strcasecmp(optarg, "eeprom") == 0) { 443 | memtype = EEPROM; 444 | } else if(strcasecmp(optarg, "ram") == 0) { 445 | memtype = RAM; 446 | } else if(strcasecmp(optarg, "opt") == 0) { 447 | memtype = OPT; 448 | } else { 449 | // Start addr is specified explicitely 450 | memtype = UNKNOWN; 451 | if(sscanf(optarg, "%x", (unsigned*)&start) != 1) 452 | spawn_error("Invalid memory type or location specified"); 453 | start_addr_specified = true; 454 | } 455 | break; 456 | case 'b': 457 | bytes_count = atoi(optarg); 458 | bytes_count_specified = true; 459 | break; 460 | case 'V': 461 | print_version_and_exit( (bool)0); 462 | break; 463 | case 'R': 464 | action = RESET; 465 | need_file = false; 466 | break; 467 | case 'h': 468 | print_help_and_exit(argv[0], false); 469 | default: 470 | print_help_and_exit(argv[0], true); 471 | } 472 | } 473 | if (optind < argc) { 474 | // some additional unsupported arguments were given on the command line 475 | print_help_and_exit(argv[0], true); 476 | } 477 | if(argc <= 1) 478 | print_help_and_exit(argv[0], true); 479 | if(pgm_specified && !pgm) { 480 | fprintf(stderr, "No valid programmer specified. Possible values are:\n"); 481 | dump_pgms( (programmer_t *) &pgms); 482 | exit(-1); 483 | } 484 | if(!pgm) 485 | spawn_error("No programmer has been specified"); 486 | pgm->port = port; 487 | if(part_specified && !part) { 488 | fprintf(stderr, "No valid part specified. Use -l to see the list of supported devices.\n"); 489 | exit(-1); 490 | } 491 | if(!part) 492 | spawn_error("No part has been specified"); 493 | 494 | // Try define memory type by address 495 | if(memtype == UNKNOWN) { 496 | if((start >= 0x4800) && (start < 0x4880)) { 497 | memtype = OPT; 498 | } 499 | if((start >= part->ram_start) && (start < part->ram_start + part->ram_size)) { 500 | memtype = RAM; 501 | } 502 | else if((start >= part->flash_start) && (start < part->flash_start + part->flash_size)) { 503 | memtype = FLASH; 504 | } 505 | else if((start >= part->eeprom_start) && (start < part->eeprom_start + part->eeprom_size)) { 506 | memtype = EEPROM; 507 | } 508 | } 509 | 510 | switch (memtype) { 511 | case RAM: 512 | if(!start_addr_specified) { 513 | start = part->ram_start; 514 | start_addr_specified = true; 515 | } 516 | if(!bytes_count_specified || bytes_count > part->ram_size) { 517 | bytes_count = part->ram_size; 518 | } 519 | fprintf(stderr, "Determine RAM area\r\n"); 520 | break; 521 | case EEPROM: 522 | if(!start_addr_specified) { 523 | start = part->eeprom_start; 524 | start_addr_specified = true; 525 | } 526 | if(!bytes_count_specified || bytes_count > part->eeprom_size) { 527 | bytes_count = part->eeprom_size; 528 | } 529 | fprintf(stderr, "Determine EEPROM area\r\n"); 530 | break; 531 | case FLASH: 532 | if(!start_addr_specified) { 533 | start = part->flash_start; 534 | start_addr_specified = true; 535 | } 536 | if(!bytes_count_specified || bytes_count > part->flash_size) { 537 | bytes_count = part->flash_size; 538 | } 539 | fprintf(stderr, "Determine FLASH area\r\n"); 540 | break; 541 | case OPT: 542 | if(!start_addr_specified) { 543 | start = 0x4800; 544 | start_addr_specified = true; 545 | } 546 | size_t opt_size = (part->flash_size <= 8*1024 ? 0x40 : 0x80); 547 | if(!bytes_count_specified || bytes_count > opt_size) { 548 | bytes_count = opt_size; 549 | } 550 | fprintf(stderr, "Determine OPT area\r\n"); 551 | break; 552 | case UNKNOWN: 553 | ; 554 | } 555 | 556 | if(!action) 557 | spawn_error("No action has been specified"); 558 | if(!start_addr_specified) 559 | spawn_error("No memtype or start_addr has been specified"); 560 | if (need_file && !strlen(filename)) 561 | spawn_error("No filename has been specified"); 562 | if(!action || !start_addr_specified || (need_file && !strlen(filename))) 563 | print_help_and_exit(argv[0], true); 564 | if(!usb_init(pgm, pgm_serialno_specified, pgm_serialno)) 565 | spawn_error("Couldn't initialize stlink"); 566 | if(!pgm->open(pgm)) 567 | spawn_error("Error communicating with MCU. Please check your SWIM connection."); 568 | 569 | if(is_ext(filename, ".ihx") || is_ext(filename, ".hex") || is_ext(filename, ".i86")) 570 | fileformat = INTEL_HEX; 571 | else if(is_ext(filename, ".s19") || is_ext(filename, ".s8") || is_ext(filename, ".srec")) 572 | fileformat = MOTOROLA_S_RECORD; 573 | fprintf(stderr, "Due to its file extension (or lack thereof), \"%s\" is considered as %s format!\n", filename, fileformat == INTEL_HEX ? "INTEL HEX" : (fileformat == MOTOROLA_S_RECORD ? "MOTOROLA S-RECORD" : "RAW BINARY")); 574 | 575 | FILE *f; 576 | if(action == READ) { 577 | fprintf(stderr, "Reading %d bytes at 0x%x... ", bytes_count, start); 578 | int bytes_count_align = ((bytes_count-1)/256+1)*256; // Reading should be done in blocks of 256 bytes 579 | unsigned char *buf = malloc(bytes_count_align); 580 | if(!buf) spawn_error("malloc failed"); 581 | int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); 582 | if(recv < bytes_count_align) { 583 | fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", bytes_count_align, recv); 584 | spawn_error("Failed to read MCU"); 585 | } 586 | if(!(f = fopen(filename, (fileformat == RAW_BINARY) ? "wb" : "w"))) 587 | spawn_error("Failed to open file"); 588 | switch(fileformat) 589 | { 590 | case INTEL_HEX: 591 | if(ihex_write(f, buf, start, start+bytes_count) < 0) 592 | exit(-1); 593 | break; 594 | case MOTOROLA_S_RECORD: 595 | srec_write(f, buf, start, start+bytes_count); 596 | break; 597 | default: 598 | fwrite(buf, 1, bytes_count, f); 599 | } 600 | fclose(f); 601 | fprintf(stderr, "OK\n"); 602 | fprintf(stderr, "Bytes received: %d\n", bytes_count); 603 | } else if (action == VERIFY) { 604 | fprintf(stderr, "Verifing %d bytes at 0x%x... ", bytes_count, start); 605 | 606 | int bytes_count_align = ((bytes_count-1)/256+1)*256; // Reading should be done in blocks of 256 bytes 607 | unsigned char *buf = malloc(bytes_count_align); 608 | if(!buf) spawn_error("malloc failed"); 609 | int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); 610 | if(recv < bytes_count_align) { 611 | fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", bytes_count_align, recv); 612 | spawn_error("Failed to read MCU"); 613 | } 614 | 615 | if(!(f = fopen(filename, (fileformat == RAW_BINARY) ? "rb" : "r"))) 616 | spawn_error("Failed to open file"); 617 | unsigned char *buf2 = malloc(bytes_count); 618 | if(!buf2) spawn_error("malloc failed"); 619 | int bytes_to_verify; 620 | /* reading bytes to RAM */ 621 | switch(fileformat) 622 | { 623 | case INTEL_HEX: 624 | if((bytes_to_verify = ihex_read(f, buf2, start, start + bytes_count)) < 0) 625 | exit(-1); 626 | break; 627 | case MOTOROLA_S_RECORD: 628 | bytes_to_verify = srec_read(f, buf2, start, start + bytes_count); 629 | break; 630 | default: 631 | fseek(f, 0L, SEEK_END); 632 | bytes_to_verify = ftell(f); 633 | if(bytes_count_specified) 634 | bytes_to_verify = bytes_count; 635 | else if(bytes_count < bytes_to_verify) 636 | bytes_to_verify = bytes_count; 637 | fseek(f, 0, SEEK_SET); 638 | fread(buf2, 1, bytes_to_verify, f); 639 | } 640 | fclose(f); 641 | 642 | if(memcmp(buf, buf2, bytes_to_verify) == 0) { 643 | fprintf(stderr, "OK\n"); 644 | fprintf(stderr, "Bytes verified: %d\n", bytes_to_verify); 645 | } else { 646 | fprintf(stderr, "FAILED\n"); 647 | exit(-1); 648 | } 649 | 650 | 651 | } else if (action == WRITE) { 652 | if(!(f = fopen(filename, (fileformat == RAW_BINARY) ? "rb" : "r"))) 653 | spawn_error("Failed to open file"); 654 | int bytes_count_align = ((bytes_count-1)/part->flash_block_size+1)*part->flash_block_size; 655 | unsigned char *buf = malloc(bytes_count_align); 656 | if(!buf) spawn_error("malloc failed"); 657 | memset(buf, 0, bytes_count_align); // Clean aligned buffer 658 | int bytes_to_write; 659 | 660 | /* reading bytes to RAM */ 661 | switch(fileformat) 662 | { 663 | case INTEL_HEX: 664 | if((bytes_to_write = ihex_read(f, buf, start, start + bytes_count)) < 0) 665 | exit(-1); 666 | break; 667 | case MOTOROLA_S_RECORD: 668 | bytes_to_write = srec_read(f, buf, start, start + bytes_count); 669 | break; 670 | default: 671 | fseek(f, 0L, SEEK_END); 672 | bytes_to_write = ftell(f); 673 | if(bytes_count_specified) 674 | bytes_to_write = bytes_count; 675 | else if(bytes_count < bytes_to_write) 676 | bytes_to_write = bytes_count; 677 | fseek(f, 0, SEEK_SET); 678 | fread(buf, 1, bytes_to_write, f); 679 | } 680 | fprintf(stderr, "%d bytes at 0x%x... ", bytes_to_write, start); 681 | 682 | /* flashing MCU */ 683 | int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); 684 | if(pgm->reset) { 685 | // Restarting core (if applicable) 686 | pgm->reset(pgm); 687 | } 688 | fprintf(stderr, "OK\n"); 689 | fprintf(stderr, "Bytes written: %d\n", sent); 690 | fclose(f); 691 | } else if (action == UNLOCK) { 692 | int sent; 693 | 694 | if (part->read_out_protection_mode == ROP_UNKNOWN) spawn_error("No unlocking mode defined for this device. You may need to edit the file stm8.c"); 695 | 696 | if (part->read_out_protection_mode == ROP_STM8S) { 697 | int bytes_to_write=part->option_bytes_size; 698 | 699 | unsigned char *buf=malloc(bytes_to_write); 700 | if(!buf) spawn_error("malloc failed"); 701 | 702 | for (int i=0; i0)&&((i&1)==0)) buf[i]=0xff; 705 | } 706 | /* flashing MCU */ 707 | sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); 708 | } 709 | else if (part->read_out_protection_mode == ROP_STM8L) { 710 | unsigned char c = 0xAA; 711 | pgm->write_range(pgm, part, &c, start, 1, memtype); 712 | sent = pgm->write_range(pgm, part, &c, start, 1, memtype); 713 | } 714 | else spawn_error("Unimplemented unlocking mode"); 715 | 716 | if(pgm->reset) { 717 | // Restarting core (if applicable) 718 | pgm->reset(pgm); 719 | } 720 | fprintf(stderr, "Unlocked device. Option bytes reset to default state.\n"); 721 | fprintf(stderr, "Bytes written: %d\n", sent); 722 | } else if (action == RESET) { 723 | fprintf(stderr, "Resetting board...\n"); 724 | pgm->reset(pgm); 725 | } 726 | if(pgm->close) 727 | pgm->close(pgm); 728 | libusb_close(pgm->dev_handle); 729 | libusb_exit(pgm->ctx); 730 | return(0); 731 | } 732 | -------------------------------------------------------------------------------- /stm8.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "stm8.h" 3 | 4 | #define REGS_STM8S { \ 5 | .CLK_CKDIVR = 0x50c6, \ 6 | .FLASH_PUKR = 0x5062, \ 7 | .FLASH_DUKR = 0x5064, \ 8 | .FLASH_IAPSR = 0x505f, \ 9 | .FLASH_CR2 = 0x505b, \ 10 | .FLASH_NCR2 = 0x505c, \ 11 | .FLASH_DM_CSR2 = 0x7F99 \ 12 | } 13 | 14 | // Note: FLASH_NCR2 not present on stm8l 15 | #define REGS_STM8L { \ 16 | .CLK_CKDIVR = 0x50c0, \ 17 | .FLASH_PUKR = 0x5052, \ 18 | .FLASH_DUKR = 0x5053, \ 19 | .FLASH_IAPSR = 0x5054, \ 20 | .FLASH_CR2 = 0x5051, \ 21 | .FLASH_NCR2 = 0x0000, \ 22 | .FLASH_DM_CSR2 = 0x7F99 \ 23 | } 24 | 25 | const stm8_device_t stm8_devices[] = { 26 | { 27 | .name = "stlux385", 28 | .ram_start = 0x0000, 29 | .ram_size = 2*1024, 30 | .eeprom_start = 0x4000, 31 | .eeprom_size = 1024, 32 | .flash_start = 0x8000, 33 | .flash_size = 32*1024, 34 | .flash_block_size = 128, 35 | .option_bytes_size = 128, 36 | .read_out_protection_mode = ROP_STM8S, 37 | REGS_STM8S 38 | }, 39 | { 40 | .name = "stlux???a", 41 | .ram_start = 0x0000, 42 | .ram_size = 2*1024, 43 | .eeprom_start = 0x4000, 44 | .eeprom_size = 1024, 45 | .flash_start = 0x8000, 46 | .flash_size = 32*1024, 47 | .flash_block_size = 128, 48 | .option_bytes_size = 128, 49 | .read_out_protection_mode = ROP_STM8S, 50 | REGS_STM8S 51 | }, 52 | { 53 | .name = "stm8af526?", 54 | .ram_start = 0x0000, 55 | .ram_size = 6*1024, 56 | .eeprom_start = 0x4000, 57 | .eeprom_size = 1024, 58 | .flash_start = 0x8000, 59 | .flash_size = 32*1024, 60 | .flash_block_size = 128, 61 | .option_bytes_size =0, 62 | .read_out_protection_mode = ROP_UNKNOWN, 63 | REGS_STM8S 64 | }, 65 | { 66 | .name = "stm8af528?", 67 | .ram_start = 0x0000, 68 | .ram_size = 6*1024, 69 | .eeprom_start = 0x4000, 70 | .eeprom_size = 2048, 71 | .flash_start = 0x8000, 72 | .flash_size = 64*1024, 73 | .flash_block_size = 128, 74 | .option_bytes_size =0, 75 | .read_out_protection_mode = ROP_UNKNOWN, 76 | REGS_STM8S 77 | }, 78 | { 79 | .name = "stm8af52a?", 80 | .ram_start = 0x0000, 81 | .ram_size = 6*1024, 82 | .eeprom_start = 0x4000, 83 | .eeprom_size = 2048, 84 | .flash_start = 0x8000, 85 | .flash_size = 128*1024, 86 | .flash_block_size = 128, 87 | .option_bytes_size = 128, 88 | .read_out_protection_mode = ROP_STM8S, 89 | REGS_STM8S 90 | }, 91 | { 92 | .name = "stm8af6213", 93 | .ram_start = 0x0000, 94 | .ram_size = 1*1024, 95 | .eeprom_start = 0x4000, 96 | .eeprom_size = 640, 97 | .flash_start = 0x8000, 98 | .flash_size = 4*1024, 99 | .flash_block_size = 64, 100 | .option_bytes_size =0, 101 | .read_out_protection_mode = ROP_UNKNOWN, 102 | REGS_STM8S 103 | }, 104 | { 105 | .name = "stm8af6223", 106 | .ram_start = 0x0000, 107 | .ram_size = 1*1024, 108 | .eeprom_start = 0x4000, 109 | .eeprom_size = 640, 110 | .flash_start = 0x8000, 111 | .flash_size = 8*1024, 112 | .flash_block_size = 64, 113 | .option_bytes_size =0, 114 | .read_out_protection_mode = ROP_UNKNOWN, 115 | REGS_STM8S 116 | }, 117 | { 118 | .name = "stm8af6223a", 119 | .ram_start = 0x0000, 120 | .ram_size = 1*1024, 121 | .eeprom_start = 0x4000, 122 | .eeprom_size = 640, 123 | .flash_start = 0x8000, 124 | .flash_size = 8*1024, 125 | .flash_block_size = 64, 126 | .option_bytes_size =0, 127 | .read_out_protection_mode = ROP_UNKNOWN, 128 | REGS_STM8S 129 | }, 130 | { 131 | .name = "stm8af6226", 132 | .ram_start = 0x0000, 133 | .ram_size = 2*1024, 134 | .eeprom_start = 0x4000, 135 | .eeprom_size = 640, 136 | .flash_start = 0x8000, 137 | .flash_size = 8*1024, 138 | .flash_block_size = 64, 139 | .option_bytes_size =0, 140 | .read_out_protection_mode = ROP_UNKNOWN, 141 | REGS_STM8S 142 | }, 143 | { 144 | .name = "stm8af624?", 145 | .ram_start = 0x0000, 146 | .ram_size = 2*1024, 147 | .eeprom_start = 0x4000, 148 | .eeprom_size = 512, 149 | .flash_start = 0x8000, 150 | .flash_size = 16*1024, 151 | .flash_block_size = 128, 152 | .option_bytes_size =0, 153 | .read_out_protection_mode = ROP_UNKNOWN, 154 | REGS_STM8S 155 | }, 156 | { 157 | .name = "stm8af6266", 158 | .ram_start = 0x0000, 159 | .ram_size = 2*1024, 160 | .eeprom_start = 0x4000, 161 | .eeprom_size = 1024, 162 | .flash_start = 0x8000, 163 | .flash_size = 32*1024, 164 | .flash_block_size = 128, 165 | .option_bytes_size =0, 166 | .read_out_protection_mode = ROP_UNKNOWN, 167 | REGS_STM8S 168 | }, 169 | { 170 | .name = "stm8af6268", 171 | .ram_start = 0x0000, 172 | .ram_size = 2*1024, 173 | .eeprom_start = 0x4000, 174 | .eeprom_size = 1024, 175 | .flash_start = 0x8000, 176 | .flash_size = 32*1024, 177 | .flash_block_size = 128, 178 | .option_bytes_size =0, 179 | .read_out_protection_mode = ROP_UNKNOWN, 180 | REGS_STM8S 181 | }, 182 | { 183 | .name = "stm8af6269", 184 | .ram_start = 0x0000, 185 | .ram_size = 6*1024, 186 | .eeprom_start = 0x4000, 187 | .eeprom_size = 1024, 188 | .flash_start = 0x8000, 189 | .flash_size = 32*1024, 190 | .flash_block_size = 128, 191 | .option_bytes_size =0, 192 | .read_out_protection_mode = ROP_UNKNOWN, 193 | REGS_STM8S 194 | }, 195 | { 196 | .name = "stm8af628?", 197 | .ram_start = 0x0000, 198 | .ram_size = 6*1024, 199 | .eeprom_start = 0x4000, 200 | .eeprom_size = 2048, 201 | .flash_start = 0x8000, 202 | .flash_size = 64*1024, 203 | .flash_block_size = 128, 204 | .option_bytes_size =0, 205 | .read_out_protection_mode = ROP_UNKNOWN, 206 | REGS_STM8S 207 | }, 208 | { 209 | .name = "stm8af62a?", 210 | .ram_start = 0x0000, 211 | .ram_size = 6*1024, 212 | .eeprom_start = 0x4000, 213 | .eeprom_size = 2048, 214 | .flash_start = 0x8000, 215 | .flash_size = 128*1024, 216 | .flash_block_size = 128, 217 | .option_bytes_size = 128, 218 | .read_out_protection_mode = ROP_STM8S, 219 | REGS_STM8S 220 | }, 221 | { 222 | .name = "stm8al313?", 223 | .ram_start = 0x0000, 224 | .ram_size = 2*1024, 225 | .eeprom_start = 0x1000, 226 | .eeprom_size = 1024, 227 | .flash_start = 0x8000, 228 | .flash_size = 8*1024, 229 | .flash_block_size = 128, 230 | .option_bytes_size =0, 231 | .read_out_protection_mode = ROP_UNKNOWN, 232 | REGS_STM8L 233 | }, 234 | { 235 | .name = "stm8al314?", 236 | .ram_start = 0x0000, 237 | .ram_size = 2*1024, 238 | .eeprom_start = 0x1000, 239 | .eeprom_size = 1024, 240 | .flash_start = 0x8000, 241 | .flash_size = 16*1024, 242 | .flash_block_size = 128, 243 | .option_bytes_size =0, 244 | .read_out_protection_mode = ROP_UNKNOWN, 245 | REGS_STM8L 246 | }, 247 | { 248 | .name = "stm8al316?", 249 | .ram_start = 0x0000, 250 | .ram_size = 2*1024, 251 | .eeprom_start = 0x1000, 252 | .eeprom_size = 1024, 253 | .flash_start = 0x8000, 254 | .flash_size = 32*1024, 255 | .flash_block_size = 128, 256 | .option_bytes_size =0, 257 | .read_out_protection_mode = ROP_UNKNOWN, 258 | REGS_STM8L 259 | }, 260 | { 261 | .name = "stm8al318?", 262 | .ram_start = 0x0000, 263 | .ram_size = 4*1024, 264 | .eeprom_start = 0x1000, 265 | .eeprom_size = 2*1024, 266 | .flash_start = 0x8000, 267 | .flash_size = 64*1024, 268 | .flash_block_size = 128, 269 | .option_bytes_size = 13, 270 | .read_out_protection_mode = ROP_UNKNOWN, 271 | REGS_STM8L 272 | }, 273 | { 274 | .name = "stm8al31e8?", 275 | .ram_start = 0x0000, 276 | .ram_size = 4*1024, 277 | .eeprom_start = 0x1000, 278 | .eeprom_size = 2*1024, 279 | .flash_start = 0x8000, 280 | .flash_size = 64*1024, 281 | .flash_block_size = 128, 282 | .option_bytes_size = 13, 283 | .read_out_protection_mode = ROP_UNKNOWN, 284 | REGS_STM8L 285 | }, 286 | { 287 | .name = "stm8al3l4?", 288 | .ram_start = 0x0000, 289 | .ram_size = 2*1024, 290 | .eeprom_start = 0x1000, 291 | .eeprom_size = 1024, 292 | .flash_start = 0x8000, 293 | .flash_size = 16*1024, 294 | .flash_block_size = 128, 295 | .option_bytes_size =0, 296 | .read_out_protection_mode = ROP_UNKNOWN, 297 | REGS_STM8L 298 | }, 299 | { 300 | .name = "stm8al3l6?", 301 | .ram_start = 0x0000, 302 | .ram_size = 2*1024, 303 | .eeprom_start = 0x1000, 304 | .eeprom_size = 1024, 305 | .flash_start = 0x8000, 306 | .flash_size = 32*1024, 307 | .flash_block_size = 128, 308 | .option_bytes_size =0, 309 | .read_out_protection_mode = ROP_UNKNOWN, 310 | REGS_STM8L 311 | }, 312 | { 313 | .name = "stm8al3l8?", 314 | .ram_start = 0x0000, 315 | .ram_size = 4*1024, 316 | .eeprom_start = 0x1000, 317 | .eeprom_size = 2*1024, 318 | .flash_start = 0x8000, 319 | .flash_size = 64*1024, 320 | .flash_block_size = 128, 321 | .option_bytes_size = 13, 322 | .read_out_protection_mode = ROP_UNKNOWN, 323 | REGS_STM8L 324 | }, 325 | { 326 | .name = "stm8al3le8?", 327 | .ram_start = 0x0000, 328 | .ram_size = 4*1024, 329 | .eeprom_start = 0x1000, 330 | .eeprom_size = 2*1024, 331 | .flash_start = 0x8000, 332 | .flash_size = 64*1024, 333 | .flash_block_size = 128, 334 | .option_bytes_size = 13, 335 | .read_out_protection_mode = ROP_UNKNOWN, 336 | REGS_STM8L 337 | }, 338 | { 339 | .name = "stm8l001j3", 340 | .ram_start = 0x0000, 341 | .ram_size = 1.5*1024, 342 | .eeprom_start = 0, 343 | .eeprom_size = 0, 344 | .flash_start = 0x8000, 345 | .flash_size = 8*1024, 346 | .flash_block_size = 64, 347 | .option_bytes_size = 9, 348 | .read_out_protection_mode = ROP_STM8S, 349 | REGS_STM8L 350 | }, 351 | { 352 | .name = "stm8l050j3", 353 | .ram_start = 0x0000, 354 | .ram_size = 1*1024, 355 | .eeprom_start = 0x1000, 356 | .eeprom_size = 256, 357 | .flash_start = 0x8000, 358 | .flash_size = 8*1024, 359 | .flash_block_size = 64, 360 | .option_bytes_size = 13, 361 | .read_out_protection_mode = ROP_STM8L, 362 | REGS_STM8L 363 | }, 364 | { 365 | .name = "stm8l051f3", 366 | .ram_start = 0x0000, 367 | .ram_size = 1*1024, 368 | .eeprom_start = 0x1000, 369 | .eeprom_size = 256, 370 | .flash_start = 0x8000, 371 | .flash_size = 8*1024, 372 | .flash_block_size = 64, 373 | .option_bytes_size =0, 374 | .read_out_protection_mode = ROP_UNKNOWN, 375 | REGS_STM8L 376 | }, 377 | { 378 | .name = "stm8l052c6", 379 | .ram_start = 0x0000, 380 | .ram_size = 2*1024, 381 | .eeprom_start = 0x1000, 382 | .eeprom_size = 256, 383 | .flash_start = 0x8000, 384 | .flash_size = 32*1024, 385 | .flash_block_size = 128, 386 | .option_bytes_size = 13, 387 | .read_out_protection_mode = ROP_STM8L, 388 | REGS_STM8L 389 | }, 390 | { 391 | .name = "stm8l052r8", 392 | .ram_start = 0x0000, 393 | .ram_size = 4*1024, 394 | .eeprom_start = 0x1000, 395 | .eeprom_size = 256, 396 | .flash_start = 0x8000, 397 | .flash_size = 64*1024, 398 | .flash_block_size = 64, 399 | .option_bytes_size =0, 400 | .read_out_protection_mode = ROP_UNKNOWN, 401 | REGS_STM8L 402 | }, 403 | { 404 | .name = "stm8l101f1", 405 | .ram_start = 0x0000, 406 | .ram_size = 0x05FF, 407 | .eeprom_start = 0x9FFF, // Overlapping flash and eeprom 408 | .eeprom_size = 0, 409 | .flash_start = 0x8000, 410 | .flash_size = 2*1024, 411 | .flash_block_size = 64, 412 | .option_bytes_size = 9, 413 | .read_out_protection_mode = ROP_STM8S, 414 | REGS_STM8L 415 | }, 416 | { 417 | .name = "stm8l101?2", 418 | .ram_start = 0x0000, 419 | .ram_size = 0x05FF, 420 | .eeprom_start = 0x9FFF, // Overlapping flash and eeprom 421 | .eeprom_size = 0, 422 | .flash_start = 0x8000, 423 | .flash_size = 4*1024, 424 | .flash_block_size = 64, 425 | .option_bytes_size = 9, 426 | .read_out_protection_mode = ROP_STM8S, 427 | REGS_STM8L 428 | }, 429 | { 430 | .name = "stm8l101?3", 431 | .ram_start = 0x0000, 432 | .ram_size = 0x05FF, 433 | .eeprom_start = 0x9FFF, // Overlapping flash and eeprom 434 | .eeprom_size = 0, 435 | .flash_start = 0x8000, 436 | .flash_size = 8*1024, 437 | .flash_block_size = 64, 438 | .option_bytes_size = 9, 439 | .read_out_protection_mode = ROP_STM8S, 440 | REGS_STM8L 441 | }, 442 | { 443 | .name = "stm8l151?2", 444 | .ram_start = 0x0000, 445 | .ram_size = 1*1024, 446 | .eeprom_start = 0x1000, 447 | .eeprom_size = 256, 448 | .flash_start = 0x8000, 449 | .flash_size = 4*1024, 450 | .flash_block_size = 64, 451 | .option_bytes_size =0, 452 | .read_out_protection_mode = ROP_UNKNOWN, 453 | REGS_STM8L 454 | }, 455 | { 456 | .name = "stm8l151?3", 457 | .ram_start = 0x0000, 458 | .ram_size = 1*1024, 459 | .eeprom_start = 0x1000, 460 | .eeprom_size = 256, 461 | .flash_start = 0x8000, 462 | .flash_size = 8*1024, 463 | .flash_block_size = 64, 464 | .option_bytes_size =0, 465 | .read_out_protection_mode = ROP_UNKNOWN, 466 | REGS_STM8L 467 | }, 468 | { 469 | .name = "stm8l151?4", 470 | .ram_start = 0x0000, 471 | .ram_size = 2*1024, 472 | .eeprom_start = 0x1000, 473 | .eeprom_size = 1024, 474 | .flash_start = 0x8000, 475 | .flash_size = 16*1024, 476 | // Flash block size 128 according to the "PM0054 Programming manual". 477 | // Flash block size 64 according to the datasheet (section 9.5.3, "Memory characteristics"). 478 | // According to user feedback, stm8flash works with 128, but not with 64. 479 | .flash_block_size = 128, 480 | .option_bytes_size = 13, 481 | .read_out_protection_mode = ROP_STM8L, 482 | REGS_STM8L 483 | }, 484 | { 485 | .name = "stm8l151?6", 486 | .ram_start = 0x0000, 487 | .ram_size = 2*1024, 488 | .eeprom_start = 0x1000, 489 | .eeprom_size = 1024, 490 | .flash_start = 0x8000, 491 | .flash_size = 32*1024, 492 | .flash_block_size = 128, 493 | .option_bytes_size = 13, 494 | .read_out_protection_mode = ROP_STM8L, 495 | REGS_STM8L 496 | }, 497 | { 498 | .name = "stm8l151?8", 499 | .ram_start = 0x0000, 500 | .ram_size = 4*1024, 501 | .eeprom_start = 0x1000, 502 | .eeprom_size = 2048, 503 | .flash_start = 0x8000, 504 | .flash_size = 64*1024, 505 | .flash_block_size = 128, 506 | .option_bytes_size = 13, 507 | .read_out_protection_mode = ROP_STM8L, 508 | REGS_STM8L 509 | }, 510 | { 511 | .name = "stm8l152?4", 512 | .ram_start = 0x0000, 513 | .ram_size = 2*1024, 514 | .eeprom_start = 0x1000, 515 | .eeprom_size = 1024, 516 | .flash_start = 0x8000, 517 | .flash_size = 16*1024, 518 | .flash_block_size = 128, 519 | .option_bytes_size = 13, 520 | .read_out_protection_mode = ROP_STM8L, 521 | REGS_STM8L 522 | }, 523 | { 524 | .name = "stm8l152?6", 525 | .ram_start = 0x0000, 526 | .ram_size = 2*1024, 527 | .eeprom_start = 0x1000, 528 | .eeprom_size = 1024, 529 | .flash_start = 0x8000, 530 | .flash_size = 32*1024, 531 | .flash_block_size = 128, 532 | .option_bytes_size = 13, 533 | .read_out_protection_mode = ROP_STM8L, 534 | REGS_STM8L 535 | }, 536 | { 537 | .name = "stm8l152?8", 538 | .ram_start = 0x0000, 539 | .ram_size = 4*1024, 540 | .eeprom_start = 0x1000, 541 | .eeprom_size = 2048, 542 | .flash_start = 0x8000, 543 | .flash_size = 64*1024, 544 | .flash_block_size = 128, 545 | .option_bytes_size =0, 546 | .read_out_protection_mode = ROP_UNKNOWN, 547 | REGS_STM8L 548 | }, 549 | { 550 | .name = "stm8l162?8", 551 | .ram_start = 0x0000, 552 | .ram_size = 2*1024, 553 | .eeprom_start = 0x1000, 554 | .eeprom_size = 2048, 555 | .flash_start = 0x8000, 556 | .flash_size = 64*1024, 557 | .flash_block_size = 128, 558 | .option_bytes_size =0, 559 | .read_out_protection_mode = ROP_UNKNOWN, 560 | REGS_STM8L 561 | }, 562 | { 563 | .name = "stm8s001j3", 564 | .ram_start = 0x0000, 565 | .ram_size = 1*1024, 566 | .eeprom_start = 0x4000, 567 | .eeprom_size = 128, 568 | .flash_start = 0x8000, 569 | .flash_size = 8*1024, 570 | .flash_block_size = 64, 571 | .option_bytes_size = 11, 572 | .read_out_protection_mode = ROP_STM8S, 573 | REGS_STM8S 574 | }, 575 | { 576 | .name = "stm8s003?3", 577 | .ram_start = 0x0000, 578 | .ram_size = 1*1024, 579 | .eeprom_start = 0x4000, 580 | .eeprom_size = 128, 581 | .flash_start = 0x8000, 582 | .flash_size = 8*1024, 583 | .flash_block_size = 64, 584 | .option_bytes_size = 11, 585 | .read_out_protection_mode = ROP_STM8S, 586 | REGS_STM8S 587 | }, 588 | { 589 | .name = "stm8s005?6", 590 | .ram_start = 0x0000, 591 | .ram_size = 2*1024, 592 | .eeprom_start = 0x4000, 593 | .eeprom_size = 128, 594 | .flash_start = 0x8000, 595 | .flash_size = 32*1024, 596 | .flash_block_size = 128, 597 | .option_bytes_size = 15, 598 | .read_out_protection_mode = ROP_STM8S, 599 | REGS_STM8S 600 | }, 601 | { 602 | .name = "stm8s007c8", 603 | .ram_start = 0x0000, 604 | .ram_size = 6*1024, 605 | .eeprom_start = 0x4000, 606 | .eeprom_size = 128, 607 | .flash_start = 0x8000, 608 | .flash_size = 64*1024, 609 | .flash_block_size = 128, 610 | .option_bytes_size =0, 611 | .read_out_protection_mode = ROP_UNKNOWN, 612 | REGS_STM8S 613 | }, 614 | { 615 | .name = "stm8s103f2", 616 | .ram_start = 0x0000, 617 | .ram_size = 1*1024, 618 | .eeprom_start = 0x4000, 619 | .eeprom_size = 640, 620 | .flash_start = 0x8000, 621 | .flash_size = 4*1024, 622 | .flash_block_size = 64, 623 | .option_bytes_size = 11, 624 | .read_out_protection_mode = ROP_STM8S, 625 | REGS_STM8S 626 | }, 627 | { 628 | .name = "stm8s103?3", 629 | .ram_start = 0x0000, 630 | .ram_size = 1*1024, 631 | .eeprom_start = 0x4000, 632 | .eeprom_size = 640, 633 | .flash_start = 0x8000, 634 | .flash_size = 8*1024, 635 | .flash_block_size = 64, 636 | .option_bytes_size = 11, 637 | .read_out_protection_mode = ROP_STM8S, 638 | REGS_STM8S 639 | }, 640 | { 641 | .name = "stm8s105?4", 642 | .ram_start = 0x0000, 643 | .ram_size = 2*1024, 644 | .eeprom_start = 0x4000, 645 | .eeprom_size = 1024, 646 | .flash_start = 0x8000, 647 | .flash_size = 16*1024, 648 | .flash_block_size = 128, 649 | .option_bytes_size = 15, 650 | .read_out_protection_mode = ROP_STM8S, 651 | REGS_STM8S 652 | }, 653 | { 654 | .name = "stm8s105?6", 655 | .ram_start = 0x0000, 656 | .ram_size = 2*1024, 657 | .eeprom_start = 0x4000, 658 | .eeprom_size = 1024, 659 | .flash_start = 0x8000, 660 | .flash_size = 32*1024, 661 | .flash_block_size = 128, 662 | .option_bytes_size = 15, 663 | .read_out_protection_mode = ROP_STM8S, 664 | REGS_STM8S 665 | }, 666 | { 667 | .name = "stm8s207c8", 668 | .ram_start = 0x0000, 669 | .ram_size = 6*1024, 670 | .eeprom_start = 0x4000, 671 | .eeprom_size = 1536, 672 | .flash_start = 0x8000, 673 | .flash_size = 64*1024, 674 | .flash_block_size = 128, 675 | .option_bytes_size =0, 676 | .read_out_protection_mode = ROP_UNKNOWN, 677 | REGS_STM8S 678 | }, 679 | { 680 | .name = "stm8s207cb", 681 | .ram_start = 0x0000, 682 | .ram_size = 6*1024, 683 | .eeprom_start = 0x4000, 684 | .eeprom_size = 2048, 685 | .flash_start = 0x8000, 686 | .flash_size = 128*1024, 687 | .flash_block_size = 128, 688 | .option_bytes_size = 17, 689 | .read_out_protection_mode = ROP_STM8S, 690 | REGS_STM8S 691 | }, 692 | { 693 | .name = "stm8s207k8", 694 | .ram_start = 0x0000, 695 | .ram_size = 6*1024, 696 | .eeprom_start = 0x4000, 697 | .eeprom_size = 1024, 698 | .flash_start = 0x8000, 699 | .flash_size = 64*1024, 700 | .flash_block_size = 128, 701 | .option_bytes_size = 17, 702 | .read_out_protection_mode = ROP_STM8S, 703 | REGS_STM8S 704 | }, 705 | { 706 | .name = "stm8s207m8", 707 | .ram_start = 0x0000, 708 | .ram_size = 6*1024, 709 | .eeprom_start = 0x4000, 710 | .eeprom_size = 2048, 711 | .flash_start = 0x8000, 712 | .flash_size = 64*1024, 713 | .flash_block_size = 128, 714 | .option_bytes_size =0, 715 | .read_out_protection_mode = ROP_UNKNOWN, 716 | REGS_STM8S 717 | }, 718 | { 719 | .name = "stm8s207mb", 720 | .ram_start = 0x0000, 721 | .ram_size = 6*1024, 722 | .eeprom_start = 0x4000, 723 | .eeprom_size = 2048, 724 | .flash_start = 0x8000, 725 | .flash_size = 128*1024, 726 | .flash_block_size = 128, 727 | .option_bytes_size =0, 728 | .read_out_protection_mode = ROP_UNKNOWN, 729 | REGS_STM8S 730 | }, 731 | { 732 | .name = "stm8s207r8", 733 | .ram_start = 0x0000, 734 | .ram_size = 6*1024, 735 | .eeprom_start = 0x4000, 736 | .eeprom_size = 1536, 737 | .flash_start = 0x8000, 738 | .flash_size = 64*1024, 739 | .flash_block_size = 128, 740 | .option_bytes_size =0, 741 | .read_out_protection_mode = ROP_UNKNOWN, 742 | REGS_STM8S 743 | }, 744 | { 745 | .name = "stm8s207rb", 746 | .ram_start = 0x0000, 747 | .ram_size = 6*1024, 748 | .eeprom_start = 0x4000, 749 | .eeprom_size = 2048, 750 | .flash_start = 0x8000, 751 | .flash_size = 128*1024, 752 | .flash_block_size = 128, 753 | .option_bytes_size = 17, 754 | .read_out_protection_mode = ROP_STM8S, 755 | REGS_STM8S 756 | }, 757 | { 758 | .name = "stm8s207s8", 759 | .ram_start = 0x0000, 760 | .ram_size = 6*1024, 761 | .eeprom_start = 0x4000, 762 | .eeprom_size = 1536, 763 | .flash_start = 0x8000, 764 | .flash_size = 64*1024, 765 | .flash_block_size = 128, 766 | .option_bytes_size =0, 767 | .read_out_protection_mode = ROP_UNKNOWN, 768 | REGS_STM8S 769 | }, 770 | { 771 | .name = "stm8s207sb", 772 | .ram_start = 0x0000, 773 | .ram_size = 6*1024, 774 | .eeprom_start = 0x4000, 775 | .eeprom_size = 1536, 776 | .flash_start = 0x8000, 777 | .flash_size = 128*1024, 778 | .flash_block_size = 128, 779 | .option_bytes_size =0, 780 | .read_out_protection_mode = ROP_UNKNOWN, 781 | REGS_STM8S 782 | }, 783 | { 784 | .name = "stm8s207?6", 785 | .ram_start = 0x0000, 786 | .ram_size = 6*1024, 787 | .eeprom_start = 0x4000, 788 | .eeprom_size = 1024, 789 | .flash_start = 0x8000, 790 | .flash_size = 32*1024, 791 | .flash_block_size = 128, 792 | .option_bytes_size =0, 793 | .read_out_protection_mode = ROP_UNKNOWN, 794 | REGS_STM8S 795 | }, 796 | { 797 | .name = "stm8s208c6", 798 | .ram_start = 0x0000, 799 | .ram_size = 6*1024, 800 | .eeprom_start = 0x4000, 801 | .eeprom_size = 2048, 802 | .flash_start = 0x8000, 803 | .flash_size = 32*1024, 804 | .flash_block_size = 128, 805 | .option_bytes_size =0, 806 | .read_out_protection_mode = ROP_UNKNOWN, 807 | REGS_STM8S 808 | }, 809 | { 810 | .name = "stm8s208r6", 811 | .ram_start = 0x0000, 812 | .ram_size = 6*1024, 813 | .eeprom_start = 0x4000, 814 | .eeprom_size = 2048, 815 | .flash_start = 0x8000, 816 | .flash_size = 32*1024, 817 | .flash_block_size = 128, 818 | .option_bytes_size =0, 819 | .read_out_protection_mode = ROP_UNKNOWN, 820 | REGS_STM8S 821 | }, 822 | { 823 | .name = "stm8s208s6", 824 | .ram_start = 0x0000, 825 | .ram_size = 6*1024, 826 | .eeprom_start = 0x4000, 827 | .eeprom_size = 1536, 828 | .flash_start = 0x8000, 829 | .flash_size = 32*1024, 830 | .flash_block_size = 128, 831 | .option_bytes_size =0, 832 | .read_out_protection_mode = ROP_UNKNOWN, 833 | REGS_STM8S 834 | }, 835 | { 836 | .name = "stm8s208?8", 837 | .ram_start = 0x0000, 838 | .ram_size = 6*1024, 839 | .eeprom_start = 0x4000, 840 | .eeprom_size = 2048, 841 | .flash_start = 0x8000, 842 | .flash_size = 64*1024, 843 | .flash_block_size = 128, 844 | .option_bytes_size =0, 845 | .read_out_protection_mode = ROP_UNKNOWN, 846 | REGS_STM8S 847 | }, 848 | { 849 | .name = "stm8s208?b", 850 | .ram_start = 0x0000, 851 | .ram_size = 6*1024, 852 | .eeprom_start = 0x4000, 853 | .eeprom_size = 2048, 854 | .flash_start = 0x8000, 855 | .flash_size = 128*1024, 856 | .flash_block_size = 128, 857 | .option_bytes_size = 17, 858 | .read_out_protection_mode = ROP_STM8S, 859 | REGS_STM8S 860 | }, 861 | { 862 | .name = "stm8s903?3", 863 | .ram_start = 0x0000, 864 | .ram_size = 1*1024, 865 | .eeprom_start = 0x4000, 866 | .eeprom_size = 640, 867 | .flash_start = 0x8000, 868 | .flash_size = 8*1024, 869 | .flash_block_size = 64, 870 | .option_bytes_size = 11, 871 | .read_out_protection_mode = ROP_STM8S, 872 | REGS_STM8S 873 | }, 874 | { 875 | .name = "stm8splnb1", 876 | .ram_start = 0x0000, 877 | .ram_size = 1*1024, 878 | .eeprom_start = 0x4000, 879 | .eeprom_size = 640, 880 | .flash_start = 0x8000, 881 | .flash_size = 8*1024, 882 | .flash_block_size = 128, 883 | .option_bytes_size =0, 884 | .read_out_protection_mode = ROP_UNKNOWN, 885 | REGS_STM8S 886 | }, 887 | { 888 | .name = "stm8tl5??4", 889 | .ram_start = 0x0000, 890 | .ram_size = 4096, 891 | .eeprom_start = 0x9FFF, // Overlapping flash and eeprom 892 | .eeprom_size = 0, 893 | .flash_start = 0x8000, 894 | .flash_size = 16*1024, 895 | .flash_block_size = 64, 896 | .option_bytes_size =0, 897 | .read_out_protection_mode = ROP_UNKNOWN, 898 | REGS_STM8L 899 | }, 900 | { 901 | .name = "stnrg???a", 902 | .ram_start = 0x0000, 903 | .ram_size = 6*1024, 904 | .eeprom_start = 0x4000, 905 | .eeprom_size = 1024, 906 | .flash_start = 0x8000, 907 | .flash_size = 32*1024, 908 | .flash_block_size = 128, 909 | .option_bytes_size = 128, 910 | .read_out_protection_mode = ROP_STM8S, 911 | REGS_STM8S 912 | }, 913 | { NULL }, 914 | }; 915 | --------------------------------------------------------------------------------