$(MAKE) -C gdbserver clean
flash:
- $(MAKE) -C flash CONFIG_USE_LIBSG="$(CONFIG_USE_LIBSG)"
+ $(MAKE) -C flash
gdbserver:
- $(MAKE) -C gdbserver
+ $(MAKE) -C gdbserver CONFIG_USE_LIBSG="$(CONFIG_USE_LIBSG)"
.PHONY: clean all flash gdbserver
#elif CONFIG_STM32F4_DISCOVERY
#define GPIOD 0x40020C00 /* port D */
-# define GPIOD_MODER (GPIOD + 0x00) /* port mode register */
-# define GPIOD_ODR (GPIOD + 0x14) /* port output data register */
+#define GPIOD_MODER (GPIOD + 0x00) /* port mode register */
+#define LED_PORT_ODR (GPIOD + 0x14) /* port output data register */
-# define LED_GREEN (1 << 12) /* port B, pin 12 */
-# define LED_ORANGE (1 << 13) /* port B, pin 13 */
-# define LED_RED (1 << 14) /* port B, pin 14 */
-# define LED_BLUE (1 << 15) /* port B, pin 15 */
+#define LED_GREEN (1 << 12) /* port D, pin 12 */
+#define LED_ORANGE (1 << 13) /* port D, pin 13 */
+#define LED_RED (1 << 14) /* port D, pin 14 */
+#define LED_BLUE (1 << 15) /* port D, pin 15 */
+ void _tmain(void) {
+ main();
+ }
static inline void setup_leds(void)
{
*(volatile uint32_t*)GPIOD_MODER |= (1 << (12 * 2)) | (1 << (13 * 2)) |
#include "gdb-remote.h"
+#define DEFAULT_LOGGING_LEVEL 50
+#define DEFAULT_GDB_LISTEN_PORT 4242
+
+#define STRINGIFY_inner(name) #name
+#define STRINGIFY(name) STRINGIFY_inner(name)
+
#define FLASH_BASE 0x08000000
+
+ //Allways update the FLASH_PAGE before each use, by calling stlink_calculate_pagesize
#define FLASH_PAGE (sl->flash_pgsz)
- #define FLASH_PAGE_MASK (~((1 << 10) - 1))
- #define FLASH_SIZE (FLASH_PAGE * 128)
-volatile int do_exit = 0;
-void ctrl_c(int sig)
-{
- do_exit = 1;
-}
-
static const char hex[] = "0123456789abcdef";
static const char* current_memory_map = NULL;
- /*
- * Chip IDs are explained in the appropriate programming manual for the
- * DBGMCU_IDCODE register (0xE0042000)
- */
-
- #define CORE_M3_R1 0x1BA00477
- #define CORE_M3_R2 0x4BA00477
- #define CORE_M4_R0 0x2BA01477
-struct chip_params {
- uint32_t chip_id;
- char* description;
- uint32_t flash_size_reg;
- uint32_t max_flash_size, flash_pagesize;
- uint32_t sram_size;
- uint32_t bootrom_base, bootrom_size;
-} const devices[] = {
- { 0x410, "F1 Medium-density device", 0x1ffff7e0,
- 0x20000, 0x400, 0x5000, 0x1ffff000, 0x800 }, // table 2, pm0063
- { 0x411, "F2 device", 0, /* No flash size register found in the docs*/
- 0x100000, 0x20000, 0x20000, 0x1fff0000, 0x7800 }, // table 1, pm0059
- { 0x412, "F1 Low-density device", 0x1ffff7e0,
- 0x8000, 0x400, 0x2800, 0x1ffff000, 0x800 }, // table 1, pm0063
- /*Page size is variable */
- { 0x413, "F4 device", 0x1FFF7A10, //RM0090 error same as unique ID
- 0x100000, 0x4000, 0x30000, 0x1fff0000, 0x7800 }, // table 1, pm0081
- { 0x414, "F1 High-density device", 0x1ffff7e0,
- 0x80000, 0x800, 0x10000, 0x1ffff000, 0x800 }, // table 3 pm0063
- // This ignores the EEPROM! (and uses the page erase size,
- // not the sector write protection...)
- { 0x416, "L1 Med-density device", 0x1FF8004C, // table 1, pm0062
- 0x20000, 0x100, 0x4000, 0x1ff00000, 0x1000 },
- { 0x418, "F1 Connectivity line device", 0x1ffff7e0,
- 0x40000, 0x800, 0x10000, 0x1fffb000, 0x4800 },
- { 0x420, "F1 Medium-density value line device", 0x1ffff7e0,
- 0x20000, 0x400, 0x2000, 0x1ffff000, 0x800 },
- { 0x428, "F1 High-density value line device", 0x1ffff7e0,
- 0x80000, 0x800, 0x8000, 0x1ffff000, 0x800 },
- { 0x430, "F1 XL-density device", 0x1ffff7e0, // pm0068
- 0x100000, 0x800, 0x18000, 0x1fffe000, 0x1800 },
- { 0 }
-};
--
-int serve(stlink_t *sl, int port);
-char* make_memory_map(stlink_t *sl, const struct chip_params *params, uint32_t flash_size);
+typedef struct _st_state_t {
+ // things from command line, bleh
+ int stlink_version;
+ // "/dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTE531X6-if00-port0" is only 58 chars
+ char devicename[100];
+ int logging_level;
+ int listen_port;
+} st_state_t;
-int main(int argc, char** argv) {
- stlink_t *sl = NULL;
- int port = 0;
- uint32_t flash_size;
-
- const char * HelpStr = "\nUsage:\n"
- "\tst-util [Arguments]\n"
- "\tArguments (no more than 2):\n"
- "\t\t<Port>: Port. Default: 4242.\n"
- "\t\t{usb|sgauto|/dev/sgX}: Transport, "
- "where X = {0, 1, 2, ...}. Default: USB.\n"
- "\tExamples:\n"
- "\t\tst-util 1234\n"
- "\t\tst-util sgauto\n"
- "\t\tst-util 1234 usb\n"
- "\t\tst-util /dev/sgX 1234\n"
- "\t\tst-util 1234 /dev/sgX\n";
-
-
- // Parsing the arguments of command line ...
-
- if (argc == 1 || argc > 3) {
- fprintf(stderr, HelpStr, NULL);
- return 1;
- }
-
- for(int a = 1; a < argc; a++) {
-
- // Port
- int p = atoi(argv[a]);
- if (p < 0 || p > 0xFFFF) {
- fprintf(stderr, "Invalid port\n");
- fprintf(stderr, HelpStr, NULL);
- return 1;
- }
- if (p > 0 && port == 0) {port = p; continue;}
-
- // if (p == 0) ...
-
- if (sl != NULL) {
- fprintf(stderr, "Invalid argumets\n");
- fprintf(stderr, HelpStr, NULL);
- return 1;
- }
-
- // usb
- if (!strcmp(argv[a], "usb")) {
- sl = stlink_open_usb(10);
- if(sl == NULL) return 1;
- continue;
+int serve(stlink_t *sl, int port);
+char* make_memory_map(stlink_t *sl);
+
+
+int parse_options(int argc, char** argv, st_state_t *st) {
+ static struct option long_options[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"verbose", optional_argument, NULL, 'v'},
+ {"device", required_argument, NULL, 'd'},
+ {"stlink_version", required_argument, NULL, 's'},
+ {"stlinkv1", no_argument, NULL, '1'},
+ {"listen_port", required_argument, NULL, 'p'},
+ {0, 0, 0, 0},
+ };
+ const char * help_str = "%s - usage:\n\n"
+ " -h, --help\t\tPrint this help\n"
+ " -vXX, --verbose=XX\tspecify a specific verbosity level (0..99)\n"
+ " -v, --verbose\tspecify generally verbose logging\n"
+ " -d <device>, --device=/dev/stlink2_1\n"
+ "\t\t\tWhere is your stlink device connected?\n"
+ " -s X, --stlink_version=X\n"
+ "\t\t\tChoose what version of stlink to use, (defaults to 2)\n"
+ " -1, --stlinkv1\tForce stlink version 1\n"
+ " -p 4242, --listen_port=1234\n"
+ "\t\t\tSet the gdb server listen port. "
+ "(default port: " STRINGIFY(DEFAULT_GDB_LISTEN_PORT) ")\n"
+ ;
+
+
+ int option_index = 0;
+ int c;
+ int q;
+ while ((c = getopt_long(argc, argv, "hv::d:s:1p:", long_options, &option_index)) != -1) {
+ switch (c) {
+ case 0:
+ printf("XXXXX Shouldn't really normally come here, only if there's no corresponding option\n");
+ printf("option %s", long_options[option_index].name);
+ if (optarg) {
+ printf(" with arg %s", optarg);
}
-
- // /dev/sgX
- if (!strncmp(argv[a], "/dev/sgX", 7)) {
- if(!CONFIG_USE_LIBSG) {
- fprintf(stderr, "libsg not use\n");
- return 1;
- }
- sl = stlink_quirk_open(argv[a], 0);
- if(sl == NULL) return 1;
- continue;
+ printf("\n");
+ break;
+ case 'h':
+ printf(help_str, argv[0]);
+ exit(EXIT_SUCCESS);
+ break;
+ case 'v':
+ if (optarg) {
+ st->logging_level = atoi(optarg);
+ } else {
+ st->logging_level = DEFAULT_LOGGING_LEVEL;
}
-
- // sg_auto
- if (!strcmp(argv[a], "sgauto")) {
- if(!CONFIG_USE_LIBSG) {
- fprintf(stderr, "libsg not use\n");
- return 1;
- }
-
- // Search ST-LINK (from /dev/sg0 to /dev/sg99)
- for(int DevNum = 0; DevNum <= 99; DevNum++)
- {
- if(DevNum < 10) {
- char DevName[] = "/dev/sgX";
- DevName[7] = DevNum + '0';
- if ( !access(DevName, F_OK) )
- sl = stlink_quirk_open(DevName, 0);
- }
- else {
- char DevName[] = "/dev/sgXY";
- DevName[7] = DevNum/10 + '0';
- DevName[8] = DevNum%10 + '0';
- if ( !access(DevName, F_OK) )
- sl = stlink_quirk_open(DevName, 0);
- }
- if (sl != NULL) break;
- }
-
- if(sl == NULL) return 1;
- continue;
+ break;
+ case 'd':
+ if (strlen(optarg) > sizeof (st->devicename)) {
+ fprintf(stderr, "device name too long: %zd\n", strlen(optarg));
+ } else {
+ strcpy(st->devicename, optarg);
}
-
- // Invalid argumets
- fprintf(stderr, "Invalid argumets\n");
- fprintf(stderr, HelpStr, NULL);
- return 1;
+ break;
+ case '1':
+ st->stlink_version = 1;
+ break;
+ case 's':
+ sscanf(optarg, "%i", &q);
+ if (q < 0 || q > 2) {
+ fprintf(stderr, "stlink version %d unknown!\n", q);
+ exit(EXIT_FAILURE);
+ }
+ st->stlink_version = q;
+ break;
+ case 'p':
+ sscanf(optarg, "%i", &q);
+ if (q < 0) {
+ fprintf(stderr, "Can't use a negative port to listen on: %d\n", q);
+ exit(EXIT_FAILURE);
+ }
+ st->listen_port = q;
+ break;
}
-
- // Default transport: USB
- if (sl == NULL) sl = stlink_open_usb(10);
- // Default port: 4242
- if (port == 0) port = 4242;
-
- // End parsing
-
-
- if (sl == NULL) return 1;
-
- if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) {
- stlink_exit_dfu_mode(sl);
- }
-
- if(stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
- stlink_enter_swd_mode(sl);
- }
-
- stlink_identify_device(sl);
- printf("Chip ID is %08x, Core ID is %08x.\n", sl->chip_id, sl->core_id);
-
- sl->verbose=0;
+ }
- const struct chip_params* params = NULL;
+ if (optind < argc) {
+ printf("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf("%s ", argv[optind++]);
+ printf("\n");
+ }
+ return 0;
+}
- for(int i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
- if(devices[i].chip_id == (sl->chip_id & 0xFFF)) {
- params = &devices[i];
- break;
- }
- }
- if(params == NULL) {
- fprintf(stderr, "Cannot recognize the connected device!\n");
- return 0;
- }
+int main(int argc, char** argv) {
- printf("Device connected: %s\n", params->description);
+ stlink_t *sl = NULL;
- if(sl->chip_id==STM32F4_CHIP_ID) {
- flash_size=0x100000; //todo: RM0090 error; size register same address as unique ID
- printf("Device parameters: SRAM: 0x%x bytes, Flash: up to 0x%x bytes with variable page size\n",
- params->sram_size, flash_size);
- }
- else {
- printf("Device parameters: SRAM: 0x%x bytes, Flash: up to 0x%x bytes in pages of 0x%x bytes\n",
- params->sram_size, params->max_flash_size, params->flash_pagesize);
- stlink_read_mem32(sl, params->flash_size_reg, 4);
- flash_size = sl->q_buf[0] | (sl->q_buf[1] << 8);
- //flash_size_reg is in 1k blocks.
- flash_size *= 0x400;
- }
+ st_state_t state;
+ memset(&state, 0, sizeof(state));
+ // set defaults...
+ state.stlink_version = 2;
+ state.logging_level = DEFAULT_LOGGING_LEVEL;
+ state.listen_port = DEFAULT_GDB_LISTEN_PORT;
+ parse_options(argc, argv, &state);
+ switch (state.stlink_version) {
+ case 2:
+ sl = stlink_open_usb(state.logging_level);
+ if(sl == NULL) return 1;
+ break;
+ case 1:
+ sl = stlink_v1_open(state.logging_level);
+ if(sl == NULL) return 1;
+ break;
+ }
+
- uint32_t chip_id = sl->chip_id;
- uint32_t core_id = sl->core_id;
++ printf("Chip ID is %08x, Core ID is %08x.\n", sl->chip_id, sl->core_id);
- /* Fix chip_id for F4 */
- if (((chip_id & 0xFFF) == 0x411) && (core_id == CORE_M4_R0)) {
- printf("Fixing wrong chip_id for STM32F4 Rev A errata\n");
- chip_id = 0x413;
- }
-
- printf("Chip ID is %08x, Core ID is %08x.\n", chip_id, core_id);
- /* Init PAGE_SIZE for fixed page size devices.
- * stlink_calculate_pagesize will then return this value for them.
- * variable pagesize devices must allways update FLASH_PAGE before use! */
- FLASH_PAGE = params->flash_pagesize;
- sl->flash_size=flash_size;
++ sl->verbose=0;
- printf("Flash size is %d\n", flash_size);
- current_memory_map = make_memory_map(sl, params, flash_size);
+ current_memory_map = make_memory_map(sl);
- while(serve(sl, port) == 0);
+ while(serve(sl, state.listen_port) == 0);
/* Switch back to mass storage mode before closing. */
stlink_run(sl);
char* map = malloc(4096);
map[0] = '\0';
- snprintf(map, 4096, memory_map_template,
+ if(sl->chip_id==STM32F4_CHIP_ID) {
+ strcpy(map, memory_map_template_F4);
- }
-
- else {
- snprintf(map, 4096, memory_map_template,
- flash_size,
- params->sram_size,
- flash_size, params->flash_pagesize,
- params->bootrom_base, params->bootrom_size);
++ } else {
++ snprintf(map, 4096, memory_map_template,
+ sl->flash_size,
+ sl->sram_size,
+ sl->flash_size, sl->flash_pgsz,
+ sl->sys_base, sl->sys_size);
-
+ }
return map;
}
return sl->core_id;
}
- uint16_t stlink_chip_id(stlink_t *sl) {
-void stlink_identify_device(stlink_t *sl) {
- uint32_t core_id=stlink_core_id(sl);
- stlink_read_mem32(sl, 0xE0042000, 4);
++uint32_t stlink_chip_id(stlink_t *sl) {
+ stlink_read_mem32(sl, 0xE0042000, 4);
uint32_t chip_id = sl->q_buf[0] | (sl->q_buf[1] << 8) | (sl->q_buf[2] << 16) |
(sl->q_buf[3] << 24);
- /* Fix chip_id for F4 */
- if (((chip_id & 0xFFF) == 0x411) && (core_id == CORE_M4_R0)) {
- //printf("Fixing wrong chip_id for STM32F4 Rev A errata\n");
- chip_id = 0x413;
- }
- sl->chip_id=chip_id;
- sl->core_id=core_id;
+ return chip_id;
}
/**
return;
}
- sl->core_id = stlink_core_id(sl);
-
+/**
+ * reads and decodes the flash parameters, as dynamically as possible
+ * @param sl
+ * @return 0 for success, or -1 for unsupported core type.
+ */
+int stlink_load_device_params(stlink_t *sl) {
+ ILOG("Loading device parameters....\n");
+ const chip_params_t *params = NULL;
++
++ sl->core_id = stlink_core_id(sl);
+ uint32_t chip_id = stlink_chip_id(sl);
++
++ /* Fix chip_id for F4 rev A errata */
++ if (((chip_id & 0xFFF) == 0x411) && (sl->core_id == CORE_M4_R0)) {
++ chip_id = 0x413;
++ }
++
+ sl->chip_id = chip_id;
+ for(size_t i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
+ if(devices[i].chip_id == (chip_id & 0xFFF)) {
+ params = &devices[i];
+ break;
+ }
+ }
+ if (params == NULL) {
+ WLOG("unknown chip id! %#x\n", chip_id);
+ return -1;
+ }
+
+ // These are fixed...
+ sl->flash_base = STM32_FLASH_BASE;
+ sl->sram_base = STM32_SRAM_BASE;
+
+ // read flash size from hardware, if possible...
+ if ((chip_id & 0xFFF) == STM32_CHIPID_F2) {
+ sl->flash_size = 0; // FIXME - need to work this out some other way, just set to max possible?
++ } else if ((chip_id & 0xFFF) == STM32_CHIPID_F4) {
++ sl->flash_size = 0x100000; //todo: RM0090 error; size register same address as unique ID
+ } else {
+ stlink_read_mem32(sl, params->flash_size_reg, 4);
+ uint32_t flash_size = sl->q_buf[0] | (sl->q_buf[1] << 8);
+ sl->flash_size = flash_size * 1024;
+ }
+ sl->flash_pgsz = params->flash_pagesize;
+ sl->sram_size = params->sram_size;
+ sl->sys_base = params->bootrom_base;
+ sl->sys_size = params->bootrom_size;
+
+ ILOG("Device connected is: %s\n", params->description);
++ // TODO make note of variable page size here.....
+ ILOG("SRAM size: %#x bytes (%d KiB), Flash: %#x bytes (%d KiB) in pages of %zd bytes\n",
+ sl->sram_size, sl->sram_size / 1024, sl->flash_size, sl->flash_size / 1024,
+ sl->flash_pgsz);
+ return 0;
+}
+
void stlink_reset(stlink_t *sl) {
- D(sl, "\n*** stlink_reset ***\n");
+ DLOG("*** stlink_reset ***\n");
sl->backend->reset(sl);
}
return 0;
}
- * @param page
+ uint32_t calculate_F4_sectornum(uint32_t flashaddr){
+ flashaddr &= ~STM32_FLASH_BASE; //Page now holding the actual flash address
+ if (flashaddr<0x4000) return (0);
+ else if(flashaddr<0x8000) return(1);
+ else if(flashaddr<0xc000) return(2);
+ else if(flashaddr<0x10000) return(3);
+ else if(flashaddr<0x20000) return(4);
+ else return(flashaddr/0x20000)+4;
+
+ }
+
+ uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr){
+ if(sl->chip_id == STM32F4_CHIP_ID) {
+ uint32_t sector=calculate_F4_sectornum(flashaddr);
+ if (sector<4) sl->flash_pgsz=0x4000;
+ else if(sector<5) sl->flash_pgsz=0x10000;
+ else sl->flash_pgsz=0x20000;
+ }
+ return (sl->flash_pgsz);
+ }
+
+/**
+ * Erase a page of flash, assumes sl is fully populated with things like chip/core ids
+ * @param sl stlink context
- int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t page)
++ * @param flashaddr an address in the flash page to erase
+ * @return 0 on success -ve on failure
+ */
+ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
{
-- /* page an addr in the page to erase */
- ILOG("Erasing flash page at addr: %#x\n", page);
- if (sl->core_id == STM32L_CORE_ID)
-
- stlink_identify_device(sl);
-
++ ILOG("Erasing flash page at addr: %#x\n", flashaddr);
+ if (sl->chip_id == STM32F4_CHIP_ID)
+ {
+ /* wait for ongoing op to finish */
+ wait_flash_busy(sl);
+
+ /* unlock if locked */
+ unlock_flash_if(sl);
+
+ /* select the page to erase */
+ // calculate the actual page from the address
+ uint32_t sector=calculate_F4_sectornum(flashaddr);
+
+ fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x\n", sector, stlink_calculate_pagesize(sl, flashaddr));
+ write_flash_cr_snb(sl, sector);
+
+ /* start erase operation */
+ set_flash_cr_strt(sl);
+
+ /* wait for completion */
+ wait_flash_busy(sl);
+
+ /* relock the flash */
+ //todo: fails to program if this is in
+ lock_flash(sl);
+ #if DEBUG_FLASH
+ fprintf(stdout, "Erase Final CR:0x%x\n", read_flash_cr(sl));
+ #endif
+ }
-
+ else if (sl->core_id == STM32L_CORE_ID)
{
- #define STM32L_FLASH_REGS_ADDR ((uint32_t)0x40023c00)
- #define STM32L_FLASH_ACR (STM32L_FLASH_REGS_ADDR + 0x00)
- #define STM32L_FLASH_PECR (STM32L_FLASH_REGS_ADDR + 0x04)
- #define STM32L_FLASH_PDKEYR (STM32L_FLASH_REGS_ADDR + 0x08)
- #define STM32L_FLASH_PEKEYR (STM32L_FLASH_REGS_ADDR + 0x0c)
- #define STM32L_FLASH_PRGKEYR (STM32L_FLASH_REGS_ADDR + 0x10)
- #define STM32L_FLASH_OPTKEYR (STM32L_FLASH_REGS_ADDR + 0x14)
- #define STM32L_FLASH_SR (STM32L_FLASH_REGS_ADDR + 0x18)
- #define STM32L_FLASH_OBR (STM32L_FLASH_REGS_ADDR + 0x0c)
- #define STM32L_FLASH_WRPR (STM32L_FLASH_REGS_ADDR + 0x20)
uint32_t val;
/* relock the flash */
lock_flash(sl);
}
+
else {
- fprintf(stderr, "unknown device!\n");
+ WLOG("unknown coreid: %x\n", sl->core_id);
return -1;
}
int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned len) {
size_t off;
flash_loader_t fl;
-
- stlink_identify_device(sl);
-
+ ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n",
+ len, len, addr, addr);
/* check addr range is inside the flash */
+ stlink_calculate_pagesize(sl, addr);
if (addr < sl->flash_base) {
- fprintf(stderr, "addr too low\n");
+ WLOG("addr too low %#x < %#x\n", addr, sl->flash_base);
return -1;
} else if ((addr + len) < addr) {
- fprintf(stderr, "addr overruns\n");
+ WLOG("addr overruns\n");
return -1;
} else if ((addr + len) > (sl->flash_base + sl->flash_size)) {
- fprintf(stderr, "addr too high\n");
+ WLOG("addr too high\n");
return -1;
} else if ((addr & 1) || (len & 1)) {
- fprintf(stderr, "unaligned addr or size\n");
+ WLOG("unaligned addr or size\n");
return -1;
} else if (addr & (sl->flash_pgsz - 1)) {
- fprintf(stderr, "addr not a multiple of pagesize, not supported\n");
+ WLOG("addr not a multiple of pagesize, not supported\n");
return -1;
}
+ // Make sure we've loaded the context with the chip details
+ stlink_core_id(sl);
/* erase each page */
- for (off = 0; off < len; off += stlink_calculate_pagesize(sl, addr + off) ) {
- //addr must be an addr inside the page
+ int page_count = 0;
- for (off = 0; off < len; off += sl->flash_pgsz) {
++ for (off = 0; off < len; off += stlink_calculate_pagesize(sl, addr + off)) {
+ /* addr must be an addr inside the page */
if (stlink_erase_flash_page(sl, addr + off) == -1) {
- fprintf(stderr, "erase_flash_page(0x%zx) == -1\n", addr + off);
- return -1;
+ WLOG("Failed to erase_flash_page(%#zx) == -1\n", addr + off);
+ return -1;
}
+ page_count++;
}
-
-#if 1 /* todo: use in debugging mode only */
- fprintf(stdout, "WriteFlash - Addr:0x%x len:0x%x\n", addr, len);
- //fprintf(stdout, "CoreID:0x%x ChipID:0x%x\n", sl->core_id, sl->chip_id);
-#endif
-
+ ILOG("Finished erasing %d pages of %d (%#x) bytes\n",
+ page_count, sl->flash_pgsz, sl->flash_pgsz);
- if (sl->core_id == STM32L_CORE_ID)
- {
- /* use fast word write. todo: half page. */
+ if (sl->chip_id == STM32F4_CHIP_ID) {
+ /* todo: check write operation */
- uint32_t val;
+ /* First unlock the cr */
+ unlock_flash_if(sl);
- #if 0 /* todo: check write operation */
+ /* set parallelisim to 32 bit*/
+ write_flash_cr_psiz(sl, 2);
- uint32_t nwrites = sl->flash_pgsz;
+ /* set programming mode */
+ set_flash_cr_pg(sl);
- redo_write:
+ #define PROGRESS_CHUNK_SIZE 0x1000
+ /* write a word in program memory */
+ for (off = 0; off < len; off += sizeof(uint32_t)) {
+ if (sl->verbose >= 1) {
+ if ((off & (PROGRESS_CHUNK_SIZE - 1)) == 0) {
+ /* show progress. writing procedure is slow
+ and previous errors are misleading */
+ const uint32_t pgnum = (off / PROGRESS_CHUNK_SIZE)+1;
+ const uint32_t pgcount = len / PROGRESS_CHUNK_SIZE;
+ fprintf(stdout, "Writing %ukB chunk %u out of %u\n", PROGRESS_CHUNK_SIZE/1024, pgnum, pgcount);
+ }
+ }
- #endif /* todo: check write operation */
+ memcpy(sl->q_buf, (const void*)(base + off), sizeof(uint32_t));
+ stlink_write_mem32(sl, addr + off, sizeof(uint32_t));
- /* disable pecr protection */
- write_uint32(sl->q_buf, 0x89abcdef);
- stlink_write_mem32(sl, STM32L_FLASH_PEKEYR, sizeof(uint32_t));
- write_uint32(sl->q_buf, 0x02030405);
- stlink_write_mem32(sl, STM32L_FLASH_PEKEYR, sizeof(uint32_t));
-
- /* check pecr.pelock is cleared */
- stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
- val = read_uint32(sl->q_buf, 0);
- if (val & (1 << 0))
- {
- fprintf(stderr, "pecr.pelock not clear\n");
- return -1;
- }
+ /* wait for sr.busy to be cleared */
+ wait_flash_busy(sl);
- /* unlock program memory */
- write_uint32(sl->q_buf, 0x8c9daebf);
- stlink_write_mem32(sl, STM32L_FLASH_PRGKEYR, sizeof(uint32_t));
- write_uint32(sl->q_buf, 0x13141516);
- stlink_write_mem32(sl, STM32L_FLASH_PRGKEYR, sizeof(uint32_t));
-
- /* check pecr.prglock is cleared */
- stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
- val = read_uint32(sl->q_buf, 0);
- if (val & (1 << 1))
- {
- fprintf(stderr, "pecr.prglock not clear\n");
- return -1;
- }
+ }
+ /* Relock flash */
+ lock_flash(sl);
- /* write a word in program memory */
- for (off = 0; off < len; off += sizeof(uint32_t))
- {
- if (sl->verbose >= 1)
- {
- if ((off & (sl->flash_pgsz - 1)) == 0)
- {
- /* show progress. writing procedure is slow
- and previous errors are misleading */
- const uint32_t pgnum = off / sl->flash_pgsz;
- const uint32_t pgcount = len / sl->flash_pgsz;
- fprintf(stdout, "%u pages written out of %u\n", pgnum, pgcount);
- }
- }
+ #if 0 /* todo: debug mode */
+ fprintf(stdout, "Final CR:0x%x\n", read_flash_cr(sl));
+ #endif
- memcpy(sl->q_buf, (const void*)(base + off), sizeof(uint32_t));
- stlink_write_mem32(sl, addr + off, sizeof(uint32_t));
- /* wait for sr.busy to be cleared */
- while (1)
- {
- stlink_read_mem32(sl, STM32L_FLASH_SR, sizeof(uint32_t));
- if ((read_uint32(sl->q_buf, 0) & (1 << 0)) == 0) break ;
- }
- #if 0 /* todo: check redo write operation */
+ } //STM32F4END
- /* check written bytes. todo: should be on a per page basis. */
- stlink_read_mem32(sl, addr + off, sizeof(uint32_t));
- if (memcmp(sl->q_buf, base + off, sizeof(uint32_t)))
- {
- /* re erase the page and redo the write operation */
- uint32_t page;
- uint32_t val;
+ else if (sl->core_id == STM32L_CORE_ID) {
+ /* use fast word write. todo: half page. */
- /* fail if successive write count too low */
- if (nwrites < sl->flash_pgsz) {
- fprintf(stderr, "writes operation failure count too high, aborting\n");
- return -1;
- }
+ uint32_t val;
- nwrites = 0;
+ #if 0 /* todo: check write operation */
- /* assume addr aligned */
- if (off % sl->flash_pgsz) off &= ~(sl->flash_pgsz - 1);
- page = addr + off;
+ uint32_t nwrites = sl->flash_pgsz;
- fprintf(stderr, "invalid write @%x(%x): %x != %x. retrying.\n",
- page, addr + off, read_uint32(base + off, 0), read_uint32(sl->q_buf, 0));
+ redo_write:
- /* reset lock bits */
- stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
- val = read_uint32(sl->q_buf, 0) | (1 << 0) | (1 << 1) | (1 << 2);
- write_uint32(sl->q_buf, val);
- stlink_write_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+ #endif /* todo: check write operation */
- stlink_erase_flash_page(sl, page);
+ /* disable pecr protection */
+ write_uint32(sl->q_buf, 0x89abcdef);
+ stlink_write_mem32(sl, STM32L_FLASH_PEKEYR, sizeof(uint32_t));
+ write_uint32(sl->q_buf, 0x02030405);
+ stlink_write_mem32(sl, STM32L_FLASH_PEKEYR, sizeof(uint32_t));
+
+ /* check pecr.pelock is cleared */
+ stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+ val = read_uint32(sl->q_buf, 0);
+ if (val & (1 << 0)) {
+ fprintf(stderr, "pecr.pelock not clear\n");
+ return -1;
+ }
+
+ /* unlock program memory */
+ write_uint32(sl->q_buf, 0x8c9daebf);
+ stlink_write_mem32(sl, STM32L_FLASH_PRGKEYR, sizeof(uint32_t));
+ write_uint32(sl->q_buf, 0x13141516);
+ stlink_write_mem32(sl, STM32L_FLASH_PRGKEYR, sizeof(uint32_t));
+
+ /* check pecr.prglock is cleared */
+ stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+ val = read_uint32(sl->q_buf, 0);
+ if (val & (1 << 1)) {
+ fprintf(stderr, "pecr.prglock not clear\n");
+ return -1;
+ }
+
+ /* write a word in program memory */
+ for (off = 0; off < len; off += sizeof(uint32_t)) {
+ if (sl->verbose >= 1) {
+ if ((off & (sl->flash_pgsz - 1)) == 0) {
+ /* show progress. writing procedure is slow
+ and previous errors are misleading */
+ const uint32_t pgnum = off / sl->flash_pgsz;
+ const uint32_t pgcount = len / sl->flash_pgsz;
+ fprintf(stdout, "%u pages written out of %u\n", pgnum, pgcount);
+ }
+ }
+
+ memcpy(sl->q_buf, (const void*)(base + off), sizeof(uint32_t));
+ stlink_write_mem32(sl, addr + off, sizeof(uint32_t));
+
+ /* wait for sr.busy to be cleared */
+ while (1) {
+ stlink_read_mem32(sl, STM32L_FLASH_SR, sizeof(uint32_t));
+ if ((read_uint32(sl->q_buf, 0) & (1 << 0)) == 0) break ;
+ }
- goto redo_write;
- }
+ #if 0 /* todo: check redo write operation */
- /* increment successive writes counter */
- ++nwrites;
+ /* check written bytes. todo: should be on a per page basis. */
+ stlink_read_mem32(sl, addr + off, sizeof(uint32_t));
+ if (memcmp(sl->q_buf, base + off, sizeof(uint32_t))) {
+ /* re erase the page and redo the write operation */
+ uint32_t page;
+ uint32_t val;
- #endif /* todo: check redo write operation */
+ /* fail if successive write count too low */
+ if (nwrites < sl->flash_pgsz) {
+ fprintf(stderr, "writes operation failure count too high, aborting\n");
+ return -1;
+ }
- }
+ nwrites = 0;
- /* reset lock bits */
- stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
- val = read_uint32(sl->q_buf, 0) | (1 << 0) | (1 << 1) | (1 << 2);
- write_uint32(sl->q_buf, val);
- stlink_write_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+ /* assume addr aligned */
+ if (off % sl->flash_pgsz) off &= ~(sl->flash_pgsz - 1);
+ page = addr + off;
+
+ fprintf(stderr, "invalid write @0x%x(0x%x): 0x%x != 0x%x. retrying.\n",
+ page, addr + off, read_uint32(base + off, 0), read_uint32(sl->q_buf, 0));
+
+ /* reset lock bits */
+ stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+ val = read_uint32(sl->q_buf, 0) | (1 << 0) | (1 << 1) | (1 << 2);
+ write_uint32(sl->q_buf, val);
+ stlink_write_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+
+ stlink_erase_flash_page(sl, page);
+
+ goto redo_write;
+ }
+
+ /* increment successive writes counter */
+ ++nwrites;
+
+ #endif /* todo: check redo write operation */
+ }
+ /* reset lock bits */
+ stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+ val = read_uint32(sl->q_buf, 0) | (1 << 0) | (1 << 1) | (1 << 2);
+ write_uint32(sl->q_buf, val);
+ stlink_write_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
- }
-
-
-
+ } else if (sl->core_id == STM32VL_CORE_ID) {
+ ILOG("Starting Flash write for VL core id\n");
+ /* flash loader initialization */
+ if (init_flash_loader(sl, &fl) == -1) {
+ WLOG("init_flash_loader() == -1\n");
+ return -1;
+ }
- else if (sl->core_id == STM32VL_CORE_ID) {
- /* flash loader initialization */
- if (init_flash_loader(sl, &fl) == -1) {
- fprintf(stderr, "init_flash_loader() == -1\n");
- return -1;
- }
- /* write each page. above WRITE_BLOCK_SIZE fails? */
+ /* write each page. above WRITE_BLOCK_SIZE fails? */
#define WRITE_BLOCK_SIZE 0x40
- for (off = 0; off < len; off += WRITE_BLOCK_SIZE) {
- /* adjust last write size */
- size_t size = WRITE_BLOCK_SIZE;
- if ((off + WRITE_BLOCK_SIZE) > len) size = len - off;
-
- /* unlock and set programming mode */
- unlock_flash_if(sl);
- set_flash_cr_pg(sl);
-
- if (run_flash_loader(sl, &fl, addr + off, base + off, size) == -1) {
- fprintf(stderr, "run_flash_loader(0x%zx) == -1\n", addr + off);
- return -1;
- }
- lock_flash(sl);
- }
- }
-
-
-
-
- else
- {
- fprintf(stderr, "unknown device!\n");
- return -1;
+ int write_block_count = 0;
+ for (off = 0; off < len; off += WRITE_BLOCK_SIZE) {
+ ILOG("Writing flash block %d of size %d (%#x)\n", write_block_count,
+ WRITE_BLOCK_SIZE, WRITE_BLOCK_SIZE);
+ /* adjust last write size */
+ size_t size = WRITE_BLOCK_SIZE;
+ if ((off + WRITE_BLOCK_SIZE) > len) size = len - off;
+
+ /* unlock and set programming mode */
+ unlock_flash_if(sl);
+ set_flash_cr_pg(sl);
+ //DLOG("Finished setting flash cr pg, running loader!\n");
+ if (run_flash_loader(sl, &fl, addr + off, base + off, size) == -1) {
+ WLOG("run_flash_loader(%#zx) failed! == -1\n", addr + off);
+ return -1;
+ }
+ lock_flash(sl);
+ DLOG("Finished writing block %d\n", write_block_count++);
+ }
+ } else {
+ WLOG("unknown coreid, not sure how to write: %x\n", sl->core_id);
+ return -1;
}
-
-
-
-
-#if(0)
- //todo: F4 Can't stlink_read_mem32 an entire sector, not enough ram!
+ ILOG("Starting verification of write complete\n");
for (off = 0; off < len; off += sl->flash_pgsz) {
size_t aligned_size;
if (aligned_size & (4 - 1))
aligned_size = (cmp_size + 4) & ~(4 - 1);
- fprintf(stdout, "AlignedSize:0x%x\n", aligned_size);
++ fprintf(stdout, "AlignedSize:%#zx\n", aligned_size);
stlink_read_mem32(sl, addr + off, aligned_size);
if (memcmp(sl->q_buf, base + off, cmp_size))
#define STM32VL_CORE_ID 0x1ba01477
#define STM32L_CORE_ID 0x2ba01477
#define STM32F4_CORE_ID 0x2ba01477
+
+// stm32 chipids, only lower 12 bits..
+#define STM32_CHIPID_F1_MEDIUM 0x410
+#define STM32_CHIPID_F2 0x411
+#define STM32_CHIPID_F1_LOW 0x412
+#define STM32_CHIPID_F4 0x413
+#define STM32_CHIPID_F1_HIGH 0x414
+#define STM32_CHIPID_L1_MEDIUM 0x416
+#define STM32_CHIPID_F1_CONN 0x418
+#define STM32_CHIPID_F1_VL_MEDIUM 0x420
+#define STM32_CHIPID_F1_VL_HIGH 0x428
+#define STM32_CHIPID_F1_XL 0x430
+
+// Constant STM32 memory map figures
+#define STM32_FLASH_BASE 0x08000000
+#define STM32_SRAM_BASE 0x20000000
+ /*
+ * Chip IDs are explained in the appropriate programming manual for the
+ * DBGMCU_IDCODE register (0xE0042000)
+ */
+ #define CORE_M3_R1 0x1BA00477
+ #define CORE_M3_R2 0x4BA00477
+ #define CORE_M4_R0 0x2BA01477
+
+ /* using chip id for F4 ident, since core id is same as F1 */
+ #define STM32F4_CHIP_ID 0x413
+
/* Enough space to hold both a V2 command or a V1 command packaged as generic scsi*/
#define C_BUF_LEN 32
- .flash_size_reg = 0x1FFF7A10,
- .flash_pagesize = 0x20000,
+ typedef struct chip_params_ {
+ uint32_t chip_id;
+ char* description;
+ uint32_t flash_size_reg;
+ uint32_t flash_pagesize;
+ uint32_t sram_size;
+ uint32_t bootrom_base, bootrom_size;
+ } chip_params_t;
+
+
+ // These maps are from a combination of the Programming Manuals, and
+ // also the Reference manuals. (flash size reg is normally in ref man)
+ static const chip_params_t devices[] = {
+ { // table 2, PM0063
+ .chip_id = 0x410,
+ .description = "F1 Medium-density device",
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x400,
+ .sram_size = 0x5000,
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ { // table 1, PM0059
+ .chip_id = 0x411,
+ .description = "F2 device",
+ .flash_size_reg = 0, /* no flash size reg found in the docs! */
+ .flash_pagesize = 0x20000,
+ .sram_size = 0x20000,
+ .bootrom_base = 0x1fff0000,
+ .bootrom_size = 0x7800
+ },
+ { // PM0063
+ .chip_id = 0x412,
+ .description = "F1 Low-density device",
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x400,
+ .sram_size = 0x2800,
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ {
+ .chip_id = 0x413,
+ .description = "F4 device",
++ .flash_size_reg = 0x1FFF7A10, //RM0090 error same as unique ID
++ .flash_pagesize = 0x4000,
+ .sram_size = 0x30000,
+ .bootrom_base = 0x1fff0000,
+ .bootrom_size = 0x7800
+ },
+ {
+ .chip_id = 0x414,
+ .description = "F1 High-density device",
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x800,
+ .sram_size = 0x10000,
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ {
+ // This ignores the EEPROM! (and uses the page erase size,
+ // not the sector write protection...)
+ .chip_id = 0x416,
+ .description = "L1 Med-density device",
+ .flash_size_reg = 0x1ff8004c,
+ .flash_pagesize = 0x100,
+ .sram_size = 0x4000,
+ .bootrom_base = 0x1ff00000,
+ .bootrom_size = 0x1000
+ },
+ {
+ .chip_id = 0x418,
+ .description = "F1 Connectivity line device",
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x800,
+ .sram_size = 0x10000,
+ .bootrom_base = 0x1fffb000,
+ .bootrom_size = 0x4800
+ },
+ {
+ .chip_id = 0x420,
+ .description = "F1 Medium-density Value Line device",
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x400,
+ .sram_size = 0x2000,
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ {
+ .chip_id = 0x428,
+ .description = "F1 High-density value line device",
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x800,
+ .sram_size = 0x8000,
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ {
+ .chip_id = 0x430,
+ .description = "F1 XL-density device",
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x800,
+ .sram_size = 0x18000,
+ .bootrom_base = 0x1fffe000,
+ .bootrom_size = 0x1800
+ }
+ };
+
+
typedef struct {
uint32_t r[16];
uint32_t xpsr;
// transport layer verboseness: 0 for no debug info, 10 for lots
int verbose;
uint32_t core_id;
- uint16_t chip_id;
+ uint32_t chip_id;
int core_stat;
-
-
- /* medium density stm32 flash settings */
-#define STM32_FLASH_BASE 0x08000000
-#define STM32_FLASH_SIZE (128 * 1024)
#define STM32_FLASH_PGSZ 1024
#define STM32L_FLASH_PGSZ 256
+
+ #define STM32F4_FLASH_PGSZ 16384
+ #define STM32F4_FLASH_SIZE (128 * 1024 * 8)
+
stm32_addr_t flash_base;
size_t flash_size;
size_t flash_pgsz;
int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr);
// PUBLIC
-- uint16_t stlink_chip_id(stlink_t *sl);
++ uint32_t stlink_chip_id(stlink_t *sl);
void stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid);
// privates, publics, the rest....
printf("-- mode after entering swd mode: %d\n", stlink_current_mode(sl));
- printf("-- chip id: %#x\n", stlink_chip_id(sl));
- printf("-- core_id: %#x\n", stlink_core_id(sl));
- stlink_identify_device(sl);
+ printf("-- chip id: %#x\n", sl->chip_id);
+ printf("-- core_id: %#x\n", sl->core_id);
cortex_m3_cpuid_t cpuid;
stlink_cpu_id(sl, &cpuid);